|
22 |
BSVによるUARTの再設計 (5) |
次にUartを送受信化します。送信部のFSMと並行で動作する受信部のFSMを設計します。
import StmtFSM::*;
interface Uart_ifc;
method Bit#(1) sout; // シリアル出力
(* prefix="" *)
method Action write((* port="write" *) Bit#(8) nodata); // パラレル入力
(* prefix="" *)
method Action sin((* port="sin" *) Bit#(1) nidata); // シリアル入力
method ActionValue#(Bit#(8)) read; // パラレル出力
method Bool pdone; // 送信完了フラグ
method Bool gdone; // 受信完了フラグ
endinterface
(* synthesize, always_ready="sin, sout, pdone, gdone" *)
module mkUart(Uart_ifc);
// レジスタ定義
Reg#(Bit#(8)) odata <- mkRegU; // 送信データレジスタ
Reg#(Bit#(1)) osdata <- mkReg(1'h1); // シリアル出力データレジスタ
Reg#(Bit#(8)) idata <- mkRegU; // 受信データレジスタ
Reg#(Bit#(1)) isdata <- mkReg(1'h1); // シリアル入力データレジスタ
Reg#(Bool) putfsmDone <- mkReg(False); // 送信完了フラグ
Reg#(Bool) getfsmDone <- mkReg(False); // 受信完了フラグ
// 送信ステートマシンの定義
Stmt putseq = seq
osdata <= 1'h0; // スタートビット
repeat (8) action
osdata <= odata[0]; // データを1ビットずつシリアル出力
odata <= (odata >> 1); // 右シフト
endaction
osdata <= 1'h1; // ストップビット
putfsmDone <= True; // 送信完了フラグをセット
endseq;
FSM putfsm <- mkFSM(putseq);
// 受信ステートマシンの定義
Stmt getseq = seq
await(isdata == 1'h0); // スタートビットを待つ
repeat (8) action
idata <= {isdata, (idata >> 1)[6:0]}; // データを1ビットずつ受信
endaction
getfsmDone <= True; // 受信完了フラグをセット
endseq;
FSM getfsm <- mkFSM(getseq);
// 受信ステートマシンの再起動
rule restartGetFSM if (getfsm.done);
getfsm.start;
endrule
// シリアル出力
method Bit#(1) sout;
return osdata;
endmethod
// パラレル入力(データを書き込む)
method Action write(Bit#(8) nodata) if (putfsm.done);
odata <= nodata;
putfsmDone <= False;
putfsm.start;
endmethod
// シリアル入力
method Action sin(Bit#(1) nidata);
isdata <= nidata;
endmethod
// パラレル出力(データを読み込む)
method ActionValue#(Bit#(8)) read if (getfsmDone);
getfsmDone <= False; // 受信完了フラグをリセット
return idata;
endmethod
// 送信完了フラグ
method Bool pdone;
return putfsmDone;
endmethod
// 受信完了フラグ
method Bool gdone;
return getfsmDone;
endmethod
endmodule
送受信のFSMにおいて、起動のタイミングが非対称的です。
- 送信FSMの起動は上位からパラレル入力をロードされてパラシリが開始する
- 受信FSMはシリアルデータがいつくるかわからないので、常に起動されていなくてはならない
従って、送信側は
// パラレル入力(データを書き込む)
method Action write(Bit#(8) nodata) if (putfsm.done);
odata <= nodata;
putfsmDone <= False;
putfsm.start;
endmethod
このように、データが書き込まれた契機でfsmをスタートさせるのに対し、受信側は
// 受信ステートマシンの再起動
rule restartGetFSM if (getfsm.done);
getfsm.start;
endrule
FSMの終了を待ってその起動をかけるルールを追加しています。これはAutoFSMとして自動起動にすることも可能です。
Leave a Comment