aboutsummaryrefslogtreecommitdiffstats
path: root/atk16_fpga/cu.v
diff options
context:
space:
mode:
Diffstat (limited to 'atk16_fpga/cu.v')
-rw-r--r--atk16_fpga/cu.v201
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