Skip to content

Instantly share code, notes, and snippets.

@ikwzm
Created March 12, 2012 11:03
Show Gist options
  • Save ikwzm/2021193 to your computer and use it in GitHub Desktop.
Save ikwzm/2021193 to your computer and use it in GitHub Desktop.
ASYNC_FIFO

Asynchronous FIFO VHDL Sample Code

ちょいと休日で暇だったので書いてみました。 著作権などは放棄しますので、自由にコピペしてもらっても構いません。 でも責任も放棄してますので、何か問題があったも責任はとりませんのであしからず。

基本的には書き込みポインタと読み出しポインタをグレイコードに変換して、異なるクロックドメイン間で伝達しています。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ASYNC_FIFO is
generic (
DEPTH : integer := 4;
WIDTH : integer := 3
);
port (
RST : in std_logic;
WCLK : in std_logic;
WE : in std_logic;
WDATA : in std_logic_vector(2**WIDTH-1 downto 0);
WRDY : out std_logic;
RCLK : in std_logic;
RE : in std_logic;
RDATA : out std_logic_vector(2**WIDTH-1 downto 0);
RRDY : out std_logic
);
end ASYNC_FIFO;
architecture RTL of ASYNC_FIFO is
component ASYNC_FIFO_CTRL is
generic (
DEPTH : integer := 16
);
port (
RST : in std_logic;
WCLK : in std_logic;
WE : in std_logic;
WPTR : out std_logic_vector(DEPTH-1 downto 0);
WRDY : out std_logic;
WAFF : out std_logic;
RCLK : in std_logic;
RE : in std_logic;
RPTR : out std_logic_vector(DEPTH-1 downto 0);
RRDY : out std_logic
);
end component;
component SDPRAM
generic (
DEPTH : integer;
WIDTH : integer;
WEBIT : integer;
ID : integer
);
port (
WCLK : in std_logic;
WE : in std_logic_vector(2**WEBIT-1 downto 0);
WA : in std_logic_vector( DEPTH-1 downto 0);
RCLK : in std_logic;
RA : in std_logic_vector( DEPTH-1 downto 0);
D : in std_logic_vector(2**WIDTH-1 downto 0);
Q : out std_logic_vector(2**WIDTH-1 downto 0)
);
end component;
signal rptr : std_logic_vector(DEPTH-1 downto 0);
signal wptr : std_logic_vector(DEPTH-1 downto 0);
signal wen : std_logic_vector( 0 downto 0);
signal wready : std_logic;
begin
CTRL: ASYNC_FIFO_CTRL
generic map (
DEPTH => DEPTH
)
port map (
RST => RST ,
WCLK => WCLK ,
WE => WE ,
WPTR => wptr ,
WRDY => wready,
WAFF => open ,
RCLK => RCLK ,
RE => RE ,
RPTR => rptr ,
RRDY => RRDY
);
RAM: SDPRAM
generic map(
DEPTH => DEPTH,
WIDTH => WIDTH,
WEBIT => 0,
ID => 0
)
port map (
WCLK => WCLK ,
WE => wen ,
WA => wptr ,
RCLK => RCLK ,
RA => rptr ,
D => WDATA ,
Q => RDATA
);
wen <= (others => '1') when (WE = '1' and wready = '1') else (others => '0');
WRDY <= wready;
end RTL;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ASYNC_FIFO_CTRL is
generic (
DEPTH : integer := 16
);
port (
RST : in std_logic;
WCLK : in std_logic;
WE : in std_logic;
WPTR : out std_logic_vector(DEPTH-1 downto 0);
WRDY : out std_logic;
WAFF : out std_logic;
RCLK : in std_logic;
RE : in std_logic;
RPTR : out std_logic_vector(DEPTH-1 downto 0);
RRDY : out std_logic
);
end ASYNC_FIFO_CTRL;
architecture RTL of ASYNC_FIFO_CTRL is
-------------------------------------------------------------------------------
-- ライト制御ブロック->リード制御ブロックへのライトポインタ信号
-------------------------------------------------------------------------------
signal async_wptr_dec1_gray : std_logic_vector(DEPTH-1 downto 0);
-------------------------------------------------------------------------------
-- リード制御ブロック->ライト制御ブロックへのリードポインタ信号
-------------------------------------------------------------------------------
signal async_rptr_dec2_gray : std_logic_vector(DEPTH-1 downto 0);
-------------------------------------------------------------------------------
-- グレイコードをバイナリコードに変換する関数
-------------------------------------------------------------------------------
function TO_BINARY(V:std_logic_vector) return std_logic_vector is
alias gray : std_logic_vector(V'length-1 downto 0) is V;
variable bin : std_logic_vector(V'length-1 downto 0);
begin
for i in bin'range loop
if (i = bin'high) then
bin(i) := gray(i);
else
bin(i) := gray(i) xor bin(i+1);
end if;
end loop;
return bin;
end TO_BINARY;
-------------------------------------------------------------------------------
-- バイナリコードをグレイコードに変換する関数
-------------------------------------------------------------------------------
function TO_GRAYCODE(V:std_logic_vector) return std_logic_vector is
alias bin : std_logic_vector(V'length-1 downto 0) is V;
variable gray : std_logic_vector(V'length-1 downto 0);
begin
for i in gray'range loop
if (i = gray'high) then
gray(i) := bin(i);
else
gray(i) := bin(i) xor bin(i+1);
end if;
end loop;
return gray;
end TO_GRAYCODE;
-------------------------------------------------------------------------------
-- 整数をグレイコードに変換する関数
-------------------------------------------------------------------------------
function TO_GRAYCODE(N:integer;L:integer) return std_logic_vector is
variable v : std_logic_vector(L-1 downto 0);
begin
v := std_logic_vector(TO_SIGNED(N,L));
return TO_GRAYCODE(v);
end TO_GRAYCODE;
begin
-------------------------------------------------------------------------------
-- ライト制御ブロック
-------------------------------------------------------------------------------
WBLK: block
signal wptr_curr : unsigned(DEPTH-1 downto 0);
signal wptr_curr_gray : std_logic_vector(DEPTH-1 downto 0);
signal wptr_dec1_gray : std_logic_vector(DEPTH-1 downto 0);
signal rptr_dec2_gray : std_logic_vector(DEPTH-1 downto 0);
signal rptr_dec2_gray_p : std_logic_vector(DEPTH-1 downto 0);
signal full : boolean;
signal almost_full : boolean;
signal count_up : boolean;
begin
---------------------------------------------------------------------------
-- wptr_curr : 現在のライトポインタ
-- wptr_curr_gray : 現在のライトポインタをグレイコードに変換した信号
-- wptr_dec1_gray : 現在のライトポインタ-1をグレイコードに変換した信号
---------------------------------------------------------------------------
process (WCLK, RST) begin
if (RST = '1') then
wptr_curr <= TO_UNSIGNED( 0,DEPTH);
wptr_dec1_gray <= TO_GRAYCODE(-1,DEPTH);
elsif (WCLK'event and WCLK = '1') then
if (count_up) then
wptr_curr <= wptr_curr+1;
wptr_dec1_gray <= wptr_curr_gray;
end if;
end if;
end process;
wptr_curr_gray <= TO_GRAYCODE(std_logic_vector(wptr_curr));
---------------------------------------------------------------------------
-- ポインタ更新フラグ
---------------------------------------------------------------------------
count_up <= (full = FALSE and WE = '1');
---------------------------------------------------------------------------
-- 現在のリードポインタ-2をグレイコードに変換した信号
-- この信号はリード制御ブロックから WCLK とは非同期に通知
-- される信号(async_rptr_dec2_gray)を WCLK で2回叩いたもの.
---------------------------------------------------------------------------
process (WCLK, RST) begin
if (RST = '1') then
rptr_dec2_gray_p <= TO_GRAYCODE(-2,DEPTH);
rptr_dec2_gray <= TO_GRAYCODE(-2,DEPTH);
elsif (WCLK'event and WCLK = '1') then
rptr_dec2_gray_p <= async_rptr_dec2_gray;
rptr_dec2_gray <= rptr_dec2_gray_p;
end if;
end process;
---------------------------------------------------------------------------
-- ライト制御ブロック->リード制御ブロックへのライトポインタ
-- 実際はライトポインタ-2をグレイコードに変換した信号
---------------------------------------------------------------------------
async_wptr_dec1_gray <= wptr_dec1_gray;
---------------------------------------------------------------------------
-- FIFO が一杯でデータが書き込めないことを示すフラグ
---------------------------------------------------------------------------
process (WCLK, RST) begin
if (RST = '1') then
full <= FALSE;
elsif (WCLK'event and WCLK = '1') then
full <= (rptr_dec2_gray = wptr_dec1_gray) or
(rptr_dec2_gray = wptr_curr_gray and count_up);
end if;
end process;
---------------------------------------------------------------------------
-- almost_full
---------------------------------------------------------------------------
process (rptr_dec2_gray, wptr_dec1_gray, wptr_curr)
variable rptr_dec2 : unsigned(DEPTH-1 downto 0);
variable diff_ptr : unsigned(DEPTH-1 downto 0);
begin
rptr_dec2 := unsigned(TO_BINARY(TO_X01(rptr_dec2_gray)));
diff_ptr := rptr_dec2 - wptr_curr;
almost_full <= (rptr_dec2_gray = wptr_dec1_gray) or
(diff_ptr <= 8-1);
end process;
---------------------------------------------------------------------------
-- WPTR : ライトポインタ
-- WRDY : FIFO にデータを書き込める状態であることを示す信号
---------------------------------------------------------------------------
WPTR <= std_logic_vector(wptr_curr);
WRDY <= '1' when (not full ) else '0';
WAFF <= '1' when (almost_full) else '0';
end block;
-------------------------------------------------------------------------------
-- リード制御ブロック
-------------------------------------------------------------------------------
RBLK: block
signal rptr_curr : unsigned(DEPTH-1 downto 0);
signal rptr_inc1 : unsigned(DEPTH-1 downto 0);
signal rptr_curr_gray : std_logic_vector(DEPTH-1 downto 0);
signal rptr_dec1_gray : std_logic_vector(DEPTH-1 downto 0);
signal rptr_dec2_gray : std_logic_vector(DEPTH-1 downto 0);
signal wptr_dec1_gray_p : std_logic_vector(DEPTH-1 downto 0);
signal wptr_dec1_gray : std_logic_vector(DEPTH-1 downto 0);
signal empty : boolean;
signal count_up : boolean;
begin
---------------------------------------------------------------------------
-- rptr_curr : 現在のリードポインタ
-- rptr_curr_gray : 現在のリードポインタをグレイコードに変換した信号
-- rptr_dec1_gray : 現在のリードポインタ-1をグレイコードに変換した信号
-- rptr_dec2_gray : 現在のリードポインタ-2をグレイコードに変換した信号
---------------------------------------------------------------------------
process (RCLK, RST) begin
if (RST = '1') then
rptr_curr <= TO_UNSIGNED( 0,DEPTH);
rptr_dec1_gray <= TO_GRAYCODE(-1,DEPTH);
rptr_dec2_gray <= TO_GRAYCODE(-2,DEPTH);
elsif (RCLK'event and RCLK = '1') then
if (count_up) then
rptr_curr <= rptr_inc1;
rptr_dec1_gray <= rptr_curr_gray;
rptr_dec2_gray <= rptr_dec1_gray;
end if;
end if;
end process;
rptr_curr_gray <= TO_GRAYCODE(std_logic_vector(rptr_curr));
---------------------------------------------------------------------------
-- ポインタ更新フラグ
---------------------------------------------------------------------------
count_up <= (empty = FALSE and RE = '1');
---------------------------------------------------------------------------
-- 現在のリードポインタ+1
---------------------------------------------------------------------------
rptr_inc1 <= rptr_curr+1;
---------------------------------------------------------------------------
-- 現在のライトポインタ-1をグレイコードに変換した信号
-- この信号はライト制御ブロックから RCLK とは非同期に
-- 通知される信号(async_wptr_dec1_gray)を RCLK で叩いたもの.
---------------------------------------------------------------------------
process (RCLK, RST) begin
if (RST = '1' ) then
wptr_dec1_gray_p <= TO_GRAYCODE(-1,DEPTH);
wptr_dec1_gray <= TO_GRAYCODE(-1,DEPTH);
elsif (RCLK'event and RCLK = '1') then
wptr_dec1_gray_p <= async_wptr_dec1_gray;
wptr_dec1_gray <= wptr_dec1_gray_p;
end if;
end process;
---------------------------------------------------------------------------
-- リード制御ブロック->ライト制御ブロックへのリードポインタ
-- 実際はリードポインタ-2をグレイコードに変換した信号
---------------------------------------------------------------------------
async_rptr_dec2_gray <= rptr_dec2_gray;
---------------------------------------------------------------------------
-- empty : FIFO が空でデータが無いことを示すフラグ
-- RRDY : FIFO にデータがあって読み出せる状態であることを示す信号
---------------------------------------------------------------------------
process (RCLK, RST) begin
if (RST = '1') then
empty <= TRUE;
RRDY <= '0'; -- リセット時は'0'にしておいたほうが安全
elsif (RCLK'event and RCLK = '1') then
if (wptr_dec1_gray = rptr_dec1_gray) or
(wptr_dec1_gray = rptr_curr_gray and count_up) then
empty <= TRUE;
RRDY <= '0';
else
empty <= FALSE;
RRDY <= '1';
end if;
end if;
end process;
---------------------------------------------------------------------------
-- リードポインタ
---------------------------------------------------------------------------
RPTR <= std_logic_vector(rptr_inc1) when (count_up) else
std_logic_vector(rptr_curr);
end block;
end RTL;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity SDPRAM is
generic (
DEPTH : integer := 6; -- バッファの深さ(ワード数)を2のべき乗値で指定する
WIDTH : integer := 6; -- バッファの幅(ビット数)を2のべき乗値で指定する
WEBIT : integer := 0; -- WE信号のビット数を2のべき乗値で指定する
ID : integer := 0 -- どのモジュールで使われているかを示すタグ
);
port (
WCLK : in std_logic;
WE : in std_logic_vector(2**WEBIT-1 downto 0);
WA : in std_logic_vector( DEPTH-1 downto 0);
RCLK : in std_logic;
RA : in std_logic_vector( DEPTH-1 downto 0);
D : in std_logic_vector(2**WIDTH-1 downto 0);
Q : out std_logic_vector(2**WIDTH-1 downto 0)
);
end SDPRAM;
architecture RTL of SDPRAM is
type RAM_ARRAY is array (0 to 2**DEPTH-1) of
std_logic_vector(2**WIDTH-1 downto 0);
signal ram : RAM_ARRAY;
signal rd_ptr : integer range 0 to 2**DEPTH-1;
signal wr_ptr : integer range 0 to 2**DEPTH-1;
signal bit_we : std_logic_vector(2**WIDTH-1 downto 0);
begin
process (WE)
constant BIT_WE_SIZE : integer := (2**WIDTH)/(2**WEBIT);
begin
for i in WE'range loop
for n in 0 to BIT_WE_SIZE-1 loop
bit_we(i*BIT_WE_SIZE + n) <= WE(i);
end loop;
end loop;
end process;
rd_ptr <= TO_INTEGER(unsigned(RA));
wr_ptr <= TO_INTEGER(unsigned(WA));
process (RCLK) begin
if (RCLK'event and RCLK = '1') then
Q <= ram(rd_ptr);
end if;
end process;
process (WCLK) begin
if (WCLK'event and WCLK = '1') then
for bit in bit_we'range loop
if (bit_we(bit) = '1') then
ram(wr_ptr)(bit) <= D(bit);
end if;
end loop;
end if;
end process;
end RTL;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library unisim;
entity SDPRAM is
generic (
DEPTH : integer := 6; -- バッファの深さ(ワード数)を2のべき乗値で指定する
WIDTH : integer := 6; -- バッファの幅(ビット数)を2のべき乗値で指定する
WEBIT : integer := 0; -- WE信号のビット数を2のべき乗値で指定する
ID : integer := 0 -- どのモジュールで使われているかを示すタグ
);
port (
WCLK : in std_logic;
WE : in std_logic_vector(2**WEBIT-1 downto 0);
WA : in std_logic_vector(DEPTH-1 downto 0);
RCLK : in std_logic;
RA : in std_logic_vector(DEPTH-1 downto 0);
D : in std_logic_vector(2**WIDTH-1 downto 0);
Q : out std_logic_vector(2**WIDTH-1 downto 0)
);
end SDPRAM;
architecture XILINX of SDPRAM is
component RAM16X1D
generic (
TimingChecksOn : boolean
);
port (
DPO : out std_logic;
SPO : out std_logic;
D : in std_logic;
WE : in std_logic;
WCLK : in std_logic;
A0 : in std_logic;
A1 : in std_logic;
A2 : in std_logic;
A3 : in std_logic;
DPRA0 : in std_logic;
DPRA1 : in std_logic;
DPRA2 : in std_logic;
DPRA3 : in std_logic
);
end component;
signal bit_we : std_logic_vector(2**WIDTH-1 downto 0);
begin
process (WE)
constant BIT_WE_SIZE : integer := (2**WIDTH)/(2**WEBIT);
begin
for i in WE'range loop
for n in 0 to BIT_WE_SIZE-1 loop
bit_we(i*BIT_WE_SIZE + n) <= WE(i);
end loop;
end loop;
end process;
GT4:if (DEPTH > 4) generate
GT4_BLK:block
constant BANK : integer := (2**(DEPTH-4));
type RAM_ARRAY is array (0 to BANK-1) of std_logic_vector(2**WIDTH-1 downto 0);
signal ram_data_o : RAM_ARRAY;
signal spo : RAM_ARRAY;
signal ram_we : RAM_ARRAY;
signal bank_sel : integer range 0 to BANK-1;
begin
A: for i in 0 to BANK-1 generate
ram_we(i) <= bit_we when (unsigned(WA(WA'LEFT downto 4)) = i) else (others => '0');
B: for bit in 0 to 2**WIDTH-1 generate
RAM: RAM16X1D generic map (TimingChecksOn => FALSE) port map(
DPO => ram_data_o(i)(bit),
SPO => spo(i)(bit),
D => D(bit),
WE => ram_we(i)(bit),
WCLK => WCLK,
A0 => WA(0),
A1 => WA(1),
A2 => WA(2),
A3 => WA(3),
DPRA0 => RA(0),
DPRA1 => RA(1),
DPRA2 => RA(2),
DPRA3 => RA(3)
);
end generate;
end generate;
bank_sel <= TO_INTEGER(unsigned(RA(RA'LEFT downto 4)));
process (RCLK) begin
if (RCLK'event and RCLK = '1') then
Q <= ram_data_o(bank_sel);
end if;
end process;
end block;
end generate;
LE4:if (DEPTH <= 4) generate
LE4_BLK:block
signal wptr : std_logic_vector(3 downto 0);
signal rptr : std_logic_vector(3 downto 0);
signal spo : std_logic_vector(2**WIDTH-1 downto 0);
signal dpo : std_logic_vector(2**WIDTH-1 downto 0);
begin
wptr <= std_logic_vector(RESIZE(unsigned(WA), 4));
rptr <= std_logic_vector(RESIZE(unsigned(RA), 4));
B: for bit in 0 to 2**WIDTH-1 generate
RAM: RAM16X1D generic map (TimingChecksOn => FALSE) port map(
SPO => spo(bit),
DPO => dpo(bit),
D => D(bit),
WE => bit_we(bit),
WCLK => WCLK,
A0 => wptr(0),
A1 => wptr(1),
A2 => wptr(2),
A3 => wptr(3),
DPRA0 => rptr(0),
DPRA1 => rptr(1),
DPRA2 => rptr(2),
DPRA3 => rptr(3)
);
end generate;
process (RCLK) begin
if (RCLK'event and RCLK = '1') then
Q <= dpo;
end if;
end process;
end block;
end generate;
end XILINX;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment