RISC-Vの実装であるRocket-Chipは、RISC-Vの最新使用に追従しているため最初に見るべきデザインとしてはよくできているが、
- Chiselで記述されており(初心者には)可読性が低い。
- 外部のSoCプラットフォームについて情報がない
ことから、なかなかオリジナルのSoCをくみ上げるためのデザインとしてポーティングしにくい。
とはいえ、TileLinkは単なるバスのはずだし、クロックとリセットさえ突っ込めばとりあえずフェッチリクエストが上がってくるはずだ。 そのあたりを解析して、Rocket-Chipを利用したオリジナルSoCプラットフォーム構築のための情報収集を行っていこう。
SiFive の Freedom SoCとFreechips ProjectのRocket Chipのブート時の挙動を解析しているのだが、どうも理解できないところが多い。
FreeChips ProjectのRocket Coreが生成しているログ
FreeChips ProjectがRocket CoreのVerilog記述だけを抜き出して、TestBenchを被せてRTLシミュレーションを実行してみた。 最初の20命令を抜き出して、どのような命令を実行しているのかをチェックする。
C0: 42 [1] pc=[0000000800] W[r 0=0000000000000804][1] R[r 0=0000000000000000] R[r12=d72473afd72473af] inst=[00c0006f] j pc + 0xc C0: 44 [1] pc=[000000080c] W[r 0=0000000000000004][0] R[r 0=0000000000000000] R[r31=d72473afd72473af] inst=[0ff0000f] fence C0: 45 [1] pc=[0000000810] W[r 0=515059a2515059a2][1] R[r 8=9178322291783222] R[r18=d72473afd72473af] inst=[7b241073] csrw dscratch, s0 C0: 50 [1] pc=[0000000814] W[r 8=0000000000000000][1] R[r 0=0000000000000000] R[r20=d72473afd72473af] inst=[f1402473] csrr s0, mhartid C0: 68 [1] pc=[0000000818] W[r 0=0000000000000100][0] R[r 0=0000000000000000] R[r 8=0000000000000000] inst=[10802023] sw s0, 256(zero) C0: 79 [1] pc=[000000081c] W[r 0=0000000000000400][1] R[r 8=0000000000000000] R[r 0=0000000000000000] inst=[40044403] lbu s0, 1024(s0) C0: 86 [0] pc=[000000081c] W[r 8=0000000000000000][1] R[r 8=0000000000000000] R[r 0=0000000000000000] inst=[40044403] lbu s0, 1024(s0) C0: 89 [1] pc=[0000000820] W[r 8=0000000000000000][1] R[r 8=0000000000000000] R[r 1=0000000000000003] inst=[00147413] andi s0, s0, 1 C0: 90 [1] pc=[0000000824] W[r 0=0000000000000000][0] R[r 8=0000000000000000] R[r 0=0000000000000000] inst=[02041063] bnez s0, pc + 32 C0: 94 [1] pc=[0000000828] W[r 8=0000000000000000][1] R[r 0=0000000000000000] R[r20=0000000000000003] inst=[f1402473] csrr s0, mhartid C0: 97 [1] pc=[000000082c] W[r 0=0000000000000400][1] R[r 8=0000000000000000] R[r 0=0000000000000000] inst=[40044403] lbu s0, 1024(s0) C0: 104 [0] pc=[000000082c] W[r 8=0000000000000000][1] R[r 8=0000000000000000] R[r 0=0000000000000000] inst=[40044403] lbu s0, 1024(s0) C0: 107 [1] pc=[0000000830] W[r 8=0000000000000000][1] R[r 8=0000000000000000] R[r 2=0000000000000003] inst=[00247413] andi s0, s0, 2 C0: 108 [1] pc=[0000000834] W[r 0=0000000000000000][0] R[r 8=0000000000000000] R[r 0=0000000000000000] inst=[fc0418e3] bnez s0, pc - 48 C0: 112 [1] pc=[0000000838] W[r 0=000000000000083c][1] R[r31=0000000000000003] R[r29=0000000000000003] inst=[fddff06f] j pc - 0x24 C0: 114 [1] pc=[0000000814] W[r 8=0000000000000000][1] R[r 0=0000000000000000] R[r20=0000000000000003] inst=[f1402473] csrr s0, mhartid C0: 117 [1] pc=[0000000818] W[r 0=0000000000000100][0] R[r 0=0000000000000000] R[r 8=0000000000000000] inst=[10802023] sw s0, 256(zero) C0: 128 [1] pc=[000000081c] W[r 0=0000000000000400][1] R[r 8=0000000000000000] R[r 0=0000000000000000] inst=[40044403] lbu s0, 1024(s0) C0: 135 [0] pc=[000000081c] W[r 8=0000000000000000][1] R[r 8=0000000000000000] R[r 0=0000000000000000] inst=[40044403] lbu s0, 1024(s0) C0: 138 [1] pc=[0000000820] W[r 8=0000000000000000][1] R[r 8=0000000000000000] R[r 1=0000000000000003] inst=[00147413] andi s0, s0, 1
Freedom E300 Everywhere の Rocket Coreが生成しているログ
一方で、Freedom E300 Everywhere の Verilog記述だけを抜き出して、TestBenchを被せてRTLシミュレーションを実行してみた。 最初の命令群を抜き出して、どのような命令を実行しているのかチェックする。
C0: 31 [1] pc=[00010000] W[r10=00000000][1] R[r 0=00000000] R[r20=e4a715cb] inst=[f1402573] csrr a0, mhartid C0: 34 [1] pc=[00010004] W[r10=20000000][1] R[r 0=00000000] R[r 0=00000000] inst=[20000537] lui a0, 0x20000 C0: 260 [1] pc=[00010008] W[r 0=20000020][1] R[r10=20000000] R[r 0=00000000] inst=[02052283] lw t0, 32(a0) C0: 261 [1] pc=[0001000c] W[r 0=00000000][1] R[r 0=00000000] R[r 0=00000000] inst=[00000013] nop C0: 262 [1] pc=[00010010] W[r 0=00000000][1] R[r 0=00000000] R[r 0=00000000] inst=[00000013] nop C0: 263 [1] pc=[00010014] W[r 0=00000000][1] R[r 0=00000000] R[r 0=00000000] inst=[00000013] nop C0: 264 [1] pc=[00010018] W[r 0=00000000][1] R[r 0=00000000] R[r 0=00000000] inst=[00000013] nop C0: 265 [1] pc=[0001001c] W[r 0=00000000][1] R[r 0=00000000] R[r 0=00000000] inst=[00000013] nop C0: 266 [1] pc=[00010020] W[r 0=00000000][1] R[r 0=00000000] R[r 0=00000000] inst=[00000013] nop C0: 267 [1] pc=[00010024] W[r 0=00000000][1] R[r 0=00000000] R[r 0=00000000] inst=[00000013] nop C0: 268 [0] pc=[00010028] W[r 5=00c6cf01][1] R[r 0=00000000] R[r 0=00000000] inst=[00000013] nop C0: 273 [1] pc=[00010028] W[r 0=00000000][1] R[r 0=00000000] R[r 0=00000000] inst=[00000013] nop C0: 274 [1] pc=[0001002c] W[r 5=deadc000][1] R[r27=20000003] R[r10=e4a715cb] inst=[deadc2b7] lui t0, 0xdeadc C0: 275 [1] pc=[00010030] W[r 5=deadbeef][1] R[r 5=deadc000] R[r15=e4a715cb] inst=[eef28293] addi t0, t0, -273 C0: 276 [1] pc=[00010034] W[r 0=20000000][0] R[r10=20000000] R[r 5=deadbeef] inst=[00552023] sw t0, 0(a0) C0: 287 [1] pc=[00010038] W[r 0=20000004][0] R[r10=20000000] R[r 5=deadbeef] inst=[00552223] sw t0, 4(a0) C0: 298 [1] pc=[0001003c] W[r 0=20000008][0] R[r10=20000000] R[r 5=deadbeef] inst=[00552423] sw t0, 8(a0) C0: 319 [1] pc=[00010040] W[r11=00010040][1] R[r 0=00000000] R[r 0=00000000] inst=[00000597] auipc a1, 0x0 C0: 320 [1] pc=[00010044] W[r11=00010050][1] R[r11=00010040] R[r16=deadbeef] inst=[01058593] addi a1, a1, 16 C0: 321 [1] pc=[00010048] W[r 5=40000000][1] R[r 0=00000000] R[r 0=00000000] inst=[400002b7] lui t0, 0x40000 C0: 322 [1] pc=[0001004c] W[r 0=00010050][1] R[r 5=40000000] R[r 0=00000000] inst=[00028067] jr t0
根本的に異なるのは、ブートアドレスが
- Freechips Project Rocket-Core : PC=0x00000800 (デバッグモジュール)
- SiFive Freedom E300 Everywhere : PC=0x00010000 (BootROM)
となっており、同じコアを使っているのになぜかスタートアドレスが異なるという事態になっている。
そもそも、何故このような違いが発生するのだろうか?
Freechips Project Rocket-Core のリセット後の挙動
Freechips Project の Rocket Coreは、リセット直後にTileLinkからフェッチが入っており、 0x10040 という不思議なアドレスからフェッチが入っている。
何故だろうと解析をしていったのだが、これはどうもBootROMのhangアドレスによって決められているようだ。やはり、最初にBootROMへのフェッチが入っているのは間違いなさそう。
/** Size, location and contents of the boot rom. */ case class BootROMParams( address: BigInt = 0x10000, size: Int = 0x10000, hang: BigInt = 0x10040, contentFileName: String) case object BootROMParams extends Field[BootROMParams]
- bootrom/bootrom.dmp (コンパイル結果をダンプしたもの)
0000000000010040 <_hang>: 10040: f1402573 csrr a0,mhartid 10044: 00000597 auipc a1,0x0 10048: 03c58593 addi a1,a1,60 # 10080 <_dtb> 1004c: 10500073 wfi 10050: bff5 j 1004c <_hang+0xc>
ここで、WFI(Wait for Interrupt) が実行され、Interrupt待ちの状態になっているが、Coreに対してio_interrupts_debug
信号が既にAssertになっている。
これにより、直ぐにDebug割り込みが入り、0x0000_0800にジャンプしているという訳だ。
一方で、SiFive Freedom E300 EverywhereではデフォルトでDebug InterruptがAssertされていない。これにより、デバッグコードにはジャンプしない。