SURF  1.0
AxiStreamScatterGather.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : AxiStreamScatterGather.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2013-03-01
5 -- Last update: 2015-04-08
6 -------------------------------------------------------------------------------
7 -- Description: Takes 6 APV bursts with 128 channels of data each and
8 -- transforms them into 128 "MultiSamples" with 6 samples each.
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_unsigned.all;
22 use ieee.std_logic_arith.all;
23 use work.StdRtlPkg.all;
24 use work.AxiLitePkg.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;
34  AXIS_SLAVE_FRAME_SIZE_G : integer := 129;
35  SLAVE_AXIS_CONFIG_G : AxiStreamConfigType := ssiAxiStreamConfig(2);
36  MASTER_AXIS_CONFIG_G : AxiStreamConfigType := ssiAxiStreamConfig(12));
37  port (
38  -- Master system clock, 125Mhz
39  axiClk : in sl;
40  axiRst : in sl;
41 
42  -- (optional) Axi Bus for status and debug
47 
48  -- Input data
52 
53 -- longWordCount : out slv(7 downto 0);
54 -- badWordCount : out slv(7 downto 0);
55 -- longWords : out slv(15 downto 0);
56 -- badWords : out slv(15 downto 0);
57 
58  -- Output data
62 
63 end entity AxiStreamScatterGather;
64 
65 architecture rtl of AxiStreamScatterGather is
66 
67  constant SEQUENCE_LENGTH_C : integer := MASTER_AXIS_CONFIG_G.TDATA_BYTES_C/SLAVE_AXIS_CONFIG_G.TDATA_BYTES_C;
68  constant SLAVE_DATA_LENGTH_C : integer := SLAVE_AXIS_CONFIG_G.TDATA_BYTES_C*8;
69  constant MASTER_DATA_LENGTH_C : integer := MASTER_AXIS_CONFIG_G.TDATA_BYTES_C*8;
70 
71  constant RAM_DEPTH_RAW_C : integer := AXIS_SLAVE_FRAME_SIZE_G * SEQUENCE_LENGTH_C * 2;
72  constant RAM_ADDR_LENGTH_C : integer := bitSize(RAM_DEPTH_RAW_C);
73  constant RAM_DEPTH_C : integer := 2**RAM_ADDR_LENGTH_C;
74 
75  -------------------------------------------------------------------------------------------------
76  -- RAM
77  -------------------------------------------------------------------------------------------------
78  type RamType is array (0 to RAM_DEPTH_C-1) of slv(SLAVE_DATA_LENGTH_C-1 downto 0);
79  signal ram : RamType;
80  signal txRamRdData : slv(SLAVE_DATA_LENGTH_C-1 downto 0);
81 
82  signal txFifoRdData : sl;
83  signal txFifoValid : sl;
84 
85  --------------------------------------------------------------------------------------------------
86  type RegType is record
87  rxRamWrEn : sl;
88  rxRamWrData : slv(SLAVE_DATA_LENGTH_C-1 downto 0);
89  rxRamWrAddr : slv(RAM_ADDR_LENGTH_C-1 downto 0);
90  rxSofAddr : slv(RAM_ADDR_LENGTH_C-1 downto 0);
91  rxFifoWrEn : sl;
92  rxWordCount : slv(bitSize(AXIS_SLAVE_FRAME_SIZE_G)-1 downto 0);
93  rxFrameNumber : slv(bitSize(SEQUENCE_LENGTH_C-1)-1 downto 0);
94  rxError : sl;
95 
96  mSsiMaster : SsiMasterType;
97  txRamRdAddr : slv(RAM_ADDR_LENGTH_C-1 downto 0);
98  txRamRdEn : sl;
99  txFifoRdEn : sl;
100  txWordCount : slv(bitSize(AXIS_SLAVE_FRAME_SIZE_G-1)-1 downto 0);
101  txFrameNumber : slv(bitSize(SEQUENCE_LENGTH_C-1)-1 downto 0);
102  txSof : sl;
103 
106 
107  longWordCount : slv(7 downto 0);
108  longWords : slv(15 downto 0);
109  badWordCount : slv(7 downto 0);
110  badWords : slv(15 downto 0);
111  end record RegType;
112 
113  constant REG_INIT_C : RegType := (
114  rxRamWrEn => '0',
115  rxRamWrData => (others => '0'),
116  rxRamWrAddr => (others => '0'),
117  rxSofAddr => (others => '0'),
118  rxFifoWrEn => '0',
119  rxWordCount => (others => '0'),
120  rxFrameNumber => (others => '0'),
121  rxError => '0',
122 
123  mSsiMaster => ssiMasterInit(MASTER_AXIS_CONFIG_G),
124  txRamRdAddr => (others => '0'),
125  txRamRdEn => '0',
126  txFifoRdEn => '0',
127  txWordCount => (others => '0'),
128  txFrameNumber => (others => '0'),
129  txSof => '1',
130 
133 
134  longWordCount => (others => '0'),
135  badWordCount => (others => '0'),
136  longWords => (others => '0'),
137  badWords => (others => '0'));
138 
139  signal r : RegType := REG_INIT_C;
140  signal rin : RegType;
141 
142  signal sSsiMaster : SsiMasterType;
143 
144 begin
145 
146  -------------------------------------------------------------------------------------------------
147  -- Infer a RAM
148  -------------------------------------------------------------------------------------------------
149  ramProc : process (axiClk) is
150  begin
151  if (rising_edge(axiClk)) then
152  txRamRdData <= ram(conv_integer(r.txRamRdAddr)) after TPD_G;
153  if (r.rxRamWrEn = '1') then
154  ram(conv_integer(r.rxRamWrAddr)) <= r.rxRamWrData after TPD_G;
155  end if;
156  end if;
157  end process ramProc;
158 
159  -------------------------------------------------------------------------------------------------
160  -- Use fifo to indicate to TX side that a new frame is ready
161  -------------------------------------------------------------------------------------------------
162  StatusFifo : entity work.Fifo
163  generic map (
164  TPD_G => TPD_G,
165  GEN_SYNC_FIFO_G => true,
166  BRAM_EN_G => false,
167  FWFT_EN_G => true,
168  USE_BUILT_IN_G => false,
169  DATA_WIDTH_G => 1,
170  ADDR_WIDTH_G => 4)
171  port map (
172  rst => axiRst,
173  wr_clk => axiClk,
174  wr_en => r.rxFifoWrEn,
175  din(0) => r.rxError,
176  full => open,
177  rd_clk => axiClk,
178  rd_en => r.txFifoRdEn,
179  dout(0) => txFifoRdData,
180  valid => txFifoValid);
181 
182  sSsiMaster <= axis2SsiMaster(SLAVE_AXIS_CONFIG_G, sAxisMaster);
185 
186  comb : process (axiRst, axilReadMaster, axilWriteMaster, r, sSsiMaster, txFifoRdData,
187  txFifoValid, txRamRdData) is
188  variable v : RegType;
189  variable mDataLow : integer;
190  variable mDataHigh : integer;
191  variable axilStatus : AxiLiteStatusType;
192  begin
193  v := r;
194 
195  ----------------------------------------------------------------------------------------------
196  -- Rx logic
197  ----------------------------------------------------------------------------------------------
198  v.rxRamWrEn := '0';
199  v.rxRamWrData := sSsiMaster.data(SLAVE_DATA_LENGTH_C-1 downto 0);
200  v.rxFifoWrEn := '0';
201 
202  if (sSsiMaster.valid = '1') then
203  -- Default - Write to RAM and increment wr addr by sequence length
204  v.rxWordCount := r.rxWordCount + 1;
205  v.rxRamWrAddr := r.rxRamWrAddr + SEQUENCE_LENGTH_C;
206  v.rxRamWrEn := '1';
207 
208  -- Protect against long frames by freezing wr addr
209  if (r.rxWordCount = AXIS_SLAVE_FRAME_SIZE_G) then
210  v.rxRamWrAddr := r.rxRamWrAddr;
211  v.rxError := '1';
212  v.longWordCount := r.longWordCount + 1;
213  v.longWords(r.rxWordCount'range) := r.rxWordCount;
214  end if;
215 
216  -- Log start address on each sof to easily come back to it + 1 on next frame
217  if (sSsiMaster.sof = '1') then
218  v.rxRamWrAddr := r.rxSofAddr;
219  end if;
220 
221  if (sSsiMaster.eof = '1' or sSsiMaster.eofe = '1') then
222  v.rxFrameNumber := r.rxFrameNumber + 1;
223  v.rxWordCount := (others => '0');
224  v.rxError := r.rxError or sSsiMaster.eofe;
225 
226  v.rxSofAddr := r.rxSofAddr + 1;
227 
228  -- Check for proper number of words
229  if (r.rxWordCount /= AXIS_SLAVE_FRAME_SIZE_G-1) then
230  v.rxError := '1';
231  v.badWordCount := r.badWordCount + 1;
232  v.badWords(r.rxWordCount'range) := r.rxWordCount;
233  end if;
234 
235  -- Check for end of frame sequence
236  if (r.rxFrameNumber = SEQUENCE_LENGTH_C-1) then
237  v.rxFrameNumber := (others => '0');
238  v.rxFifoWrEn := '1';
239  v.rxSofAddr := r.rxSofAddr + ((AXIS_SLAVE_FRAME_SIZE_G*SEQUENCE_LENGTH_C) - (SEQUENCE_LENGTH_C-1));
240 
241 -- v.rxFifoWrData(0) := v.rxError; -- Use v because it could be set this cycle
242  end if;
243  end if;
244  end if;
245 
246  if (r.rxFifoWrEn = '1') then
247  -- Reset rx error after each write.
248  -- Need to check timing on this.
249  v.rxError := '0';
250  end if;
251 
252  ----------------------------------------------------------------------------------------------
253  -- TX logic
254  ----------------------------------------------------------------------------------------------
255  v.mSsiMaster.valid := '0';
256  v.mSsiMaster.sof := '0';
257  v.mSsiMaster.eof := '0';
258  v.mSsiMaster.eofe := '0';
259  v.txFifoRdEn := '0';
260  v.txRamRdEn := '0';
261 
262  if (txFifoValid = '1' and r.txFifoRdEn = '0') then
263 
264  v.txRamRdEn := '1';
265  v.txRamRdAddr := r.txRamRdAddr + 1;
266 
267  if (r.txRamRdEn = '1') then
268  v.txFrameNumber := r.txFrameNumber + 1;
269 
270  mDataHigh := ((conv_integer(r.txFrameNumber) + 1) * SLAVE_DATA_LENGTH_C) - 1;
271  mDataLow := (conv_integer(r.txFrameNumber) * SLAVE_DATA_LENGTH_C);
272  for i in 0 to SLAVE_DATA_LENGTH_C-1 loop
273  v.mSsiMaster.data(i+mDataLow) := txRamRdData(i);
274  end loop;
275 
276  if (r.txFrameNumber = SEQUENCE_LENGTH_C-1) then
277  v.mSsiMaster.valid := '1';
278  v.mSsiMaster.sof := r.txSof;
279  v.mSsiMaster.eofe := r.txSof and txFifoRdData; -- Assert eofe without eof to indicate sofe
280  v.txSof := '0';
281  v.txFrameNumber := (others => '0');
282  v.txWordCount := r.txWordCount + 1;
283  if (r.txWordCount = AXIS_SLAVE_FRAME_SIZE_G-1) then
284  v.txWordCount := (others => '0');
285  v.txFifoRdEn := '1';
286  v.mSsiMaster.eof := '1';
287  v.mSsiMaster.eofe := txFifoRdData;
288  v.txRamRdAddr := r.txRamRdAddr;
289  v.txSof := '1';
290  end if;
291  end if;
292 
293  end if;
294 
295  end if;
296 
297 
298  ----------------------------------------------------------------------------------------------
299  -- Do reset here so that AXI logic can't be reset
300  ----------------------------------------------------------------------------------------------
301  if (axiRst = '1') then
302  v := REG_INIT_C;
305  end if;
306 
307  ----------------------------------------------------------------------------------------------
308  -- AXI Interface
309  ----------------------------------------------------------------------------------------------
310  axiSlaveWaitTxn(axilWriteMaster, axilReadMaster, v.axilWriteSlave, v.axilReadSlave, axilStatus);
311 
312  if (axilStatus.writeEnable = '1') then
313  axiSlaveWriteResponse(v.axilWriteSlave);
314  end if;
315 
316  if (axilStatus.readEnable = '1') then
317  -- Decode address and assign read data
318  v.axilReadSlave.rdata := (others => '0');
319  case axilReadMaster.araddr(7 downto 0) is
320  when X"00" =>
321  v.axilReadSlave.rdata(r.rxRamWrAddr'range) := r.rxRamWrAddr;
322  when X"04" =>
323  v.axilReadSlave.rdata(r.rxSofAddr'range) := r.rxSofAddr;
324  when X"08" =>
325  v.axilReadSlave.rdata(r.rxWordCount'range) := r.rxWordCount;
326  when X"0C" =>
327  v.axilReadSlave.rdata(r.rxFrameNumber'range) := r.rxFrameNumber;
328  v.axilReadSlave.rdata(31) := r.rxError;
329 
330  when X"10" =>
331  v.axilReadSlave.rdata(r.txRamRdAddr'range) := r.txRamRdAddr;
332  when X"14" =>
333  v.axilReadSlave.rdata(r.txWordCount'range) := r.txWordCount;
334  when X"18" =>
335  v.axilReadSlave.rdata(r.txFrameNumber'range) := r.txFrameNumber;
336  when X"1C" =>
337  v.axilReadSlave.rdata(r.longWords'range) := r.longWords;
338  when X"20" =>
339  v.axilReadSlave.rdata(r.longWordCount'range) := r.longWordCount;
340  when X"24" =>
341  v.axilReadSlave.rdata(r.badWords'range) := r.badWords;
342  when X"28" =>
343  v.axilReadSlave.rdata(r.badWordCount'range) := r.badWordCount;
344 
345  when others => null;
346  end case;
347  axiSlaveReadResponse(v.axilReadSlave);
348  end if;
349 
350  ----------------------------------------------------------------------------------------------
351  -- Reset
352  ----------------------------------------------------------------------------------------------
353 -- if (axiRst = '1') then
354 -- v := REG_INIT_C;
355 -- end if;
356 
357  ----------------------------------------------------------------------------------------------
358  -- Outputs
359  ----------------------------------------------------------------------------------------------
360 
361  rin <= v;
362 
363  mAxisMaster <= ssi2AxisMaster(MASTER_AXIS_CONFIG_G, r.mSsiMaster);
366 
367 -- longWordCount <= r.longWordCount;
368 -- badWordCount <= r.badWordCount;
369 -- longWords <= r.longWords;
370 -- badWords <= r.badWords;
371  end process comb;
372 
373 
374 
375  sync : process (axiClk) is
376  begin
377  if (rising_edge(axiClk)) then
378  r <= rin after TPD_G;
379  end if;
380  end process sync;
381 
382 
383 end architecture rtl;
slv( 127 downto 0) data
Definition: SsiPkg.vhd:67
out sAxisCtrlAxiStreamCtrlType
sl sof
Definition: SsiPkg.vhd:72
BRAM_EN_Gboolean := true
Definition: Fifo.vhd:32
AxiLiteWriteMasterType
Definition: AxiLitePkg.vhd:111
std_logic sl
Definition: StdRtlPkg.vhd:28
FWFT_EN_Gboolean := false
Definition: Fifo.vhd:33
sl eofe
Definition: SsiPkg.vhd:74
out mAxisMasterAxiStreamMasterType
slv( 31 downto 0) rdata
Definition: AxiLitePkg.vhd:89
in axilReadMasterAxiLiteReadMasterType := AXI_LITE_READ_MASTER_INIT_C
natural range 1 to 16 TDATA_BYTES_C
in rd_clksl
Definition: Fifo.vhd:61
TPD_Gtime := 1 ns
Definition: Fifo.vhd:28
SLAVE_AXIS_CONFIG_GAxiStreamConfigType := ssiAxiStreamConfig( 2)
_library_ ieeeieee
DATA_WIDTH_Ginteger range 1 to ( 2** 24):= 16
Definition: Fifo.vhd:41
in wr_clksl
Definition: Fifo.vhd:50
SsiMasterType
Definition: SsiPkg.vhd:65
in mAxisSlaveAxiStreamSlaveType
out axilWriteSlaveAxiLiteWriteSlaveType
in axilWriteMasterAxiLiteWriteMasterType := AXI_LITE_WRITE_MASTER_INIT_C
out fullsl
Definition: Fifo.vhd:58
out validsl
Definition: Fifo.vhd:65
AxiLiteReadMasterType
Definition: AxiLitePkg.vhd:59
in rd_ensl := '0'
Definition: Fifo.vhd:62
AxiLiteReadSlaveType :=(arready => '0',rdata =>( others => '0'),rresp =>( others => '0'),rvalid => '0') AXI_LITE_READ_SLAVE_INIT_C
Definition: AxiLitePkg.vhd:95
sl valid
Definition: SsiPkg.vhd:66
GEN_SYNC_FIFO_Gboolean := false
Definition: Fifo.vhd:31
out axilReadSlaveAxiLiteReadSlaveType
MASTER_AXIS_CONFIG_GAxiStreamConfigType := ssiAxiStreamConfig( 12)
AxiLiteReadMasterType :=(araddr =>( others => '0'),arprot =>( others => '0'),arvalid => '0',rready => '1') AXI_LITE_READ_MASTER_INIT_C
Definition: AxiLitePkg.vhd:69
AxiStreamCtrlType :=(pause => '0',overflow => '0',idle => '1') AXI_STREAM_CTRL_UNUSED_C
AxiLiteReadSlaveType
Definition: AxiLitePkg.vhd:85
in rstsl :=not RST_POLARITY_G
Definition: Fifo.vhd:48
AxiLiteWriteMasterType :=(awaddr =>( others => '0'),awprot =>( others => '0'),awvalid => '0',wdata =>( others => '0'),wstrb =>( others => '1'),wvalid => '0',bready => '1') AXI_LITE_WRITE_MASTER_INIT_C
Definition: AxiLitePkg.vhd:125
ADDR_WIDTH_Ginteger range 4 to 48:= 4
Definition: Fifo.vhd:42
USE_BUILT_IN_Gboolean := false
Definition: Fifo.vhd:37
AxiStreamSlaveType :=(tReady => '1') AXI_STREAM_SLAVE_FORCE_C
slv( 31 downto 0) araddr
Definition: AxiLitePkg.vhd:61
out sAxisSlaveAxiStreamSlaveType
sl eof
Definition: SsiPkg.vhd:73
AxiLiteWriteSlaveType :=(awready => '0',wready => '0',bresp =>( others => '0'),bvalid => '0') AXI_LITE_WRITE_SLAVE_INIT_C
Definition: AxiLitePkg.vhd:156
in mAxisCtrlAxiStreamCtrlType
Definition: Fifo.vhd:26
in sAxisMasterAxiStreamMasterType
std_logic_vector slv
Definition: StdRtlPkg.vhd:29
in wr_ensl := '0'
Definition: Fifo.vhd:51