⭐
使用頻度の高い部品のHDL記述例 -内部RAM-
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