1 ------------------------------------------------------------------------------- 2 -- File : AxiStreamFifo.vhd 3 -- Company : SLAC National Accelerator Laboratory 4 -- Created : 2014-04-25 5 -- Last update: 2016-08-31 6 ------------------------------------------------------------------------------- 8 -- Block to serve as an async FIFO for AXI Streams. This block also allows the 9 -- bus to be compress/expanded, allowing different standard sizes on each side 10 -- of the FIFO. Re-sizing is always little endian. 11 ------------------------------------------------------------------------------- 12 -- This file is part of 'SLAC Firmware Standard Library'. 13 -- It is subject to the license terms in the LICENSE.txt file found in the 14 -- top-level directory of this distribution and at: 15 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 16 -- No part of 'SLAC Firmware Standard Library', including this file, 17 -- may be copied, modified, propagated, or distributed except according to 18 -- the terms contained in the LICENSE.txt file. 19 ------------------------------------------------------------------------------- 22 use ieee.std_logic_1164.
all;
23 use ieee.std_logic_unsigned.
all;
24 use ieee.std_logic_arith.
all;
34 -- General Configurations 40 -- =0 = only when frame ready 41 -- >1 = only when frame ready or # entries 42 -- FIFO configurations 54 -- If VALID_THOLD_G /=1, FIFO that stores on tLast txns can be smaller. 55 -- Set to 0 for same size as primary fifo (default) 56 -- Set >4 for custom size. 57 -- Use at own risk. Overflow of tLast fifo is not checked 60 -- Index = 0 is output, index = n is input 63 -- AXI Stream Port Configurations 76 -- FIFO status & config , synchronous to sAxisClk 84 mTLastTUser : out slv(127 downto 0));
-- when VALID_THOLD_G /= 1, used to look ahead at tLast's tUser 91 constant LAST_FIFO_ADDR_WIDTH_C : range 4 to 48 := 97 -- Use wider of two interfaces 99 constant DATA_BITS_C : := (DATA_BYTES_C * 8);
101 -- Use SLAVE TKEEP Mode 103 constant KEEP_BITS_C : := ite(KEEP_MODE_C = TKEEP_NORMAL_C, DATA_BYTES_C, 104 ite(KEEP_MODE_C = TKEEP_COMP_C, bitSize(DATA_BYTES_C-1), 0));
106 -- User user bit mode of slave 109 -- Use whichever interface has the least number of user bits 112 constant FIFO_USER_BITS_C : := minimum(SLAVE_USER_BITS_C, MASTER_USER_BITS_C);
114 constant FIFO_USER_TOT_C : := ite(USER_MODE_C = TUSER_FIRST_LAST_C, FIFO_USER_BITS_C*2, 115 ite(USER_MODE_C = TUSER_LAST_C, FIFO_USER_BITS_C, 116 ite(USER_MODE_C = TUSER_NORMAL_C, DATA_BYTES_C * FIFO_USER_BITS_C, 119 -- Use SLAVE settings for strobe, dest and ID bit values 124 constant FIFO_BITS_C : := 1 + DATA_BITS_C + KEEP_BITS_C + FIFO_USER_TOT_C + STRB_BITS_C + DEST_BITS_C + ID_BITS_C;
128 -- Convert record to slv 130 variable retValue : slv(FIFO_BITS_C-1 downto 0) := (others => '0');
135 assignSlv(i, retValue, din.tLast);
138 assignSlv(i, retValue, din.tData(DATA_BITS_C-1 downto 0));
141 if KEEP_MODE_C = TKEEP_NORMAL_C then 142 assignSlv(i, retValue, din.tKeep(KEEP_BITS_C-1 downto 0));
143 elsif KEEP_MODE_C = TKEEP_COMP_C then 144 assignSlv(i, retValue, toSlv(getTKeep(din.tKeep(DATA_BYTES_C-1 downto 1)), KEEP_BITS_C));
-- Assume lsb is present 148 if USER_MODE_C = TUSER_FIRST_LAST_C then 149 assignSlv(i, retValue, resize(axiStreamGetUserField(FIFO_AXIS_CONFIG_C, din, 0), FIFO_USER_BITS_C));
-- First byte 150 assignSlv(i, retValue, resize(axiStreamGetUserField(FIFO_AXIS_CONFIG_C, din, -1), FIFO_USER_BITS_C));
-- Last valid byte 152 elsif USER_MODE_C = TUSER_LAST_C then 153 assignSlv(i, retValue, resize(axiStreamGetUserField(FIFO_AXIS_CONFIG_C, din, -1), FIFO_USER_BITS_C));
-- Last valid byte 156 for j in 0 to DATA_BYTES_C-1 loop 157 assignSlv(i, retValue, resize(axiStreamGetUserField(FIFO_AXIS_CONFIG_C, din, j), FIFO_USER_BITS_C));
161 -- Strobe is optional 162 if STRB_BITS_C > 0 then 163 assignSlv(i, retValue, din.tStrb(STRB_BITS_C-1 downto 0));
167 if DEST_BITS_C > 0 then 168 assignSlv(i, retValue, din.tDest(DEST_BITS_C-1 downto 0));
172 if ID_BITS_C > 0 then 173 assignSlv(i, retValue, din.tId(ID_BITS_C-1 downto 0));
180 -- Convert slv to record 181 -
procedure iSlvToAxi (din :
in slv(FIFO_BITS_C1
downto 0);
186 variable user : slv(FIFO_USER_BITS_C-1 downto 0) := (others => '0');
195 assignRecord(i, din, master.tLast);
198 assignRecord(i, din, master.tData(DATA_BITS_C-1 downto 0));
201 if KEEP_MODE_C = TKEEP_NORMAL_C then 202 assignRecord(i, din, master.tKeep(KEEP_BITS_C-1 downto 0));
203 byteCnt := getTKeep(master.tKeep);
204 elsif KEEP_MODE_C = TKEEP_COMP_C then 205 byteCnt := conv_integer(din((KEEP_BITS_C+i)-1 downto i))+1;
206 master.tKeep := genTKeep(byteCnt);
207 i := i + KEEP_BITS_C;
208 else -- KEEP_MODE_C = TKEEP_FIXED_C 209 master.tKeep := genTKeep(DATA_BYTES_C);
210 byteCnt := DATA_BYTES_C;
211 i := i + KEEP_BITS_C;
215 if USER_MODE_C = TUSER_FIRST_LAST_C then 216 assignRecord(i, din, user);
217 axiStreamSetUserField (MASTER_AXI_CONFIG_G, master, resize(user, MASTER_USER_BITS_C), 0);
-- First byte 219 assignRecord(i, din, user);
220 axiStreamSetUserField (MASTER_AXI_CONFIG_G, master, resize(user, MASTER_USER_BITS_C), -1);
-- Last valid byte 222 elsif USER_MODE_C = TUSER_LAST_C then 223 assignRecord(i, din, user);
224 axiStreamSetUserField (MASTER_AXI_CONFIG_G, master, resize(user, MASTER_USER_BITS_C), -1);
-- Last valid byte 227 for j in 0 to DATA_BYTES_C-1 loop 228 assignRecord(i, din, user);
233 -- Strobe is optional 234 if STRB_BITS_C > 0 then 235 assignRecord(i, din, master.tStrb(STRB_BITS_C-1 downto 0));
237 master.tStrb := master.tKeep;
-- Strobe follows keep if unused 241 if DEST_BITS_C > 0 then 242 assignRecord(i, din, master.tDest(DEST_BITS_C-1 downto 0));
246 if ID_BITS_C > 0 then 247 assignRecord(i, din, master.tId(ID_BITS_C-1 downto 0));
255 constant WR_LOGIC_EN_C : := (WR_BYTES_C < RD_BYTES_C);
256 constant WR_SIZE_C : := ite(WR_LOGIC_EN_C, RD_BYTES_C / WR_BYTES_C, 1);
258 type WrRegType is record 259 count : slv(bitSize(WR_SIZE_C)-1 downto 0);
261 end record WrRegType;
263 constant WR_REG_INIT_C : WrRegType := ( 264 count => (others => '0'), 268 signal wrR : WrRegType := WR_REG_INIT_C;
269 signal wrRin : WrRegType;
274 signal fifoDin : slv(FIFO_BITS_C-1 downto 0);
275 signal fifoWrite : sl;
276 signal fifoWriteLast : sl;
277 signal fifoWriteUser : slv(FIFO_USER_TOT_C-1 downto 0);
280 signal fifoAFull : sl;
281 signal fifoReady : sl;
282 signal fifoPFull : sl;
284 signal fifoDout : slv(FIFO_BITS_C-1 downto 0);
285 signal fifoRead : sl;
286 signal fifoReadLast : sl;
287 signal fifoReadUser : slv(FIFO_USER_TOT_C-1 downto 0) := (others => '0');
288 signal fifoValidInt : sl;
289 signal fifoValid : sl;
290 signal fifoValidLast : sl;
291 signal fifoInFrame : sl;
296 constant RD_LOGIC_EN_C : := (RD_BYTES_C < WR_BYTES_C);
297 constant RD_SIZE_C : := ite(RD_LOGIC_EN_C, WR_BYTES_C / RD_BYTES_C, 1);
299 type RdRegType is record 300 count : slv(bitSize(RD_SIZE_C)-1 downto 0);
301 bytes : slv(bitSize(DATA_BYTES_C)-1 downto 0);
304 end record RdRegType;
306 constant RD_REG_INIT_C : RdRegType := ( 307 count => (others => '0'), 308 bytes => conv_std_logic_vector(RD_BYTES_C, bitSize(DATA_BYTES_C)), 313 signal rdR : RdRegType := RD_REG_INIT_C;
314 signal rdRin : RdRegType;
333 report "Data widths must be even number multiples of each other" severity failure;
335 -- Cant use tkeep_fixed on master side when resizing or if not on slave side 338 report "AxiStreamFifo: Can't have TKEEP_MODE = TKEEP_FIXED on master side if not on slave side" 341 ------------------------- 343 ------------------------- 345 variable v : WrRegType;
349 idx := conv_integer(wrR.count);
352 if fifoReady = '1' then 354 -- init when count = 0 355 if (wrR.count = 0) then 356 v.wrMaster.tKeep := (others => '0');
357 v.wrMaster.tData := (others => '0');
358 v.wrMaster.tStrb := (others => '0');
359 v.wrMaster.tUser := (others => '0');
362 v.wrMaster.tData((WR_BYTES_C*8*idx)+((WR_BYTES_C*8)-1) downto (WR_BYTES_C*8*idx)) := sAxisMaster.tData((WR_BYTES_C*8)-1 downto 0);
363 v.wrMaster.tStrb((WR_BYTES_C*idx)+(WR_BYTES_C-1) downto (WR_BYTES_C*idx)) := sAxisMaster.tStrb(WR_BYTES_C-1 downto 0);
364 v.wrMaster.tKeep((WR_BYTES_C*idx)+(WR_BYTES_C-1) downto (WR_BYTES_C*idx)) := sAxisMaster.tKeep(WR_BYTES_C-1 downto 0);
366 v.wrMaster.tUser((WR_BYTES_C*SLAVE_USER_BITS_C*idx)+((WR_BYTES_C*SLAVE_USER_BITS_C)-1) downto (WR_BYTES_C*SLAVE_USER_BITS_C*idx)) 373 -- Determine end mode, valid and ready 377 v.count := (others => '0');
380 v.count := wrR.count + 1;
389 -- Write logic enabled 390 if WR_LOGIC_EN_C then 391 fifoDin <= iAxiToSlv(wrR.wrMaster);
392 fifoWrite <= wrR.wrMaster.tValid and fifoReady;
393 fifoWriteLast <= wrR.wrMaster.tValid and fifoReady and wrR.wrMaster.tLast;
394 fifoWriteUser <= wrR.wrMaster.tUser(FIFO_USER_TOT_C-1 downto 0);
395 -- Bypass write logic 410 if sAxisRst = '1' or WR_LOGIC_EN_C = false then 411 wrR <= WR_REG_INIT_C after TPD_G;
413 wrR <= wrRin after TPD_G;
419 ------------------------- 421 ------------------------- 480 valid => fifoValidInt,
515 wr_en => fifoWriteLast,
516 din => fifoWriteUser
(FIFO_USER_TOT_C-
1 downto 0),
525 rd_en => fifoReadLast,
526 dout => fifoReadUser
(FIFO_USER_TOT_C-
1 downto 0),
528 valid => fifoValidLast,
538 if mAxisRst = '1' or fifoReadLast = '1' then 539 fifoInFrame <= '0' after TPD_G;
541 fifoInFrame <= '1' after TPD_G;
546 fifoValid <= fifoValidInt and fifoInFrame;
551 fifoValidLast <= '0';
552 fifoValid <= fifoValidInt;
556 mTLastTUser(FIFO_USER_TOT_C-1 downto 0) <= fifoReadUser;
558 ------------------------- 560 ------------------------- 562 rdComb :
process (axisSlave, fifoDout, fifoValid, rdR)
is 563 variable v : RdRegType;
569 idx := conv_integer(rdR.count);
571 iSlvToAxi (fifoDout, fifoValid, fifoMaster, byteCnt);
574 if axisSlave.tReady = '1' or rdR.rdMaster.tValid = '0' then 577 v.rdMaster.tData((RD_BYTES_C*8)-1 downto 0) := fifoMaster.tData((RD_BYTES_C*8*idx)+((RD_BYTES_C*8)-1) downto (RD_BYTES_C*8*idx));
578 v.rdMaster.tStrb(RD_BYTES_C-1 downto 0) := fifoMaster.tStrb((RD_BYTES_C*idx)+(RD_BYTES_C-1) downto (RD_BYTES_C*idx));
579 v.rdMaster.tKeep(RD_BYTES_C-1 downto 0) := fifoMaster.tKeep((RD_BYTES_C*idx)+(RD_BYTES_C-1) downto (RD_BYTES_C*idx));
581 v.rdMaster.tUser((RD_BYTES_C*MASTER_USER_BITS_C)-1 downto 0) 582 := fifoMaster.tUser((RD_BYTES_C*MASTER_USER_BITS_C*idx)+((RD_BYTES_C*MASTER_USER_BITS_C)-1) downto (RD_BYTES_C*MASTER_USER_BITS_C*idx));
585 v.rdMaster.tId := fifoMaster.tId;
587 -- Reached end of fifo data or no more valid bytes in last word 588 if fifoMaster.tValid = '1' then 589 if (rdR.count = (RD_SIZE_C-1)) or ((rdR.bytes >= byteCnt) and (fifoMaster.tLast = '1')) then 590 v.count := (others => '0');
591 v.bytes := conv_std_logic_vector(RD_BYTES_C, bitSize(DATA_BYTES_C));
595 v.count := rdR.count + 1;
596 v.bytes := rdR.bytes + RD_BYTES_C;
598 v.rdMaster.tLast := '0';
602 -- Drop transfers with no tKeep bits set, except on tLast 604 (uOr(v.rdMaster.tKeep(RD_BYTES_C-1 downto 0)) or 613 -- Read logic enabled 614 if RD_LOGIC_EN_C then 615 axisMaster <= rdR.rdMaster;
616 fifoRead <= v.ready and fifoValid;
617 fifoReadLast <= v.ready and fifoValid and fifoMaster.tLast;
621 axisMaster <= fifoMaster;
622 fifoRead <= axisSlave.tReady and fifoValid;
623 fifoReadLast <= axisSlave.tReady and fifoValid and fifoMaster.tLast;
628 -- If fifo is asynchronous, must use async reset on rd side. 632 if mAxisRst = '1' or RD_LOGIC_EN_C = false then 633 rdR <= RD_REG_INIT_C after TPD_G;
635 rdR <= rdRin after TPD_G;
640 -- Synchronize master side tvalid back to slave side ctrl.idle 641 -- This is a total hack 649 dataIn => axisMaster.tValid,
653 ------------------------- 655 ------------------------- FIFO_ADDR_WIDTH_Ginteger range 4 to 48:= 9
ALTERA_RAM_Gstring := "M9K"
out progFullVecslv( CASCADE_SIZE_G- 1 downto 0)
PIPE_STAGES_Gnatural range 0 to 16:= 0
FIFO_FIXED_THRESH_Gboolean := true
natural range 0 to 8 TDEST_BITS_C
out doutslv( DATA_WIDTH_G- 1 downto 0)
(TUSER_NORMAL_C,TUSER_FIRST_LAST_C,TUSER_LAST_C,TUSER_NONE_C) TUserModeType
in sAxisMasterAxiStreamMasterType
XIL_DEVICE_Gstring := "7SERIES"
CASCADE_SIZE_Ginteger range 1 to ( 2** 24):= 1
RST_ASYNC_Gboolean := false
in rstsl :=not RST_POLARITY_G
SLAVE_READY_EN_Gboolean := true
MASTER_AXI_CONFIG_GAxiStreamConfigType := AXI_STREAM_CONFIG_INIT_C
in dinslv( DATA_WIDTH_G- 1 downto 0)
out sAxisSlaveAxiStreamSlaveType
SLAVE_AXI_CONFIG_GAxiStreamConfigType := AXI_STREAM_CONFIG_INIT_C
VALID_THOLD_Ginteger range 0 to ( 2** 24):= 1
USE_BUILT_IN_Gboolean := false
CASCADE_PAUSE_SEL_Ginteger range 0 to ( 2** 24):= 0
natural range 1 to 16 TDATA_BYTES_C
in mAxisSlaveAxiStreamSlaveType
INT_PIPE_STAGES_Gnatural range 0 to 16:= 0
PIPE_STAGES_Gnatural range 0 to 16:= 0
EMPTY_THRES_Ginteger range 1 to ( 2** 24):= 1
out mAxisMasterAxiStreamMasterType
ALTERA_SYN_Gboolean := false
TkeepModeType TKEEP_MODE_C
natural range 0 to 8 TID_BITS_C
out sAxisSlaveAxiStreamSlaveType
FULL_THRES_Ginteger range 1 to ( 2** 24):= 1
in sAxisMasterAxiStreamMasterType
SYNC_STAGES_Ginteger range 3 to ( 2** 24):= 3
FIFO_PAUSE_THRESH_Ginteger range 1 to ( 2** 24):= 1
LAST_FIFO_ADDR_WIDTH_Ginteger range 0 to 48:= 0
out mTLastTUserslv( 127 downto 0)
TUserModeType TUSER_MODE_C
natural range 0 to 8 TUSER_BITS_C
out mAxisMasterAxiStreamMasterType
GEN_SYNC_FIFO_Gboolean := false
AxiStreamConfigType :=(TSTRB_EN_C => false,TDATA_BYTES_C => 16,TDEST_BITS_C => 4,TID_BITS_C => 0,TKEEP_MODE_C => TKEEP_NORMAL_C,TUSER_BITS_C => 4,TUSER_MODE_C => TUSER_NORMAL_C) AXI_STREAM_CONFIG_INIT_C
GEN_SYNC_FIFO_Gboolean := false
(TKEEP_NORMAL_C,TKEEP_COMP_C,TKEEP_FIXED_C) TKeepModeType
in mAxisSlaveAxiStreamSlaveType
USE_DSP48_Gstring := "no"
LAST_STAGE_ASYNC_Gboolean := true
ALTERA_RAM_Gstring := "M9K"
ADDR_WIDTH_Ginteger range 4 to 48:= 4
in fifoPauseThreshslv( FIFO_ADDR_WIDTH_G- 1 downto 0) :=( others => '1')
XIL_DEVICE_Gstring := "7SERIES"
USE_BUILT_IN_Gboolean := false
FWFT_EN_Gboolean := false
DATA_WIDTH_Ginteger range 1 to ( 2** 24):= 16
CASCADE_SIZE_Ginteger range 1 to ( 2** 24):= 1
out wr_data_countslv( ADDR_WIDTH_G- 1 downto 0)
PIPE_STAGES_Gnatural range 0 to 16:= 1
out sAxisCtrlAxiStreamCtrlType
out rd_data_countslv( ADDR_WIDTH_G- 1 downto 0)
ALTERA_SYN_Gboolean := false