24 |
BSVの問題点? |
Uartを設計中に問題にぶつかりましたが一応解決したのでそれを示します。なお本件はbscサポートフォーラムに投稿済みです。
以下はUartのモジュールとそのテストベンチです。
Uart.bsv:
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 (getfsm.done);
// 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
このリスト中の以下のコメントアウト部分については後記事で記します。
// method ActionValue#(Bit#(8)) read if (getfsmDone);
Tb.bsv:
import StmtFSM::*;
import Uart::*;
import Connectable::*;
typedef Bit#(8) Byte;
(* synthesize *)
module mkTb();
// UARTインターフェースのインスタンスを生成
Uart_ifc uart <- mkUart;
// テストバイトレジスタの定義
Reg#(Byte) tbrReg <- mkRegU;
// UARTの送信と受信を接続
mkConnection(uart.sout, uart.sin);
// データを取得する関数
function Action getData;
return
action
// UARTからデータを読み取り、tbrRegに格納
let data <- uart.read;
tbrReg <= data;
endaction;
endfunction
// データを送信する関数
function Stmt putData(Byte c);
return (seq
// UARTにデータを書き込む
uart.write(c);
endseq);
endfunction
// 応答を確認する関数
function Stmt checkResp(Byte correctData);
return (seq
// データを取得
getData;
// 正しいデータと比較
if (correctData != tbrReg) seq
// データが異なる場合、表示して終了
$display("%d->%d", correctData, tbrReg);
$finish;
endseq
endseq);
endfunction
// テストシーケンスの定義
Stmt test = seq
repeat(20) noAction; // 初期の待機
putData(1); // データ1を送信
checkResp(1); // 応答を確認
putData(2); // データ2を送信
checkResp(2); // 応答を確認
putData(3); // データ3を送信
checkResp(3); // 応答を確認
putData(4); // データ4を送信
checkResp(4); // 応答を確認
putData(8'hff); // データ255を送信
$display("test OK"); // テスト成功を表示
repeat(30) noAction; // 終了前の待機
$finish; // テスト終了
endseq;
mkAutoFSM(test); // テストシーケンスを自動化
endmodule