Skip to content
HORIE Tetsuya edited this page Sep 4, 2018 · 7 revisions

Lance Rocket wikiへようこそ!

KOZOS on RISC-V

kozos ブランチにて、KOZOSをTinyLanceに移植中です。

以下、移植作業メモ

0thステップ

12ステップで作る組込みOS自作入門』には存在しないステップだけど…

Freedom E300を他のFPGAボードに移植するのは、そこそこ難易度が高いので、余計なもの(SPI Flushメモリ用モジュールとか)を取っ払ったTinyLanceを作る。

Freedom E300から以下のものを削除。

  • SPI,SPIFlashモジュール
    ArtyからNexys4 DDRに移植する時の最難関だった。IntelのFPGAに移植する時も苦戦しそう。
  • I2Cモジュール
    勉強用には不要かな。
  • PWMモジュール
    モーターとかを繋ぎたくなったら必要だけど、上位モデルのBaby Lanceを使う事にする。
  • Debugモジュール
    12ステップで作る組込みOS自作入門』では、デバッガは使っていないので削除。

Freedom E300をNexys4 DDRに移植する時につけた7セグメントLEDもいらないだろうし、UARTもGPIOとの接続を切って独立させてGPIOを削ってもいいかもしれないが・・・

TinyLance-v0.9でタグ付け。

1stステップ

開発環境の構築

リポジトリのクローン。

Lance Rocket SDKは不要で、Lance Rocketのリポジトリだけで十分。bootromを開発していくので。

git clone --recursive -b TinyLance-v0.9 https://github.com/horie-t/lance-rocket.git
開発ツールのインストール。
cd lance-rocket/rocket-chip
export RISCV=/usr/local/share/riscv    # 好みのディレクトリに変更可能
export MAKEFLAGS="$MAKEFLAGS -j4"      # 4は開発PCのCPUのコア数の2倍ぐらいでOK
./build.sh
./build-rv32ima.sh

移植に必要なTinyLanceの仕様

TinyLance(元になったFreedom E300)の

  • リセット時のプログラム・カウンタの値(リセット・ベクタ)
  • メモリ・マップ
  • UARTのレジスタ

に関する知識が必要。

リセット・ベクタ

リセットにプログラム・カウンタは 0x10000 にセットされる。

この値は、System.scala で、

class TinyLanceSystemModuleImp[+L <: TinyLanceSystem](_outer: L)
(中略)
  // Reset vector is set to the location of the mask rom
  val maskROMParams = p(PeripheryMaskROMKey)
  global_reset_vector := maskROMParams(0).address.U

と、設定される。マスクROMの設定値は、Config.scala で、以下のようアドレスが設定されている。

class TinyLancePeripherals extends Config((site, here, up) => {
(中略)
  case PeripheryMaskROMKey => List(
    MaskROMParams(address = 0x10000, name = "BootROM"))
メモリ・マップ

メモリ・マップは、Configファイルを見れば、だいたい分かる。

class TinyLancePeripherals extends Config((site, here, up) => {
  case PeripheryGPIOKey => List(
    GPIOParams(address = 0x10012000, width = 32, includeIOF = true))
  case PeripheryUARTKey => List(
    UARTParams(address = 0x10013000))
  case PeripherySeg7LEDKey => List(
    Seg7LEDParams(address = 0x10017000))
  case PeripheryMockAONKey =>
    MockAONParams(address = 0x10000000)
  case PeripheryMaskROMKey => List(
    MaskROMParams(address = 0x10000, name = "BootROM"))
})

makeでverilogをターゲットに実行した時に、出力される結果が確実。上記Configファイル以外で設定されている値も出力される。

Generated Address Map
	       0 -     1000 ARWX  debug-controller@0             # デバッグモジュール
	   10000 -    12000  R XC rom@10000                      # Boot ROM(ステップ1ではここを書き換える)
	 2000000 -  2010000 ARW   clint@2000000                  # 内部割り込み等の制御用
	 c000000 - 10000000 ARW   interrupt-controller@c000000   # 外部割り込み
	10000000 - 10001000 ARW   aon@10000000                   # Always ON モジュール(タイマーモジュール等)
	10012000 - 10013000 ARW   gpio@10012000                  # GPIO(LED等とつなぐ、UARTもここを経由)
	10013000 - 10014000 ARW   serial@10013000                # UART
	10017000 - 10018000 ARW   seg7led@10017000               # 7セグメントLED
	80000000 - 80004000 ARWX  dtim@80000000                  # Data Tightly Integraged Memory(CPUの直結のRAM。いわゆる、スクラッチパッド・メモリ)

RAMは、80000000 - 80004000 の範囲なので、startup.sで設定するspレジスタは、80004000に設定すればよい。

Boot ROMは、10000 - 12000 の範囲なので、ld.scrのSECTIONSの最初は以下のようにする。

SECTIONS
{
	. = 0x10000;		/* ROMの先頭番地 */

UARTのレジスタ・マッピングは、serial@10013000 から開始して、『Freedom E300 Platform Reference Manual』 の「Chapter 12Universal AsynchronousReceiver/Transmitter (UART)」 のレジスタを参照すればよい。

ただし、UARTの出力は、GPIOを経由しているので、以下のように設定が必要。

    *(int32_t *)(GPIO_CTRL_ADDR + GPIO_IOF_SEL) &= ~IOF0_UART0_MASK;
    *(int32_t *)(GPIO_CTRL_ADDR + GPIO_IOF_EN) |= IOF0_UART0_MASK;

Makefileは、Freedomのものをベースに作成。

C-Kermitのインストールは以下の通り

sudo apt-get install ckermit

接続に必要な設定は、『プログラマのためのFPGAによるRISC-Vマイコンの作り方』 のサポートページ C-Kermintのインストール を参照。

移植結果は、KOZOS-1st-stepの通り。

2ndステップ

2ndステップは、1stステップの解説がメイン。これから必要になるユーティリティ関数が追加されるが、ハードウェアの違いは特に意識不要。

移植結果は、KOZOS-2nd-stepの通り。

3rdステップ

セクションの定義でハマる。

グローバル変数や、static変数は、「.data」、「.bss」セクション ではなく 「.sdata」、「.sbss」セクションに配置されていた。コンパイルオプションでなんとかできそうな感じだが、ここは素直に、両セクションの定義を追加しておく。

移植結果は、KOZOS-3rd-stepの通り。

4thステップ

ファイル転送には、lrzszパッケージのインストールが必要。

sudo apt-get install lrzsz

sendコマンドオプション。BINARYオプションをつけないとText(DOS File)で送信される?(デフォルトはバイナリのはずなんだが… Textモードで、MS-DOSマシンへの送信になっているっぽい)

SEND /BINARY defines.h

移植結果は、KOZOS-4th-stepの通り。

5thステップ

ELFファイルのサイズが大き過ぎて、メモリ破壊が発生する。H8/3609Fの命令語のサイズは16ビット、RISC-Vは32ビットなので単純に考えると2倍のメモリが必要。RISC-Vの圧縮命令(16ビットの命令語)が必要なのは、こんな場合かな。

Config.scalaファイルを修正して、CPUコアのDTIMのサイズを大きくする。(コンパイル時に圧縮命令を出力させればいいのかもしれないが、調べていない)

class With1TinyLanceCore extends Config((site, here, up) => {
  case XLen => 32
  case RocketTilesKey => List(RocketTileParams(
      core = RocketCoreParams(
        useVM = false,
        fpu = None,
        mulDiv = Some(MulDivParams(mulUnroll = 8))),
      btb = None,
      dcache = Some(DCacheParams(
        rowBits = site(SystemBusKey).beatBits,
        nSets = 512, // 32Kb scratchpad
        nWays = 1,
        nTLBEntries = 4,
        nMSHRs = 0,
        blockBytes = site(CacheBlockBytes),
        scratch = Some(0x80000000L))),
      icache = Some(ICacheParams(
        rowBits = site(SystemBusKey).beatBits,
        nSets = 64,
        nWays = 1,
        nTLBEntries = 4,
        blockBytes = site(CacheBlockBytes)))))
  case RocketCrossingKey => List(RocketCrossingParams(
    crossingType = SynchronousCrossing(),
    master = TileMasterPortParams()
  ))
})

// Default TinyLanceConfig
class DefaultTinyLanceConfig extends Config (
  new WithNBreakpoints(2)        ++
  new WithNExtTopInterrupts(0)   ++
  new WithJtagDTM                ++
  new WithNoMemPort ++
  new WithNMemoryChannels(0) ++
  new With1TinyLanceCore ++
  new BaseConfig
)

転送がうまく行かなかったりするので、転送速度を9600bpsに下げる。(本当は不要かも)

移植結果は、KOZOS-5th-stepの通り。

6thステップ

本章は、ブート・ローダと、OSの2に別れての開発になる。

  • ブート・ローダは、本リポジトリの src/main/c_cpp/bootrom/kozos/
  • OSは、 Lance Rocket SDK の software/kozos/

になるので、注意が必要。

リポジトリの再クローン。

Lance Rocket SDKが必要になる。Lance RocketはGitのサブモジュールとなっている。(これだと6thステップが完了状態だが…)

git clone --recursive -b KOZOS-6th-step https://github.com/horie-t/lance-rocket-sdk.git

移植結果は、KOZOS-6th-stepの通り。(ここから参照リポジトリが変わります)

7thステップ

7thステップ以降は、Boot ROMの修正はなかったので、Lance Rocket SDKのWiki を参照