ChiselでBF処理系を作る(1)
BFに対する理解とアーキテクチャについて
前回まででChiselを使った開発フローについて理解したが、実際になにか作ってみることにする。
今回はBrainf**kという言語(以後BFと略する)の処理系をChiselを使って実装してみようと思う。
お題の理由としては以下となる。
- (当初考えていた)オレオレCPUを作るなら、Chiselの理解度が高い状態で臨みたい
- 命令数が少なく、また単純なので難易度設定として適切
- BF処理系を作るのは楽しい
完成物
kamiyaowl/arty-chisel-brainfxxk - Github
参照ドキュメント
今回の開発にあたって、以下ページを何度も読み返している。特に英語ができない私にとっては日本語情報は本当にありがたかった。改めて感謝を。
BFについて
まずはBF言語について簡単に説明しておく。
構成
BFプログラムと、現在実行している命令のポインタ、30000個の要素を持つuint8_tの配列、配列のどのデータを操作するかを示すポインタの4要素である。
命令セット
以下の8種類のみ使用できる
+
現在参照しているデータをインクリメント
-
現在参照しているデータをデクリメント
>
データ参照ポインタをインクリメント
<
データ参照ポインタをデクリメント
,
外部入力を現在参照しているデータに上書き
.
現在参照しているデータを外部出力
[
現在参照しているデータが0なら、対応する]
に命令ポインタを移動
]
対応する[
に命令ポインタを移動
コード例
これを利用するとHello world!
は以下のようなプログラムになる
一見複雑そうに見えるがからくりはこうである。例えば最初のH
を出力する箇所を確認する。
>+++++++++[<++++++++>-]<.
>+++++++++
→ mem[1] += 9
[<++++++++>-]
→ mem[0] += 8
, mem[1] -= 1
(mem[1] > 0
の間繰り返し)
<.
→ put(mem[0])
となっている。c言語に書き下すならこうだ
処理系実装
上記の例にもあるようにかなり簡単に実装できるので、まずは理解を深めるためにも自分の得意な言語で処理系を実装することを推奨する。
最初からHDL実装をしようとすると、意外と理論から実装に落とすフェーズに勘違いがあったりして躓くことがしばしあるからだ。
参考までにc++で実装したので、以下に貼っておく。
brainfxxk.cpp - Gist
方式検討
ここまででBFの実装については理解できたと思うので、いよいよHDLに起こすことを検討する。
今回は手元にArty A7があったので、これにポーティングできることをとりあえず目標とする。
構成
お風呂に入りながら考えたが、stdin/outがあるのが面倒なので途中にFIFOをもたせるようなインターフェースがいいだろうと考えた。
graph LR
PC -- USB --- USB_Uart
USB_Uart --Tx--> UartTxRx
UartTxRx--Rx--> USB_Uart
UartTxRx -- program/stdin -->FIFO_din
FIFO_din -- program --> BF_Processor
FIFO_din -- stdin--> BF_Processor
BF_Processor -- stdout --> FIFO_dout
FIFO_dout -- stdout --> UartTxRx
External_SW --program/run -->UntiChatter
UntiChatter -->BF_Processor
簡単に説明しておく
- PCとのやり取りはすべてUartを経由する
- ProcessorをUartと直結してしまうと(当然だが)Uartの転送が終わるまで動けなくなるのでFIFOを設ける
- BFのプログラムを格納するメモリはBF_Processor内部に持たせる(結構悩んだ)
- プログラム転送モードと実行モードの切替は、オンボードのスライドスイッチを使う
- スライドスイッチ入力はチャタリング対策を施す
- クロックはシステムクロック1つのみとし非同期パスは作らない
- 周波数は目標100MHzとする
まとめ
記事のきりが良いのでここで区切るが、次回からは実装が簡単だった順番に紹介しようと思う。実際はProcessorから作っていったが…。
次回 - ChiselでBF処理系を作る(2)