UCB(University of California Berkeley)の実装したRISC-Vコアとしては代表的なものが2つあり、1つのリポジトリでブランチが切られている。
- Rocket-Chip : masterブランチ
- BOOM-v1 : boom2ブランチ
- BOOM-v1 : boom-v1ブランチ
しかしどうもRocket-Chipのシミュレーションを試行していると、Rocket-ChipとBOOMで、異なるriscv-toolsを使わなければならない気がしている。
boom2ブランチでのriscv-toolsサブモジュールでのツールチェインをビルドし、それをRISCV=/home/msyksphinz/riscv64_boom/
としてインストールしている。
一方masterブランチでのriscv-toolsサブモジュールでのツールチェインは、RISCV=/home/msyksphinz/riscv64/
としてインストールしている。
そして、Rocket-Chipを実行するときはRISCV=/home/msyksphinz/riscv64/
, BOOMを実行するときはRISCV=/home/msyksphinz/riscv64_boom
を使うなど切り替えるようにして実行している。
この違いは何なのだろう?
例えば、RISCV=/home/msyksphinz/riscv/
(Rocket-Chip用にビルドしたツールチェイン)にパスを通してBOOMをシミュレーションすると、なぜか無限ループに陥ってしまう。
- Rocket-Chip用のriscv-toolsにパスを通した場合のシミュレーションログ
C0: 24 [0] pc=[0000001000] W[r 0=0000000000001000][0] R[r 0=3ef5069c0fbbdc7f] R[r 0=664f9c28ef95a723] inst=[0000006f] j pc + 0x0 C0: 25 [0] pc=[0000001000] W[r 0=0000000000001000][0] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[0000006f] j pc + 0x0 C0: 26 [0] pc=[0000001000] W[r 0=0000000000001000][0] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[0000006f] j pc + 0x0 C0: 27 [0] pc=[0000001000] W[r 0=0000000000001000][0] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[0000006f] j pc + 0x0 C0: 28 [1] pc=[0000001000] W[r 0=0000000000001004][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[0000006f] j pc + 0x0 C0: 29 [1] pc=[0000001000] W[r 0=0000000000001004][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[0000006f] j pc + 0x0 C0: 30 [1] pc=[0000001000] W[r 0=0000000000001004][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[0000006f] j pc + 0x0 C0: 31 [1] pc=[0000001000] W[r 0=0000000000001004][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[0000006f] j pc + 0x0 C0: 32 [1] pc=[0000001000] W[r 0=0000000000001004][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[0000006f] j pc + 0x0
- BOOM用のriscv-toolsにパスを通した場合のシミュレーションログ
C0: 17348 [1] pc=[0080000144] W[r29=00000000000007ff][1] R[r 0=0000000000000000] R[r31=0000000000000003] inst=[7ff00e93] li t4, 2047 C0: 17349 [1] pc=[0080000148] W[r28=0000000000000008][1] R[r 0=0000000000000000] R[r 8=0000000000000003] inst=[00800e13] li t3, 8 C0: 17350 [1] pc=[008000014c] W[r 0=0000000000000000][0] R[r 3=00000000000007ff] R[r29=00000000000007ff] inst=[21d19263] bne gp, t4, pc + 516 C0: 17351 [1] pc=[0080000150] W[r 1=ffffffff80000000][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[800000b7] lui ra, 0x80000 C0: 17352 [1] pc=[0080000154] W[r 1=000000007fffffff][1] R[r 1=ffffffff80000000] R[r31=0000000000000003] inst=[fff0809b] addiw ra, ra, -1 C0: 17353 [1] pc=[0080000158] W[r 3=000000007fffffff][1] R[r 1=000000007fffffff] R[r 0=0000000000000000] inst=[00008193] mv gp, ra C0: 17354 [1] pc=[008000015c] W[r29=ffffffff80000000][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[80000eb7] lui t4, 0x80000 C0: 17355 [1] pc=[0080000160] W[r29=000000007fffffff][1] R[r29=ffffffff80000000] R[r31=0000000000000003] inst=[fffe8e9b] addiw t4, t4, -1 C0: 17356 [1] pc=[0080000164] W[r28=0000000000000009][1] R[r 0=0000000000000000] R[r 9=0000000000000003] inst=[00900e13] li t3, 9 C0: 17357 [1] pc=[0080000168] W[r 0=0000000000000000][0] R[r 3=000000007fffffff] R[r29=000000007fffffff] inst=[1fd19463] bne gp, t4, pc + 488 C0: 17358 [1] pc=[008000016c] W[r 1=ffffffff80000000][1] R[r 0=0000000000000000] R[r 0=0000000000000000] inst=[800000b7] lui ra, 0x80000 C0: 17359 [1] pc=[0080000170] W[r 1=000000007fffffff][1] R[r 1=ffffffff80000000] R[r31=0000000000000003] inst=[fff0809b] addiw ra, ra, -1 C0: 17360 [1] pc=[0080000174] W[r 3=00000000800007fe][1] R[r 1=000000007fffffff] R[r31=0000000000000003] inst=[7ff08193] addi gp, ra, 2047
module switch riscv/riscv64
を設定してBOOMを実行する。
RISCV=/home/msyksphinz/riscv64/ make && make output/rv64ui-p-addi.out
で実行する。
C0: 0 [0] pc=[0000001000] W[r 0=0000000000000000][0] R[r23=260bcc317122ae33] R[r31=10b4a6fd8b9b6017] inst=[e3fbf3fb] custom3.rd.rs1.rs2 (args unknown) C0: 1 [0] pc=[0000001000] W[r 0=0000000000000000][0] R[r23=260bcc317122ae33] R[r31=10b4a6fd8b9b6017] inst=[e3fbf3fb] custom3.rd.rs1.rs2 (args unknown) C0: 2 [0] pc=[0000001000] W[r 0=0000000000000000][0] R[r23=260bcc317122ae33] R[r31=10b4a6fd8b9b6017] inst=[e3fbf3fb] custom3.rd.rs1.rs2 (args unknown) C0: 3 [0] pc=[0000001000] W[r 0=0000000000000000][0] R[r23=260bcc317122ae33] R[r31=10b4a6fd8b9b6017] inst=[e3fbf3fb] custom3.rd.rs1.rs2 (args unknown) C0: 4 [0] pc=[0000001000] W[r 0=0000000000000000][0] R[r23=260bcc317122ae33] R[r31=10b4a6fd8b9b6017] inst=[e3fbf3fb] custom3.rd.rs1.rs2 (args unknown) emulator-Top-DefaultConfig: ../fesvr/dtm.cc:556: void dtm_t::producer_thread(): Assertion `get_field(hartinfo, DMI_HARTINFO_NSCRATCH) > 0' failed.
fesvr(RISC-V Front-End Server)の実装の違いが原因っぽい。
Rocket-Chipが立ち上がる仕組み
本ブログでも何度か開設したが、Rocket-Chipの立ち上がりは、TsetHarness内に含まれるSimDTM.vにより管理されている。
emulator/generated_src/freechips.rocketchip.system.DefaultConfig.v
module TestHarness( input clock, input reset, output io_success ); wire ExampleRocketSystem_clock; ... SimDTM SimDTM ( .exit(SimDTM_exit), .debug_req_ready(SimDTM_debug_req_ready), .debug_req_valid(SimDTM_debug_req_valid), ...
SimDTMはvsrc/SimDTM.v
で定義されており、これは内部でC++で記述されているdtm_t
で記述されている。
vsrc/SimDTM.v
module SimDTM( input clk, input reset, output debug_req_valid, ... else begin __exit = debug_tick( __debug_req_valid, __debug_req_ready, __debug_req_bits_addr, __debug_req_bits_op, __debug_req_bits_data,
csrc/SimDTM.cc
extern "C" int debug_tick ( unsigned char* debug_req_valid, unsigned char debug_req_ready, int* debug_req_bits_addr, int* debug_req_bits_op, ...
この時の、スタートアップの方法に違いがあるようだ。
- Rocket-Chipの場合
csrc/dtm.cc
void dtm_t::reset() { for (int hartsel = 0; hartsel < num_harts; hartsel ++ ){ select_hart(hartsel); // this command also does a halt and resume fence_i(); // after this command, the hart will run from _start. write_csr(0x7b1, get_entry_point()); } // In theory any hart can handle the memory accesses, // this will enforce that hart 0 handles them. select_hart(0); read(DMI_DMSTATUS); } ... void dtm_t::fence_i() { halt(current_hart); const uint32_t prog[] = { FENCE_I, EBREAK }; //TODO: Use the transfer = 0. uint32_t command = AC_ACCESS_REGISTER_POSTEXEC | AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE | AC_AR_SIZE(xlen) | AC_AR_REGNO(X0); RUN_AC_OR_DIE(command, prog, sizeof(prog)/sizeof(*prog), 0, 0); resume(current_hart); }
- BOOMの場合
csrc/dtm.cc
void dtm_t::reset() { fence_i(); // set pc and un-halt write_csr(0x7b1, 0x80000000U); clear_csr(0x7b0, 8); } ... void dtm_t::fence_i() { const uint32_t prog[] = { FENCE_I, JUMP(rom_ret(), ram_base() + 4) }; run_program(prog, sizeof(prog)/sizeof(*prog), 0); }
デバッグレジスタの0x7b1版というのは、DebugPCのこと。Rocket-Chipの場合は、ELFファイルのエントリポイントを直接入れるが、BOOMは律儀に0x8000_0000からブートするという仕組みになっているようだ。
一方で0x7b0は、Debug Control Statusレジスタなのだが、clear_csr(0x7b0, 8);
の8って何だろうなあ。4bit目をクリアしても意味ない気が。。。
まあとりあえず、このあたりのスタートアップで使用するFront-End Serverの違いにより、いろいろと処理が異なってくるということか。