|
2 |
メモリをBSVで書く (2) |
書き換え後は、BRAMCoreをimportしてmkBRAMCore1Loadをブリッタの中に置きます。引数は語数、出力レジスタの有無、ファイル名、ファイルが2進かどうかです。
import StmtFSM::*;
import FIFOF::*;
import BRAMCore::*;
// MemPort: 画面メモリ側の面。PROM は内蔵なので VRAM のポート A だけが出る
interface MemPort;
(* always_ready *) method VAddr_t vaddr;
(* always_ready *) method Bool vwe;
(* always_ready *) method Pattern_t vdout;
(* always_enabled *) method Action vdin(Pattern_t d);
endinterface
Reg#(VAddr_t) v_addr <- mkRegU;
Reg#(Bool) fvwe <- mkReg(False);
Reg#(Bool) fobj <- mkReg(False),
fbase <- mkReg(False);
Reg#(Pattern_t) vd <- mkRegU;
Wire#(Pattern_t) vdata <- mkWire;
// パターン ROM 25728 x 4。prom.mem を $readmemh で読む同期 ROM で、
// put したアドレスの内容が次の周期から read に出る。
`ifdef PROM_DEPTH
Integer promDepth = `PROM_DEPTH;
`else
Integer promDepth = 25728;
`endif
BRAM_PORT#(PAddr_t, Pattern_t) prom <- mkBRAMCore1Load(promDepth, False, "prom.mem", False);
action
prom.put(False, {pack(ys)[7:0], pack(xs)[6:0]}, ?);
UInt#(8) y_addr = truncate(yd);
UInt#(8) x_addr = truncate(xd);
v_addr <= {pack(y_addr), pack(x_addr)};
endaction
noAction; // リード待ち(1サイクル)
action
case (b.op)
BLIT_COPY: vd <= prom.read;
BLIT_OR: vd <= vdata | prom.read;
BLIT_ANDN: vd <= vdata & ~prom.read;
BLIT_ERASE: vd <= 0;
endcase
xs <= xs + 1;
xd <= xd + 1;
endaction
interface MemPort mem;
method VAddr_t vaddr = v_addr;
method Bool vwe = fvwe;
method Pattern_t vdout = vd;
method Action vdin(Pattern_t d); vdata <= d; endmethod
endinterface
アドレスを置くactionはレジスタへの代入からprom.putに、ラッチのactionはワイヤからprom.readに変わりました。putは書き込みフラグ、アドレス、書き込みデータを取り、ROMなので書き込みフラグはFalse、データは不定の?です。putしたアドレスの内容は次の周期からreadに出るので、間のnoActionを含めて1画素あたりのサイクル数は変わりません。消えたのはp_addrレジスタ、romdataワイヤ、MemPortの2ポート、mkGameFSMの同名の2ポート、master.vのROMインスタンスと2本の配線です。
生成Verilogでは、bsc付属のBRAM1Load.vがFILENAMEにprom.mem、MEMSIZEに25728を与えてインスタンスされます。BRAM1Load.vの中が$readmemhなので、memの運用は今までと同じです。語数はBlitter.bsvのpromDepthにあり、テストベンチのように別の語数で作りたいときは-D PROM_DEPTH=32768のように与えます。
Leave a Comment