FPGA開発日記

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

SiFiveのFreedom E300 Platformを単体でカスタマイズできるようにする (2. バスのマップと新しいモジュールの追加)

RISC-Vの実装であるRocket-Chipは、RISC-Vの最新使用に追従しているため最初に見るべきデザインとしてはよくできているが、

  • Chiselで記述されており(初心者には)可読性が低い。
  • 外部のSoCプラットフォームについて情報がない

ことから、なかなかオリジナルのSoCをくみ上げるためのデザインとしてポーティングしにくい。

とはいえ、TileLinkは単なるバスのはずだし、クロックとリセットさえ突っ込めばとりあえずフェッチリクエストが上がってくるはずだ。 そのあたりを解析して、Rocket-Chipを利用したオリジナルSoCプラットフォーム構築のための情報収集を行っていこう。

関連記事

Freedmo-SoC の「Instruction & Data Cache」の領域に向けてメモリのフェッチを発行する

前回紹介したとおり、Freedom SoC E300 Platform のメモリマップには "Instruction & Data RAM" という項目があるため、ここにメモリアクセスを発行すると外部からデータをフェッチしてキャッシュに配置してくれるのだろう、と思い、 0x8000_0000に向けてメモリ読み込み (実際には0x8000_0000に向けてプログラムをジャンプさせる)コードを書いてシミュレーションしてみたが、途中でフェッチが止まってしまいうまく動かなかった。

そこでダンプデータを使ってアクセスの行方を探っていたのだが、

  • ICache からメモリフェッチが Rocket CoreのIFに向けて発行される (0x8000_0000)
  • Rocket CoreのIFからRocketTileに向けてリクエストが発行される (0x8000_0000)
  • Peripheral-Busを通じて、RocketTileの逆方向のバスを通じてリクエストがRocket-Coreに戻ってくる。
  • DCache/ICache にリクエストが入って消えた。

というわけで、"Instruction & Data RAM"という場所にアクセスしても意味がないらしい。

f:id:msyksphinz:20180211021741p:plain
図. リクエストの解析の様子。Rocket-Coreから出てきたリクエストは、Rocket-Tileの外へ出ていき、そして戻って来て、ICache/DCacheのアクセスとなっていた

というか、Freedom E300のマニュアル的には、外部からこれらのキャッシュにアクセスするためのメモリアドレスであって、Rocket-Coreがメモリアクセスを行うためには、0x8000_0000ではなくて、普通にE31 Coreplex のメモリマップの場所を使わなければならない。

f:id:msyksphinz:20180209230017p:plain
表. Freedom E300 Platform のメモリマップ
f:id:msyksphinz:20180209230407p:plain
表. Coreplex E31 のメモリマップ

つまり、Coreplex E31のマニュアルにのっとると、システムバスとかペリフェラルバスからのアクセスを発生させるためには、0x2000_0000 もしくは 0x4000_0000 へアクセスを行わなければならない。

で、0x2000_0000にアクセスするとPeripheral-Bus なのでとりあえず外部に出るのだが、そこにはFreedom E300 PlatformではQSPIにつながっており、QSPIのプロトコルに変換されて外に出ていくわけだ。

実現したいことは、Freedom E300 Platformに適当にSRAMを接続してそこから命令とデータをフェッチできる環境を作りたい。 とりあえず、QSPIを取り除いて、そこにROMでもRAMでも接続してみたい。

f:id:msyksphinz:20180211025506p:plain
図. とりあえず実現したいRISC-V SoCブロック。まずはQSPIを取り除いて、だれでもアクセスできるTestRAMを接続したい。

Freedom E300 Platformの改造

Scalaについてはよくわからないのだが、QSPIの接続されている0x2000_0000のアドレスマップに張り付いているモジュールを取り除き、MaskROMを0x2000_0000に接続する。 なぜRAMではなくROMなのかというと、その場で接続できるRAMモジュールが見当たらなかったためだ(笑)。

diff --git a/src/main/scala/everywhere/e300artydevkit/Config.scala b/src/main/scala/everywhere/e300artydevkit/Config.scala
index a85d1e6..3dd9f90 100644
--- a/src/main/scala/everywhere/e300artydevkit/Config.scala
+++ b/src/main/scala/everywhere/e300artydevkit/Config.scala
@@ -35,11 +35,11 @@ class E300DevKitPeripherals extends Config((site, here, up) => {
   case PeripherySPIKey => List(
     SPIParams(csWidth = 4, rAddress = 0x10024000, sampleDelay = 3),
     SPIParams(csWidth = 1, rAddress = 0x10034000, sampleDelay = 3))
-  case PeripherySPIFlashKey => List(
-    SPIFlashParams(
-      fAddress = 0x20000000,
-      rAddress = 0x10014000,
-      sampleDelay = 3))
+  // case PeripherySPIFlashKey => List(
+  //   SPIFlashParams(
+  //     fAddress = 0x20000000,
+  //     rAddress = 0x10014000,
+  //     sampleDelay = 3))
   case PeripheryUARTKey => List(
     UARTParams(address = 0x10013000),
     UARTParams(address = 0x10023000))
@@ -48,7 +48,9 @@ class E300DevKitPeripherals extends Config((site, here, up) => {
   case PeripheryMockAONKey =>
     MockAONParams(address = 0x10000000)
   case PeripheryMaskROMKey => List(
-    MaskROMParams(address = 0x10000, name = "BootROM"))
+    MaskROMParams(address = 0x10000,    name = "BootROM"),
+    MaskROMParams(address = 0x20000000, name = "TestROM")
+  )
 })

 // Freedom E300 Arty Dev Kit Peripherals
diff --git a/src/main/scala/everywhere/e300artydevkit/FPGAChip.scala b/src/main/scala/everywhere/e300artydevkit/FPGAChip.scala
index e0b0634..ea3edb8 100644
--- a/src/main/scala/everywhere/e300artydevkit/FPGAChip.scala
+++ b/src/main/scala/everywhere/e300artydevkit/FPGAChip.scala
@@ -44,13 +44,13 @@ class E300ArtyDevKitFPGAChip(implicit override val p: Parameters) extends ArtySh
     // SPI flash IOBUFs
     //---------------------------------------------------------------------

-    IOBUF(qspi_sck, dut.io.pins.qspi.sck)
-    IOBUF(qspi_cs,  dut.io.pins.qspi.cs(0))
-
-    IOBUF(qspi_dq(0), dut.io.pins.qspi.dq(0))
-    IOBUF(qspi_dq(1), dut.io.pins.qspi.dq(1))
-    IOBUF(qspi_dq(2), dut.io.pins.qspi.dq(2))
-    IOBUF(qspi_dq(3), dut.io.pins.qspi.dq(3))
+    // IOBUF(qspi_sck, dut.io.pins.qspi.sck)
+    // IOBUF(qspi_cs,  dut.io.pins.qspi.cs(0))
+    //
+    // IOBUF(qspi_dq(0), dut.io.pins.qspi.dq(0))
+    // IOBUF(qspi_dq(1), dut.io.pins.qspi.dq(1))
+    // IOBUF(qspi_dq(2), dut.io.pins.qspi.dq(2))
+    // IOBUF(qspi_dq(3), dut.io.pins.qspi.dq(3))

     //---------------------------------------------------------------------
     // JTAG IOBUFs

diff --git a/src/main/scala/everywhere/e300artydevkit/Platform.scala b/src/main/scala/everywhere/e300artydevkit/Platform.scala
index be1789a..289f97e 100644
--- a/src/main/scala/everywhere/e300artydevkit/Platform.scala
+++ b/src/main/scala/everywhere/e300artydevkit/Platform.scala
@@ -39,7 +39,7 @@ class E300ArtyDevKitPlatformIO(implicit val p: Parameters) extends Bundle {
   val pins = new Bundle {
     val jtag = new JTAGPins(() => PinGen(), false)
     val gpio = new GPIOPins(() => PinGen(), p(PeripheryGPIOKey)(0))
-    val qspi = new SPIPins(() => PinGen(), p(PeripherySPIFlashKey)(0))
+    /* val qspi = new SPIPins(() => PinGen(), p(PeripherySPIFlashKey)(0)) */
     val aon = new MockAONWrapperPins()
   }
   val jtag_reset = Bool(INPUT)
@@ -159,8 +159,8 @@ class E300ArtyDevKitPlatform(implicit val p: Parameters) extends Module {
   // Result of Pin Mux
   GPIOPinsFromPort(io.pins.gpio, sys.gpio(0))

-  // Dedicated SPI Pads
-  SPIPinsFromPort(io.pins.qspi, sys.qspi(0), clock = sys.clock, reset = sys.reset, syncStages = 3)
+  // // Dedicated SPI Pads
+  // SPIPinsFromPort(io.pins.qspi, sys.qspi(0), clock = sys.clock, reset = sys.reset, syncStages = 3)

   // JTAG Debug Interface
   val sjtag = sys.debug.systemjtag.get
diff --git a/src/main/scala/everywhere/e300artydevkit/System.scala b/src/main/scala/everywhere/e300artydevkit/System.scala
index c3fbd96..8ef51e9 100644
--- a/src/main/scala/everywhere/e300artydevkit/System.scala
+++ b/src/main/scala/everywhere/e300artydevkit/System.scala
@@ -26,7 +26,7 @@ class E300ArtyDevKitSystem(implicit p: Parameters) extends RocketCoreplex
     with HasPeripheryDebug
     with HasPeripheryMockAON
     with HasPeripheryUART
-    with HasPeripherySPIFlash
+    /* with HasPeripherySPIFlash */
     with HasPeripherySPI
     with HasPeripheryGPIO
     with HasPeripheryPWM
@@ -40,7 +40,7 @@ class E300ArtyDevKitSystemModule[+L <: E300ArtyDevKitSystem](_outer: L)
     with HasPeripheryUARTModuleImp
     with HasPeripherySPIModuleImp
     with HasPeripheryGPIOModuleImp
-    with HasPeripherySPIFlashModuleImp
+    /* with HasPeripherySPIFlashModuleImp */
     with HasPeripheryMockAONModuleImp
     with HasPeripheryPWMModuleImp
     with HasPeripheryI2CModuleImp {

これで再生成を行う。

make -f Makefile.e300artydevkit clean && make -f Makefile.e300artydevkit verilog
make -f Makefile.e300artydevkit romgen

これで、MaskROMが2種類作られる。ただし、とりあえず初期値は1つしか指定できないようだ。

make -f Makefile.e300artydevkit romgen
make -C /home/msyksphinz/work/freedom/bootrom/xip romgen
make[1]: ディレクトリ '/home/msyksphinz/work/freedom/bootrom/xip' に入ります
/home/msyksphinz/work/freedom/rocket-chip/scripts/vlsi_rom_gen /home/msyksphinz/work/freedom/builds/e300artydevkit/sifive.freedom.everywhere.e300artydevkit.E300ArtyDevKitConfig.rom.conf /home/msyksphinz/work/freedom/builds/e300artydevkit/xip.hex > /home/msyksphinz/work/freedom/builds/e300artydevkit/rom.v
/home/msyksphinz/work/freedom/rocket-chip/scripts/vlsi_rom_gen:131: UserWarning: vlsi_rom_gen detected multiple ROMs. ROM contents will be duplicated.
  warnings.warn('vlsi_rom_gen detected multiple ROMs. ROM contents will be duplicated.')
...

このVerilogファイルを使って再度RTLシミュレーションを行ってみた。 まだROMの状態ではあるが、TestROMに対して正常なメモリアクセスを発行させることができたようだ。 次は、テスト用のRAMを作って、接続作業を行ってみる。

f:id:msyksphinz:20180211025016p:plain