RAMRTL記述

[] [] []


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

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];

次の書き方もあるが、こちらXSTではサポートされておらず、またQuartusIIはバイパスがついた回路で論理合成されたので使わない方がよい。

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

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

always @(posedge clk)

    begin

    if(we) ram[adr] = din;

    dout = ram[adr];

    end

Virtex,SpartanファミリではブロックRAMの他にLUTRAMをメモリに転用したDistributed RAMが備わっている。またStratixファミリではブロックRAM3種類のサイズがある。どのタイプのRAMを使うかは指定しなくても(たぶんRAMサイズによって)自動的に選択されるが、特に指定したい場合は合成制約で指定する。

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

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

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

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

// QuartusIIの場合。value={MLAB|M9K|M144K|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(we_a) 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


[] [] []