A 16-bit microcontroller designed from scratch in Verilog, featuring an ALU with 9 operations, 4 general-purpose registers, program counter, MAR/MDR, instruction register, I/O ports, and 256×16 memory — all communicating over a shared tri-state bus. Instruction execution is driven by 8 independent finite state machines with MFC handshaking, coordinated by a top-level module.
┌─────────────────── 16-bit Shared Bus ───────────────────┐
│ │
┌──────┐ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ PC │◄──┼──►│ R0 │ │ R1 │ │ R2 │ │ R3 │ │
└──────┘ │ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
┌─────────┐ ┌─────┐ │ ┌──────┐ ┌──────┐ ┌───────────┐ │
│ Memory │◄─┤ MAR │◄──┼──►│ IR │ │ ID │ │ ALU │ │
│ 256x16 │ └─────┘ │ └──────┘ └──────┘ │ (9 ops) │ │
│ │ ┌─────┐ │ └───────────┘ │
│ │◄►│ MDR │◄──┤ ┌────────┐ ┌────────┐ │
└─────────┘ └─────┘ │ │ Port 0 │ │ Port 1 │ │
│ │ (I/O) │ │ (Input)│ │
│ └────────┘ └────────┘ │
└──────────────────────────────────────────────────────────┘
┌─────────────────────────── Toplevel.v ───────────────────────────┐
│ │
│ Fetch FSM ──done──► Instruction Decoder ──start──► Exec FSM │
│ ▲ (opcode routing) │ │
│ └──────────────────── done ◄───────────────────────┘ │
│ │
│ Exec FSMs: MOV | MOVI | ALU Register | ALU Immediate │
│ LOAD | STORE │
└───────────────────────────────────────────────────────────────────┘
[15:12] Opcode | [11:6] DST | [5:0] SRC
| Opcode | FSM | Instruction | Description | Example |
|---|---|---|---|---|
0000 |
0 | ADD | Rd = Rd + Rs | ADD R0, R1 |
0001 |
1 | SUB | Rd = Rd - Rs | SUB R2, R3 |
0010 |
2 | NOT | Rd = ~Rd | NOT R3 |
0011 |
3 | AND | Rd = Rd & Rs | AND R0, R1 |
0100 |
4 | OR | Rd = Rd | Rs | OR R0, R2 |
0101 |
5 | XOR | Rd = Rd ^ Rs | XOR R1, R3 |
0110 |
6 | XNOR | Rd = ~(Rd ^ Rs) | XNOR P0, R3 |
0111 |
7 | ADDI | Rd = Rd + imm | ADDI P0, #1E |
1000 |
8 | SUBI | Rd = Rd - imm | SUBI R3, #12 |
1001 |
9 | MOV | Rd = Rs | MOV P0, R3 |
1010 |
10 | MOVI | Rd = imm | MOVI R3, #19 |
1011 |
11 | STORE | Mem[Rs] = Rd | STORE P0, (R3) |
1100 |
12 | LOAD | Rd = Mem[Rs] | LOAD (R3), R2 |
| Code | Name | Type |
|---|---|---|
000000 |
R0 | General-purpose register |
000001 |
R1 | General-purpose register |
000010 |
R2 | General-purpose register |
000011 |
R3 | General-purpose register |
000100 |
P0 | I/O Port 0 (bidirectional) |
000101 |
P1 | I/O Port 1 (input-only) |
The processor uses 8 FSMs coordinated through start/done handshaking. The top-level module (Toplevel.v) routes the decoded opcode to the correct execution FSM after fetch completes.
| FSM | Module | States | Trigger | Purpose |
|---|---|---|---|---|
| Fetch | fetchFSM.v |
10 | Any exec FSM done | PC → MAR → Memory → MDR → IR → ID decode |
| MOV | movFSM.v |
5 | FSM == 9 | Register-to-register transfer |
| MOVI | moviFSM.v |
5 | FSM == 10 | Load immediate value into register |
| ALU Register | registerFSM.v |
10 | FSM ∈ {0,2,4,5,6,7,8} | Two-operand ALU ops between registers |
| ALU Immediate | immediateFSM.v |
11 | FSM ∈ {1,3} | ALU ops with immediate operand |
| LOAD | Load_FSM.v |
4 | FSM == 11 | Memory read with MFC handshaking |
| STORE | STORE_FSM.v |
4 | FSM == 12 | Memory write with MFC handshaking |
┌──────────────────────────────────┐
▼ │
┌───────────┐ │
│ FETCH │ (10 states) │
│ PC→MAR→ │ │
│ MEM→MDR→ │ │
│ IR→DECODE │ │
└─────┬─────┘ │
│ inst_fetch_done │
▼ │
┌────────────────┐ │
│ Opcode Router │ (Toplevel.v assigns) │
└───┬──┬──┬──┬──┘ │
│ │ │ │ │
┌─────┘ │ │ └─────┐ │
▼ ▼ ▼ ▼ │
┌─────┐ ┌────┐ ┌────┐ ┌──────┐ │
│ MOV │ │MOVI│ │ALU │ │LOAD/ │ │
│ │ │ │ │REG/│ │STORE │ │
│ │ │ │ │IMM │ │ │ │
└──┬──┘ └─┬──┘ └─┬──┘ └──┬───┘ │
│ │ │ │ │
└──────┴──────┴───────┘ │
│ *_done │
└──────────────────────────────────┘
| Module | File | Description |
|---|---|---|
| Top Level | Toplevel.v |
Instantiates all components, routes bus signals, decodes opcode to FSM |
| Program Counter | program_counter.v |
16-bit PC with increment and tri-state output |
| ALU | ALU.v |
9 operations: ADD, SUB, NOT, AND, OR, XOR, XNOR, ADDI, SUBI |
| Instruction Register | IR.v |
Latches 16-bit instruction from bus |
| Instruction Decoder | ID.v |
Splits instruction into opcode [15:12], DST [11:6], SRC [5:0] |
| MAR | MAR.v |
Memory Address Register — holds address for memory access |
| MDR | MDR.v |
Memory Data Register — dual-port (bus side + memory side) |
| Memory | memory.v |
256×16 memory with MFC signaling and pre-loaded program |
| Register | register.v |
General-purpose 16-bit register with tri-state bus interface |
| I/O Port 0 | port0.v |
Bidirectional I/O port with sensor input |
| I/O Port 1 | port1.v |
Input-only port |
The testbench (Toplevel_tb.v) initializes memory with 8 instructions that exercise the full instruction set:
Addr Binary Assembly Description
───────────────────────────────────────────────────────────────
0 1010_100011_011001 MOVI R3, #25 Load 25 into R3
1 1000_100011_010010 SUBI R3, #18 R3 = 25 - 18 = 7
2 1001_110000_100011 MOV P0, R3 Copy R3 to Port 0
3 0010_100011_000000 NOT R3 R3 = ~R3 (bitwise NOT)
4 0110_110000_100011 XNOR P0, R3 P0 = ~(P0 ^ R3)
5 0111_110000_111111 ADDI P0, #30 P0 = P0 + 30
6 1011_110000_100101 STORE P0, (R3) Mem[R3] = P0
7 1100_100101_100010 LOAD (R3), R2 R2 = Mem[R3]
This program tests: immediate loading, arithmetic, register transfer, bitwise logic, memory store, and memory load — covering all FSM paths.
# Compile the top-level testbench (includes all modules)
iverilog -o Toplevel_tb.vvp Toplevel_tb.v Toplevel.v fetchFSM.v movFSM.v \
moviFSM.v registerFSM.v immediateFSM.v Load_FSM.v STORE_FSM.v \
ALU.v ID.v IR.v MAR.v MDR.v memory.v program_counter.v register.v \
port0.v port1.v
# Run simulation
vvp Toplevel_tb.vvp
# View waveforms
gtkwave Toplevel_tb.vcd- Fetch cycle: PC increments after each instruction, MAR latches address, MFC handshake completes
- MOVI: R3 loads value 25 (0x19) from immediate field
- SUBI: R3 decrements from 25 to 7
- MOV: Port 0 receives R3's value
- NOT: R3 gets bitwise inverted
- XNOR: Port 0 updated with XNOR result
- ADDI: Port 0 incremented by 30
- STORE/LOAD: Value written to memory then read back into R2
16-bit-microcontroller/
├── Toplevel.v # Top-level module (component instantiation + bus routing)
├── Toplevel_tb.v # Full system testbench with memory simulation
├── ALU.v # Arithmetic Logic Unit (9 operations)
├── registerFSM.v # ALU register-register operation FSM (10 states)
├── immediateFSM.v # ALU immediate operation FSM (11 states)
├── fetchFSM.v # Instruction fetch FSM (10 states)
├── movFSM.v # Register MOV FSM (5 states)
├── moviFSM.v # Move immediate FSM (5 states)
├── Load_FSM.v # Memory load FSM (4 states)
├── STORE_FSM.v # Memory store FSM (4 states)
├── ID.v # Instruction decoder
├── IR.v # Instruction register
├── MAR.v # Memory Address Register
├── MDR.v # Memory Data Register
├── memory.v # 256x16 memory with pre-loaded program
├── program_counter.v # Program Counter
├── program_counter_tb.v # PC unit testbench
├── register.v # General-purpose register
├── port0.v # I/O Port 0 (bidirectional)
├── port1.v # I/O Port 1 (input)
└── README.md
- Verilog — Hardware description language
- Icarus Verilog (iverilog) — Simulation and compilation
- GTKWave — Waveform viewer for verification