SURF  1.0
AxiStreamShift.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : AxiStreamShift.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2014-04-25
5 -- Last update: 2016-10-27
6 -------------------------------------------------------------------------------
7 -- Description:
8 -- Block to shift data bytes within an AXI stream. Both left and right shifting
9 -- are allowed. This block will move a packet at a time. Transfer of a new packet
10 -- will pause until a new shift command is provided.
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 -------------------------------------------------------------------------------
20 
21 library ieee;
22 use ieee.std_logic_1164.all;
23 use ieee.std_logic_arith.all;
24 use ieee.std_logic_unsigned.all;
25 
26 use work.StdRtlPkg.all;
27 use work.ArbiterPkg.all;
28 use work.AxiStreamPkg.all;
29 
30 --! @see entity
31  --! @ingroup axi
32 entity AxiStreamShift is
33  generic (
34  TPD_G : time := 1 ns;
36  PIPE_STAGES_G : integer range 0 to 16 := 0;
37  ADD_VALID_EN_G : boolean := false;
38  BYP_SHIFT_G : boolean := false);
39  port (
40  -- Clock and reset
41  axisClk : in sl;
42  axisRst : in sl;
43  -- Start control
44  axiStart : in sl;
45  axiShiftDir : in sl; -- 0 = left (lsb to msb)
46  axiShiftCnt : in slv(3 downto 0);
47  -- Slave
50  -- Master
53 end AxiStreamShift;
54 
55 architecture rtl of AxiStreamShift is
56 
57  type StateType is (S_IDLE_C, S_FIRST_C, S_SHIFT_C, S_LAST_C);
58 
59  type RegType is record
60  state : StateType;
61  shiftDir : sl;
62  shiftBytes : slv(3 downto 0);
63  slave : AxiStreamSlaveType;
64  master : AxiStreamMasterType;
65  delay : AxiStreamMasterType;
66  end record RegType;
67 
68  constant REG_INIT_C : RegType := (
69  state => S_IDLE_C,
70  shiftDir => '0',
71  shiftBytes => (others => '0'),
72  slave => AXI_STREAM_SLAVE_INIT_C,
73  master => AXI_STREAM_MASTER_INIT_C,
75  );
76 
77  signal r : RegType := REG_INIT_C;
78  signal rin : RegType;
79 
80  -- Set shift ranges
81  procedure shiftData (shiftBytes : in slv(3 downto 0);
82  shiftDir : in sl;
83  shiftFirst : in boolean;
84  mInput : in AxiStreamMasterType;
85  mDelay : in AxiStreamMasterType;
86  mOut : inout AxiStreamMasterType) is
87  variable shiftInt : positive;
88  variable lDiv : positive;
89  variable rDiv : positive;
90  variable nextEmpty : boolean;
91  constant user : integer := AXIS_CONFIG_G.TUSER_BITS_C;
92  begin
93 
95 
96  if shiftBytes = 0 then
97  mOut := mInput;
98  else
99 
100  shiftInt := conv_integer(shiftBytes);
101 
102  if shiftDir = '0' then
103  lDiv := shiftInt;
104  rDiv := AXIS_CONFIG_G.TDATA_BYTES_C - shiftInt;
105  else
106  lDiv := AXIS_CONFIG_G.TDATA_BYTES_C - shiftInt;
107  rDiv := shiftInt;
108  end if;
109 
110  nextEmpty := true;
111 
112  for i in 0 to AXIS_CONFIG_G.TDATA_BYTES_C-1 loop
113  if i < lDiv then
114  mOut.tData((i*8)+7 downto (i*8)) := mDelay.tData(((i+rDiv)*8)+7 downto (i+rDiv)*8);
115  mOut.tUser((i*user)+(user-1) downto (i*user)) := mDelay.tUser(((i+rDiv)*user)+(user-1) downto (i+rDiv)*user);
116 
117  if shiftFirst then
118  mOut.tStrb(i) := ite(ADD_VALID_EN_G = true, '1', '0');
119  mOut.tKeep(i) := ite(ADD_VALID_EN_G = true, '1', '0');
120  else
121  mOut.tStrb(i) := mDelay.tStrb(i+rDiv);
122  mOut.tKeep(i) := mDelay.tKeep(i+rDiv);
123  end if;
124 
125  -- There are valid values which will be taken from the delayed register.
126  if mInput.tValid = '1' and mInput.tKeep(i+rDiv) = '1' then
127  nextEmpty := false;
128  end if;
129  else
130  mOut.tData((i*8)+7 downto (i*8)) := mInput.tData(((i-lDiv)*8)+7 downto (i-lDiv)*8);
131  mOut.tUser((i*user)+(user-1) downto (i*user)) := mInput.tUser(((i-lDiv)*user)+(user-1) downto (i-lDiv)*user);
132  mOut.tStrb(i) := mInput.tStrb(i-lDiv) and (not mDelay.tLast);
133  mOut.tKeep(i) := mInput.tKeep(i-lDiv) and (not mDelay.tLast);
134  end if;
135  end loop;
136 
137  -- Choose ID and Dest values
138  if shiftFirst then
139  mOut.tId := mInput.tId;
140  mOut.tDest := mInput.tDest;
141  else
142  mOut.tId := mDelay.tId;
143  mOut.tDest := mDelay.tDest;
144  end if;
145 
146  -- Detect frame end from next register or current register
147  if (mDelay.tValid = '1' and mDelay.tLast = '1') or (mInput.tValid = '1' and mInput.tLast = '1' and nextEmpty) then
148  mOut.tLast := '1';
149  mOut.tValid := '1';
150  else
151  mOut.tLast := '0';
152  mOut.tValid := mInput.tValid;
153  end if;
154  end if;
155  end procedure;
156 
157  signal pipeAxisMaster : AxiStreamMasterType;
158  signal pipeAxisSlave : AxiStreamSlaveType;
159 
160 -- attribute dont_touch : string;
161 -- attribute dont_touch of r : signal is "TRUE";
162 
163 begin
164 
165  BYP_SHIFT : if (BYP_SHIFT_G = true) generate
168  end generate;
169 
170  GEN_SHIFT : if (BYP_SHIFT_G = false) generate
171 
172  comb : process (axiShiftCnt, axiShiftDir, axiStart, axisRst, pipeAxisSlave, r, sAxisMaster) is
173  variable v : RegType;
174  variable sMaster : AxiStreamMasterType;
175  begin
176  -- Latch the current value
177  v := r;
178 
179  -- Init Ready
180  v.slave.tReady := '0';
181 
182  -- Data shift
183  shiftData (r.shiftBytes, r.shiftDir, (r.state = S_FIRST_C), sAxisMaster, r.delay, sMaster);
184 
185  -- State machine
186  case r.state is
187 
188  -- IDLE
189  when S_IDLE_C =>
190  v.slave := AXI_STREAM_SLAVE_INIT_C;
191  v.master := AXI_STREAM_MASTER_INIT_C;
192  v.delay := AXI_STREAM_MASTER_INIT_C;
193  v.shiftDir := axiShiftDir;
194  v.shiftBytes := axiShiftCnt;
195 
196  -- Shift start request
197  if axiStart = '1' then
198  v.state := S_FIRST_C;
199  end if;
200 
201  -- First shift
202  when S_FIRST_C =>
203  v.slave.tReady := '1';
204 
205  -- Keep sampling shift configuration if start is held
206  if axiStart = '1' then
207  v.shiftDir := axiShiftDir;
208  v.shiftBytes := axiShiftCnt;
209  end if;
210 
211  if sAxisMaster.tValid = '1' then
212  v.delay := sAxisMaster;
213  v.state := S_SHIFT_C;
214 
215  -- Left or no shift
216  if r.shiftDir = '0' or r.shiftBytes = 0 then
217  v.master := sMaster;
218 
219  -- Frame is done
220  if sMaster.tLast = '1' then
221  v.state := S_LAST_C;
222  end if;
223  end if;
224  end if;
225 
226  -- Move a frame until tLast
227  when S_SHIFT_C =>
228 
229  -- Advance pipeline
230  if r.master.tValid = '0' or pipeAxisSlave.tReady = '1' then
231  v.slave.tReady := '1';
232 
233  if sAxisMaster.tValid = '1' then
234  v.delay := sAxisMaster;
235  v.master := sMaster;
236  else
237  v.master.tValid := '0';
238  end if;
239 
240  -- Frame is done
241  if sMaster.tLast = '1' then
242  v.master := sMaster;
243 
244  -- Last is is delayed block
245  if r.delay.tLast = '1' then
246  v.slave.tReady := '0';
247  end if;
248 
249  v.state := S_LAST_C;
250  end if;
251  end if;
252 
253  -- Last transfer
254  when S_LAST_C =>
255  if pipeAxisSlave.tReady = '1' then
256  v.state := S_IDLE_C;
257  v.master.tValid := '0';
258  end if;
259  end case;
260 
261  -- Mask off the unused tStrb and tKeep bits
262  if (AXIS_CONFIG_G.TDATA_BYTES_C /= 16) then
263  v.master.tKeep(15 downto AXIS_CONFIG_G.TDATA_BYTES_C) := (others => '0');
264  v.master.tStrb(15 downto AXIS_CONFIG_G.TDATA_BYTES_C) := (others => '0');
265  end if;
266 
267  -- Reset
268  if (axisRst = '1') then
269  v := REG_INIT_C;
270  end if;
271 
272  -- Register the variable for next clock cycle
273  rin <= v;
274 
275  -- Outputs
276  sAxisSlave <= v.slave;
277  pipeAxisMaster <= r.master;
278 
279  end process comb;
280 
281  U_Pipeline : entity work.AxiStreamPipeline
282  generic map (
283  TPD_G => TPD_G,
285  port map (
286  axisClk => axisClk,
287  axisRst => axisRst,
288  sAxisMaster => pipeAxisMaster,
289  sAxisSlave => pipeAxisSlave,
291  mAxisSlave => mAxisSlave);
292 
293  seq : process (axisClk) is
294  begin
295  if (rising_edge(axisClk)) then
296  r <= rin after TPD_G;
297  end if;
298  end process seq;
299 
300  end generate;
301 
302 end rtl;
slv( 7 downto 0) tId
PIPE_STAGES_Gnatural range 0 to 16:= 0
out sAxisSlaveAxiStreamSlaveType
std_logic sl
Definition: StdRtlPkg.vhd:28
AxiStreamMasterType :=(tValid => '0',tData =>( others => '0'),tStrb =>( others => '1'),tKeep =>( others => '1'),tLast => '0',tDest =>( others => '0'),tId =>( others => '0'),tUser =>( others => '0')) AXI_STREAM_MASTER_INIT_C
ADD_VALID_EN_Gboolean := false
in sAxisMasterAxiStreamMasterType
out sAxisSlaveAxiStreamSlaveType
slv( 15 downto 0) tStrb
slv( 15 downto 0) tKeep
natural range 1 to 16 TDATA_BYTES_C
in mAxisSlaveAxiStreamSlaveType
in axiShiftCntslv( 3 downto 0)
TPD_Gtime := 1 ns
slv( 127 downto 0) tData
out mAxisMasterAxiStreamMasterType
in sAxisMasterAxiStreamMasterType
AxiStreamSlaveType :=(tReady => '0') AXI_STREAM_SLAVE_INIT_C
BYP_SHIFT_Gboolean := false
slv( 127 downto 0) tUser
natural range 0 to 8 TUSER_BITS_C
out mAxisMasterAxiStreamMasterType
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
slv( 7 downto 0) tDest
in mAxisSlaveAxiStreamSlaveType
AXIS_CONFIG_GAxiStreamConfigType := AXI_STREAM_CONFIG_INIT_C
PIPE_STAGES_Ginteger range 0 to 16:= 0
std_logic_vector slv
Definition: StdRtlPkg.vhd:29