Posts Tagged with "BSV"

既に発行済みのブログであっても適宜修正・追加することがあります。
We may make changes and additions to blogs already published.
posted by sakurai on September 16, 2022 #510

Graphic Controlerの再設計

完成したIP diagramを510.1に示します。3個のサブモジュールをまとめたので、graphic階層はなくなりました。

図%%.1
図510.1 BSVによるグラフィックコントローラ

BSVソース

GraphicFSM.bsv:

// グラフィックディスプレイコントローラー、BSVによる実装
import StmtFSM::*;
// 各種タイミングパラメータの定義
`define HD  800  // 水平解像度
`define HFP 16   // 水平フロントポーチ
`define HSP 80   // 水平同期期間
`define HBP 160  // 水平バックポーチ
`define HO  `HFP + `HSP + `HBP  // 水平オフセット
`define HL  `HD + `HO  // 一行当たりのピクセル数

`define VD  600  // 垂直解像度
`define VFP 1    // 垂直フロントポーチ
`define VSP 3    // 垂直同期期間
`define VBP 21   // 垂直バックポーチ
`define VO  `VFP + `VSP + `VBP  // 垂直オフセット
`define VL  `VD + `VO  // 一画面当たりの行数

// その他の定義
`define EHD 512  // 有効水平解像度
`define EVD 512  // 有効垂直解像度

// ログ幅の定義
`define HW  11  // log2(1056) = 10.04439
`define VW  10  // log2(628) = 9.294621

// アドレス型の定義
typedef Bit#(16) Addr_t;

// インターフェースの定義
interface GraphicFSM_ifc;
   method Bool xhs();      // 水平同期信号出力
   method Bool xvs();      // 垂直同期信号出力
   method Addr_t address();  // VRAMアドレス出力
   (* prefix="" *)
   method Action idata(Bit#(4) indata); // VRAMデータ入力
   (* prefix="" *)
   method Action expl(Bool exp);  // 爆発入力
   method Bit#(1) rd();  // 赤出力
   method Bit#(1) gd(); // 緑出力
   method Bit#(1) bd();  // 青出力
endinterface

// モジュールの定義
(* synthesize,always_ready,always_enabled *)
module mkGraphicFSM(GraphicFSM_ifc);

   Reg#(UInt#(`HW)) x <- mkRegU;     // 水平方向のカウンタ
   Reg#(UInt#(`VW)) y <- mkRegU;     // 垂直方向のカウンタ
   Reg#(Bool) in_xhs <- mkReg(False),   // 水平同期信号フラグ
             in_xvs <- mkReg(False),  // 垂直同期信号フラグ
              in_hdt <- mkReg(False),
              in_vdt <- mkReg(False);
   UInt#(`HW) ehoff = (`HD-`EHD)/2;
   UInt#(`VW) evoff = (`VD-`EVD)/2;
   Reg#(Bit#(4)) in_data <-mkRegU;  // VRAMデータ
   Reg#(Bool) in_exp <- mkReg(False); // 爆発フラグ

// メインループの定義
   Stmt main = seq
      while(True) seq
//       for (y <= 0; y < `VL; y <= y+1) seq
         y <= 0;
         while (y < `VL) seq
//          for (x <= 0; x < `HL; x <= x+1) action  --- for consumes two cycles, then we like to use while
            x <= 0;
            while (x < `HL) action
               if (((`HD+`HFP)<=x)&&(x<(`HD+`HFP+`HSP))) in_xhs <= False;
               else in_xhs <= True;
               if ((ehoff<=x)&&(x<ehoff+`EHD)) in_hdt <= True;
               else in_hdt <= False;
               x <= x + 1;
               if (((`VD+`VFP)<=y)&&(y<(`VD+`VFP+`VSP))) in_xvs <= False;
               else in_xvs <= True;
               if ((evoff<=y)&&(y<evoff+`EVD)) in_vdt <= True;
               else in_vdt <= False;
            endaction // for -> while
            y <= y + 1;
         endseq // for -> while
         $display("%3d %3d", y, x);
      endseq // while(True)
   endseq; // Stmt       // xから水平オフセット(ehoff)を減算してパックし、右に1ビットシフトする。
   Bit#(`HW)xx = pack(x-ehoff)>>1;

   // yから垂直オフセット(evoff)を減算してパックし、右に1ビットシフトする。
   Bit#(`VW)yy = pack(y-evoff)>>1;
    // xxとyyを8ビットに切り詰める。
   Bit#(8)xxx = truncate(xx);
   Bit#(8)yyy = truncate(yy);
   // xxxとyyyを合成して16ビットのアドレスを作成。
   Bit#(16) in_addr = {yyy, xxx};
   // 水平データタイミング(in_hdt)と垂直データタイミング(in_vdt)をANDで合成。
   Bool in_dt = in_hdt && in_vdt;
   // 爆発フラグ(in_exp)に基づいて赤色成分のデータを処理。
   Bit#(1) in_rd = !in_exp ? in_data[2] & pack(in_dt) : (in_data[2] | in_data[1] | in_data[0]) & pack(in_dt);
   // 爆発フラグ(in_exp)に基づいて緑色成分のデータを処理。
   Bit#(1) in_gd = !in_exp ? in_data[1] & pack(in_dt) : 1'b0;
   // 爆発フラグ(in_exp)に基づいて青色成分のデータを処理。
   Bit#(1) in_bd = !in_exp ? in_data[0] & pack(in_dt) : 1'b0;

   // ステートマシン生成
   mkAutoFSM(main);

   // メソッド定義
   method Bool xhs();
      return in_xhs;
   endmethod
   method Bool xvs();
      return in_xvs;
   endmethod
   method Addr_t address();
      return in_addr;
   endmethod
   method Action idata(Bit#(4) indata);
      in_data <= indata;
   endmethod
   method Action expl(Bool exp);
      in_exp <= exp;
   endmethod
   method Bit#(1) rd();
      return in_rd;
   endmethod
   method Bit#(1) gd();
      return in_gd;
   endmethod
   method Bit#(1) bd();
      return in_bd;
   endmethod

endmodule: mkGraphicFSM
  • actionからendactionまでは1サイクル実行です。
  • verilogと同様、"<="はノンブロッキング代入でDFFが、"="はブロッキング代入で組み合わせ回路がそれぞれ生成されます。

当初、水平のオフセットを表す定数EHOFFは、上記のような

UInt#(`HW) ehoff = (`HD-`EHD)/2;

という変数ではなく、define文により

`define EHOFF      (`HD-`EHD)/2

のように定義していたのですが、defineの中でカッコや乗除算は使用できないようなので、変数としました。

ところが、生成されたVerilogを確認したところ、bscの最適化により定数となっており、レジスタは存在しませんでした。結論として、マクロで定数定義してもレジスタ宣言しても、オーバヘッドは変わりません。


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


ページ: