ChiselでBF処理系を作る(4)
UART送受信モジュールの実装
前回はFIFOの実装をした。次はPCとの通信の要であるUart送受信の実装を行う。
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
style UartTxRx fill:#f66,stroke:#f33
UART信号
まずは信号についておさらいする。
データ線は普段はHigh固定で、最初のLowをスタートビットと言う通信開始のシグナルとして使う。
その後D0~D7の順でデータを送信し、その後ストップビットと呼ばれるHigh期間を(一般的には)1つ設ける。
設定によってはStopbitが2bitあったり、パリティビットを挿入することもできるが今回は不要なので省略する。
通信周波数としてはbaudrateとして決まっており、一般的には9600~115200あたりがよく使われている。お気づきかもしれないが非常に低速である。
実装
以下のようなコードで実現した。Chiselとしての新規要素はほぼないため、設計方針と合わせて送受について解説する。
まず全体の戦略としてbaudrateがシステム周波数に対して非常に遅いことを利用し、システム周波数を使った回路で送受を行う。
(baudrateに合わせた周波数をPLLなどで合成してもよいが、システムクロックとの間に非同期パスができるためである)
具体的にはチャタリング除去回路のときと同様にカウンタを用意してデータを読み書きするタイミングを制御する。
FPGA内部とのI/Fは、前回作成したFIFOに接続できるように準拠する。
UartTxRx.scala - Github
送信(Tx)
こちらはかなり単純で、FIFOからデータを受信したらカウンタを使った単純なステートマシンを用いてstartbit, d[0] ~ d[8], stopbitを順繰り送信する。
以下はFIFOからのデータの受信を待機し(txActive
がフラグ)、baudrateに一致するようなタイミングでtxTrigger
をアサートする回路である。このbaudrateの周期を作るために幅の大きいtxDurationCounter
を使っている。
こちらはtxActive
かつtxTrigger
のときに送信するデータを制御している。
txCounter
を使って送信データを切り替えているだけのかなりシンプルな回路である。
受信(Rx)
基本的には送信と同じだが、baudrateのTrigger生成のみ差分がある。UARTにはクロックがないため、周波数を一致させるだけだと遷移中に値をキャプチャしてしまう可能性がある。
上図のbad rxTriggerの用にスタートビットを検出した瞬間からbaudrateに応じた周期を生成すると遷移した瞬間をキャプチャしてしまう。
そこでカウンタの値を符号付きにし、初回だけ半周期分引いた値を設定することで位相を遅らせ、データの中央でキャプチャすることができる。
以下のコードはほとんどがTxと同様だが、rxDurationCounter := -halfDuration.S
されているところが特徴
あとは生成されたTriggerでデータをキャプチャし、完成されたデータをFIFOに送信している。
まとめ
今回はUART送受信について解説した。HDLの種類はともあれ、どのような方式で実装するかイメージできるかが重要な気がする。自分ももっと高度な回路を設計する能力を身につける必要がある。
次回はBF Processorと全体結線について解説する。
次回 - ChiselでBF処理系を作る(5)