FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages/

Rocket-Chip を改造して外部SRAMからプログラムをロードして実行する

RISC-V の実装である Rocket-Chip を改造して、外部にSRAMを接続してそこにプログラムを置き、RISC-V Rocket-Chipからプログラムをフェッチして実行できるようにする。

Rocket-Chipの概観はこうだ。 Rocket-Chip はTileと呼ばれるコアの部分と、そこから外へ出たバスで構成されている。 バスの外にはいろんなデバイスやメモリが接続されているのだが、そのうちの一つにはAXIバスで接続された巨大なメモリが存在している。

f:id:msyksphinz:20180305230338p:plain
図. Rocket-Chipの構成図

Rocket-Chipのデフォルトのメモリマップは以下のようになっている。 これは、生成時のログから取得したものだ。

Generated Address Map
               0 -     1000 ARWX  debug-controller@0
            3000 -     4000 ARWX  error-device@3000
           10000 -    20000  R XC rom@10000
         2000000 -  2010000 ARW   clint@2000000
         c000000 - 10000000 ARW   interrupt-controller@c000000
        60000000 - 80000000  RWX  mmio@60000000
        80000000 - 90000000  RWXC memory@80000000

RISC-V Rocket-Chipのブートローダ

Rocket-ChipはSiFiveのFreedom SoCと同様に、最初にブート専用のROMから命令がフェッチされ、そこから外部メモリにフェッチが飛ぶようになっている。 このブート専用のROMはBootROM.scalaで記述されていて、どのプログラムを読み込むかはcoreplex/Config.scalaに設定されている。 coreplex/Config.scalaにはイメージファイルの場所が設定されており、デフォルトではbootrom/boot.imgなので、これを切り替えることで任意のブートプログラムを実行することができる。 ただし、このBootROMはコンパイルした時点でバイナリをハードワイヤに埋め込んでしまうので、コンパイル後の修正はできない。 書き換えるときは何度も再合成する必要がある。

diff --git a/src/main/scala/coreplex/Configs.scala b/src/main/scala/coreplex/Configs.scala
index a6d6068..06db207 100644
--- a/src/main/scala/coreplex/Configs.scala
+++ b/src/main/scala/coreplex/Configs.scala
@@ -25,7 +25,7 @@ class BaseCoreplexConfig extends Config ((site, here, up) => {
   case MemoryBusKey => MemoryBusParams(beatBytes = site(XLen)/8, blockBytes = site(CacheBlockBytes))
   // Additional device Parameters
   case ErrorParams => ErrorParams(Seq(AddressSet(0x3000, 0xfff)), maxAtomic=site(XLen)/8, maxTransfer=4096)
-  case BootROMParams => BootROMParams(contentFileName = "bootrom/bootrom.img")
+  case BootROMParams => BootROMParams(contentFileName = "../program/rocket_boot/bootrom.img")
   case DebugModuleParams => DefaultDebugModuleParams(site(XLen))
 })

上記のデザインでは、rocket_boot/bootrom.img を設定しているが、このコードは以下のようになっており、0x8000_0000にジャンプしてプログラムを実行するようになっている。 ちなみに、ついでにスタックポインタを設定している。spのデフォルト値は0x80001000だ。

  • rocket_boot/bootrom.S
#define DRAM_BASE 0x80000000

.section .text.start, "ax", @progbits
.globl _start
_start:
        li s0, DRAM_BASE
        csrr a0, mhartid
        la a1, _dtb
        jr s0

.section .text.hang, "ax", @progbits
.globl _hang
_hang:
        csrr    a0, mhartid
        la      a1, _dtb
        li              sp, 0x80010000
        li              a2, 0x80000000
    jr      a2

fin_loop:
        j       fin_loop

AXI4RAMにプログラムをロードして実行する

上記のメモリマップが示している通り、接続されているAXIRAMにアクセスするためには0x8000_0000 - 0x9000_0000にアクセスすればよいし、この領域はXフラグ(フェッチ可能領域)も立っているためプログラムを配置しても問題ない。

このAXIRAMの実体は、Rocket-ChipのVerilog-HDL生成時に同時に生成されるBehavior SRAMVerilog-HDLファイルだ。

下記のreadmemhを追加することで、simple_main.hexが0x8000_0000から配置される。

  • freechips.rocketchip.system.DefaultConfig.behav_srams.v
module mem_ext(
  input W0_clk,
  input [24:0] W0_addr,
  input W0_en,
  input [63:0] W0_data,
  input [7:0] W0_mask,
  input R0_clk,
  input [24:0] R0_addr,
  input R0_en,
  output [63:0] R0_data
);

  reg reg_R0_ren;
  reg [24:0] reg_R0_addr;
...

  initial begin
    $readmemh ("../../../program/simple_main/simple_main.hex", ram);
  end

endmodule

シミュレーションすると、0x8000_0000からブートできるようになった。

...
C0:        116 [1] pc=[0080000018] W[r11=0000000000000064][1] R[r 0=0000000000000000] R[r 4=ffffffffdeadbeef] inst=[06400593] li      a1, 100
C0:        117 [1] pc=[008000001c] W[r 0=0000000000000003][1] R[r15=0000000000000000] R[r16=0000000000000003] inst=[0307e6bb] remw    a3, a5, a6
C0:        122 [1] pc=[0080000020] W[r 0=0000000000000005][1] R[r15=0000000000000000] R[r10=0000000000000005] inst=[02a7e63b] remw    a2, a5, a0
C0:        123 [1] pc=[0080000024] W[r 0=0000000000000000][0] R[r13=0000000000000000] R[r 0=0000000000000000] inst=[0000e291] bnez    a3, pc + 4
C0:        124 [1] pc=[0080000026] W[r14=0000000000000003][1] R[r14=0000000000000000] R[r 3=0000000000000007] inst=[0000270d] addiw   a4, a4, 3
C0:        128 [1] pc=[0080000028] W[r 0=0000000000000000][0] R[r12=0000000000000000] R[r 0=0000000000000000] inst=[0000e211] bnez    a2, pc + 4
C0:        129 [1] pc=[008000002a] W[r14=0000000000000008][1] R[r14=0000000000000003] R[r 5=0000000000000007] inst=[00002715] addiw   a4, a4, 5
C0:        130 [1] pc=[008000002c] W[r14=0000000000000008][1] R[r14=0000000000000008] R[r15=0000000000000000] inst=[00009f3d] addw    a4, a4, a5
C0:        131 [1] pc=[008000002e] W[r15=0000000000000001][1] R[r15=0000000000000000] R[r 1=0000000000000003] inst=[00002785] addiw   a5, a5, 1
C0:        132 [1] pc=[0080000030] W[r 0=0000000000000000][0] R[r15=0000000000000001] R[r11=0000000000000064] inst=[feb796e3] bne     a5, a1, pc - 20
C0:        136 [1] pc=[008000001c] W[r 0=0000000000000003][1] R[r15=0000000000000001] R[r16=0000000000000003] inst=[0307e6bb] remw    a3, a5, a6
C0:        141 [1] pc=[0080000020] W[r 0=0000000000000005][1] R[r15=0000000000000001] R[r10=0000000000000005] inst=[02a7e63b] remw    a2, a5, a0
C0:        142 [1] pc=[0080000024] W[r 0=0000000000000000][0] R[r13=0000000000000001] R[r 0=0000000000000000] inst=[0000e291] bnez    a3, pc + 4
C0:        146 [1] pc=[0080000028] W[r 0=0000000000000000][0] R[r12=0000000000000001] R[r 0=0000000000000000] inst=[0000e211] bnez    a2, pc + 4
...