├── .gitignore ├── tests ├── io_test.asm ├── mov_test.asm ├── call_test.asm ├── multiplication_test.asm ├── alu_test.asm └── tests.bats ├── gtkwave ├── reg-sel.txt ├── states.txt ├── gen-filters.py └── opcode.txt ├── rtl ├── library │ ├── tristate_buffer.v │ ├── clock.v │ ├── register.v │ ├── counter.v │ └── ram.v ├── tb │ ├── alu_tb.v │ ├── counter_tb.v │ ├── register_tb.v │ └── machine_tb.v ├── cpu_registers.v ├── alu.v ├── machine.v ├── parameters.v ├── cpu_control.v └── cpu.v ├── Makefile ├── asm └── asm.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.gtkw 2 | *.vcd 3 | 4 | computer 5 | memory.list 6 | -------------------------------------------------------------------------------- /tests/io_test.asm: -------------------------------------------------------------------------------- 1 | .text 2 | 3 | in 1 4 | out 0 5 | 6 | hlt 7 | -------------------------------------------------------------------------------- /gtkwave/reg-sel.txt: -------------------------------------------------------------------------------- 1 | 000 A 2 | 001 B 3 | 010 C 4 | 011 D 5 | 100 E 6 | 101 F 7 | 110 G 8 | 111 M/T 9 | -------------------------------------------------------------------------------- /tests/mov_test.asm: -------------------------------------------------------------------------------- 1 | .text 2 | 3 | ldi B 42 4 | mov M B %k 5 | mov A M %k 6 | out 0 7 | 8 | ldi B 21 9 | mov A B 10 | out 0 11 | 12 | hlt 13 | 14 | 15 | .data 16 | 17 | k = 255 18 | -------------------------------------------------------------------------------- /rtl/library/tristate_buffer.v: -------------------------------------------------------------------------------- 1 | module tristate_buffer( 2 | input [WIDTH-1:0] in, 3 | input enable, 4 | output [WIDTH-1:0] out 5 | ); 6 | 7 | parameter WIDTH = 8; 8 | 9 | assign out = enable ? in : 'bz; 10 | 11 | endmodule 12 | -------------------------------------------------------------------------------- /tests/call_test.asm: -------------------------------------------------------------------------------- 1 | .text 2 | 3 | start: 4 | ldi A 0x0A 5 | out 0 6 | call %load 7 | out 0 8 | hlt 9 | 10 | load: 11 | push A 12 | ldi A 42 13 | call %output 14 | pop A 15 | ret 16 | 17 | output: 18 | out 0 19 | ret 20 | -------------------------------------------------------------------------------- /rtl/library/clock.v: -------------------------------------------------------------------------------- 1 | module clock( 2 | input wire enable, 3 | output reg clk = 0, 4 | output wire clk_inv 5 | ); 6 | 7 | always begin 8 | #5 clk = ~clk & enable; 9 | end 10 | 11 | assign clk_inv = ~clk; 12 | 13 | endmodule 14 | -------------------------------------------------------------------------------- /tests/multiplication_test.asm: -------------------------------------------------------------------------------- 1 | .text 2 | 3 | start: 4 | 5 | lda %r 6 | ldi B 4 7 | add 8 | sta %r 9 | 10 | lda %i 11 | dec 12 | sta %i 13 | 14 | jnz %start 15 | 16 | lda %r 17 | out 0 18 | hlt 19 | 20 | 21 | .data 22 | 23 | r = 0 24 | i = 4 25 | -------------------------------------------------------------------------------- /tests/alu_test.asm: -------------------------------------------------------------------------------- 1 | .text 2 | 3 | ldi A 0xFF 4 | ldi B 0x0F 5 | and 6 | mov G A 7 | 8 | ldi A 0xFF 9 | or 10 | mov F A 11 | 12 | ldi A 0xFF 13 | xor 14 | mov E A 15 | 16 | ldi A 0xFF 17 | add 18 | mov D A 19 | 20 | ldi A 1 21 | ldi B 2 22 | sub 23 | 24 | hlt 25 | -------------------------------------------------------------------------------- /gtkwave/states.txt: -------------------------------------------------------------------------------- 1 | 00 NEXT 2 | 01 FETCH_PC 3 | 02 FETCH_INST 4 | 03 HALT 5 | 04 JUMP 6 | 05 OUT 7 | 06 ALU_OUT 8 | 07 ALU_EXEC 9 | 08 MOV_STORE 10 | 09 MOV_FETCH 11 | 0a MOV_LOAD 12 | 0c FETCH_SP 13 | 0d PC_STORE 14 | 0e TMP_JUMP 15 | 0f RET 16 | 10 INC_SP 17 | 11 SET_ADDR 18 | 12 IN 19 | 13 REG_STORE 20 | 14 SET_REG 21 | -------------------------------------------------------------------------------- /rtl/library/register.v: -------------------------------------------------------------------------------- 1 | module register( 2 | input wire [WIDTH-1:0] in, 3 | input wire clk, 4 | input wire reset, 5 | input wire enable, 6 | output reg [WIDTH-1:0] out 7 | ); 8 | 9 | parameter WIDTH = 8; 10 | 11 | always @(posedge clk) begin 12 | if (enable) 13 | out <= in; 14 | end 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | COMPUTER = $(wildcard rtl/*.v) 2 | LIBRARIES = $(wildcard rtl/library/*.v) 3 | 4 | build: 5 | iverilog -o computer -Wall \ 6 | $(COMPUTER) \ 7 | $(LIBRARIES) \ 8 | rtl/tb/machine_tb.v 9 | 10 | run: build 11 | vvp -n computer 12 | 13 | clean: 14 | rm -rf computer 15 | 16 | view: 17 | gtkwave machine.vcd gtkwave/config.gtkw 18 | 19 | tests: 20 | bats tests/tests.bats 21 | 22 | .PHONY: build run clean view tests 23 | -------------------------------------------------------------------------------- /rtl/tb/alu_tb.v: -------------------------------------------------------------------------------- 1 | module alu_tb; 2 | 3 | reg [7:0] in_a; 4 | reg [7:0] in_b; 5 | reg cin = 0; 6 | 7 | wire [7:0] sum; 8 | wire cout; 9 | 10 | alu alu (cin, cout, in_a, in_b, sum); 11 | 12 | initial begin 13 | #10 in_a = 10; 14 | #10 in_b = 20; 15 | 16 | #10 in_a = 50; 17 | #10 in_b = 10; 18 | end 19 | 20 | initial begin 21 | $monitor("time = %2d, CIN = %1b, COUT = %1b, A = %d, B = %d, SUM = %d", $time, cin, cout, in_a, in_b, sum); 22 | end 23 | 24 | endmodule 25 | -------------------------------------------------------------------------------- /rtl/tb/counter_tb.v: -------------------------------------------------------------------------------- 1 | module test; 2 | 3 | /* Make a reset that pulses once. */ 4 | reg reset = 0; 5 | initial begin 6 | # 17 reset = 1; 7 | # 11 reset = 0; 8 | # 29 reset = 1; 9 | # 11 reset = 0; 10 | # 100 $stop; 11 | end 12 | 13 | /* Make a regular pulsing clock. */ 14 | reg clk = 0; 15 | always #5 clk = !clk; 16 | 17 | wire [7:0] value; 18 | counter c1 (value, clk, reset); 19 | 20 | initial 21 | $monitor("At time %t, value = %h (%0d)", 22 | $time, value, value); 23 | endmodule // test 24 | -------------------------------------------------------------------------------- /rtl/library/counter.v: -------------------------------------------------------------------------------- 1 | module counter( 2 | input wire clk, 3 | input wire [WIDTH-1:0] in, 4 | input wire sel_in, 5 | input wire reset, 6 | input wire down, 7 | output reg [WIDTH-1:0] out 8 | ); 9 | 10 | parameter WIDTH = 8; 11 | 12 | initial 13 | out = 0; 14 | 15 | always @(posedge clk) begin 16 | if (sel_in) 17 | out <= in; 18 | else 19 | if (down) 20 | out <= out - 1; 21 | else 22 | out <= out + 1; 23 | end 24 | 25 | always @(posedge reset) begin 26 | out <= 0; 27 | end 28 | 29 | endmodule 30 | -------------------------------------------------------------------------------- /rtl/library/ram.v: -------------------------------------------------------------------------------- 1 | module ram( 2 | input wire clk, 3 | input wire [7:0] addr, 4 | input wire we, // Write Enable (write if we is high else read) 5 | input wire oe, // Enable Output 6 | inout wire [7:0] data 7 | ); 8 | 9 | reg [7:0] mem [0:255]; 10 | reg [7:0] buffer; 11 | 12 | always @(posedge clk) begin 13 | if (we) begin 14 | mem[addr] <= data; 15 | $display("Memory: set [0x%h] => 0x%h (%d)", addr, data, data); 16 | end else begin 17 | buffer <= mem[addr]; 18 | end 19 | end 20 | 21 | assign data = (oe & ~we) ? buffer : 'bz; 22 | 23 | endmodule 24 | -------------------------------------------------------------------------------- /rtl/tb/register_tb.v: -------------------------------------------------------------------------------- 1 | module register_tb; 2 | 3 | reg [7:0] in = 15; 4 | 5 | /* Make a reset that pulses once. */ 6 | reg reset = 0; 7 | reg enable = 1; 8 | 9 | initial begin 10 | # 17 reset = 1; 11 | # 10 in = 10; 12 | # 10 enable = 0; 13 | # 10 in = 5; 14 | # 10 enable = 1; 15 | # 100 $stop; 16 | end 17 | 18 | /* Make a regular pulsing clock. */ 19 | reg clk = 0; 20 | always #5 clk = !clk; 21 | 22 | wire [7:0] value; 23 | register r1 (in, clk, enable, reset, value); 24 | 25 | initial 26 | $monitor("At time %t, value = %h (%0d), enable = %b", 27 | $time, value, value, enable); 28 | 29 | endmodule 30 | -------------------------------------------------------------------------------- /rtl/cpu_registers.v: -------------------------------------------------------------------------------- 1 | module cpu_registers( 2 | input wire clk, 3 | input wire [7:0] data_in, 4 | input wire [2:0] sel_in, 5 | input wire [2:0] sel_out, 6 | input wire enable_write, 7 | input wire output_enable, 8 | output wire [7:0] data_out, 9 | output wire [7:0] rega, 10 | output wire [7:0] regb 11 | ); 12 | 13 | reg [7:0] registers[0:7]; 14 | 15 | always @ (posedge clk) begin 16 | if (enable_write) 17 | registers[sel_in] = data_in; 18 | end 19 | 20 | assign data_out = (output_enable) ? registers[sel_out] : 'bz; 21 | 22 | wire [7:0] regc, regd, rege, regf, regg, regt; 23 | assign rega = registers[0]; 24 | assign regb = registers[1]; 25 | assign regc = registers[2]; 26 | assign regd = registers[3]; 27 | assign rege = registers[4]; 28 | assign regf = registers[5]; 29 | assign regg = registers[6]; 30 | assign regt = registers[7]; 31 | 32 | endmodule 33 | -------------------------------------------------------------------------------- /tests/tests.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | function compile_and_run() { 4 | local asm_file="$1" 5 | ./asm/asm.py "./tests/${asm_file}" > ./memory.list 6 | make clean 7 | make run 8 | } 9 | 10 | @test "test I/O" { 11 | compile_and_run io_test.asm | grep -E 'REGISTERS: A: ff, B: [xz]+, C: [xz]+, D: [xz]+, E: [xz]+, F: [xz]+, G: [xz]+, Temp: [xz]+' 12 | } 13 | 14 | @test "test ALU" { 15 | compile_and_run alu_test.asm | grep -E 'REGISTERS: A: ff, B: 02, C: [xz]+, D: 0e, E: f0, F: ff, G: 0f, Temp: [xz]+' 16 | } 17 | 18 | @test "test call" { 19 | compile_and_run call_test.asm | awk '/Output:/ { print $2; }' | tr '\n' ' ' | grep '10 42 10' 20 | } 21 | 22 | @test "test multiplication" { 23 | compile_and_run multiplication_test.asm | grep 'Output: 16' 24 | } 25 | 26 | @test "test mov" { 27 | compile_and_run mov_test.asm | awk '/Output:/ { print $2; }' | tr '\n' ' ' | grep '42 21' 28 | } 29 | -------------------------------------------------------------------------------- /rtl/alu.v: -------------------------------------------------------------------------------- 1 | module alu( 2 | input wire enable, 3 | input wire clk, 4 | input wire [2:0] mode, 5 | input wire [N-1:0] in_a, 6 | input wire [N-1:0] in_b, 7 | output wire [N-1:0] out, 8 | output reg flag_zero, 9 | output reg flag_carry 10 | ); 11 | 12 | `include "rtl/parameters.v" 13 | 14 | parameter N = 8; 15 | 16 | reg [N-1:0] buf_out; 17 | 18 | initial begin 19 | flag_carry = 0; 20 | flag_zero = 0; 21 | end 22 | 23 | always @(posedge clk) begin 24 | if (enable) begin 25 | case (mode) 26 | `ALU_ADD: {flag_carry, buf_out} = in_a + in_b; 27 | `ALU_ADC: {flag_carry, buf_out} = in_a + in_b + flag_carry; 28 | `ALU_SUB: {flag_carry, buf_out} = in_a - in_b; 29 | `ALU_INC: {flag_carry, buf_out} = in_a + 1; 30 | `ALU_DEC: {flag_carry, buf_out} = in_a - 1; 31 | `ALU_AND: buf_out = in_a & in_b; 32 | `ALU_OR: buf_out = in_a | in_b; 33 | `ALU_XOR: buf_out = in_a ^ in_b; 34 | default: buf_out = 'hxx; 35 | endcase 36 | 37 | flag_zero = (buf_out == 0) ? 1 : 0; 38 | 39 | end 40 | end 41 | 42 | assign out = buf_out; 43 | 44 | endmodule 45 | -------------------------------------------------------------------------------- /rtl/machine.v: -------------------------------------------------------------------------------- 1 | module machine( 2 | input wire clk, 3 | input wire reset 4 | ); 5 | 6 | // ========================== 7 | // CPU 8 | // ========================== 9 | 10 | wire [7:0] addr_bus; 11 | wire [7:0] bus; 12 | wire c_ri; 13 | wire c_ro; 14 | wire mem_clk; 15 | wire mem_io; 16 | cpu m_cpu ( 17 | .clk(clk), 18 | .reset(reset), 19 | .addr_bus(addr_bus), 20 | .bus(bus), 21 | .mem_clk(mem_clk), 22 | .c_ri(c_ri), 23 | .c_ro(c_ro), 24 | .mem_io(mem_io) 25 | ); 26 | 27 | 28 | // ========================== 29 | // RAM 30 | // ========================== 31 | 32 | ram m_ram ( 33 | .clk(mem_clk), 34 | .addr(addr_bus), 35 | .data(bus), 36 | .we(c_ri), 37 | .oe(c_ro) 38 | ); 39 | 40 | 41 | // ========================== 42 | // DEBUG I/O PERIPHERAL 43 | // ========================== 44 | 45 | always @ (posedge mem_io & mem_clk) begin 46 | if (addr_bus == 8'h00) 47 | $display("Output: %d ($%h)", bus, bus); 48 | else if (addr_bus == 8'h01) 49 | $display("Input: set $FF on data bus"); 50 | else 51 | $display("Unknown I/O on address $%h: %d ($%h)", addr_bus, bus, bus); 52 | end 53 | 54 | assign bus = (mem_io & mem_clk & (addr_bus == 8'h01)) ? 8'hFF : 8'hZZ; 55 | 56 | endmodule 57 | -------------------------------------------------------------------------------- /gtkwave/gen-filters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | instructions = { 4 | "0000 0000": "NOP", 5 | "0000 0001": "CALL", 6 | "0000 0010": "RET", 7 | "0000 0011": "OUT", 8 | "0000 0100": "IN", 9 | "0000 0101": "HLT", 10 | "0000 0110": "CMP", 11 | 12 | "0001 1000": "JMP", 13 | "0001 1001": "JZ", 14 | "0001 1010": "JNZ", 15 | "0001 1011": "JC", 16 | "0001 1100": "JNC", 17 | 18 | "0100 0000": "ADD", 19 | "0100 1000": "SUB", 20 | "0101 0000": "INC", 21 | "0101 1000": "DEC", 22 | "0110 0000": "AND", 23 | "0110 1000": "OR", 24 | "0111 0000": "XOR", 25 | "0111 1000": "ADC" 26 | } 27 | 28 | regs = { 29 | "000": "A", 30 | "001": "B", 31 | "010": "C", 32 | "011": "D", 33 | "100": "E", 34 | "101": "F", 35 | "110": "G" 36 | } 37 | 38 | for k, v in regs.items(): 39 | instructions["0001 0" + k] = "LDI " + v 40 | instructions["0010 0" + k] = "PUSH " + v 41 | instructions["0010 1" + k] = "POP " + v 42 | 43 | for k1, v1 in regs.items(): 44 | for k2, v2 in regs.items(): 45 | if k1 == k2: 46 | txt = "invalid" 47 | else: 48 | txt = " ".join((v1, v2)) 49 | 50 | instructions[" ".join(("10", k1, k2))] = "MOV " + txt 51 | 52 | 53 | for k, v in regs.items(): 54 | instructions["10 111 %s" % k] = "MOV M %s" % v 55 | instructions["10 %s 111" % k] = "MOV %s M" % v 56 | 57 | for k, v in instructions.items(): 58 | print k.replace(" ", ""), v 59 | -------------------------------------------------------------------------------- /rtl/tb/machine_tb.v: -------------------------------------------------------------------------------- 1 | module machine_tb; 2 | 3 | // ========================== 4 | // System clock 5 | // ========================== 6 | 7 | wire clk; 8 | reg enable_clk = 0; 9 | clock m_sys_clk ( 10 | .enable(enable_clk), 11 | .clk(clk) 12 | ); 13 | 14 | 15 | // ========================== 16 | // Machine 17 | // ========================== 18 | 19 | reg reset = 0; 20 | machine m_machine( 21 | .reset(reset), 22 | .clk(clk) 23 | ); 24 | 25 | 26 | // ========================== 27 | // Tests and monitoring 28 | // ========================== 29 | 30 | initial begin 31 | $readmemh("memory.list", m_machine.m_ram.mem); 32 | $dumpfile("machine.vcd"); 33 | $dumpvars(0, m_machine); 34 | 35 | # 10 reset = 1; 36 | # 10 reset = 0; 37 | # 10 enable_clk = 1; 38 | end 39 | 40 | always @ (posedge m_machine.m_cpu.halted) begin 41 | $display("============================================"); 42 | $display("CPU halted normally."); 43 | $display( 44 | "REGISTERS: A: %h, B: %h, C: %h, D: %h, E: %h, F: %h, G: %h, Temp: %h", 45 | m_machine.m_cpu.m_registers.rega, 46 | m_machine.m_cpu.m_registers.regb, 47 | m_machine.m_cpu.m_registers.regc, 48 | m_machine.m_cpu.m_registers.regd, 49 | m_machine.m_cpu.m_registers.rege, 50 | m_machine.m_cpu.m_registers.regf, 51 | m_machine.m_cpu.m_registers.regg, 52 | m_machine.m_cpu.m_registers.regt 53 | ); 54 | $stop; 55 | end 56 | 57 | endmodule 58 | -------------------------------------------------------------------------------- /rtl/parameters.v: -------------------------------------------------------------------------------- 1 | `define OP_NOP 8'b00_000_000 2 | `define OP_CALL 8'b00_000_001 3 | `define OP_RET 8'b00_000_010 4 | `define OP_OUT 8'b00_000_011 5 | `define OP_IN 8'b00_000_100 6 | `define OP_HLT 8'b00_000_101 7 | `define OP_CMP 8'b00_000_110 8 | `define OP_LDI 8'b00_010_000 9 | `define OP_JMP 8'b00_011_000 10 | `define OP_PUSH 8'b00_100_000 11 | `define OP_POP 8'b00_101_000 12 | `define OP_ALU 8'b01_000_000 13 | `define OP_MOV 8'b10_000_000 14 | 15 | `define PATTERN_LDI 8'b00_010_??? 16 | `define PATTERN_JMP 8'b00_011_??? 17 | `define PATTERN_MOV 8'b10_???_??? 18 | `define PATTERN_ALU 8'b01_???_000 19 | `define PATTERN_PUSH 8'b00_100_??? 20 | `define PATTERN_POP 8'b00_101_??? 21 | 22 | 23 | `define STATE_NEXT 8'h00 24 | `define STATE_FETCH_PC 8'h01 25 | `define STATE_FETCH_INST 8'h02 26 | `define STATE_HALT 8'h03 27 | `define STATE_JUMP 8'h04 28 | `define STATE_OUT 8'h05 29 | `define STATE_ALU_OUT 8'h06 30 | `define STATE_ALU_EXEC 8'h07 31 | `define STATE_MOV_STORE 8'h08 32 | `define STATE_MOV_FETCH 8'h09 33 | `define STATE_MOV_LOAD 8'h0a 34 | `define STATE_FETCH_SP 8'h0c 35 | `define STATE_PC_STORE 8'h0d 36 | `define STATE_TMP_JUMP 8'h0e 37 | `define STATE_RET 8'h0f 38 | `define STATE_INC_SP 8'h10 39 | `define STATE_SET_ADDR 8'h11 40 | `define STATE_IN 8'h12 41 | `define STATE_REG_STORE 8'h13 42 | `define STATE_SET_REG 8'h14 43 | 44 | `define ALU_ADD 3'b000 45 | `define ALU_SUB 3'b001 46 | `define ALU_INC 3'b010 47 | `define ALU_DEC 3'b011 48 | `define ALU_AND 3'b100 49 | `define ALU_OR 3'b101 50 | `define ALU_XOR 3'b110 51 | `define ALU_ADC 3'b111 52 | 53 | `define JMP_JMP 3'b000 54 | `define JMP_JZ 3'b001 55 | `define JMP_JNZ 3'b010 56 | `define JMP_JC 3'b011 57 | `define JMP_JNC 3'b100 58 | 59 | `define REG_A 3'b000 60 | `define REG_T 3'b111 61 | 62 | `define T1 4'b0000 63 | `define T2 4'b0001 64 | `define T3 4'b0010 65 | `define T4 4'b0011 66 | `define T5 4'b0100 67 | `define T6 4'b0101 68 | `define T7 4'b0110 69 | `define T8 4'b0111 70 | -------------------------------------------------------------------------------- /gtkwave/opcode.txt: -------------------------------------------------------------------------------- 1 | 01101000 OR 2 | 10000111 MOV A M 3 | 00101000 POP A 4 | 10000100 MOV A E 5 | 10000101 MOV A F 6 | 01001000 SUB 7 | 01100000 AND 8 | 10111011 MOV M D 9 | 10111010 MOV M C 10 | 10001110 MOV B G 11 | 10001111 MOV B M 12 | 10011010 MOV D C 13 | 10011011 MOV invalid 14 | 10101100 MOV F E 15 | 10101101 MOV invalid 16 | 10111100 MOV M E 17 | 00101001 POP B 18 | 10000110 MOV A G 19 | 00010101 LDI F 20 | 00010100 LDI E 21 | 10111101 MOV M F 22 | 10011001 MOV D B 23 | 10011000 MOV D A 24 | 00000110 CMP 25 | 10001101 MOV B F 26 | 10001100 MOV B E 27 | 10100110 MOV E G 28 | 10100111 MOV E M 29 | 10101111 MOV F M 30 | 10101110 MOV F G 31 | 00101010 POP C 32 | 00101011 POP D 33 | 10110010 MOV G C 34 | 10110011 MOV G D 35 | 10010110 MOV C G 36 | 10010111 MOV C M 37 | 00000100 IN 38 | 00000101 HLT 39 | 00010110 LDI G 40 | 00011100 JNC 41 | 10000010 MOV A C 42 | 10000011 MOV A D 43 | 00011010 JNZ 44 | 00011011 JC 45 | 10100101 MOV E F 46 | 10100100 MOV invalid 47 | 10011111 MOV D M 48 | 01000000 ADD 49 | 10010101 MOV C F 50 | 10010100 MOV C E 51 | 10110001 MOV G B 52 | 10110000 MOV G A 53 | 01011000 DEC 54 | 10000001 MOV A B 55 | 10000000 MOV invalid 56 | 10011100 MOV D E 57 | 10011101 MOV D F 58 | 10001000 MOV B A 59 | 10001001 MOV invalid 60 | 00100011 PUSH D 61 | 00100010 PUSH C 62 | 10111110 MOV M G 63 | 00100000 PUSH A 64 | 00100001 PUSH B 65 | 00000001 CALL 66 | 00000000 NOP 67 | 00011001 JZ 68 | 10011110 MOV D G 69 | 10001011 MOV B D 70 | 10001010 MOV B C 71 | 10010000 MOV C A 72 | 10010001 MOV C B 73 | 10110100 MOV G E 74 | 10110101 MOV G F 75 | 10100000 MOV E A 76 | 10100001 MOV E B 77 | 01111000 ADC 78 | 00000010 RET 79 | 00000011 OUT 80 | 10101010 MOV F C 81 | 10101011 MOV F D 82 | 00010011 LDI D 83 | 00010010 LDI C 84 | 00101110 POP G 85 | 10010011 MOV C D 86 | 10010010 MOV invalid 87 | 10110111 MOV G M 88 | 10110110 MOV invalid 89 | 10100011 MOV E D 90 | 10100010 MOV E C 91 | 10101001 MOV F B 92 | 10101000 MOV F A 93 | 00100101 PUSH F 94 | 00100100 PUSH E 95 | 00010000 LDI A 96 | 00010001 LDI B 97 | 00011000 JMP 98 | 00101100 POP E 99 | 00101101 POP F 100 | 10111000 MOV M A 101 | 10111001 MOV M B 102 | 01110000 XOR 103 | 01010000 INC 104 | 00100110 PUSH G 105 | -------------------------------------------------------------------------------- /rtl/cpu_control.v: -------------------------------------------------------------------------------- 1 | module cpu_control( 2 | input wire [7:0] instruction, 3 | input wire clk, 4 | input wire reset_cycle, 5 | output reg [7:0] state, 6 | output reg [3:0] cycle, 7 | output reg [7:0] opcode 8 | ); 9 | 10 | `include "rtl/parameters.v" 11 | 12 | initial 13 | cycle = 0; 14 | 15 | always @ (posedge clk) begin 16 | casez (instruction) 17 | `PATTERN_LDI: opcode = `OP_LDI; 18 | `PATTERN_MOV: opcode = `OP_MOV; 19 | `PATTERN_ALU: opcode = `OP_ALU; 20 | `PATTERN_JMP: opcode = `OP_JMP; 21 | `PATTERN_PUSH: opcode = `OP_PUSH; 22 | `PATTERN_POP: opcode = `OP_POP; 23 | default: opcode = instruction; 24 | endcase 25 | 26 | case (cycle) 27 | `T1: state = `STATE_FETCH_PC; 28 | `T2: state = `STATE_FETCH_INST; 29 | `T3: state = (opcode == `OP_HLT) ? `STATE_HALT : 30 | (opcode == `OP_MOV) ? `STATE_MOV_FETCH : 31 | (opcode == `OP_ALU || opcode == `OP_CMP) ? `STATE_ALU_EXEC : 32 | (opcode == `OP_RET || opcode == `OP_POP) ? `STATE_INC_SP : 33 | (opcode == `OP_PUSH) ? `STATE_FETCH_SP : 34 | (opcode == `OP_IN || opcode == `OP_OUT || opcode == `OP_CALL || opcode == `OP_LDI || opcode == `OP_JMP) ? `STATE_FETCH_PC : 35 | `STATE_NEXT; 36 | `T4: state = (opcode == `OP_JMP) ? `STATE_JUMP : 37 | (opcode == `OP_LDI) ? `STATE_SET_REG : 38 | (opcode == `OP_MOV) ? `STATE_MOV_LOAD : 39 | (opcode == `OP_ALU) ? `STATE_ALU_OUT : 40 | (opcode == `OP_OUT || opcode == `OP_IN) ? `STATE_SET_ADDR : 41 | (opcode == `OP_PUSH) ? `STATE_REG_STORE : 42 | (opcode == `OP_CALL) ? `STATE_SET_REG : 43 | (opcode == `OP_RET || opcode == `OP_POP) ? `STATE_FETCH_SP : 44 | `STATE_NEXT; 45 | `T5: state = (opcode == `OP_MOV) ? `STATE_MOV_STORE : 46 | (opcode == `OP_CALL) ? `STATE_FETCH_SP : 47 | (opcode == `OP_RET) ? `STATE_RET : 48 | (opcode == `OP_OUT) ? `STATE_OUT : 49 | (opcode == `OP_POP) ? `STATE_SET_REG : 50 | (opcode == `OP_IN) ? `STATE_IN : 51 | `STATE_NEXT; 52 | `T6: state = (opcode == `OP_CALL) ? `STATE_PC_STORE : 53 | `STATE_NEXT; 54 | `T7: state = (opcode == `OP_CALL) ? `STATE_TMP_JUMP : 55 | `STATE_NEXT; 56 | `T8: state = `STATE_NEXT; 57 | default: $display("Cannot decode : cycle = %d, instruction = %h", cycle, instruction); 58 | endcase 59 | 60 | cycle = (cycle > 6) ? 0 : cycle + 1; 61 | end 62 | 63 | always @ (posedge reset_cycle) begin 64 | cycle = 0; 65 | end 66 | 67 | endmodule 68 | -------------------------------------------------------------------------------- /asm/asm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import re 4 | import sys 5 | 6 | progf = sys.argv[1] 7 | 8 | inst = { 9 | "nop": 0x00, 10 | "call": 0b00000001, 11 | "ret": 0b00000010, 12 | "lda": 0b10000111, 13 | "out": 0b00000011, 14 | "in": 0b00000100, 15 | "hlt": 0b00000101, 16 | "cmp": 0b00000110, 17 | "sta": 0b10111000, 18 | "jmp": 0b00011000, 19 | "jz": 0b00011001, 20 | "jnz": 0b00011010, 21 | "je": 0b00011001, 22 | "jne": 0b00011010, 23 | "jc": 0b00011011, 24 | "jnc": 0b00011100, 25 | "push": 0b00100000, 26 | "pop": 0b00101000, 27 | "add": 0b01000000, 28 | "sub": 0b01001000, 29 | "inc": 0b01010000, 30 | "dec": 0b01011000, 31 | "and": 0b01100000, 32 | "or": 0b01101000, 33 | "xor": 0b01110000, 34 | "adc": 0b01111000, 35 | "ldi": 0b00010000, 36 | "mov": 0b10000000, 37 | } 38 | 39 | reg = { 40 | "A": 0b000, 41 | "B": 0b001, 42 | "C": 0b010, 43 | "D": 0b011, 44 | "E": 0b100, 45 | "F": 0b101, 46 | "G": 0b110, 47 | "M": 0b111, 48 | } 49 | 50 | TEXT, DATA = 0, 1 51 | MEM_SIZE = 256 52 | 53 | mem = [0 for _ in range(MEM_SIZE)] 54 | cnt = 0 55 | 56 | labels = {} 57 | data = {} 58 | data_addr = {} 59 | 60 | def rich_int(v): 61 | if v.startswith("0x"): 62 | return int(v, 16) 63 | elif v.startswith("0b"): 64 | return int(v, 2) 65 | else: 66 | return int(v) 67 | 68 | with open(progf) as f: 69 | for l in f: 70 | l = re.sub(";.*", "", l) 71 | 72 | l = l.strip() 73 | if l == "": 74 | continue 75 | 76 | if l == ".text": 77 | section = TEXT 78 | elif l == ".data": 79 | section = DATA 80 | else: 81 | if section == DATA: 82 | n, v = map(str.strip, l.split("=", 2)) 83 | data[str(n)] = int(v) 84 | elif section == TEXT: 85 | kw = l.split() 86 | if kw[0][-1] == ":": 87 | labels[kw[0].rstrip(":")] = cnt 88 | else: 89 | current_inst = kw[0] 90 | 91 | if current_inst == "ldi": 92 | r = reg[kw[1]] 93 | kw[0] = (inst[kw[0]] & 0b11111000) | r 94 | del kw[1] 95 | kw[1] = rich_int(kw[1]) 96 | elif current_inst in ("push", "pop"): 97 | r = reg[kw[1]] 98 | kw[0] = (inst[kw[0]] & 0b11111000) | r 99 | del kw[1] 100 | elif current_inst == "mov": 101 | op1 = reg[kw[1]] 102 | op2 = reg[kw[2]] 103 | kw[0] = (inst[kw[0]] & 0b11111000) | op2 104 | kw[0] = (kw[0] & 0b11000111) | (op1 << 3) 105 | del kw[2] 106 | del kw[1] 107 | else: 108 | kw[0] = inst[kw[0]] 109 | 110 | for a in kw: 111 | mem[cnt] = a 112 | cnt += 1 113 | 114 | # Write data into memory 115 | for k, v in data.items(): 116 | data_addr[k] = cnt 117 | mem[cnt] = v 118 | cnt += 1 119 | 120 | data_addr.update(labels) 121 | 122 | # Replace variables 123 | for i, b in enumerate(mem): 124 | if str(b).startswith("%"): 125 | mem[i] = data_addr[b.lstrip("%")] 126 | 127 | print ' '.join(['%02x' % int(b) for b in mem]) 128 | -------------------------------------------------------------------------------- /rtl/cpu.v: -------------------------------------------------------------------------------- 1 | module cpu( 2 | input wire clk, 3 | input wire reset, 4 | output wire [7:0] addr_bus, 5 | output wire c_ri, 6 | output wire c_ro, 7 | output reg mem_clk, 8 | output wire mem_io, // Select memory if low or I/O if high 9 | inout wire [7:0] bus 10 | ); 11 | 12 | `include "rtl/parameters.v" 13 | 14 | wire flag_zero; 15 | wire flag_carry; 16 | 17 | 18 | // ========================== 19 | // Clocks 20 | // ========================== 21 | 22 | reg cycle_clk = 0; 23 | reg internal_clk = 0; 24 | reg [2:0] cnt = 'b100; 25 | reg halted = 0; 26 | always @ (posedge clk & ~halted) begin 27 | {cycle_clk, mem_clk, internal_clk} <= cnt; 28 | 29 | case (cnt) 30 | 'b100 : cnt = 'b010; 31 | 'b010 : cnt = 'b001; 32 | 'b001 : cnt = 'b100; 33 | endcase 34 | end 35 | 36 | 37 | // ========================== 38 | // Registers 39 | // ========================== 40 | 41 | // General Purpose Registers 42 | wire [2:0] sel_in; 43 | wire [2:0] sel_out; 44 | wire [7:0] rega_out; 45 | wire [7:0] regb_out; 46 | wire c_rfi, c_rfo; 47 | cpu_registers m_registers ( 48 | .clk(internal_clk), 49 | .data_in(bus), 50 | .sel_in(sel_in), 51 | .sel_out(sel_out), 52 | .enable_write(c_rfi), 53 | .output_enable(c_rfo), 54 | .data_out(bus), 55 | .rega(rega_out), 56 | .regb(regb_out) 57 | ); 58 | 59 | // Instruction Register 60 | wire [7:0] regi_out; 61 | wire c_ii; 62 | register m_regi ( 63 | .in(bus), 64 | .clk(internal_clk), 65 | .enable(c_ii), 66 | .reset(reset), 67 | .out(regi_out) 68 | ); 69 | 70 | // Memory Address Register 71 | wire c_mi; 72 | register m_mar ( 73 | .in(bus), 74 | .clk(internal_clk), 75 | .enable(c_mi), 76 | .reset(reset), 77 | .out(addr_bus) 78 | ); 79 | 80 | 81 | // ========================== 82 | // Program Counter 83 | // ========================== 84 | 85 | wire [7:0] pc_out; 86 | wire c_co, c_ci, c_j; 87 | counter m_pc ( 88 | .clk(c_ci & internal_clk), 89 | .in(bus), 90 | .sel_in(c_j), 91 | .reset(reset), 92 | .down(1'b0), 93 | .out(pc_out) 94 | ); 95 | tristate_buffer m_pc_buf ( 96 | .in(pc_out), 97 | .enable(c_co), 98 | .out(bus) 99 | ); 100 | 101 | 102 | // ========================== 103 | // Stack Pointer 104 | // ========================== 105 | 106 | wire [7:0] sp_out; 107 | wire c_si, c_sd, c_so; 108 | counter m_sp ( 109 | .clk(reset | (c_si & internal_clk)), 110 | .in(8'hFF), 111 | .sel_in(reset), 112 | .reset(1'b0), 113 | .down(c_sd), 114 | .out(sp_out) 115 | ); 116 | tristate_buffer m_sp_buf ( 117 | .in(sp_out), 118 | .enable(c_so), 119 | .out(bus) 120 | ); 121 | 122 | 123 | // ========================== 124 | // ALU 125 | // ========================== 126 | 127 | wire c_eo; 128 | wire c_ee; 129 | wire [7:0] alu_out; 130 | wire [2:0] alu_mode; 131 | alu m_alu ( 132 | .clk(internal_clk), 133 | .enable(c_ee), 134 | .in_a(rega_out), 135 | .in_b(regb_out), 136 | .out(alu_out), 137 | .mode(alu_mode), 138 | .flag_zero(flag_zero), 139 | .flag_carry(flag_carry) 140 | ); 141 | tristate_buffer m_alu_buf ( 142 | .in(alu_out), 143 | .enable(c_eo), 144 | .out(bus) 145 | ); 146 | 147 | 148 | // ========================== 149 | // Control logic 150 | // ========================== 151 | 152 | wire c_halt, next_state, mov_memory, jump_allowed; 153 | wire [7:0] state; 154 | wire [7:0] instruction; 155 | wire [7:0] opcode; 156 | wire [3:0] cycle; 157 | wire [2:0] operand1; 158 | wire [2:0] operand2; 159 | 160 | assign instruction = regi_out; 161 | assign operand1 = instruction[5:3]; 162 | assign operand2 = instruction[2:0]; 163 | assign next_state = state == `STATE_NEXT | reset; 164 | 165 | assign mem_io = state == `STATE_OUT | state == `STATE_IN; 166 | 167 | assign mov_memory = operand1 == 3'b111 | operand2 == 3'b111; 168 | assign jump_allowed = operand2 == `JMP_JMP 169 | | ((operand2 == `JMP_JZ) & flag_zero) 170 | | ((operand2 == `JMP_JNZ) & ~flag_zero) 171 | | ((operand2 == `JMP_JC) & flag_carry) 172 | | ((operand2 == `JMP_JNC) & ~flag_carry); 173 | assign alu_mode = (opcode == `OP_ALU) ? operand1 : 174 | (opcode == `OP_CMP) ? `ALU_SUB : 'bx; 175 | 176 | assign sel_in = (opcode == `OP_ALU | opcode == `OP_IN) ? `REG_A : 177 | (opcode == `OP_MOV) ? operand1 : 178 | (opcode == `OP_POP | opcode == `OP_LDI) ? operand2 : 179 | (opcode == `OP_CALL) ? `REG_T : 180 | 'bx; 181 | 182 | assign sel_out = (opcode == `OP_OUT) ? `REG_A : 183 | (opcode == `OP_PUSH | opcode == `OP_MOV) ? operand2 : 184 | (opcode == `OP_CALL) ? `REG_T : 185 | 'bx; 186 | 187 | assign c_rfi = state == `STATE_ALU_OUT | 188 | state == `STATE_IN | 189 | state == `STATE_SET_ADDR | 190 | state == `STATE_SET_REG | 191 | (state == `STATE_MOV_STORE & operand1 != 3'b111); 192 | assign c_rfo = state == `STATE_OUT | 193 | state == `STATE_TMP_JUMP | 194 | state == `STATE_REG_STORE | 195 | (state == `STATE_MOV_STORE & operand2 != 3'b111); 196 | assign c_ci = state == `STATE_FETCH_PC | 197 | state == `STATE_RET | 198 | (state == `STATE_JUMP & jump_allowed) | 199 | state == `STATE_TMP_JUMP | 200 | (state == `STATE_MOV_FETCH & mov_memory); 201 | assign c_co = state == `STATE_FETCH_PC | 202 | state == `STATE_PC_STORE | 203 | (state == `STATE_MOV_FETCH & mov_memory); 204 | assign c_eo = state == `STATE_ALU_OUT; 205 | assign c_halt = state == `STATE_HALT; 206 | assign c_ii = state == `STATE_FETCH_INST; 207 | assign c_j = (state == `STATE_JUMP & jump_allowed) | 208 | state == `STATE_RET | 209 | state == `STATE_TMP_JUMP; 210 | assign c_mi = state == `STATE_FETCH_PC | 211 | state == `STATE_FETCH_SP | 212 | state == `STATE_SET_ADDR | 213 | ((state == `STATE_MOV_FETCH | state == `STATE_MOV_LOAD) & mov_memory); 214 | assign c_ro = state == `STATE_FETCH_INST | 215 | (state == `STATE_JUMP & jump_allowed) | 216 | state == `STATE_RET | 217 | state == `STATE_SET_ADDR | 218 | state == `STATE_SET_REG | 219 | (state == `STATE_MOV_LOAD & mov_memory) | 220 | (state == `STATE_MOV_STORE & operand2 == 3'b111); 221 | assign c_ri = (state == `STATE_MOV_STORE & operand1 == 3'b111) | 222 | state == `STATE_REG_STORE | 223 | state == `STATE_PC_STORE; 224 | assign c_so = state == `STATE_FETCH_SP; 225 | assign c_sd = state == `STATE_TMP_JUMP | 226 | state == `STATE_REG_STORE; 227 | assign c_si = state == `STATE_TMP_JUMP | 228 | state == `STATE_REG_STORE | 229 | state == `STATE_INC_SP; 230 | assign c_ee = state == `STATE_ALU_EXEC; 231 | 232 | cpu_control m_ctrl ( 233 | .instruction(instruction), 234 | .state(state), 235 | .reset_cycle(next_state), 236 | .clk(cycle_clk), 237 | .cycle(cycle), 238 | .opcode(opcode) 239 | ); 240 | 241 | always @ (posedge c_halt) begin 242 | halted = 1; 243 | end 244 | 245 | endmodule 246 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 8-bit computer in Verilog 2 | ========================= 3 | 4 | This project contains: 5 | 6 | * a 8-bit CPU with a basic instruction set 7 | * 256 bytes of RAM 8 | 9 | 10 | ## How to use it 11 | 12 | Build an exemple: 13 | 14 | ``` 15 | ./asm/asm.py tests/multiplication_test.asm > memory.list 16 | ``` 17 | 18 | Run the computer: 19 | 20 | ``` 21 | make clean && make run 22 | ``` 23 | 24 | 25 | ## Assembly 26 | 27 | ### Instructions set 28 | 29 | #### Data transfert group 30 | 31 | | Instruction | Description | 32 | |---------------|------------------------------------------------------------| 33 | | `lda` | Alias for `mov A M D` | 34 | | `sta` | Alias for `mov M A D` | 35 | | `ldi r D` | Load _D_ into _r_ register | 36 | | `mov r M D` | Copy the data at memory address D into register _r_ | 37 | | `mov r2 r1` | Copy register _r1_ into _r2_ | 38 | | `mov M r D` | Copy the data from register _r_ into memory in address _D_ | 39 | 40 | 41 | Legend: 42 | 43 | * _D_ is a byte of data. It can be a memory address or directly the data depending on the instruction. 44 | * _r_ is a register. 45 | * _M_ means "memory", it's used to tell to the `mov` instruction the source/destination of the copy. 46 | 47 | 48 | #### Arithmetic group 49 | 50 | | Instruction | Description | 51 | |---------------|------------------------------------------------------------| 52 | | `add` | Perform A = A + B (A, B are registers) | 53 | | `adc` | Perform A = A + B + carry (A, B are registers) | 54 | | `sub` | Perform A = A - B (A, B are registers) | 55 | | `inc` | Perform A = A + 1 (A is a register) | 56 | | `dec` | Perform A = A - 1 (A is a register) | 57 | | `cmp` | Perform A - B without updating A, just update flags | 58 | 59 | 60 | #### Logical group 61 | 62 | | Instruction | Description | 63 | |---------------|------------------------------------------------------------| 64 | | `and` | Perform A = A AND B (A, B are registers) | 65 | | `or` | Perform A = A OR B (A, B are registers) | 66 | | `xor` | Perform A = A XOR B (A, B are registers) | 67 | 68 | 69 | #### Branching group 70 | 71 | | Instruction | Description | 72 | |---------------|------------------------------------------------------------------------------| 73 | | `jmp D` | Jump to _D_ | 74 | | `jz D ` | Jump to _D_ if flag zero is set | 75 | | `jnz D` | Jump to _D_ if flag zero is not set | 76 | | `je D ` | Jump to _D_ if register A equals register B after `cmp` (alias `jz`) | 77 | | `jne D` | Jump to _D_ if register A doesn't equal register B after `cmp` (alias `jnz`) | 78 | | `jc D ` | Jump to _D_ if carry flag is set | 79 | | `jnc D` | Jump to _D_ if carry flag is not set | 80 | | `call D` | Call sub-routine _D_ | 81 | | `ret` | Return to the parent routine | 82 | 83 | 84 | #### Machine control 85 | 86 | | Instruction | Description | 87 | |---------------|------------------------------------------------------------| 88 | | `nop` | Do nothing | 89 | | `hlt` | Halt the CPU | 90 | 91 | 92 | #### I/O group 93 | 94 | | Instruction | Description | 95 | |---------------|------------------------------------------------------------------------------| 96 | | `in D` | Put the content of the data bus in the A register and set _D_ on address bus | 97 | | `out D` | Put the content of accumulator on the data bus and set _D_ on address bus | 98 | 99 | 100 | #### Stack operation group 101 | 102 | | Instruction | Description | 103 | |---------------|-------------------------------------------------------------| 104 | | `push r` | Push the content of register _r_ on the stack | 105 | | `pop r` | Pop the content from the stack and put it into register _r_ | 106 | 107 | 108 | 109 | ## Internal function 110 | 111 | ### Instruction decoding 112 | 113 | T1 and T2 are always `FETCH_PC` and `FETCH_INST`. 114 | 115 | List of instruction associated with states: 116 | 117 | | Instruction | T3 | T4 | T5 | T6 | T7 | 118 | |-------------|-------------|-------------|-------------|------------|------------| 119 | | `NOP` | | | | | | 120 | | `ALU` | `ALU_EXEC` | `ALU_STORE` | | | | 121 | | `CMP` | `ALU_EXEC` | | | | | 122 | | `OUT` | `FETCH_PC` | `SET_ADDR` | `OUT` | | | 123 | | `IN ` | `FETCH_PC` | `SET_ADDR` | `IN` | | | 124 | | `HLT` | `HALT` | | | | | 125 | | `JMP` | `FETCH_PC` | `JUMP` | | | | 126 | | `LDI` | `FETCH_PC` | `SET_REG` | | | | 127 | | `MOV` | `MOV_FETCH` | `MOV_LOAD` | `MOV_STORE` | | | 128 | | `CALL` | `FETCH_PC` | `SET_REG` | `FETCH_SP` | `PC_STORE` | `TMP_JUMP` | 129 | | `RET` | `INC_SP` | `FETCH_SP` | `RET` | | | 130 | | `PUSH` | `FETCH_SP` | `REG_STORE` | | | | 131 | | `POP` | `INC_SP` | `FETCH_SP` | `SET_REG` | | | 132 | 133 | 134 | States versus signals enabled: 135 | 136 | | States | II | CI | CO | RFI | RFO | EO | EE | MI | RO | RI | HALT | J | SO | SD | SI | MEM/IO | 137 | |---------------|----|----|----|-----|-----|----|----|----|----|----|------|---|----|----|----|--------| 138 | | `ALU_EXEC` | | | | | | | X | | | | | | | | | | 139 | | `ALU_STORE` | | | | X | | X | | | | | | | | | | | 140 | | `FETCH_INST` | X | | | | | | | | X | | | | | | | | 141 | | `FETCH_PC` | | X | X | | | | | X | | | | | | | | | 142 | | `FETCH_SP` | | | | | | | | X | | | | | X | | | | 143 | | `HALT` | | | | | | | | | | | X | | | | | | 144 | | `INC_SP` | | | | | | | | | | | | | | | X | | 145 | | `IN` | | | | X | | | | | | | | | | | | X | 146 | | `JUMP` | | * | | | | | | | * | | | * | | | | | 147 | | `MOV_FETCH` | | * | * | | | | | * | | | | | | | | | 148 | | `MOV_LOAD` | | | | * | * | | | * | * | | | | | | | | 149 | | `MOV_STORE` | | | | * | * | | | | * | * | | | | | | | 150 | | `OUT` | | | | | X | | | | | | | | | | | X | 151 | | `PC_STORE` | | | X | | | | | | | X | | | | | | | 152 | | `REG_STORE` | | | | | X | | | | | X | | | | X | X | | 153 | | `RET` | | X | | | | | | | X | | | X | | | | | 154 | | `SET_ADDR` | | | | | | | | X | X | | | | | | | | 155 | | `SET_REG` | | | | X | | | | | X | | | | | | | | 156 | | `TMP_JUMP` | | X | | | X | | | | | | | X | | X | X | | 157 | 158 | 159 | ### Clocks 160 | 161 | ``` 162 | CLK: 163 | +-+ +-+ +-+ +-+ +-+ +-+ + 164 | | | | | | | | | | | | | | 165 | | | | | | | | | | | | | | 166 | + +-+ +-+ +-+ +-+ +-+ +-+ 167 | 168 | CYCLE_CLK: 169 | +---+ +---+ 170 | | | | | 171 | | | | | 172 | + +---+---+ +---+---+ 173 | 174 | MEM_CLK: 175 | +---+ +---+ 176 | | | | | 177 | | | | | 178 | +---+ +---+---+ +---+ 179 | 180 | INTERNAL_CLK: 181 | +---+ +---+ 182 | | | | | 183 | | | | | 184 | +---+---+ +---+---+ + 185 | ``` 186 | 187 | 188 | 189 | ## Resources 190 | 191 | * [ejrh's CPU in Verilog](https://github.com/ejrh/cpu) 192 | * [Ben Eater's video series](https://eater.net/8bit/) 193 | * [Steven Bell's microprocessor](https://stanford.edu/~sebell/oc_projects/ic_design_finalreport.pdf) 194 | --------------------------------------------------------------------------------