RAMRTL記述

[] [] []


FPGAにはデュアルポートで使えるブロックRAMが備わっている。ブロックRAMを使うにはIP生成ツールで生成したものをインスタンシエートするのが一般的だが、ビット幅や出力レジスタ有無が見えないので可読性が悪いし、ツールバージョンやターゲットデバイスが変わるたびに生成し直さなければならず移植性もよくない。そこで、RTL記述で書いた方が可読性や移植性がよくなる。ただしIP生成するよりは贅沢にブロックRAMを使ってしまう(例えば9ビット幅のブロックRAM8ビット幅として使ってしまう)のが欠点。

1) シングルポートRAM

/* シングルポートRAM - ライト前の値がリードされる */

reg[WD-1:0] ram[0:2**WA-1];

always @(posedge clk) begin

    if(we) ram[adr] <= din;

    dout <= ram[adr];

end

 

/* ングルポートRAM - ライト後の値がリードされる */

reg[WD-1:0] ram[0:2**WA-1];

always @(posedge clk) begin

    if(we) ram[adr] <= din;

    adr_reg <= adr;

end

assign dout = ram[adr_reg];

次のブロッキング代入をつかった書き方もあるが、ノンブロッキング代入に統一した方が紛らわしくなくてよい。

×

/* シングルポートRAM - ライト後の値がリードされる */

reg[WD-1:0] ram[0:2**WA-1];

always @(posedge clk) begin

    if(we) ram[adr] = din;

    dout = ram[adr];

end

FPGAではブロックRAMの他にLUTRAMを転用したDistributed RAMが備わっている。どのタイプのRAMを使うかは(たぶんRAMサイズによって)自動的に選択されるが、特に指定したい場合は合成制約で指定する。

// Vivadoの場合。value={block|distributed}

(* ram_style="value" *) reg[WD-1:0] ram[0:2**WA-1];

// Quartusの場合。value={M20K|M9K|M144K|MLAB|logic}

(* syn_ramstyle="value" *) reg[WD-1:0] ram[0:2**WA-1];

◇◇

2) デュアルポートRAM

/* デュアルポートRAM - 同一ポート内ではライト前の値がリードされる */

reg[WD-1:0] ram[0:2**WA-1];

always @(posedge a_clk) begin

    if(a_we) ram[a_adr] <= a_din;

    a_dout <= ram[a_adr];

end

always @(posedge b_clk) begin

    if(b_we) ram[b_adr] <= b_din;

    b_dout <= ram[b_adr];

end


[] [] []