FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Western DigitalのRISC-VコアSweRV-EH1 (2. テストベンチを動かす)

Western DigitalからオリジナルのRISC-VコアSweRVがリリースされ、テストベンチが存在しないのでしばらく放置していたのだが、リビジョンが上がってテストベンチが公開された。

https://github.com/westerndigitalcorporation/swerv_eh1

しかし、ソースコードは公開されておらず、hexファイルしか存在してない!これではどのようにして動いているのか解析できない。

./testbench/hex/data.hex
./testbench/hex/program.hex

テストベンチの実行方法は以下だ。単純にhexをロードして動作させている。実行化完了すると"HELLO WORLD"と表示される。

make -f $RV_ROOT/tools/Makefile verilator-run
...
cp /home/msyksphinz/work/riscv/swerv_eh1/testbench/hex/*.hex .
./obj_dir/Vtb_top
Start of sim
HELLO WORLD
End of sim

手動で逆アセンブリしても良いのだが、唯一の解析手段としてトレースデータ(trace_port.csv)が出力されている。これを見てみることにする。

少し読みにくいので、文字列を揃えて読みやすくする。

diff --git a/testbench/tb_top.sv b/testbench/tb_top.sv
index a6dff4d..e5da3d1 100644
--- a/testbench/tb_top.sv
+++ b/testbench/tb_top.sv
@@ -131,8 +131,28 @@ module tb_top ( input logic core_clk, input logic reset_l);
        $write("%c", i_ahb_lsu.WriteData[7:0]);
      end

-   always @(posedge core_clk)
-     $fwrite(tp,"%b,%h,%h,%0h,%0h,3,%b,%h,%h,%b\n", rvtop.trace_rv_i_valid_ip, rvtop.trace_rv_i_address_ip[63:32], rvtop.trace_rv_i_address_ip[31:0], rvtop.trace_rv_i_insn_ip[63:32], rvtop.trace_rv_i_insn_ip[31:0],rvtop.trace_rv_i_exception_ip,rvtop.trace_rv_i_ecause_ip,rvtop.trace_rv_i_tval_ip,rvtop.trace_rv_i_interrupt_ip);
+   always @(posedge core_clk) begin
+     $fwrite(tp,"%03b,0x%08x_%08x,0x%08x_%08x,3,%03b,%01x,%08x,%03b  ",
+             rvtop.trace_rv_i_valid_ip,
+             rvtop.trace_rv_i_address_ip[63:32],
+             rvtop.trace_rv_i_address_ip[31: 0],
+             rvtop.trace_rv_i_insn_ip[63:32],
+             rvtop.trace_rv_i_insn_ip[31: 0],
+             rvtop.trace_rv_i_exception_ip,
+             rvtop.trace_rv_i_ecause_ip,
+             rvtop.trace_rv_i_tval_ip,
+             rvtop.trace_rv_i_interrupt_ip);
+   end // always @ (posedge core_clk)

    initial begin

ついでに、DASMも追加して逆アセンブルを表示できるようにする。

+     if (|rvtop.trace_rv_i_valid_ip[1:0]) begin
+       $fwrite (tp, "// ");
+       if (rvtop.trace_rv_i_valid_ip[1]) begin
+         $fwrite(tp, " | DASM(%08x)", rvtop.trace_rv_i_insn_ip[63:32]);
+       end
+       if (rvtop.trace_rv_i_valid_ip[0]) begin
+         $fwrite(tp, " | DASM(%08x)", rvtop.trace_rv_i_insn_ip[31: 0]);
+       end
+     end // else: !if(|rvtop.trace_rv_i_valid_ip[1:0])
+     $fwrite (tp, "\n");
+   end // always @ (posedge core_clk)

trace_port.csvを見てみる。さらに、先頭の3ビットが"000"のものはバブルなので除去すると以下のようになる。

$ grep -v ^000 trace_port.csv
001,0x00000000_00000000,0x00000000_b0219173,3,000,00,00000000,000  //  | DASM(b0219173)
001,0x00000000_00000004,0x00000000_ee0002b7,3,000,00,00000000,000  //  | DASM(ee0002b7)
001,0x00000000_00000008,0x00000000_0002e293,3,000,00,00000000,000  //  | DASM(0002e293)
001,0x00000000_0000000c,0x00000000_30529173,3,000,00,00000000,000  //  | DASM(30529173)
001,0x00000000_00000010,0x00000000_5d555337,3,000,00,00000000,000  //  | DASM(5d555337)
001,0x00000000_00000014,0x00000000_55536313,3,000,00,00000000,000  //  | DASM(55536313)
001,0x00000000_00000018,0x00000000_7c0310f3,3,000,00,00000000,000  //  | DASM(7c0310f3)
001,0x00000000_0000001c,0x00000000_000002b7,3,000,00,00000000,000  //  | DASM(000002b7)
001,0x00000000_00000020,0x00000000_0002e293,3,000,00,00000000,000  //  | DASM(0002e293)
001,0x00000000_00000024,0x00000000_7f829173,3,000,00,00000000,000  //  | DASM(7f829173)
001,0x00000000_00000028,0x00000000_000002b7,3,000,00,00000000,000  //  | DASM(000002b7)
001,0x00000000_0000002c,0x00000000_0002e293,3,000,00,00000000,000  //  | DASM(0002e293)
001,0x00000000_00000030,0x00000000_7f929173,3,000,00,00000000,000  //  | DASM(7f929173)
011,0x00000038_00000034,0xf0040537_00000013,3,000,00,00000000,000  //  | DASM(f0040537) | DASM(00000013)
011,0x00000040_0000003c,0x00100013_00056513,3,000,00,00000000,000  //  | DASM(00100013) | DASM(00056513)
011,0x00000048_00000044,0x04806493_000004b7,3,000,00,00000000,000  //  | DASM(04806493) | DASM(000004b7)
001,0x00000048_0000004c,0x04806493_00108093,3,000,00,00000000,000  //  | DASM(00108093)
011,0x00000054_00000050,0xd05805b7_00108093,3,000,00,00000000,000  //  | DASM(d05805b7) | DASM(00108093)
011,0x0000005c_00000058,0x000004b7_0005e593,3,000,00,00000000,000  //  | DASM(000004b7) | DASM(0005e593)
011,0x00000064_00000060,0x0095a023_0484e493,3,000,00,00000000,000  //  | DASM(0095a023) | DASM(0484e493)
001,0x00000064_00000068,0x0095a023_000004b7,3,000,00,00000000,000  //  | DASM(000004b7)
011,0x00000070_0000006c,0x0095a023_0454e493,3,000,00,00000000,000  //  | DASM(0095a023) | DASM(0454e493)
011,0x00000078_00000074,0x00748493_00000013,3,000,00,00000000,000  //  | DASM(00748493) | DASM(00000013)
001,0x00000078_0000007c,0x00748493_00000013,3,000,00,00000000,000  //  | DASM(00000013)
011,0x00000084_00000080,0x00000013_0095a023,3,000,00,00000000,000  //  | DASM(00000013) | DASM(0095a023)
011,0x0000008c_00000088,0x00000013_0095a023,3,000,00,00000000,000  //  | DASM(00000013) | DASM(0095a023)
011,0x00000094_00000090,0x00348493_00000013,3,000,00,00000000,000  //  | DASM(00348493) | DASM(00000013)

さらに逆アセンブリを追加する。

grep -v ^000 trace_port.csv | spike-dasm
001,0x00000000_00000000,0x00000000_b0219173,3,000,00,00000000,000  //  | csrrw   sp, minstret, gp
001,0x00000000_00000004,0x00000000_ee0002b7,3,000,00,00000000,000  //  | lui     t0, 0xee000
001,0x00000000_00000008,0x00000000_0002e293,3,000,00,00000000,000  //  | ori     t0, t0, 0
001,0x00000000_0000000c,0x00000000_30529173,3,000,00,00000000,000  //  | csrrw   sp, mtvec, t0
001,0x00000000_00000010,0x00000000_5d555337,3,000,00,00000000,000  //  | lui     t1, 0x5d555
001,0x00000000_00000014,0x00000000_55536313,3,000,00,00000000,000  //  | ori     t1, t1, 1365
001,0x00000000_00000018,0x00000000_7c0310f3,3,000,00,00000000,000  //  | csrrw   ra, unknown_7c0, t1
001,0x00000000_0000001c,0x00000000_000002b7,3,000,00,00000000,000  //  | lui     t0, 0x0
001,0x00000000_00000020,0x00000000_0002e293,3,000,00,00000000,000  //  | ori     t0, t0, 0
001,0x00000000_00000024,0x00000000_7f829173,3,000,00,00000000,000  //  | csrrw   sp, unknown_7f8, t0
001,0x00000000_00000028,0x00000000_000002b7,3,000,00,00000000,000  //  | lui     t0, 0x0
001,0x00000000_0000002c,0x00000000_0002e293,3,000,00,00000000,000  //  | ori     t0, t0, 0
001,0x00000000_00000030,0x00000000_7f929173,3,000,00,00000000,000  //  | csrrw   sp, unknown_7f9, t0
011,0x00000038_00000034,0xf0040537_00000013,3,000,00,00000000,000  //  | lui     a0, 0xf0040 | nop
011,0x00000040_0000003c,0x00100013_00056513,3,000,00,00000000,000  //  | li      zero, 1 | ori     a0, a0, 0
011,0x00000048_00000044,0x04806493_000004b7,3,000,00,00000000,000  //  | ori     s1, zero, 72 | lui     s1, 0x0
001,0x00000048_0000004c,0x04806493_00108093,3,000,00,00000000,000  //  | addi    ra, ra, 1
011,0x00000054_00000050,0xd05805b7_00108093,3,000,00,00000000,000  //  | lui     a1, 0xd0580 | addi    ra, ra, 1
011,0x0000005c_00000058,0x000004b7_0005e593,3,000,00,00000000,000  //  | lui     s1, 0x0 | ori     a1, a1, 0
011,0x00000064_00000060,0x0095a023_0484e493,3,000,00,00000000,000  //  | sw      s1, 0(a1) | ori     s1, s1, 72
001,0x00000064_00000068,0x0095a023_000004b7,3,000,00,00000000,000  //  | lui     s1, 0x0
011,0x00000070_0000006c,0x0095a023_0454e493,3,000,00,00000000,000  //  | sw      s1, 0(a1) | ori     s1, s1, 69
011,0x00000078_00000074,0x00748493_00000013,3,000,00,00000000,000  //  | addi    s1, s1, 7 | nop
001,0x00000078_0000007c,0x00748493_00000013,3,000,00,00000000,000  //  | nop
011,0x00000084_00000080,0x00000013_0095a023,3,000,00,00000000,000  //  | nop | sw      s1, 0(a1)
011,0x0000008c_00000088,0x00000013_0095a023,3,000,00,00000000,000  //  | nop | sw      s1, 0(a1)
  • アドレス 0xd058_0000 に文字データを書き込む。
  • H(79) → E(69) → L(69+7) → L(76) → O(79) → " "(32) → W(32+55) → O(79) → R(83) → L(76) → D(68)

という、非常にストレートで無理やり文字列を出力するプログラムだった。少し笑える。

f:id:msyksphinz:20190202222548p:plain
SweRVの実行解析結果