レジスタとADD命令とADDI命令
https://gyazo.com/ebb181d8b25ec330405182f4a6aa28ea
https://gyazo.com/224b3a3b5786bc5f80768dbd83bd2274
次は何かしらの演算をできるようにしたい。ひとまずADD命令と、レジスタに即値を入れるためのADDI命令を追加する。
計算を行うためのALUとレジスタは以前作ったものを再利用する。
既存のレジスタとALUを持ってきて、雑に接続。
既存のレジスタにはリセット機能が無かったので追加した。
code:diff
diff --git a/rtl/cpu.sv b/rtl/cpu.sv
index 8d0656c..c7ff36c 100644
--- a/rtl/cpu.sv
+++ b/rtl/cpu.sv
@@ -107,6 +107,52 @@ module cpu(
end
end
+ //-------------------------------------
+ // ALU
+ //-------------------------------------
+ logic 31:0 alu_in1, alu_in2, alu_result; + logic alu_negative, alu_zero;
+
+ assign alu_in1 = (alu_in1_src) ? rf_read_data1 : 32'b0;
+ assign alu_in2 = (alu_in2_src) ? rf_read_data2 : imm;
+
+ alu alu_inst(
+ .in1(alu_in1),
+ .in2(alu_in2),
+ .op(alu_op),
+ .result(alu_result),
+ .negative(alu_negative),
+ .zero(alu_zero)
+ );
+
+ //-------------------------------------
+ // Register File
+ //-------------------------------------
+ logic rf_we3;
+ logic 4:0 rf_addr1, rf_addr2, rf_addr3; + logic 31:0 rf_write_data3, rf_read_data1, rf_read_data2; +
+ assign rf_addr1 = instr_reg19:15; // rs1 + assign rf_addr2 = instr_reg24:20; // rs2 + assign rf_addr3 = instr_reg11:7; // rd + assign rf_we3 = (stage_reg == EX_STAGE) && dc_reg_write;
+ assign rf_write_data3 = alu_result;
+ // assign rf_write_data3 = (dc_mem_to_reg) ? mem_rdata :
+ // (jump) ? pc_reg + 4
+ // : alu_result;
+
+ regfile regfile_inst(
+ .clk(clk),
+ .reset_n(reset_n),
+ .we3(rf_we3),
+ .addr1(rf_addr1),
+ .addr2(rf_addr2),
+ .addr3(rf_addr3),
+ .writeData3(rf_write_data3),
+ .readData1(rf_read_data1),
+ .readData2(rf_read_data2)
+ );
+
always_comb begin
// デフォルト値
stage_next = stage_reg;
@@ -308,3 +354,90 @@ module immgen(
// end
endmodule
+// ALU
+//
+// code | operations
+// ------------------
+// 0000 | add
+// 0001 | sub
+// 0010 | sll
+// 0011 | slt
+// 0100 | sltu
+// 0101 | xor
+// 0110 | srl
+// 0111 | sra
+// 1000 | or
+// 1001 | and
+// ------------------
+module alu(
+ input logic 31:0 in1, in2, + output logic 31:0 result, + output logic negative, zero
+);
+
+ assign sraResult = $signed(in1) >>> in2;
+ assign sltResult = ($signed(in1) < $signed(in2)) ? 32'b1 : 32'b0;
+ assign sltuResult = (in1 < in2) ? 32'b1 : 32'b0;
+
+ assign result = (op == 4'b0000) ? (in1 + in2) : // plus
+ (op == 4'b0001) ? (in1 - in2) : // minus
+ (op == 4'b1001) ? (in1 & in2) : // and
+ (op == 4'b1000) ? (in1 | in2) : // or
+ (op == 4'b0101) ? (in1 ^ in2) : // xor
+ (op == 4'b0010) ? (in1 << in2) : // sll (shift left logical)
+ (op == 4'b0110) ? (in1 >> in2) : // srl (shift right logical)
+ (op == 4'b0111) ? sraResult : // sra (shift right arithmetic)
+ (op == 4'b0011) ? sltResult : // slt
+ (op == 4'b0100) ? sltuResult // sltu
+ : 32'hxxxxxxxx;
+ assign negative = result31; + assign zero = ~|result;
+
+ // always @(*) begin
+ // $display("op %b", op);
+ // $display("in1 %b", in1);
+ // $display("in2 %b", in2);
+ // $display("result %b", result);
+ // $display("zero %b", zero);
+ // end
+endmodule
+
+// Register File
+module regfile(
+ input logic clk,
+ input logic reset_n,
+ input logic we3,
+ input logic 4:0 addr1, addr2, addr3, + input logic 31:0 writeData3, + output logic 31:0 readData1, readData2 +);
+
+ // $0 へは書き込めるけど参照しても常に 0 が返る
+
+ assign readData1 = (addr1 === 5'b0) ? 32'b0 : registersaddr1; + assign readData2 = (addr2 === 5'b0) ? 32'b0 : registersaddr2; +
+ always_ff @(posedge clk) begin
+ if (!reset_n) begin
+ for (int i = 0; i < 32; i++) begin
+ end
+ end else if (we3) begin
+ registersaddr3 <= writeData3; + end
+ end
+
+ always @(*) begin
+ $display("x1 %d", registers1); + $display("x2 %d", registers2); + $display("x3 %d", registers3); + // $display("$2 %b", registers2); + // $display("$30 %b", registers30); + // $display("$31 %b", registers31); + end
+endmodule
diff --git a/rtl/cpu_test.sv b/rtl/cpu_test.sv
index 7623ea1..4097b4c 100644
--- a/rtl/cpu_test.sv
+++ b/rtl/cpu_test.sv
@@ -72,9 +72,9 @@ module cpu_test;
* プログラムの書き込み
*/
- instructions0 = add(0, 0, 0); // nop - instructions1 = add(0, 0, 0); // nop - instructions2 = add(0, 0, 0); // nop + instructions0 = addi(1, 0, 10); // addi x1, x0, 10 + instructions1 = add(2, 1, 1); // addi x2, x1, x1 + instructions2 = add(3, 1, 2); // addi x3, x1, x2 instructions3 = jal(0, -12 >> 1); // jal x0, -12 (0番地へ戻る) mem_monitor_on = 1;
実行されるのは以下のプログラム
code:verilog
instructions0 = addi(1, 0, 10); // addi x1, x0, 10 instructions1 = add(2, 1, 1); // addi x2, x1, x1 instructions2 = add(3, 1, 2); // addi x3, x1, x2 instructions3 = jal(0, -12 >> 1); // jal x0, -12 (0番地へ戻る) テストベンチを実行。
レジスタ x1 x2 x3 に 10、20、30が格納されていることが確認できる。
code:sh
$ make test
...
10205: pc = 00000000, stage = 0, instr = 00000000, mem_valid = 1, mem_ready = 0, mem_addr = 00000000, mem_wdata = 00000000, mem_wstrb = 0000, mem_rdata = xxxxxxxx
10215: pc = 00000000, stage = 0, instr = 00000000, mem_valid = 1, mem_ready = 0, mem_addr = 00000000, mem_wdata = 00000000, mem_wstrb = 0000, mem_rdata = 00a00093
10235: pc = 00000000, stage = 0, instr = 00000000, mem_valid = 1, mem_ready = 1, mem_addr = 00000000, mem_wdata = 00000000, mem_wstrb = 0000, mem_rdata = 00a00093
10245: pc = 00000000, stage = 1, instr = 00a00093, mem_valid = 0, mem_ready = 0, mem_addr = 00000000, mem_wdata = 00000000, mem_wstrb = 0000, mem_rdata = 00a00093
x1 10
x2 0
x3 0
10255: pc = 00000004, stage = 0, instr = 00a00093, mem_valid = 1, mem_ready = 0, mem_addr = 00000004, mem_wdata = 00000000, mem_wstrb = 0000, mem_rdata = 00a00093
10265: pc = 00000004, stage = 0, instr = 00a00093, mem_valid = 1, mem_ready = 0, mem_addr = 00000004, mem_wdata = 00000000, mem_wstrb = 0000, mem_rdata = 00108133
10285: pc = 00000004, stage = 0, instr = 00a00093, mem_valid = 1, mem_ready = 1, mem_addr = 00000004, mem_wdata = 00000000, mem_wstrb = 0000, mem_rdata = 00108133
10295: pc = 00000004, stage = 1, instr = 00108133, mem_valid = 0, mem_ready = 0, mem_addr = 00000000, mem_wdata = 00000000, mem_wstrb = 0000, mem_rdata = 00108133
x1 10
x2 20
x3 0
10305: pc = 00000008, stage = 0, instr = 00108133, mem_valid = 1, mem_ready = 0, mem_addr = 00000008, mem_wdata = 00000000, mem_wstrb = 0000, mem_rdata = 00a00093
10315: pc = 00000008, stage = 0, instr = 00108133, mem_valid = 1, mem_ready = 0, mem_addr = 00000008, mem_wdata = 00000000, mem_wstrb = 0000, mem_rdata = 002081b3
10335: pc = 00000008, stage = 0, instr = 00108133, mem_valid = 1, mem_ready = 1, mem_addr = 00000008, mem_wdata = 00000000, mem_wstrb = 0000, mem_rdata = 002081b3
10345: pc = 00000008, stage = 1, instr = 002081b3, mem_valid = 0, mem_ready = 0, mem_addr = 00000000, mem_wdata = 00000000, mem_wstrb = 0000, mem_rdata = 002081b3
x1 10
x2 20
x3 30
...