SURF  1.0
FifoAsync.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : FifoAsync.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2013-07-10
5 -- Last update: 2016-06-30
6 -------------------------------------------------------------------------------
7 -- Description: ASYNC FIFO module
8 -------------------------------------------------------------------------------
9 -- This file is part of 'SLAC Firmware Standard Library'.
10 -- It is subject to the license terms in the LICENSE.txt file found in the
11 -- top-level directory of this distribution and at:
12 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
13 -- No part of 'SLAC Firmware Standard Library', including this file,
14 -- may be copied, modified, propagated, or distributed except according to
15 -- the terms contained in the LICENSE.txt file.
16 -------------------------------------------------------------------------------
17 
18 library ieee;
19 use ieee.std_logic_1164.all;
20 use ieee.std_logic_arith.all;
21 use ieee.std_logic_unsigned.all;
22 
23 use work.StdRtlPkg.all;
24 
25 --! @see entity
26  --! @ingroup base_fifo
27 entity FifoAsync is
28  generic (
29  TPD_G : time := 1 ns;
30  RST_POLARITY_G : sl := '1'; -- '1' for active high rst, '0' for active low
31  BRAM_EN_G : boolean := true;
32  FWFT_EN_G : boolean := false;
33  USE_DSP48_G : string := "no";
34  ALTERA_SYN_G : boolean := false;
35  ALTERA_RAM_G : string := "M9K";
36  SYNC_STAGES_G : integer range 3 to (2**24) := 3;
37  PIPE_STAGES_G : natural range 0 to 16 := 0;
38  DATA_WIDTH_G : integer range 1 to (2**24) := 16;
39  ADDR_WIDTH_G : integer range 2 to 48 := 4;
40  INIT_G : slv := "0";
41  FULL_THRES_G : integer range 1 to (2**24) := 1;
42  EMPTY_THRES_G : integer range 1 to (2**24) := 1);
43  port (
44  -- Asynchronous Reset
45  rst : in sl;
46  -- Write Ports (wr_clk domain)
47  wr_clk : in sl;
48  wr_en : in sl;
49  din : in slv(DATA_WIDTH_G-1 downto 0);
50  wr_data_count : out slv(ADDR_WIDTH_G-1 downto 0);
51  wr_ack : out sl;
52  overflow : out sl;
53  prog_full : out sl;
54  almost_full : out sl;
55  full : out sl;
56  not_full : out sl;
57  -- Read Ports (rd_clk domain)
58  rd_clk : in sl;
59  rd_en : in sl;
60  dout : out slv(DATA_WIDTH_G-1 downto 0);
61  rd_data_count : out slv(ADDR_WIDTH_G-1 downto 0);
62  valid : out sl;
63  underflow : out sl;
64  prog_empty : out sl;
66  empty : out sl);
67 end FifoAsync;
68 
69 architecture rtl of FifoAsync is
70 
71  constant INIT_C : slv(DATA_WIDTH_G-1 downto 0) := ite(INIT_G = "0", slvZero(DATA_WIDTH_G), INIT_G);
72  constant RAM_DEPTH_C : integer := 2**ADDR_WIDTH_G;
73 
74  type RegType is record
75  waddr : slv(ADDR_WIDTH_G-1 downto 0);
76  raddr : slv(ADDR_WIDTH_G-1 downto 0);
77  advance : slv(ADDR_WIDTH_G-1 downto 0);
78  cnt : slv(ADDR_WIDTH_G-1 downto 0);
79  Ack : sl;
80  error : sl;
81  rdy : sl;
82  done : sl;
83  end record;
84 
85  constant READ_INIT_C : RegType := (
86  waddr => (others => '0'),
87  raddr => (others => '0'),
88  advance => toSlv(1, ADDR_WIDTH_G),
89  cnt => (others => '0'), -- empty during reset
90  Ack => '0',
91  error => '0',
92  rdy => '0',
93  done => '0');
94 
95  constant WRITE_INIT_C : RegType := (
96  waddr => (others => '0'),
97  raddr => (others => '0'),
98  advance => toSlv(1, ADDR_WIDTH_G),
99  cnt => (others => '1'), -- full during reset
100  Ack => '0',
101  error => '0',
102  rdy => '0',
103  done => '0');
104 
105  signal rdReg : RegType := READ_INIT_C;
106  signal wrReg : RegType := WRITE_INIT_C;
107 
108  signal fullStatus : sl;
109  signal readEnable : sl;
110 
111  signal readRst : sl;
112  signal writeRst : sl;
113 
114  signal rdReg_ready : sl;
115  signal wrReg_ready : sl;
116 
117  signal sValid,
118  sRdEn : sl;
119 
120  constant SYNC_INIT_C : slv(SYNC_STAGES_G-1 downto 0) := (others => '0');
121  constant GRAY_INIT_C : slv(ADDR_WIDTH_G-1 downto 0) := (others => '0');
122  signal rdReg_rdGray : slv(ADDR_WIDTH_G-1 downto 0) := GRAY_INIT_C;
123  signal rdReg_wrGray : slv(ADDR_WIDTH_G-1 downto 0) := GRAY_INIT_C;
124  signal wrReg_rdGray : slv(ADDR_WIDTH_G-1 downto 0) := GRAY_INIT_C;
125  signal wrReg_wrGray : slv(ADDR_WIDTH_G-1 downto 0) := GRAY_INIT_C;
126 
127  type RamPortType is record
128  clk : sl;
129  en : sl;
130  rst : sl;
131  we : sl;
132  addr : slv(ADDR_WIDTH_G-1 downto 0);
133  din : slv(DATA_WIDTH_G-1 downto 0);
134  dout : slv(DATA_WIDTH_G-1 downto 0);
135  end record;
136  signal portA, portB : RamPortType;
137 
138  type ReadStatusType is
139  record
140  count : slv(ADDR_WIDTH_G-1 downto 0);
141  prog_empty : sl;
142  almost_empty : sl;
143  empty : sl;
144  end record;
145  constant READ_STATUS_INIT_C : ReadStatusType := (
146  count => (others => '0'),
147  prog_empty => '1',
148  almost_empty => '1',
149  empty => '1');
150  signal fifoStatus, fwftStatus : ReadStatusType := READ_STATUS_INIT_C;
151 
152  -- Attribute for XST
153  attribute use_dsp48 : string;
154  attribute use_dsp48 of rdReg : signal is USE_DSP48_G;
155  attribute use_dsp48 of wrReg : signal is USE_DSP48_G;
156 
157 begin
158 
159  -- FULL_THRES_G upper range check
160  assert (FULL_THRES_G <= ((2**ADDR_WIDTH_G)-1))
161  report "FULL_THRES_G must be <= ((2**ADDR_WIDTH_G)-1)"
162  severity failure;
163  -- EMPTY_THRES_G upper range check
164  assert (EMPTY_THRES_G <= ((2**ADDR_WIDTH_G)-2))
165  report "EMPTY_THRES_G must be <= ((2**ADDR_WIDTH_G)-2)"
166  severity failure;
167  -- USE_DSP48_G check
168  assert ((USE_DSP48_G = "yes") or (USE_DSP48_G = "no") or (USE_DSP48_G = "auto") or (USE_DSP48_G = "automax"))
169  report "USE_DSP48_G must be either yes, no, auto, or automax"
170  severity failure;
171  -- INIT_G length check
172  assert (INIT_G = "0" or INIT_G'length = DATA_WIDTH_G) report
173  "INIT_G must either be ""0"" or the same length as DATA_WIDTH_G" severity failure;
174 
175  -------------------------------
176  -- rd_clk domain
177  -------------------------------
178  READ_RstSync : entity work.RstSync
179  generic map (
180  TPD_G => TPD_G,
183  port map (
184  clk => rd_clk,
185  asyncRst => rst,
186  syncRst => readRst);
187 
188  underflow <= rdReg.error;
189 
190  fifoStatus.count <= rdReg.cnt;
191  fifoStatus.prog_empty <= '1' when (rdReg.cnt < EMPTY_THRES_G) else readRst;
192  fifoStatus.almost_empty <= '1' when (rdReg.cnt = 1) else fifoStatus.empty;
193  fifoStatus.empty <= '1' when (rdReg.cnt = 0) else readRst;
194 
195  FIFO_Gen : if (FWFT_EN_G = false) generate
196  readEnable <= rd_en;
197  valid <= rdReg.Ack;
198  prog_empty <= fifoStatus.prog_empty;
199  almost_empty <= fifoStatus.almost_empty;
200  empty <= fifoStatus.empty;
201  rd_data_count <= fifoStatus.count;
202  dout <= portB.dout;
203  end generate;
204 
205  FWFT_Gen : if (FWFT_EN_G = true) generate
206 
207  FifoOutputPipeline_Inst : entity work.FifoOutputPipeline
208  generic map (
209  TPD_G => TPD_G,
210  RST_POLARITY_G => '1',
211  RST_ASYNC_G => false,
214  port map (
215  -- Slave Port
216  sData => portB.dout,
217  sValid => sValid,
218  sRdEn => sRdEn,
219  -- Master Port
220  mData => dout,
221  mValid => valid,
222  mRdEn => rd_en,
223  -- Clock and Reset
224  clk => rd_clk,
225  rst => readRst);
226 
227  readEnable <= (sRdEn or fwftStatus.empty) and not(fifoStatus.empty);
228  sValid <= not(fwftStatus.empty);
229 
230  prog_empty <= fwftStatus.prog_empty;
231  almost_empty <= fwftStatus.almost_empty;
232  empty <= fwftStatus.empty;
233  rd_data_count <= fwftStatus.count;
234  process (rd_clk) is
235  begin
236  if rising_edge(rd_clk) then
237  if readRst = '1' then
238  fwftStatus <= READ_STATUS_INIT_C after TPD_G;
239  else
240  fwftStatus.prog_empty <= fifoStatus.prog_empty after TPD_G;
241  fwftStatus.almost_empty <= fifoStatus.almost_empty after TPD_G;
242  fwftStatus.empty <= (sRdEn or fwftStatus.empty) and fifoStatus.empty after TPD_G;
243  fwftStatus.count <= fifoStatus.count after TPD_G;
244  end if;
245  end if;
246  end process;
247  end generate;
248 
249  SynchronizerVector_0 : entity work.SynchronizerVector
250  generic map (
251  TPD_G => TPD_G,
252  RST_ASYNC_G => false,
255  INIT_G => GRAY_INIT_C)
256  port map (
257  rst => readRst,
258  clk => rd_clk,
259  dataIn => wrReg_wrGray,
260  dataOut => rdReg_wrGray);
261 
262  Synchronizer_0 : entity work.Synchronizer
263  generic map (
264  TPD_G => TPD_G,
265  RST_ASYNC_G => false,
267  INIT_G => SYNC_INIT_C)
268  port map (
269  clk => rd_clk,
270  rst => readRst,
271  dataIn => wrReg.done,
272  dataOut => rdReg_ready);
273 
274  READ_SEQUENCE : process (rd_clk) is
275  begin
276  if rising_edge(rd_clk) then
277  if readRst = '1' then
278  rdReg <= READ_INIT_C after TPD_G;
279  rdReg_rdGray <= GRAY_INIT_C after TPD_G;
280  else
281  rdReg.done <= '1' after TPD_G;
282  rdReg.Ack <= '0' after TPD_G;
283  rdReg.error <= '0' after TPD_G;
284  if rdReg_ready = '1' then
285 
286  -- Decode the Gray code pointer
287  rdReg.waddr <= grayDecode(rdReg_wrGray) after TPD_G;
288 
289  -- Check for read operation
290  if readEnable = '1' then
291  if fifoStatus.empty = '0' then
292  -- Calculate the count
293  rdReg.cnt <= rdReg.waddr - rdReg.advance after TPD_G;
294  -- Increment the read address pointer
295  rdReg.raddr <= rdReg.raddr + 1 after TPD_G;
296  rdReg.advance <= rdReg.advance + 1 after TPD_G;
297  rdReg.Ack <= '1' after TPD_G;
298  else
299  -- Calculate the count
300  rdReg.cnt <= rdReg.waddr - rdReg.raddr after TPD_G;
301  rdReg.error <= '1' after TPD_G;
302  end if;
303  else
304  -- Calculate the count
305  rdReg.cnt <= rdReg.waddr - rdReg.raddr after TPD_G;
306  end if;
307 
308  -- Encode the Gray code pointer
309  rdReg_rdGray <= grayEncode(rdReg.raddr) after TPD_G;
310 
311  end if;
312  end if;
313  end if;
314  end process READ_SEQUENCE;
315 
316  -------------------------------
317  -- wr_clk domain
318  -------------------------------
319  WRITE_RstSync : entity work.RstSync
320  generic map (
321  TPD_G => TPD_G,
324  port map (
325  clk => wr_clk,
326  asyncRst => rst,
327  syncRst => writeRst);
328 
329  wr_data_count <= wrReg.cnt;
330  full <= fullStatus;
331  not_full <= not(fullStatus);
332  wr_ack <= wrReg.Ack;
333  overflow <= wrReg.error;
334 
335  process (wr_clk) is
336  begin
337  if rising_edge(wr_clk) then
338  if writeRst = '1' then
339  prog_full <= '1' after TPD_G;
340  almost_full <= '1' after TPD_G;
341  fullStatus <= '1' after TPD_G;
342  else
343  -- prog_full
344  if (wrReg.cnt > FULL_THRES_G) then
345  prog_full <= '1' after TPD_G;
346  else
347  prog_full <= '0' after TPD_G;
348  end if;
349  -- almost_full
350  if (wrReg.cnt = (RAM_DEPTH_C-1)) or (wrReg.cnt = (RAM_DEPTH_C-2)) or (wrReg.cnt = (RAM_DEPTH_C-3)) then
351  almost_full <= '1' after TPD_G;
352  else
353  almost_full <= '0' after TPD_G;
354  end if;
355  -- fullStatus
356  if (wrReg.cnt = (RAM_DEPTH_C-1)) or (wrReg.cnt = (RAM_DEPTH_C-2)) then
357  fullStatus <= '1' after TPD_G;
358  else
359  fullStatus <= '0' after TPD_G;
360  end if;
361  end if;
362  end if;
363  end process;
364 
365  SynchronizerVector_1 : entity work.SynchronizerVector
366  generic map (
367  TPD_G => TPD_G,
368  RST_ASYNC_G => false,
371  INIT_G => GRAY_INIT_C)
372  port map (
373  rst => writeRst,
374  clk => wr_clk,
375  dataIn => rdReg_rdGray,
376  dataOut => wrReg_rdGray);
377 
378  Synchronizer_1 : entity work.Synchronizer
379  generic map (
380  TPD_G => TPD_G,
381  RST_ASYNC_G => false,
383  INIT_G => SYNC_INIT_C)
384  port map (
385  clk => wr_clk,
386  rst => writeRst,
387  dataIn => rdReg.done,
388  dataOut => wrReg_ready);
389 
390  WRITE_SEQUENCE : process (wr_clk) is
391  begin
392  if rising_edge(wr_clk) then
393  if writeRst = '1' then
394  wrReg <= WRITE_INIT_C after TPD_G;
395  wrReg_wrGray <= GRAY_INIT_C after TPD_G;
396  else
397  wrReg.done <= '1' after TPD_G;
398  wrReg.Ack <= '0' after TPD_G;
399  wrReg.error <= '0' after TPD_G;
400  if wrReg_ready = '1' then
401  if wrReg.rdy = '0' then
402  wrReg.rdy <= '1';
403  wrReg.cnt <= (others => '0');
404  else
405 
406  -- Decode the Gray code pointer
407  wrReg.raddr <= grayDecode(wrReg_rdGray) after TPD_G;
408 
409  -- Check for write operation
410  if wr_en = '1' then
411  if fullStatus = '0' then
412  -- Calculate the count
413  wrReg.cnt <= wrReg.advance - wrReg.raddr after TPD_G;
414  -- Increment the read address pointer
415  wrReg.waddr <= wrReg.waddr + 1 after TPD_G;
416  wrReg.advance <= wrReg.advance + 1 after TPD_G;
417  wrReg.Ack <= '1' after TPD_G;
418  else
419  wrReg.error <= '1' after TPD_G;
420  -- Calculate the count
421  wrReg.cnt <= wrReg.waddr - wrReg.raddr after TPD_G;
422  end if;
423  else
424  -- Calculate the count
425  wrReg.cnt <= wrReg.waddr - wrReg.raddr after TPD_G;
426  end if;
427 
428  -- Encode the Gray code pointer
429  wrReg_wrGray <= grayEncode(wrReg.waddr) after TPD_G;
430 
431  end if;
432  end if;
433  end if;
434  end if;
435  end process WRITE_SEQUENCE;
436 
437  -------------------------------
438  -- rd_clk and wr_clk domain
439  -------------------------------
440 
441  -- RAM Port A Mapping
442  portA.clk <= wr_clk;
443  portA.en <= '1';
444  portA.we <= wr_en and not(fullStatus);
445  portA.addr <= wrReg.waddr;
446  portA.din <= din;
447 
448  -- RAM Port B Mapping
449  portB.clk <= rd_clk;
450  portB.en <= readEnable and not(fifoStatus.empty);
451  portB.rst <= readRst;
452  portB.we <= '0';
453  portB.addr <= rdReg.raddr;
454  portB.din <= (others => '0');
455 
456  SimpleDualPortRam_Inst : entity work.SimpleDualPortRam
457  generic map(
458  TPD_G => TPD_G,
459  BRAM_EN_G => BRAM_EN_G,
464  INIT_G => INIT_C)
465  port map (
466  -- Port A
467  clka => portA.clk,
468  ena => portA.en,
469  wea => portA.we,
470  addra => portA.addr,
471  dina => portA.din,
472  -- Port B
473  clkb => portB.clk,
474  enb => portB.en,
475  rstb => '0', -- Rely on rd/wr ptrs
476  addrb => portB.addr,
477  doutb => portB.dout);
478 
479 end architecture rtl;
INIT_Gslv := "0"
in rstsl
Definition: FifoAsync.vhd:45
EMPTY_THRES_Ginteger range 1 to ( 2** 24):= 1
Definition: FifoAsync.vhd:42
in addrbslv( ADDR_WIDTH_G- 1 downto 0) :=( others => '0')
out syncRstsl
Definition: RstSync.vhd:36
BRAM_EN_Gboolean := true
in wr_clksl
Definition: FifoAsync.vhd:47
in rstbsl :=not ( RST_POLARITY_G)
RST_ASYNC_Gboolean := false
IN_POLARITY_Gsl := '1'
Definition: RstSync.vhd:28
ALTERA_RAM_Gstring := "M9K"
out doutbslv( DATA_WIDTH_G- 1 downto 0)
DATA_WIDTH_Ginteger range 1 to ( 2** 24):= 16
out almost_fullsl
Definition: FifoAsync.vhd:54
std_logic sl
Definition: StdRtlPkg.vhd:28
in rstsl :=not RST_POLARITY_G
in rd_clksl
Definition: FifoAsync.vhd:58
RST_POLARITY_Gsl := '1'
Definition: FifoAsync.vhd:30
in wr_ensl
Definition: FifoAsync.vhd:48
PIPE_STAGES_Gnatural range 0 to 16:= 0
Definition: FifoAsync.vhd:37
STAGES_Gpositive := 2
SYNC_STAGES_Ginteger range 3 to ( 2** 24):= 3
Definition: FifoAsync.vhd:36
RST_ASYNC_Gboolean := false
out not_fullsl
Definition: FifoAsync.vhd:56
in rd_ensl
Definition: FifoAsync.vhd:59
out underflowsl
Definition: FifoAsync.vhd:63
in dataInslv( WIDTH_G- 1 downto 0)
out doutslv( DATA_WIDTH_G- 1 downto 0)
Definition: FifoAsync.vhd:60
in asyncRstsl
Definition: RstSync.vhd:35
out dataOutsl
in clksl
Definition: RstSync.vhd:34
out prog_emptysl
Definition: FifoAsync.vhd:64
DATA_WIDTH_Ginteger range 1 to ( 2** 24):= 16
Definition: FifoAsync.vhd:38
ALTERA_SYN_Gboolean := false
Definition: FifoAsync.vhd:34
INIT_Gslv := "0"
Definition: FifoAsync.vhd:40
RELEASE_DELAY_Ginteger range 3 to positive'high:= 3
Definition: RstSync.vhd:31
ALTERA_RAM_Gstring := "M9K"
Definition: FifoAsync.vhd:35
out prog_fullsl
Definition: FifoAsync.vhd:53
_library_ ieeeieee
Definition: Fifo.vhd:18
ADDR_WIDTH_Ginteger range 2 to 48:= 4
Definition: FifoAsync.vhd:39
ADDR_WIDTH_Ginteger range 1 to ( 2** 24):= 4
out wr_acksl
Definition: FifoAsync.vhd:51
out emptysl
Definition: FifoAsync.vhd:66
in addraslv( ADDR_WIDTH_G- 1 downto 0) :=( others => '0')
TPD_Gtime := 1 ns
Definition: RstSync.vhd:27
TPD_Gtime := 1 ns
out dataOutslv( WIDTH_G- 1 downto 0)
out rd_data_countslv( ADDR_WIDTH_G- 1 downto 0)
Definition: FifoAsync.vhd:61
USE_DSP48_Gstring := "no"
Definition: FifoAsync.vhd:33
out overflowsl
Definition: FifoAsync.vhd:52
in rstsl :=not RST_POLARITY_G
PIPE_STAGES_Gnatural range 0 to 16:= 1
ALTERA_SYN_Gboolean := false
FWFT_EN_Gboolean := false
Definition: FifoAsync.vhd:32
FULL_THRES_Ginteger range 1 to ( 2** 24):= 1
Definition: FifoAsync.vhd:41
in dinslv( DATA_WIDTH_G- 1 downto 0)
Definition: FifoAsync.vhd:49
out fullsl
Definition: FifoAsync.vhd:55
RST_ASYNC_Gboolean := false
out wr_data_countslv( ADDR_WIDTH_G- 1 downto 0)
Definition: FifoAsync.vhd:50
DATA_WIDTH_Ginteger range 1 to ( 2** 24):= 16
in sDataslv( DATA_WIDTH_G- 1 downto 0)
in rstsl :=not RST_POLARITY_G
out validsl
Definition: FifoAsync.vhd:62
out mDataslv( DATA_WIDTH_G- 1 downto 0)
BRAM_EN_Gboolean := true
Definition: FifoAsync.vhd:31
std_logic_vector slv
Definition: StdRtlPkg.vhd:29
TPD_Gtime := 1 ns
Definition: FifoAsync.vhd:29
out almost_emptysl
Definition: FifoAsync.vhd:65
in dinaslv( DATA_WIDTH_G- 1 downto 0) :=( others => '0')