SNSへはこちら

Longan NanoでRISC-Vチャレンジ(1) - 取り敢えずLEDを付ける

この前の雑記の宣言どおり、色々と進めていこうと思います。
例によって僕のポリシーは

  • 低レイヤ部分を隠蔽してしまうライブラリは極力使わない
  • 抽象化レイヤ等のライブラリは答え合わせとして使う
  • ライブラリは自分の手で作るものだ

という過激思想によって進めていく所存です。ただ、このマイコンの標準開発環境である PlatformIO はなんと Mac 非対応 ですので、自然と手探りで進めていく事になってしまいます。それはそれでアリかな!

この記事の参考サイト等は章ごとに示していくことにします。

また、CPU コアのリファレンス等はこの前の雑記で紹介した Seeed の商品ページから物色してください。

コンパイラ

targetriscv-elf としました。unknown とかよく知りません。
→ **target を riscv-unknown-elf にしないと各種ライブラリがうまく使えません。

リンカスクリプト

取り敢えず gcc のインストールディレクトリからパクって来ます。そのままだと相変わらず MEMORY コマンドは定義されていないので、(個人的なポリシーに過ぎないのですが)しっかりと記述していきます。GNU MCU Eclipse のサイトによると、gp の値として __global_pointer$.sdata の直前に ±2KByte のマージンを以てして配置すべきらしいので、そのとおりに従います。そして適当にスタック領域も確保しておきます。これを反映させたリンカスクリプトはこちら

スタートアップコード

取り敢えずハングアップせずに動くコードを。クソコードですがこちら。アセンブリコードの書き方は riscv-asm-manual/riscv-asm.md at master · riscv/riscv-asm-manual · GitHubRISC-Vについて(CPU実験その2) - Re Inventing the Wheel. を参考にさせていただきました。

どうやらデフォルトではリンカーリラクゼーション(シンボルの値を最適なアドレッシングにて再現する)が働いてしまうらしいです。これは通常動作においては良いことなのですが、レジスタの初期化に関しては正反対の方向を向くものですので、このときだけは完全に無効化します。というのも、gcc の使用上、この __global_pointer$ という気持ちの悪いシンボル名を起点に最適化を行うようなのです。

ちなみに無効化し忘れると、あら不思議

mv gp, gp

という意味のない初期化コードが生成されます。

書き込み

取り敢えず上の無をするコードをコンパイル & 書き込んで見ましょう。書き込み前はブートローダーを起動させてください。

# コンパイル
$ riscv-elf-gcc -march=rv32imac -mabi=ilp32 -Tlinker.ld -nostartfiles -o start.elf src/start.s
$ riscv-elf-objcopy -O binary start.elf start.bin
# 書き込み
$ dfu-util -d 28e9:0189 -a 0 -s 0x08000000 -D start.bin

リセットをかけると動きます。でももちろん無をするプログラムなので本当に動いているかわかりませんね。

LEDをなんとか点灯させたい

とりあえず以下のピン配置を把握せねばどうにもなりません。

今回は PC13 に LED を接続することにしましょう。

ピンの設定

リファレンスマニュアルを読んでください。RCUGPIO ペリフェラルの設定を見てください。そこに全てがあります。申し訳ないですが、この説明は省かせていただきます。

これがそのコードだ

ということでアセンブリコードにてできました。ちなみに、このレベルのコードでしたら spgp の初期化をする必要は全くありません。
また、リセットベクタは ROM の最初のアドレスにジャンプするということですから、予め isr_vector を設定しておきました。

これで LED が点灯すると思います。次は C 言語にて(雑に)動作させることを試みます。現状スタック関連がうまく動かないので、そこをどうにかしたいところです。