This is a simple CPU design written in Verilog for EE2026 Project. It is based on Basic CPU.
This design is made for the Sipeed Tang Nano FPGA board (I have written an article about this board), created on the Gowin IDE. However, it should be easy to port the code to any other FPGA board/chip.
When I created this repo, I just opened a bottle of Nutri-Express, thus came up with this name.
https://www.edaplayground.com/x/4RjK
The NECPU is a 32-bit general purpose register architecture processor with the specifications below. Registers $rs
, $rt
, and $rd
are placeholders for actual general purpose registers $0
, $1
, $2
, ..., $31
, each holding a 32-bit value. immediate
refers to an immediate value (constant) and label
refers to label in the instruction corresponding to a specific line in the code. All immediates are given as 16-bit unsigned values. Whenever an immediate is used as an operand with a register as the other operand, the immediate is zero-extended to 32-bit before computation. All labels will be converted into actual addresses using direct addressing mode.
NECPU can accomodate up to 4294967296 (2^32) addressable memory where each memory location holds 4 bytes (32 bits). NECPU is word (4 bytes) addressable. (It is not byte addressable!)
Except for LW
, every other instruction of NECPU takes exactly one clock cycle to complete. The LW
instruction, however, take 2 clock cycles to complete, since it can only read in data from external memory after the external has responded to the address output Note that the write operation of SW
actually happens half a clock cycle after the execution of the instruction. It should not affec the expected behaviour of the programme in any other ways. Hence, the time taken of a code snippet can easily be calculated.
We will use the following convension to simplify our description:
- Given a register
$r
, the content of the register$r
is given asR[$r]
. - Given a memory location
addr
, the content at the memory locationaddr
isM[addr]
. PC
is the program counter which is a special register that holds the address of the instruction currently being executed.
Instruction Format | Name | Operation |
---|---|---|
NOP | No-Op | Do nothing |
LW $rd , $rs , immediate |
Load Word | R[$rd] = M[R[$rs] + immediate] |
SW $rd , $rs , immediate |
Store Word | M[R[$rs] + immediate] = R[$rd] |
LLI $rd , immediate |
Load Lower Immediate | R[$rd][15:0] = immediate |
LUI $rd , immediate |
Load Upper Immediate | R[$rd][31:16] = immediate |
SLT $rd , $rs , $rt |
Set Less Than | R[$rd] = R[$rs] < R[$rt] |
SEQ $rd , $rs , $rt |
Set Equal | R[$rd] = R[$rs] == R[$rt] |
BEQ $rd , immediate |
Branch On Equal | PC = PC + (R[$rd] == immediate ? 2 : 1) |
BNE $rd , immediate |
Branch On Not Equal | PC = PC + (R[$rd] != immediate ? 2 : 1) |
ADD $rd , $rs , $rt |
Add | R[$rd] = R[$rs] + R[$rt] |
ADDi $rd , $rs , immediate |
Add immediate | R[$rd] = R[$rs] + immediate |
SUB $rd , $rs , $rt |
Subtract | R[$rd] = R[$rs] - R[$rt] |
SUBi $rd , $rs , immediate |
Subtract Immediate | R[$rd] = R[$rs] - immediate |
SLL $rd , $rs , $rt |
Shift Left Logical | R[$rd] = R[$rs] << R[$rt] |
SRL $rd , $rs , $rt |
Shift Right Logical | R[$rd] = R[$rs] >> R[$rt] |
AND $rd , $rs , $rt |
And | R[$rd] = R[$rs] & R[$rt] |
ANDi $rd , $rs , immediate |
And Immediate | R[$rd] = R[$rs] & immediate |
OR $rd , $rs , $rt |
Or | R[$rd] = R[$rs] |
ORi $rd , $rs , immediate |
Or Immediate | R[$rd] = R[$rs] |
INV $rd , $rs |
Invert | R[$rd] = ~ R[$rs] |
XOR $rd , $rs , $rt |
Xor | R[$rd] = R[$rs] ^ R[$rt] |
XORi $rd , $rs , immediate |
Xor Immediate | R[$rd] = R[$rs] ^ immediate |
JMP $rd |
Unconditional Jump | PC = R[$rd] |
- Type A
- SLT
- SEQ
- ADD
- SUB
- SLL
- SRL
- AND
- OR
- INV (
$rt
ignored) - XOR
- Type B
- LW
- SW
- LLI (
$rs
ignored) - LUI (
$rs
ignored) - BEQ (
$rs
ignored) - BNE (
$rs
ignored) - ADDi
- SUBi
- ANDi
- ORi
- XORi
- JMP (can also put under type A since only
$rd
is used)
Note that the BEQ
and BNE
instructions of NECPU differ from those of MIPS:
- NECPU's
BEQ
andBNE
instructions compare a register's value with animmediate
, while MIPS compares the values of two registers. - NECPU's
BEQ
andBNE
instructions can only skip the next one instruction if the condition is satisfied.
- Write testbenches for all instructions
- Extract Instruction memory out of the CPU module
- Port to Vivado/Xilinx Artix-7
- More detailed documentation