SURF  1.0
AxiStreamUnpacker.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : AxiStreamUnpacker.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2013-09-26
5 -- Last update: 2017-05-24
6 -------------------------------------------------------------------------------
7 -- Description: Takes 8 80-bit (5x16) ADC frames and reformats them into
8 -- 7 80 bit (5x14) frames.
9 -------------------------------------------------------------------------------
10 -- This file is part of 'SLAC Firmware Standard Library'.
11 -- It is subject to the license terms in the LICENSE.txt file found in the
12 -- top-level directory of this distribution and at:
13 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
14 -- No part of 'SLAC Firmware Standard Library', including this file,
15 -- may be copied, modified, propagated, or distributed except according to
16 -- the terms contained in the LICENSE.txt file.
17 -------------------------------------------------------------------------------
18 
19 library ieee;
20 use ieee.std_logic_1164.all;
21 use ieee.std_logic_arith.all;
22 use ieee.std_logic_unsigned.all;
23 
24 use work.StdRtlPkg.all;
25 use work.AxiStreamPkg.all;
26 use work.SsiPkg.all;
27 
28 --! @see entity
29  --! @ingroup axi
31 
32  generic (
33  TPD_G : time := 1 ns;
35  RANGE_HIGH_G : integer := 119;
36  RANGE_LOW_G : integer := 8);
37 -- PACK_SIZE_G : integer);
38  port (
39  axisClk : in sl;
40  axisRst : in sl;
41 
45 
49 
50  );
51 
52 end entity AxiStreamUnpacker;
53 
54 architecture rtl of AxiStreamUnpacker is
55 
56  constant STREAM_WIDTH_C : integer := AXI_STREAM_CONFIG_G.TDATA_BYTES_C*8;
57  constant PACK_SIZE_C : integer := RANGE_HIGH_G-RANGE_LOW_G+1;
58  constant SIZE_DIFFERENCE_C : integer := STREAM_WIDTH_C-PACK_SIZE_C;
59  constant ZERO_C : slv(SIZE_DIFFERENCE_C-1 downto 0) := slvZero(SIZE_DIFFERENCE_C);
60 
61  type RegType is record
62  packedSsiSlave : SsiSlaveType;
63  rawSsiMaster : SsiMasterType;
64  data : slv(STREAM_WIDTH_C*2-1 downto 0);
65  splitIndex : slv(log2(STREAM_WIDTH_C)-1 downto 0);
66  eof : sl;
67  eofe : sl;
68  doLast : sl;
69  end record RegType;
70 
71  constant REG_INIT_C : RegType := (
72  packedSsiSlave => ssiSlaveInit(AXI_STREAM_CONFIG_G),
73  rawSsiMaster => ssiMasterInit(AXI_STREAM_CONFIG_G),
74  data => (others => '0'),
75  splitIndex => (others => '0'),
76  eof => '0',
77  eofe => '0',
78  doLast => '0');
79 
80  signal r : RegType := REG_INIT_C;
81  signal rin : RegType;
82 
83  signal rawSsiSlave : SsiSlaveType;
84  signal packedSsiMaster : SsiMasterType;
85 
86  signal locRawAxisMaster : AxiStreamMasterType;
87  signal locRawAxisSlave : AxiStreamSlaveType;
88  signal locRawAxisCtrl : AxiStreamCtrlType;
89 
90 begin
91 
92  -- Convert AXI-Stream signals to SSI
93  packedSsiMaster <= axis2ssiMaster(AXI_STREAM_CONFIG_G, packedAxisMaster);
94  rawSsiSlave <= axis2ssiSlave(AXI_STREAM_CONFIG_G, locRawAxisSlave, locRawAxisCtrl);
95 
96  comb : process (axisRst, packedSsiMaster, r) is
97  variable v : RegType;
98  variable splitIndexInt : integer;
99  variable shiftIndexInt : integer;
100  variable wrData : slv(STREAM_WIDTH_C+SIZE_DIFFERENCE_C-1 downto 0);
101  begin
102  v := r;
103 
104  v.rawSsiMaster.sof := '0';
105  v.rawSsiMaster.eof := '0';
106  v.rawSsiMaster.eofe := '0';
107  v.rawSsiMaster.valid := '0';
108 
109  v.packedSsiSlave.ready := '1';
110  v.packedSsiSlave.pause := '0';
111  v.packedSsiSlave.overflow := '0';
112 
113 
114  if (packedSsiMaster.valid = '1' and r.packedSsiSlave.ready = '1') then
115  -- Shift leftover data from last txn down to the right for output
116  v.data(STREAM_WIDTH_C-1 downto 0) := r.data(STREAM_WIDTH_C*2-1 downto STREAM_WIDTH_C);
117  v.doLast := '1';
118 
119  if (packedSsiMaster.sof = '1') then
120  -- SOF txns are not packed. Just send the input data straight out.
121  v.data := (others => '0');
122  v.data(STREAM_WIDTH_C-1 downto 0) := packedSsiMaster.data(STREAM_WIDTH_C-1 downto 0);
123  v.rawSsiMaster.valid := '1';
124  v.rawSsiMaster.sof := '1';
125  v.splitIndex := (others => '0');
126  v.splitIndex := v.splitIndex-SIZE_DIFFERENCE_C;
127 
128  else
129  -- Each incomming txn contains part of the data from two outgoing txns.
130  -- First we find the split index.
131  -- On the first txn the split index is at STREAM_WIDTH_C-SIZE_DIFFERENCE_C.
132  -- It then decrements by SIZE_DIFFERENCE_C on each subsequent txn.
133 -- splitIndexInt := STREAM_WIDTH_C - (conv_integer(r.seqNum)+1)*SIZE_DIFFERENCE_C;
134  splitIndexInt := conv_integer(r.splitIndex);
135  v.splitIndex := r.splitIndex - SIZE_DIFFERENCE_C;
136 
137  -- Insert SIZE_DIFFERENCE_C zeros at the split index. Store in temporary variable.
138  -- This is how it should look:
139  -- wrData := packedSsiMaster.data(STREAM_WIDTH_C-1 downto zeroIndex) &
140  -- ZERO_C & packedSsiMaster.data(splitIndexInt downto 0);
141  -- But Vivado can't synthesize it that way, so we do this hack:
142  wrData := (others => '0');
143  wrData(STREAM_WIDTH_C+SIZE_DIFFERENCE_C-1 downto SIZE_DIFFERENCE_C) :=
144  packedSsiMaster.data(STREAM_WIDTH_C-1 downto 0);
145  wrData(splitIndexInt+SIZE_DIFFERENCE_C-1 downto splitIndexInt) :=
146  ZERO_C;
147  wrData(splitIndexInt-1 downto 0) :=
148  packedSsiMaster.data(splitIndexInt-1 downto 0);
149 
150 
151  -- Leftover bits from the previous txn have already by shifted to the far right of v.data.
152  -- We don't want to overwrite these, so we assign our zero filled value to v.data with the proper
153  -- offset to avoid doing so.
154  shiftIndexInt := PACK_SIZE_C-splitIndexInt;
155 
156  v.data(shiftIndexInt + STREAM_WIDTH_C+SIZE_DIFFERENCE_C - 1 downto shiftIndexInt) := wrData;
157 
158  -- Now shift the output segment by RANGE_LOW_G to recover LSB zeros
159  v.data(STREAM_WIDTH_C-1 downto 0) := v.data(STREAM_WIDTH_C-RANGE_LOW_G-1 downto 0) & slvZero(RANGE_LOW_G);
160 
161  -- Assert valid and pass any eof through
162  v.rawSsiMaster.valid := '1';
163  v.rawSsiMaster.eof := packedSsiMaster.eof;
164  v.rawSsiMaster.eofe := packedSsiMaster.eofe;
165 
166  if (r.splitIndex = SIZE_DIFFERENCE_C) then
167  -- This is the last txn of a group.
168  -- Don't output eof yet, as we want it to go out with the 'extra' output txn.
169  v.packedSsiSlave.ready := '0';
170  v.rawSsiMaster.eof := '0';
171  v.rawSsiMaster.eofe := '0';
172  v.eof := packedSsiMaster.eof;
173  v.eofe := packedSsiMaster.eofe;
174  end if;
175 
176  end if;
177  end if;
178 
179  if (r.splitIndex = 0 and r.doLast = '1') then
180  -- When split index reaches zero, we have received all txns in a group
181  -- We now have an extra txn that must be shifted out.
182  v.data(STREAM_WIDTH_C-1 downto 0) := r.data(STREAM_WIDTH_C*2-RANGE_LOW_G-1 downto STREAM_WIDTH_C) & slvZero(RANGE_LOW_G);
183  v.rawSsiMaster.valid := '1';
184  v.rawSsiMaster.eof := r.eof;
185  v.rawSsiMaster.eofe := r.eofe;
186  v.eof := '0';
187  v.eofe := '0';
188  v.doLast := '0';
189  v.splitIndex := r.splitIndex - SIZE_DIFFERENCE_C;
190  end if;
191 
192  -- Assign v.data to rawSsiMaster
193  -- Synthesis will merge the r.data registers with r.rawSsiMaster.data
194  v.rawSsiMaster.data(STREAM_WIDTH_C -1 downto 0) := v.data(STREAM_WIDTH_C-1 downto 0);
195 
196 
197  ----------------------------------------------------------------------------------------------
198  -- Reset
199  ----------------------------------------------------------------------------------------------
200  if (axisRst = '1') then
201  v := REG_INIT_C;
202  end if;
203 
204  rin <= v;
205 
206  ----------------------------------------------------------------------------------------------
207  -- Outputs
208  ----------------------------------------------------------------------------------------------
209  locRawAxisMaster <= ssi2AxisMaster(AXI_STREAM_CONFIG_G, r.rawSsiMaster);
210  packedAxisSlave <= ssi2AxisSlave(r.packedSsiSlave);
211  packedAxisCtrl <= ssi2AxisCtrl(r.packedSsiSlave);
212 
213  end process comb;
214 
215  seq : process (axisClk) is
216  begin
217  if (rising_edge(axisClk)) then
218  r <= rin after TPD_G;
219  end if;
220  end process seq;
221 
222  rawAxisMaster <= locRawAxisMaster;
223  locRawAxisSlave <= rawAxisSlave;
224  locRawAxisCtrl <= rawAxisCtrl;
225 
226  -- Could probably get rid of this
227 -- AxiStreamFifo_1 : entity work.AxiStreamFifoV2
228 -- generic map (
229 -- TPD_G => TPD_G,
230 -- BRAM_EN_G => false,
231 -- GEN_SYNC_FIFO_G => true,
232 -- FIFO_ADDR_WIDTH_G => 4,
233 -- FIFO_FIXED_THRESH_G => true,
234 -- FIFO_PAUSE_THRESH_G => 15,
235 -- SLAVE_AXI_CONFIG_G => AXI_STREAM_CONFIG_G,
236 -- MASTER_AXI_CONFIG_G => AXI_STREAM_CONFIG_G)
237 -- port map (
238 -- sAxisClk => axisClk,
239 -- sAxisRst => axisRst,
240 -- sAxisMaster => locRawAxisMaster,
241 -- sAxisSlave => locRawAxisSlave,
242 -- sAxisCtrl => locRawAxisCtrl,
243 -- mAxisClk => axisClk,
244 -- mAxisRst => axisRst,
245 -- mAxisMaster => rawAxisMaster,
246 -- mAxisSlave => rawAxisSlave);
247 
248 end architecture rtl;
slv( 127 downto 0) data
Definition: SsiPkg.vhd:67
sl sof
Definition: SsiPkg.vhd:72
RANGE_HIGH_Ginteger := 119
std_logic sl
Definition: StdRtlPkg.vhd:28
sl eofe
Definition: SsiPkg.vhd:74
natural range 1 to 16 TDATA_BYTES_C
out packedAxisCtrlAxiStreamCtrlType
in rawAxisCtrlAxiStreamCtrlType
in packedAxisMasterAxiStreamMasterType
SsiMasterType
Definition: SsiPkg.vhd:65
SsiSlaveType
Definition: SsiPkg.vhd:77
_library_ ieeeieee
sl valid
Definition: SsiPkg.vhd:66
out packedAxisSlaveAxiStreamSlaveType
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
sl ready
Definition: SsiPkg.vhd:78
AXI_STREAM_CONFIG_GAxiStreamConfigType := AXI_STREAM_CONFIG_INIT_C
sl eof
Definition: SsiPkg.vhd:73
out rawAxisMasterAxiStreamMasterType
in rawAxisSlaveAxiStreamSlaveType
std_logic_vector slv
Definition: StdRtlPkg.vhd:29