はじめに
この記事では比較的単純で小容量の DPRAM(Dual Port RAM) を VHDL で記述して、AMD(旧Xilinx) の FPGA に実装してみた例を紹介します。
というのも、AMD(旧Xilinx) の FPGA にロジックを実装するための CLB(Configurable Logic Block)があり、各 CLB には6入力1出力の LUT(LookUp Table) と呼ばれるものがあります。この LUT はロジックを実装する他に、64word ×1bit のメモリとして使うことが出来ます。
はるか昔のツールでは特殊な記述方法でなければ、LUT メモリを使えなかったのですが、今時のツールならば適当に記述しても上手く実装してくれるみたいです。
そこで幾つか DPRAM を VHDL で記述してみて、その実装結果を確認してみました。この記事はその第一弾です。
リポジトリ
この記事で紹介している VHDL のソースコードや、Vivado でシミュレーションやIP の生成やサンプルデザインの実装を行うための各種スクリプトは以下の Github のリポジトリにて公開しています。
記述例その1
VHDL による記述
Entity
この記事で紹介する VHDL のモジュールは次のような entity になっています。
entity DPRAM is
generic (
DATA_BITS : integer := 32;
ADDR_BITS : integer := 6;
N : integer := 1
);
port (
WCLK : in std_logic;
WE : in std_logic_vector(N -1 downto 0);
WADDR : in std_logic_vector(ADDR_BITS-1 downto 0);
WDATA : in std_logic_vector(DATA_BITS-1 downto 0);
RADDR : in std_logic_vector(ADDR_BITS-1 downto 0);
RDATA : out std_logic_vector(DATA_BITS-1 downto 0)
);
end DPRAM;
DATA_BITS でデータのビット幅、ADDR_BITS でアドレスのビット幅を指定します。
N は書き込むデータのグループ数を指定します。
例えば、DATA_BITS=32 かつ N=4 ならば、この DPRAM はバイト単位で書き込むことが出来ます。
Architecture
DPRAM のアーキテクチャの実装例を示します。ここではアーキテクチャの名前を MODEL_0 としています。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
architecture MODEL_0 of DPRAM is
constant INDEX_MIN : integer := 0;
constant INDEX_MAX : integer := 2**ADDR_BITS-1;
subtype INDEX_TYPE is integer range INDEX_MIN to INDEX_MAX;
function addr_to_index(ADDR: std_logic_vector) return INDEX_TYPE is
alias u_addr : std_logic_vector(ADDR'length-1 downto 0) is ADDR;
variable u_index : unsigned(u_addr'range);
begin
for i in u_index'range loop
if (u_addr(i) = '1') then
u_index(i) := '1';
else
u_index(i) := '0';
end if;
end loop;
return to_integer(u_index);
end function;
constant WORD_BITS : integer := DATA_BITS/N;
subtype DATA_TYPE is std_logic_vector(DATA_BITS-1 downto 0);
type DATA_VECTOR is array(integer range <>) of DATA_TYPE;
signal ram : DATA_VECTOR(INDEX_MIN to INDEX_MAX);
signal r_index : INDEX_TYPE;
signal w_index : INDEX_TYPE;
begin
w_index <= addr_to_index(WADDR);
r_index <= addr_to_index(RADDR);
process (WCLK) begin
if (WCLK'event and WCLK = '1') then
for pos in DATA_TYPE'range loop
if (WE(pos/WORD_BITS) = '1') then
ram(w_index)(pos) <= WDATA(pos);
end if;
end loop;
end if;
end process;
RDATA <= ram(r_index);
end MODEL_0;
Vivado による実装結果
サンプル IP
上記の DPRAM の実装例を使って簡単な AXI からアクセスするための IP を作りました。
IP のトップレベルは次の URL で示される VHDL で示します。
まずはこの IP を Vivado から使えるようにします。IP を作るスクリプトは以下にあります。
KV260 でのデザイン例
IP を使って KV260 用のデザインを作りました。デザインを実装するスクリプトは以下にあります。
下図にこのデザインのブロック図を示します。
AXI_DPRAM_64x32_0 のパラメーターは RAM_ADDR_WIDTH=6、RAM_DATA_WDITH=32、RAM_NUM=4 に設定しています。各々が DPRAM の ADDR_WIDTH、DATA_WIDTH、N に対応します。
Utlization
上記のデザインをインプリメンターションした際の Utlization(配置配線後のCLB/FFの利用状況)を下図に示します。
LUT as Memory の所を参照すると、64 個の LUT を使っていることが確認できます。
Schematic
どのように DPRAM が実装されているかを schematic を使って確認しました。
一番左の図が DPRAM のブロックです。
それを展開したのが左から2番目の図です。なにやら下位モジュールが32個並んています。
左から2番目の図を拡大したのが右から2番目の図です。下位モジュールの名前が RAM64X1D というのが判ります。
一番右の図が RAM64X1D の中身です。RAMD64E というのが二つ並んでいます。
これ以上展開出来無いところをみると、どうやら RAMD64E というのがプリミティブのようです。これが LUT 一個分に相当すると思われます。
まとめ
上記の VHDL の記述では、データのビット幅に対して2個の LUT が使われることがわかりました。
最近の Vivado では、適当に記述してもこのくらいの実装はしてくれるようです。
当初はこれで満足していたのですが、実はもっと良い実装方法があります。それを次の記事で紹介します。


