|
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; |