Posts Issued on May 24, 2024

BSVの問題点?

posted by sakurai on May 24, 2024 #804

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

左矢前のブログ 次のブログ右矢