LiteXのUARTデバイスの挙動を確認したくて、Migenのソースコードをチェックしている:
UARTのデバイスは、Wishboneを経由して接続されている。
litex/litex/soc/cores/uart.py
class UARTWishboneBridge(UARTBone):
def __init__(self, pads, clk_freq, baudrate=115200, cd="sys"):
self.phy = RS232PHY(pads, clk_freq, baudrate)
UARTBone.__init__(self, self.phy, clk_freq, cd)
RS232の送信用のハードウェアと、受信用のハードウェアが接続されている。
class RS232PHY(LiteXModule):
def __init__(self, pads, clk_freq, baudrate=115200, with_dynamic_baudrate=False):
tuning_word = int((baudrate/clk_freq)*2**32)
if with_dynamic_baudrate:
self._tuning_word = CSRStorage(32, reset=tuning_word)
tuning_word = self._tuning_word.storage
self.tx = RS232PHYTX(pads, tuning_word)
self.rx = RS232PHYRX(pads, tuning_word)
self.sink, self.source = self.tx.sink, self.rx.source
TXのほうを確認すると、ステートマシンが作成してある。
self.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
NextValue(count, 0),
NextValue(pads.tx, RS232_IDLE),
If(sink.valid,
NextValue(pads.tx, RS232_START),
NextValue(data, sink.data),
NextState("RUN")
)
)
fsm.act("RUN",
clk_phase_accum.enable.eq(1),
If(clk_phase_accum.tick,
NextValue(pads.tx, data),
NextValue(count, count + 1),
NextValue(data, Cat(data[1:], RS232_STOP)),
If(count == (10 - 1),
sink.ready.eq(1),
NextState("IDLE")
)
)
)
2つのステートが存在している:
- IDLE : 入力を受け付けると、pads.txにSTARTコマンド(=0)を打ち込み、dataレジスタに書き込みデータを格納し、RUNステートに遷移する。
- RUN :
clk_phase_accum
信号をベースに駆動する。これはRS232のクロックと動作周波数の比率で動作するカウンタで、RS232の信号制御用のカウントを行う。
count
によりすべての文字列を出力すれば、そこで動作終了。そうでなければ、次のdataビットを出力する。
と、非常にシンプルなステートマシンを組んでいることが分かった。これをベースに、FPGAでの挙動を確認していこうと思う。
ポイントは、データバッファとステートマシンだな。