# CPU in 40 lines of SV
This project builds a small 16-bit CPU in five incremental steps.
Each step is complete, and adds only few new lines.
Programs are written directly in SV testbench.
[Full CPU here](#full-cpu-40-loc).
```{raw} html
16-bit CPU circuit in 7nm (ASAP7) visualized in 3D. Drag to rotate, scroll to zoom.
```
### Quickstart
```bash
make fresh # if you havent started the container
make enter # to enter the running container
make sim gtkwave DESIGN=cpu_3_store_data # simulate the step 3 design & view waveform
# Ctrl+C to exit gtkwave
make sim gtkwave DESIGN=cpu_factorial # run factorial on the final CPU
make gds show_layout DESIGN=cpu_factorial # Run GDS flow
```
Example programs:
* [`sum_to_n`](https://github.com/abarajithan11/digital-design/blob/main/material/tb/cpu/tb_cpu_sum_to_n.sv)
* [`dot_product`](https://github.com/abarajithan11/digital-design/blob/main/material/tb/cpu/tb_cpu_dot_product.sv)
* [`factorial`](https://github.com/abarajithan11/digital-design/blob/main/material/tb/cpu/tb_cpu_factorial.sv)
* [`fibonacci`](https://github.com/abarajithan11/digital-design/blob/main/material/tb/cpu/tb_cpu_fibonacci.sv)
## Incremental evolution
| Level | Feature | RTL |
| --- | --- | --- |
| `0_memory` | Simple memory with zero-latency read and 1-cycle-latency write | [RTL](https://github.com/abarajithan11/digital-design/blob/main/material/rtl/cpu/memory.sv) |
| `1_load_instruction` | Just a counter to load instructions (PC) | [RTL](https://github.com/abarajithan11/digital-design/blob/main/material/rtl/cpu/cpu_1_load_instruction.sv) |
| `2_load_data_into_registers` | Sixteen registers and `LOAD` | [RTL](https://github.com/abarajithan11/digital-design/blob/main/material/rtl/cpu/cpu_2_load_data_into_registers.sv) |
| `3_store_data` | `STORE` | [RTL](https://github.com/abarajithan11/digital-design/blob/main/material/rtl/cpu/cpu_3_store_data.sv) |
| `4_move_alu` | `MOVE`, `ADD`, `SUB`, and `MUL` | [RTL](https://github.com/abarajithan11/digital-design/blob/main/material/rtl/cpu/cpu_4_move_alu.sv) |
| `5_jump` | `JNZ`: jump to a given address if a given register is not zero | [RTL](https://github.com/abarajithan11/digital-design/blob/main/material/rtl/cpu/cpu_5_jump.sv) |
## CPU Design
* Only 7 opcodes: `LOAD=0`, `STORE=1`, `MOVE=2`, `ADD=3`, `SUB=4`, `MUL=5`, and `JNZ=6`.
* Two instruction formats:
* Address type: `LOAD, STORE, JNZ` take an `addr`ess and register index (`i_reg`)
* Register type: `MOVE, ADD, SUB, MUL` take indices of three registers. Two source (`i_rs1, i_rs2`) and one destination `i_rd`.
* `JNZ` jumps to the `addr` when `regs[i_reg]` is nonzero.
Instructions
Format
4 Bits [15:12]
4 Bits [11:8]
4 Bits [7:4]
4 Bits [3:0]
LOAD, STORE, JNZ
Address
addr
i_reg
opcode
MOVE, ADD, SUB, MUL
Register
i_rs2
i_rs1
i_rd
opcode
### Reading Instructions
Each instruction field is 4-bits, so it becomes a character when displayed as hex, making it easy to read binary. Read right to left (little endian). e.g.
```
0x 1250 : 0=LOAD regs[5] <- dmem[0x12]
0x 0123 : 3=ADD regs[2] <- regs[1] + regs[0]
```
Waveform of Fibonacci program:

## Full CPU (40 LOC)
```{literalinclude} ../material/rtl/cpu/cpu.sv
:language: systemverilog
```