1
0
mirror of https://github.com/wfjm/w11.git synced 2026-03-06 19:42:03 +00:00
Files
wfjm.w11/rtl/vlib/memlib/fifo_2c_dram.vhd
2019-07-12 19:01:49 +02:00

336 lines
12 KiB
VHDL

-- $Id: fifo_2c_dram.vhd 1181 2019-07-08 17:00:50Z mueller $
-- SPDX-License-Identifier: GPL-3.0-or-later
-- Copyright 2007-2011 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
--
------------------------------------------------------------------------------
-- Module Name: fifo_2c_dram - syn
-- Description: FIFO, two clock domain, distributed RAM based, with
-- enable/busy/valid/hold interface.
--
-- Dependencies: ram_1swar_1ar_gen
-- genlib/gray_cnt_n
-- genlib/gray2bin_gen
--
-- Test bench: tb/tb_fifo_2c_dram
-- Target Devices: generic Spartan, Virtex
-- Tool versions: xst 8.2-14.7; ghdl 0.18-0.35 !! NOT FOR VIVADO !!
-- Note: for usage with Vivado use fifo_2c_dram2
--
-- Revision History:
-- Date Rev Version Comment
-- 2011-11-13 424 1.1 use capture+sync flops; reset now glitch free
-- 2011-11-07 421 1.0.2 now numeric_std clean
-- 2007-12-28 107 1.0.1 VAL=0 in cycle after RESETR=1
-- 2007-12-28 106 1.0 Initial version
--
-- Some synthesis results:
-- - 2011-11-13 Rev 424: ise 13.1 for xc3s1000-ft256-4:
-- AWIDTH DWIDTH LUT.l LUT.m LUT.s Flop Slice CLKW CLKR (xst est.)
-- 4 16 41 32 12 38 54 135MHz 115MHz ( 16 words)
-- 5 16 65 64 14 40 80 113MHz 116MHz ( 32 words)
-- - 2007-12-28 Rev 106: ise 8.2.03 for xc3s1000-ft256-4:
-- AWIDTH DWIDTH LUT.l LUT.m Flop CLKW CLKR (xst est.)
-- 4 16 40 32 42 141MHz 165MHz ( 16 words)
-- 5 16 65 64 52 108MHz 108MHz ( 32 words)
-- 6 16 95 128 61 111MHz 113MHz ( 64 words)
-- 7 16 149 256 74 100MHz 96MHz (128 words)
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.slvtypes.all;
use work.genlib.all;
use work.memlib.all;
entity fifo_2c_dram is -- fifo, 2 clock, dram based
generic (
AWIDTH : positive := 5; -- address width (sets size)
DWIDTH : positive := 16); -- data width
port (
CLKW : in slbit; -- clock (write side)
CLKR : in slbit; -- clock (read side)
RESETW : in slbit; -- W|reset from write side
RESETR : in slbit; -- R|reset from read side
DI : in slv(DWIDTH-1 downto 0); -- W|input data
ENA : in slbit; -- W|write enable
BUSY : out slbit; -- W|write port hold
DO : out slv(DWIDTH-1 downto 0); -- R|output data
VAL : out slbit; -- R|read valid
HOLD : in slbit; -- R|read hold
SIZEW : out slv(AWIDTH-1 downto 0); -- W|number slots to write
SIZER : out slv(AWIDTH-1 downto 0) -- R|number slots to read
);
end fifo_2c_dram;
architecture syn of fifo_2c_dram is
type regw_type is record
raddr_c : slv(AWIDTH-1 downto 0); -- read address (capt from CLKR)
raddr_s : slv(AWIDTH-1 downto 0); -- read address (sync in CLKW)
sizew : slv(AWIDTH-1 downto 0); -- slots to write
busy : slbit; -- busy flag
rstw : slbit; -- resetw active
rstw_sc : slbit; -- resetw (sync-capt from CLKR-CLKW)
rstw_ss : slbit; -- resetw (sync-sync from CLKR-CLKW)
rstr_c : slbit; -- resetr (capt from CLKR)
rstr_s : slbit; -- resetr (sync from CLKR)
end record regw_type;
constant regw_init : regw_type := (
slv(to_unsigned(0,AWIDTH)), -- raddr_c
slv(to_unsigned(0,AWIDTH)), -- raddr_s
slv(to_unsigned(0,AWIDTH)), -- sizew
'0', -- busy
'0','0','0', -- rstw,rstw_sc,rstw_ss
'0','0' -- rstr_c,rstr_s
);
type regr_type is record
waddr_c : slv(AWIDTH-1 downto 0); -- write address (capt from CLKW)
waddr_s : slv(AWIDTH-1 downto 0); -- write address (sync in CLKR)
sizer : slv(AWIDTH-1 downto 0); -- slots to read
val : slbit; -- valid flag
rstr : slbit; -- resetr active
rstr_sc : slbit; -- resetr (sync-capt from CLKW-CLKR)
rstr_ss : slbit; -- resetr (sync-sync from CLKW-CLKR)
rstw_c : slbit; -- resetw (capt from CLKW)
rstw_s : slbit; -- resetw (sync from CLKW)
end record regr_type;
constant regr_init : regr_type := (
slv(to_unsigned(0,AWIDTH)), -- waddr_c
slv(to_unsigned(0,AWIDTH)), -- waddr_s
slv(to_unsigned(0,AWIDTH)), -- sizer
'0', -- val
'0','0','0', -- rstr,rstr_sc,rstr_ss
'0','0' -- rstw_c,rstw_s
);
signal R_REGW : regw_type := regw_init; -- write side state registers
signal N_REGW : regw_type := regw_init; -- next values write side
signal R_REGR : regr_type := regr_init; -- read side state registers
signal N_REGR : regr_type := regr_init; -- next values read side
signal WADDR : slv(AWIDTH-1 downto 0) := (others=>'0');
signal RADDR : slv(AWIDTH-1 downto 0) := (others=>'0');
signal WADDR_BIN : slv(AWIDTH-1 downto 0) := (others=>'0');
signal RADDR_BIN : slv(AWIDTH-1 downto 0) := (others=>'0');
signal WADDR_S_BIN : slv(AWIDTH-1 downto 0) := (others=>'0');
signal RADDR_S_BIN : slv(AWIDTH-1 downto 0) := (others=>'0');
signal GCW_RST : slbit := '0';
signal GCW_CE : slbit := '0';
signal GCR_RST : slbit := '0';
signal GCR_CE : slbit := '0';
begin
RAM : ram_1swar_1ar_gen -- dual ported memory
generic map (
AWIDTH => AWIDTH,
DWIDTH => DWIDTH)
port map (
CLK => CLKW,
WE => GCW_CE,
ADDRA => WADDR,
ADDRB => RADDR,
DI => DI,
DOA => open,
DOB => DO
);
GCW : gray_cnt_gen -- gray counter for write address
generic map (
DWIDTH => AWIDTH)
port map (
CLK => CLKW,
RESET => GCW_RST,
CE => GCW_CE,
DATA => WADDR
);
GCR : gray_cnt_gen -- gray counter for read address
generic map (
DWIDTH => AWIDTH)
port map (
CLK => CLKR,
RESET => GCR_RST,
CE => GCR_CE,
DATA => RADDR
);
G2B_WW : gray2bin_gen -- gray->bin for waddr on write side
generic map (DWIDTH => AWIDTH)
port map (DI => WADDR, DO => WADDR_BIN);
G2B_WR : gray2bin_gen -- gray->bin for waddr on read side
generic map (DWIDTH => AWIDTH)
port map (DI => R_REGR.waddr_s, DO => WADDR_S_BIN);
G2B_RR : gray2bin_gen -- gray->bin for raddr on read side
generic map (DWIDTH => AWIDTH)
port map (DI => RADDR, DO => RADDR_BIN);
G2B_RW : gray2bin_gen -- gray->bin for raddr on write side
generic map (DWIDTH => AWIDTH)
port map (DI => R_REGW.raddr_s, DO => RADDR_S_BIN);
--
-- write side --------------------------------------------------------------
--
proc_regw: process (CLKW)
begin
if rising_edge(CLKW) then
R_REGW <= N_REGW;
end if;
end process proc_regw;
proc_nextw: process (R_REGW, RESETW, ENA, R_REGR,
RADDR, RADDR_S_BIN, WADDR_BIN)
variable r : regw_type := regw_init;
variable n : regw_type := regw_init;
variable ibusy : slbit := '0';
variable igcw_ce : slbit := '0';
variable igcw_rst : slbit := '0';
variable isizew : slv(AWIDTH-1 downto 0) := (others=>'0');
begin
r := R_REGW;
n := R_REGW;
isizew := slv(unsigned(RADDR_S_BIN) + unsigned(not WADDR_BIN));
ibusy := '0';
igcw_ce := '0';
igcw_rst := '0';
if unsigned(isizew) = 0 then -- if no free slots
ibusy := '1'; -- next cycle busy=1
end if;
if ENA='1' and r.busy='0' then -- if ena=1 and this cycle busy=0
igcw_ce := '1'; -- write this value
if unsigned(isizew) = 1 then -- if this last free slot
ibusy := '1'; -- next cycle busy=1
end if;
end if;
if RESETW = '1' then -- reset(write side) request
n.rstw := '1'; -- set RSTW flag
elsif r.rstw_ss = '1' then -- request gone and return seen
n.rstw := '0'; -- clear RSTW flag
end if;
if r.rstw='1' and r.rstw_ss='1' then -- RSTW seen on write and read side
igcw_rst := '1'; -- clear write address counter
end if;
if r.rstr_s = '1' then -- RSTR active
igcw_rst := '1'; -- clear write address counter
end if;
if RESETW='1' or r.rstw='1' or r.rstw_ss='1' or r.rstr_s='1'
then -- RESETW or RESETR active
ibusy := '1'; -- signal write side busy
isizew := (others=>'1');
end if;
n.busy := ibusy;
n.sizew := isizew;
n.raddr_c := RADDR; -- data captuture from CLKR
n.raddr_s := r.raddr_c;
n.rstw_sc := R_REGR.rstw_s;
n.rstw_ss := r.rstw_sc;
n.rstr_c := R_REGR.rstr;
n.rstr_s := r.rstr_c;
N_REGW <= n;
GCW_CE <= igcw_ce;
GCW_RST <= igcw_rst;
BUSY <= r.busy;
SIZEW <= r.sizew;
end process proc_nextw;
--
-- read side ---------------------------------------------------------------
--
proc_regr: process (CLKR)
begin
if rising_edge(CLKR) then
R_REGR <= N_REGR;
end if;
end process proc_regr;
proc_nextr: process (R_REGR, RESETR, HOLD, R_REGW,
WADDR, WADDR_S_BIN, RADDR_BIN)
variable r : regr_type := regr_init;
variable n : regr_type := regr_init;
variable ival : slbit := '0';
variable igcr_ce : slbit := '0';
variable igcr_rst : slbit := '0';
variable isizer : slv(AWIDTH-1 downto 0) := (others=>'0');
begin
r := R_REGR;
n := R_REGR;
isizer := slv(unsigned(WADDR_S_BIN) - unsigned(RADDR_BIN));
ival := '1';
igcr_ce := '0';
igcr_rst := '0';
if unsigned(isizer) = 0 then -- if nothing to read
ival := '0'; -- next cycle val=0
end if;
if r.val='1' and HOLD='0' then -- this cycle val=1 and no hold
igcr_ce := '1'; -- retire this value
if unsigned(isizer) = 1 then -- if this is last one
ival := '0'; -- next cycle val=0
end if;
end if;
if RESETR = '1' then -- reset(read side) request
n.rstr := '1'; -- set RSTR flag
elsif r.rstr_ss = '1' then -- request gone and return seen
n.rstr := '0'; -- clear RSTR flag
end if;
if r.rstr='1' and r.rstr_ss='1' then -- RSTR seen on read and write side
igcr_rst := '1'; -- clear read address counter
end if;
if r.rstw_s = '1' then -- RSTW active
igcr_rst := '1'; -- clear read address counter
end if;
if RESETR='1' or r.rstr='1' or r.rstr_ss='1' or r.rstw_s='1'
then -- RESETR or RESETW active
ival := '0'; -- signal read side empty
isizer := (others=>'0');
end if;
n.val := ival;
n.sizer := isizer;
n.waddr_c := WADDR; -- data captuture from CLKW
n.waddr_s := r.waddr_c;
n.rstr_sc := R_REGW.rstr_s;
n.rstr_ss := r.rstr_sc;
n.rstw_c := R_REGW.rstw;
n.rstw_s := r.rstw_c;
N_REGR <= n;
GCR_CE <= igcr_ce;
GCR_RST <= igcr_rst;
VAL <= r.val;
SIZER <= r.sizer;
end process proc_nextr;
end syn;