A custom 8-bit CPU designed and implemented in Verilog, targeting a Gowin FPGA. The CPU executes programs loaded from ROM and includes a Python-based assembler for writing and compiling assembly programs.
The CPU uses a clocked state machine with the following pipeline stages: Fetch, Fetch More (for two-byte instructions), Decode, Execute, and dedicated memory wait/write states for load and store operations.
The address space is 16-bit and is divided into three regions:
| Region | Range | Purpose |
|---|---|---|
| ROM | 0x0000 – 0x00FF | Program storage (read-only) |
| RAM | 0x0100 – 0x01FF | Data storage (read/write) |
| IO | 0x0200 – 0x02FF | Reserved for future I/O devices |
The CPU has four general-purpose 8-bit registers: R1, R2, R3, and R4.
The ALU produces three flags: Zero, Sign, and Carry.
The final ALU result is displayed on six on-board LEDs as a binary number. LED output is active-low.
Instructions are either one byte (register operations) or two bytes (immediate and memory operations). The instruction byte encodes the destination register in bits [7:6], the source register in bits [5:4], and the opcode in bits [3:0].
| Mnemonic | Format | Description |
|---|---|---|
NOP |
NOP |
No operation |
ADD |
ADD Rd, Rs |
Rd = Rd + Rs |
SUB |
SUB Rd, Rs |
Rd = Rd - Rs |
AND |
AND Rd, Rs |
Rd = Rd & Rs |
OR |
OR Rd, Rs |
Rd = Rd | Rs |
MOV |
MOV Rd, Rs |
Rd = Rs |
NOT |
NOT Rd |
Rd = ~Rd |
LDA |
LDA Rd, addr |
Rd = RAM[addr] |
STA |
STA Rs, addr |
RAM[addr] = Rs |
ADDI |
ADDI Rd, imm |
Rd = Rd + imm |
SUBI |
SUBI Rd, imm |
Rd = Rd - imm |
ANDI |
ANDI Rd, imm |
Rd = Rd & imm |
ORI |
ORI Rd, imm |
Rd = Rd | imm |
MOVI |
MOVI Rd, imm |
Rd = imm |
Immediate values and memory addresses are 8-bit (0–255). Comments in assembly begin with ;. Registers are R1–R4. Immediates can be written in decimal, hex (0x), or binary (0b).
tinycpu-asm.py assembles .asm source files into .hex files compatible with Verilog's $readmemh(), which the ROM module uses to initialize program memory at synthesis or simulation time.
Assemble a program:
python tinycpu-asm.py program.asm -o data.hex
Optional flags:
| Flag | Description |
|---|---|
-o <file> |
Output file path (defaults to <input>.hex) |
--pad <N> |
Pad output to N bytes with NOPs |
--selftest |
Run built-in instruction encoding tests and exit |
Run the self-test:
python tinycpu-asm.py --selftest
The self-test validates the encoding of every instruction type and reports pass/fail for each case.
Open 8_Bit_Project.gprj in Gowin EDA. Synthesize, place and route, then program the FPGA using the generated .fs bitstream. The ROM is initialized from data.hex at synthesis time — re-synthesize after assembling a new program.