RAMの書き方

Mon, 09 Oct 2017 16:24:08 JST (67d)

RAMの種類

FPGA上でRAMを構成する方法には、フリップフロップ、分散RAM、ブロックRAMの3種類があります。

作り方によって回路面積や読み出しのタイミングなどが異なりますが、フリップフロップは回路面積を大きく消費するため基本的には分散RAMかブロックRAMを使うようにしましょう。

分散RAMとブロックRAMの違いは、簡単に言ってしまえばあらかじめ用意されているRAMを使うのがブロックRAM、LUTを用いて構成されるのが分散RAMです。

回路面積を消費しないのはブロックRAMですが、その分すこし制約がかかります。

分散RAM

1read/1writeの分散RAMの記述例です。

重要なのは書き込みのタイミングをクロックと同期するということです。

	 module ram(clk, we, r_addr, r_data, w_addr, w_data); 
             input clk, we;
             input  [4:0] r_addr, w_addr;
             input  [31:0] w_data;
             output [31:0] r_data;
             reg [31:0] mem [0:31];             //32bitのレジスタが32個(アドレスは5bit)
             always @(posedge clk) begin
                 if(we) mem[w_addr] <= w_data; //クロックと同期して書き込まれる
             end
             assign r_data = mem[r_addr];
	 endmodule

ブロックRAM

1read/1writeのwrite firstのブロックRAMの記述例です。

重要なのは書き込みのタイミングと読み出しアドレスをそれぞれクロックと同期するということです。

	 module ram(clk, we, r_addr, r_data, w_addr, w_data); 
             input clk, we;
             input  [4:0] r_addr, w_addr;
             input  [31:0] w_data;
             output [31:0] r_data;
             reg [4:0] addr_reg;
             reg [31:0] mem [0:31];
             always @(posedge clk) begin
                 if(we) mem[w_addr] <= w_data; //書き込みのタイミングを同期
                 addr_reg <= r_addr;           //読み出しアドレスを同期
             end
             assign r_data = mem[addr_reg];
	 endmodule

RAMの初期化

RAMの初期化は、モジュール内に次の記述をすることで行うことができます。

         initial $readmemb("D:/workspace/test.bin", mem)

注意として、用いるファイルのパスは絶対パスを用い、'\'ではなく'/'で記述してください。

test.binには初期化したいデータの文字列を書きます。バリナリデータではありません。

         00001100000000000000000000000000
         00000100000000010000010000000000
         00000100000000100000000001001000
         000001_00000_00011_0000000001100101 //アンダーバーを入れてもOK

readmembの16進数版であるreadmemhもあります。 この場合、参照するファイルには

         0C00000000000000
         08_01_04_00

などと記述します。

また、次のような記述も可能です。

          integer i;
          initial begin
              for(i=0;i<32;i=i+1)
                  mem[i]=0;
          end
          initial begin
              mem[0]=32'h12345678;
              mem[1]=32'h87654321;
              ...
          end

ROMの記述

ROMの場合も、write線がないだけでRAMと同様です。 すなわち、読み出しを同期すればブロックRAMで構成されます。

	 module rom(clk, r_addr, r_data); 
             input clk;
             input  [4:0] r_addr;
             output [31:0] r_data;
             reg [4:0] addr_reg;
             reg [31:0] mem [0:31]
             always @(posedge clk) begin
                 addr_reg <= r_addr;           //読み出しアドレスを同期
             end
             assign r_data = mem[addr_reg];
	 endmodule