JAL命令とJALR命令
https://gyazo.com/b124d1b370cab549e518d1c8ee522388
https://gyazo.com/975566c04bc5617a8752737249714512
(追記)
JAL命令(その2)で指定したアドレスへ飛べるようにしたが、戻り先のアドレスをレジスタへ格納する処理はまだ未実装だった。 JALの戻り先をレジスタへ格納する処理と、レジスタへ格納した戻り先へジャンプする命令 JALR 命令を実装する。
戻り先のアドレスをレジスタへ格納
JALとJALRの時は jump がアサートされるので、戻り先のアドレスをレジスタへ格納するように修正する。
code:diff
diff --git a/rtl/cpu.sv b/rtl/cpu.sv
index f1c63ba..5259e59 100644
--- a/rtl/cpu.sv
+++ b/rtl/cpu.sv
@@ -146,12 +146,9 @@ module cpu(
assign rf_addr2 = instr_reg24:20; // rs2 assign rf_addr3 = instr_reg11:7; // rd assign rf_we3 = (stage_reg == WB_STAGE) && dc_reg_write;
-
- assign rf_write_data3 = (dc_mem_to_reg) ? mem_rdata_reg
+ assign rf_write_data3 = (dc_mem_to_reg) ? mem_rdata_reg : // lw の場合
+ (jump) ? pc_reg + 4 // jal, jalr の場合
: alu_result;
レジスタへ格納した戻り先へジャンプ
JALR命令が来た場合は、レジスタへ格納した戻り先へジャンプできるようにする。
code:diff
diff --git a/rtl/cpu.sv b/rtl/cpu.sv
index f1c63ba..5259e59 100644
--- a/rtl/cpu.sv
+++ b/rtl/cpu.sv
@@ -146,12 +146,9 @@ module cpu(
assign rf_addr2 = instr_reg24:20; // rs2 assign rf_addr3 = instr_reg11:7; // rd assign rf_we3 = (stage_reg == WB_STAGE) && dc_reg_write;
-
- assign rf_write_data3 = (dc_mem_to_reg) ? mem_rdata_reg
+ assign rf_write_data3 = (dc_mem_to_reg) ? mem_rdata_reg : // lw の場合
+ (jump) ? pc_reg + 4 // jal, jalr の場合
: alu_result;
- // assign rf_write_data3 = (dc_mem_to_reg) ? mem_rdata :
- // (jump) ? pc_reg + 4
- // : alu_result;
regfile regfile_inst(
.clk(clk),
@@ -200,8 +197,8 @@ module cpu(
// レジスタ書き戻し
WB_STAGE: begin
if (jump) begin
- // jal 命令の場合
- pc_next = pc_reg + imm;
+ pc_next = (jump_reg) ? rf_read_data1 + imm // jalr の場合
+ : pc_reg + imm; // jal の場合
end else if (branch) begin
// beq 命令の場合
pc_next = (alu_zero) ?
テストコード
テストベンチはこんな感じ。メモリの 0x94 番地に double 関数の返り値(200)が格納されればOK
code:diff
diff --git a/rtl/cpu_test.sv b/rtl/cpu_test.sv
index 7f5888c..c7867c5 100644
--- a/rtl/cpu_test.sv
+++ b/rtl/cpu_test.sv
@@ -90,8 +90,18 @@ module cpu_test;
instructions12 = sw(0, 7, 32'h8C); // M0x8C = x7 instructions13 = ori(7, 7, 32'h0678); // x7 = x7 | 0x678 instructions14 = sw(0, 7, 32'h90); // M0x90 = x7 - // 0番地へ戻る
- instructions15 = jal(0, -60 >> 1); // jal x0, -60 (0番地へ戻る) + // jal と jalr で関数呼び出し
+ instructions15 = addi(10, 0, 100); // x10 = 100 + instructions16 = jal(1, 12 >> 1); // jal x1, 12 (double 関数を呼び出す) + instructions17 = sw(0, 10, 32'h94); // M0x94 = x10 + // 無限ループ
+ instructions18 = jal(0, 0); + // double 関数
+ // x10 に渡した値を二倍にして x10 へ入れて返す関数
+ instructions19 = addi(5, 10, 0); // x5 = x10 + instructions20 = add(10, 5, 5); // x10 = x5 + x5 + instructions21 = jalr(0, 1, 0); // jalr x0, x1, 0 +
mem_monitor_on = 1;
addr = 32'h00000000;
@@ -177,6 +187,17 @@ module cpu_test;
mem_monitor_valid_reg = 0;
+ // メモリの 0x94 番地の内容を確認
+ mem_monitor_on = 1;
+ mem_monitor_valid_reg = 1;
+ mem_monitor_addr_reg = 32'h00000094;
+ mem_monitor_wstrb_reg = 4'b0000;
+ wait(mem_ready);
+ $display("mem0x94 = %d", mem_rdata); + mem_monitor_valid_reg = 0;
+
$finish;
end
実行結果。メモリの 0x94 番地に double 関数の呼び出し結果である 200 が格納されている。
https://gyazo.com/c455e700be0d959900b931d174b75a23