diff options
Diffstat (limited to 'atk16_fpga/cu.v')
| -rw-r--r-- | atk16_fpga/cu.v | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/atk16_fpga/cu.v b/atk16_fpga/cu.v new file mode 100644 index 0000000..915ce8e --- /dev/null +++ b/atk16_fpga/cu.v @@ -0,0 +1,201 @@ +`default_nettype none + +`define PH_RESET 3'd0 +`define PH_FETCH 3'd1 +`define PH_DECODE 3'd2 +`define PH_EXECUTE 3'd3 + +`define FL_CARRY 2'd3 +`define FL_OVERFLOW 2'd2 +`define FL_NEGATIVE 2'd1 +`define FL_ZERO 2'd0 + +// Legend: +// T = target register select +// L = left operand register select +// R = right operand register select +// I = immediate operand +// S = ALU operation select +// A = absolute (1) / relative (0) addressing +// D = direct (1) / indirect (0) load +// M = immediate mode (1) / register mode (0) + +// ALR (arithmetic-logic, register) +// 0000 TTTL LLRR RSSS +`define OP_ALR 4'b0000 +// ALI (arithmetic-logic, immediate) +// 0001 TTTL LLII ISSS +`define OP_ALI 4'b0001 +// LDR (load by register) +// 0010 TTTR RRXX XXAD +`define OP_LDR 4'b0010 +// STR (store to memory) +// 0011 XXXL LLRR RMAD +`define OP_STR 4'b0011 +// LDI (load by immediate) +// 0100 TTTD IIII IIII +`define OP_LDI 4'b0100 + +module cu( + input wire clk, + input wire rst +); + reg [2:0] alu_sel; + reg [15:0] alu_a; + reg [15:0] alu_b; + wire [15:0] alu_result; + wire [3:0] alu_flags; + reg [15:0] regbank [0:7]; + reg [15:0] decoded_tmp; + reg [2:0] phase = `PH_RESET; + reg [15:0] pc; + reg [15:0] ir; + + reg [15:0] mem_addr; + reg [15:0] mem_data_in; + reg mem_read_en, mem_write_en; + wire mem_done; + wire [15:0] mem_data_out; + mem_fsm mem_fsm_inst( + .clk(clk), + .addr(mem_addr), + .data_in(mem_data_in), + .read_en(mem_read_en), + .write_en(mem_write_en), + .data_out(mem_data_out), + .done(mem_done) + ); + + alu alu_inst( + .sel(alu_sel), + .a(alu_a), + .b(alu_b), + .result(alu_result), + .flags(alu_flags) + ); + + // Named reg wires for debugging purposes + wire [15:0] ra, rb, rc, rd, re, rf, rg, rh; + assign ra = regbank[0]; + assign rb = regbank[1]; + assign rc = regbank[2]; + assign rd = regbank[3]; + assign re = regbank[4]; + assign rf = regbank[5]; + assign rg = regbank[6]; + assign rh = regbank[7]; + + integer i; + always @(posedge clk or posedge rst) begin + // Handle reset button + if (rst) begin + phase <= `PH_RESET; + end + + else if (phase == `PH_RESET) begin + phase <= `PH_FETCH; + + pc <= 16'd0; + mem_read_en <= 0; + mem_write_en <= 0; + + for (i = 0; i < 8; i = i + 1) begin + regbank[i] <= 16'd0; + end + end + + // Fetch stage + else if (phase == `PH_FETCH) begin + mem_read_en <= 1; + mem_write_en <= 0; + mem_addr <= pc; + + if (mem_done) begin + mem_read_en <= 0; + mem_write_en <= 0; + ir <= mem_data_out; + phase <= `PH_DECODE; + pc <= pc + 16'd1; + end + end + + // Decode stage + else if (phase == `PH_DECODE) begin + phase <= `PH_EXECUTE; + + case (ir[15:12]) + `OP_ALR: begin + alu_sel <= ir[2:0]; // select ALU operation + alu_a <= regbank[ir[8:6]]; // read operand A + alu_b <= regbank[ir[5:3]]; // read operand B + end + `OP_ALI: begin + alu_sel <= ir[2:0]; // select ALU operation + alu_a <= regbank[ir[8:6]]; // read operand A + alu_b <= ir[5:3]; // read immediate operand + end + `OP_LDR: begin + // set target reg value to address, dereference in execute phase + if (ir[1] == 1 && ir[0] == 1) // addressing mode: absolute, direct + decoded_tmp <= regbank[ir[8:6]]; + else if (ir[1] == 0 && ir[0] == 1) // addressing mode: pc relative, direct + decoded_tmp <= regbank[ir[8:6]] + pc - 1; + /*else if (ir[1] == 1 && ir[0] == 0) begin // addressing mode: absolute, indirect + bram_wr <= 0; + bram_rd <= 1; + bram_addr <= regbank[ir[8:6]]; + decoded_tmp <= bram_data_out; + end + else if (ir[1] == 0 && ir[0] == 0) begin // addressing mode: pc relative, indirect + bram_wr <= 0; + bram_rd <= 1; + bram_addr <= regbank[ir[8:6]] + pc - 1; + decoded_tmp <= bram_data_out; + end*/ + end + `OP_STR: begin + // ir[2] = M = immediate mode (1) / register mode (0) + // ir[1] = A = absolute (1) / relative (0) addressing + // ir[0] = D = direct (1) / indirect (0) load + // TODO + end + default: begin + `ifdef __SYNTHESIS__ + $fatal(1, "decode: unhandled opcode %04b", ir[15:12]); + `endif + end + endcase + end + + // Execute stage + else if (phase == `PH_EXECUTE) begin + case (ir[15:12]) + `OP_ALR, `OP_ALI: begin + regbank[ir[11:9]] <= alu_result; // write result + phase <= `PH_FETCH; + end + `OP_LDR: begin + //$display("ir[11:9] %d, reg val: %d, mem_data_out: %d, mem_done: %d\n", ir[11:9], regbank[ir[11:9]], mem_data_out, mem_done); + mem_read_en <= 1; + mem_write_en <= 0; + mem_addr <= decoded_tmp; + + if (mem_done) begin + regbank[ir[11:9]] <= mem_data_out; // dereference address + mem_read_en <= 0; + mem_write_en <= 0; + phase <= `PH_FETCH; + end + end + `OP_STR: begin + // TODO + end + default: begin + `ifdef __SYNTHESIS__ + $fatal(1, "execute: unhandled opcode %04b", ir[15:12]); + `endif + end + endcase + end + end +endmodule |
