-
-
Notifications
You must be signed in to change notification settings - Fork 4
Home
kozos ブランチにて、KOZOSをTinyLanceに移植中です。
以下、移植作業メモ
『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でタグ付け。
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(元になった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ステップは、1stステップの解説がメイン。これから必要になるユーティリティ関数が追加されるが、ハードウェアの違いは特に意識不要。
移植結果は、KOZOS-2nd-stepの通り。
セクションの定義でハマる。
グローバル変数や、static変数は、「.data」、「.bss」セクション ではなく 「.sdata」、「.sbss」セクションに配置されていた。コンパイルオプションでなんとかできそうな感じだが、ここは素直に、両セクションの定義を追加しておく。
移植結果は、KOZOS-3rd-stepの通り。
ファイル転送には、lrzszパッケージのインストールが必要。
sudo apt-get install lrzsz
sendコマンドオプション。BINARYオプションをつけないとText(DOS File)で送信される?(デフォルトはバイナリのはずなんだが… Textモードで、MS-DOSマシンへの送信になっているっぽい)
SEND /BINARY defines.h
移植結果は、KOZOS-4th-stepの通り。
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の通り。
本章は、ブート・ローダと、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ステップ以降は、Boot ROMの修正はなかったので、Lance Rocket SDKのWiki を参照