使用頻度の高い部品のHDL記述例 -内部RAM-

2021/07/16に公開

FPGAは内部にRAMを持っているものが多く、デバイスによりますが数十Mbit程度のデータを保持する能力があります。この内部RAMを使ってデータの一時記憶をさせることは、様々な応用が利きますので、使用頻度は高いと思います。
内部RAMはFPGA内部では専用のモジュールとして実装されているので、ツールを使って生成することが多いですが、以下のような記載をすることでツール側で推論してくれて内部RAMに置き換えてくれることがあります。(どちらかというと、Xilinxの方が得意なイメージです。)

例1

単純なシングルポートRAMの例です。読み書きは同じアドレスで、we=1でデータを書き込みます。

VHDL
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity ram is
  port(
    clk  : in  std_logic;
    we   : in  std_logic;
    addr : in  std_logic_vector(5 downto 0);
    din  : in  std_logic_vector(7 downto 0);
    dout : out std_logic_vector(7 downto 0)
  );
end ram;

architecture rtl of ram is
  type mem_type is array (63 downto 0) of std_logic_vector(7 downto 0);
  signal mem : mem_type;
begin
  process(clk)
  begin
    if (clk'event and clk = '1') then
      if (we = '1') then
        mem(conv_integer(addr)) <= din;
      end if;
    dout <= mem(conv_integer(addr));
    end if;
  end process;
end rtl;
verilog
module ram
  ( 
    input  wire clk,
    input  wire we,
    input  wire [5:0] addr,
    input  wire [7:0] din,
    output reg  [7:0] dout
  );

reg [7:0] mem [63:0];

always @(posedge clk) begin 
  if (we) begin
    mem[addr] <= din;
  end
  dout <= mem[addr];
end
endmodule

例2

単純なデュアルポートRAMの例です。書き込み側と読み出し側に分かれていて、1つのクロックで動作します。

VHDL
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity ram is
  port(
    clk   : in  std_logic;
    wea   : in  std_logic;
    addra : in  std_logic_vector(5 downto 0);
    addrb : in  std_logic_vector(5 downto 0);
    dina  : in  std_logic_vector(7 downto 0);
    doutb : out std_logic_vector(7 downto 0)
  );
end ram;

architecture rtl of ram is
  type mem_type is array (63 downto 0) of std_logic_vector(7 downto 0);
  signal mem : mem_type;
begin
  process(clk)
  begin
    if (clk'event and clk = '1') then
      if (wea = '1') then
        mem(conv_integer(addra)) <= dina;
      end if;
      doutb <= mem(conv_integer(addrb));
    end if;
  end process;

end rtl;
verilog
module ram
  ( 
    input  wire clk,
    input  wire wea,
    input  wire [5:0] addra,
    input  wire [5:0] addrb,
    input  wire [7:0] dina,
    output reg  [7:0] doutb
  );

reg [7:0] mem [63:0];

always @(posedge clk) begin 
  if (wea) begin
    mem[addra] <= dina;
  end
  doutb <= mem[addrb];
end

endmodule

例3

両側異なるクロックで読み書き出来るデュアルポートRAMの例です。memを2か所で更新しているため、シミュレーション時にはwarningが出ると思いますが、論理合成は出来ると思います。

VHDL
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;

entity ram is
  port(
    clka  : in  std_logic;
    clkb  : in  std_logic;
    wea   : in  std_logic;
    web   : in  std_logic;
    addra : in  std_logic_vector(5 downto 0);
    addrb : in  std_logic_vector(5 downto 0);
    dina  : in  std_logic_vector(7 downto 0);
    dinb  : in  std_logic_vector(7 downto 0);
    douta : out std_logic_vector(7 downto 0);
    doutb : out std_logic_vector(7 downto 0)
  );
end ram;

architecture rtl of ram is
  type ram_type is array (63 downto 0) of std_logic_vector(7 downto 0);
  shared variable mem : ram_type;
begin
  process(clka)
  begin
    if (clka'event and clka = '1') then
      if wea = '1' then
        mem(conv_integer(ADDRA)) := dina;
      end if;
      douta <= mem(conv_integer(ADDRA));
    end if;
  end process;

  process(clkb)
  begin
    if (clkb'event and clkb = '1') then
      if (web = '1') then
        mem(conv_integer(ADDRB)) := dinb;
      end if;
      doutb <= mem(conv_integer(ADDRB));
    end if;
  end process;
end rtl;
verilog
module ram
  ( 
    input  wire clka,
    input  wire clkb,
    input  wire wea,
    input  wire web,
    input  wire [5:0] addra,
    input  wire [5:0] addrb,
    input  wire [7:0] dina,
    input  wire [7:0] dinb,
    output reg  [7:0] douta,
    output reg  [7:0] doutb
  );

reg [7:0] mem [63:0];

always @(posedge clka) begin 
  if (wea) begin
    mem[addra] <= dina;
  end
  douta <= mem[addra];
end

always @(posedge clkb) begin 
  if (web) begin
    mem[addrb] <= dinb;
  end
  doutb <= mem[addrb];
end
endmodule

上記の例では、bit幅固定でしたが、アドレスやデータのbit幅をパラメータ化しておくと、あちこちで使用しやすくなりますので、そのあたりは適宜調整いただくのがよいかと思います。

Discussion