1 ------------------------------------------------------------------------------- 3 -- Company : SLAC National Accelerator Laboratory 4 -- Created : 2015-06-11 5 -- Last update: 2016-06-23 6 ------------------------------------------------------------------------------- 7 -- Description: Receiver FSM 8 -- Receiver has the following functionality: 9 -- Transport side FSM. Receive check and save segments to RX buffer. 10 -- - WAIT_SOF Waits for Transport side SOF, 11 -- - CHECK Determines the segment type and checks: 12 -- ACK, NULL, DATA, or RST segment 13 -- 1. Validates checksum (when valid), 14 -- 2. Header length (number of bytes), 15 -- 3. Sequence number (Only current seqN or lastSeqN+1 allowed) 16 -- 4. Acknowledgment number (Valid range is lastAckN to lastAckN + txWindowSize) 17 -- - CHECK_SYN Toggles through SYN header addresses and saves the RSSI parameters 18 -- Checks the following: 19 -- 1. Validates checksum (when valid), 20 -- 2. Validates Ack number if the ack is sent with the SYN segment 21 -- - DATA Receives the payload part of the DATA segment 22 -- - VALID Checks if next valid SEQn is received. If yes: 23 -- 1. increment the in order SEQn 24 -- 2. save seqN, type, and occupied to the window buffer at current rxBufferAddr 25 -- 3. increment rxBufferAddr 26 -- - DROP Just report dropped packet and got back to WAIT_SOF 27 -- Receiver side FSM. Send data to App side. 28 -- - CHECK_BUFFER and DATA Send the data frame to the Application 29 -- when the data at the next txSegmentAddr is ready. 30 -- - SENT Release the windowbuffer at txBufferAddr. 31 -- Increment txBufferAddr. 32 -- Register the received SeqN for acknowledgment. 33 ------------------------------------------------------------------------------- 34 -- This file is part of 'SLAC Firmware Standard Library'. 35 -- It is subject to the license terms in the LICENSE.txt file found in the 36 -- top-level directory of this distribution and at: 37 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. 38 -- No part of 'SLAC Firmware Standard Library', including this file, 39 -- may be copied, modified, propagated, or distributed except according to 40 -- the terms contained in the LICENSE.txt file. 41 ------------------------------------------------------------------------------- 44 use ieee.std_logic_1164.
all;
45 use ieee.std_logic_unsigned.
all;
46 use ieee.std_logic_arith.
all;
54 --! @ingroup protocols_rssi 60 SEGMENT_ADDR_SIZE_G : positive := 3 -- 2^SEGMENT_ADDR_SIZE_G = Number of 64 bit wide data words 66 -- Connection FSM indicating active connection 69 -- Window size different for Rx and Tx 74 -- Last acknowledged Sequence number connected to TX module 77 -- Current received seqN 80 -- Current received ackN 83 -- Last seqN received and sent to application (this is the ackN transmitted) 86 -- Valid Segment received (1 c-c) 89 -- Segment dropped (1 c-c) 92 -- Last segment received flags (active until next segment is received) 95 -- Parameters received from peer SYN packet 114 -- SSI Transport side interface IN 118 -- SSI Application side interface OUT 125 architecture rtl
of RxFSM is
131 type tspStateType is ( 141 type AppStateType is ( 148 type RegType is record 150 -- Resception buffer window 153 -- Transport side FSM (Receive and check segments) 154 ----------------------------------------------------------- 157 inorderSeqN : slv(7 downto 0);
-- Next expected seqN 158 rxHeaderAddr : slv(7 downto 0);
167 -- Received RSSI parameters 170 rxHeadLen : slv(7 downto 0);
171 rxSeqN : slv(7 downto 0);
-- Received seqN 172 rxAckN : slv(7 downto 0);
-- Received ackN 189 tspState : TspStateType;
191 -- Application side FSM (Send segments when next in order received) 192 ----------------------------------------------------------- 195 rxLastSeqN : slv(7 downto 0);
202 appState : AppStateType;
206 constant REG_INIT_C : RegType := ( 211 -- Transport side FSM (Receive and check segments) 212 ----------------------------------------------------------- 213 inorderSeqN => (others => '0'), -- Next expected seqN 214 rxHeaderAddr => (others => '0'), 215 rxSegmentAddr => (others => '0'), 216 rxBufferAddr => (others => '0'), 222 rxF => (others => ('0')), 224 -- Received RSSI parameters 227 rxHeadLen => (others => '0'), -- Received seqN 228 rxSeqN => (others => '0'), -- Received seqN 229 rxAckN => (others => '0'), -- Received ackN 239 headerData => (others => '0'), 242 tspSsiMaster => SSI_MASTER_INIT_C, 243 tspSsiSlave => SSI_SLAVE_NOTRDY_C, 245 -- Transport side state 246 tspState => WAIT_SOF_S, 248 -- Application side FSM (Send segments when received next in odrer received) 249 ----------------------------------------------------------- 250 txBufferAddr => (others => '0'), 251 txSegmentAddr => (others => '0'), 252 rxLastSeqN => (others => '0'), 255 appSsiMaster => SSI_MASTER_INIT_C, 256 appSsiSlave => SSI_SLAVE_NOTRDY_C, 258 -- Application side state 259 appState => CHECK_BUFFER_S 263 signal r : RegType := REG_INIT_C;
264 signal rin : RegType;
265 signal s_chksumOk : sl;
269 -- Override checksum check if checksum disabled 272 ----------------------------------------------------------------------------------------------- 276 variable v : RegType;
281 ------------------------------------------------------------ 282 -- RX Transport side FSM: 283 -- Receive the segment from the peer 284 -- Check the segment: 285 -- - register the parameters from SYN header 287 -- - check header checksum 288 -- - increment in order received SeqN 289 ------------------------------------------------------------ 291 -- Pipeline the transport master 295 ---------------------------------------------------------------------- 299 v.rxHeaderAddr := (others => '0');
300 v.rxSegmentAddr := (others => '1');
-- "-1" so the first address after increment to be 0 303 -- Ready until SOF received 304 -- Also flush any dropped or non SOF segments 305 v.tspSsiSlave := SSI_SLAVE_RDY_C;
315 -- Next state condition 320 -- When SOF has been received dessert ready until package is checked 321 v.tspSsiSlave := SSI_SLAVE_RDY_C;
323 -- If the packet is longer than one set the data flag 330 v.tspState := CHECK_S;
333 ---------------------------------------------------------------------- 338 v.rxSegmentAddr := (others => '1');
340 -- Hold incoming AXI stream 341 v.tspSsiSlave := SSI_SLAVE_NOTRDY_C;
343 if (r.tspSsiMaster.valid = '1' and r.tspSsiMaster.sof = '1') then 344 -- Register flags, header length and SEQn 345 v.rxF.syn := r.headerData (63);
346 v.rxF.ack := r.headerData (62);
347 v.rxF.eack := r.headerData (61);
348 v.rxF.rst := r.headerData (60);
349 v.rxF.nul := r.headerData (59);
350 v.rxF.busy := r.headerData (56);
352 v.rxHeadLen := r.headerData (55 downto 48);
353 v.rxSeqN := r.headerData (47 downto 40);
354 v.rxAckN := r.headerData (39 downto 32);
361 -- Syn header received (header is 3 c-c long) 362 if (v.rxF.syn = '1') then 364 -- Register SYN header word 0 parameters 365 v.chkLen := 3;
-- TODO make generic 366 v.rxParam.version := r.headerData (31 downto 28);
367 v.rxParam.chksumEn := r.headerData (26 downto 26);
368 v.rxParam.maxOutsSeg := r.headerData (23 downto 16);
369 v.rxParam.maxSegSize := r.headerData (15 downto 0);
373 -- Acknowledgment not valid 374 v.tspState := DROP_S;
375 elsif (v.rxF.eack = '1' or v.rxF.rst = '1' or v.rxF.busy = '1') then 377 v.tspState := DROP_S;
380 v.tspState := SYN_CHECK_S;
383 -- Segment is ACK, DATA, RST, or NULL 391 r.rxHeadLen = toSlv(8, 8) and 393 (r.rxSeqN - r.inOrderSeqN) <= 1 and 397 -- Valid data segment 398 if (r.rxF.data = '1' and v.rxF.nul = '0' and v.rxF.rst = '0') then 399 -- Wait if the buffer full 400 -- Note: Deadlock possibility! If the peer is not accepting data! 401 if (r.windowArray(conv_integer(r.rxBufferAddr)).occupied = '0') then 402 -- Go to data segment 403 v.tspState := DATA_S;
405 -- Buffer is full -> drop segment 406 v.tspState := DROP_S;
408 elsif (r.rxF.data = '0') then 409 -- Valid non data segment 410 v.tspState := VALID_S;
412 -- Error: Data is attached to NUL or RST segment 413 v.tspState := DROP_S;
417 v.tspState := DROP_S;
421 ---------------------------------------------------------------------- 426 v.rxSegmentAddr := (others => '1');
428 -- Ready to receive further header data 429 v.tspSsiSlave := SSI_SLAVE_RDY_C;
431 -- Get the rest of the SYN header 434 v.rxHeaderAddr := r.rxHeaderAddr + 1;
437 v.rxHeaderAddr := r.rxHeaderAddr;
440 -- Register SYN header word 1 parameters 441 if (r.rxHeaderAddr = x"01" and r.tspSsiMaster.valid = '1') then 443 v.rxParam.retransTout := r.headerData (63 downto 48);
445 v.rxParam.nullSegTout := r.headerData (31 downto 16);
446 v.rxParam.maxRetrans := r.headerData (15 downto 8);
447 v.rxParam.maxCumAck := r.headerData ( 7 downto 0);
451 -- Register SYN header word 2 parameters 452 if (r.rxHeaderAddr = x"02" ) then 454 v.rxHeaderAddr := r.rxHeaderAddr;
455 v.tspSsiSlave := r.tspSsiSlave;
457 if (r.tspSsiMaster.valid = '1') then 460 v.rxParam.maxOutofseq := r.headerData (63 downto 56);
461 v.rxParam.timeoutUnit := r.headerData (55 downto 48);
462 v.rxParam.connectionId(31 downto 0):= r.headerData (47 downto 16);
465 v.tspSsiSlave := SSI_SLAVE_NOTRDY_C;
470 -- Check received data header 476 r.rxHeadLen = toSlv(24, 8) 479 v.tspState := VALID_S;
482 v.tspState := DROP_S;
486 ---------------------------------------------------------------------- 495 -- Ready to receive further header data 496 v.tspSsiSlave := SSI_SLAVE_RDY_C;
498 -- Write enable and segment address 500 v.rxSegmentAddr := r.rxSegmentAddr + 1;
503 v.rxSegmentAddr := r.rxSegmentAddr;
507 -- Wait until receiving EOF 510 -- Save tKeep of the last packet 513 -- Save packet length (+1 because it has not incremented for EOF yet) 518 v.tspState := VALID_S;
520 v.tspState := DROP_S;
523 v.tspState := DROP_S;
525 v.tspState := DROP_S;
527 ---------------------------------------------------------------------- 537 v.tspSsiSlave := SSI_SLAVE_NOTRDY_C;
539 -- Initialize when valid SYN segment received 540 -- 1. Set the initial SeqN 541 -- 2. Initialize the buffer address 542 -- 3. Initialize window 545 v.inOrderSeqN := r.rxSeqN;
546 v.rxBufferAddr := (others => '0');
547 v.windowArray := REG_INIT_C.windowArray;
549 -- Check if next valid SEQn is received. If yes: 550 -- 1. increment the in order SEQn 551 -- 2. save seqN, type, and occupied to the current buffer address 552 -- 3. increase buffer 553 elsif ( (r.rxF.data = '1' or r.rxF.nul = '1' or r.rxF.rst = '1' ) and 554 -- Next seqN absolute difference is one 555 r.rxSeqN - r.inOrderSeqN = 1 558 v.windowArray(conv_integer(r.rxBufferAddr)).seqN := r.rxSeqN;
559 v.windowArray(conv_integer(r.rxBufferAddr)).segType(0) := r.rxF.data;
560 v.windowArray(conv_integer(r.rxBufferAddr)).segType(1) := r.rxF.nul;
561 v.windowArray(conv_integer(r.rxBufferAddr)).segType(2) := r.rxF.rst;
562 v.windowArray(conv_integer(r.rxBufferAddr)).occupied := '1';
564 v.inOrderSeqN := r.rxSeqN;
567 v.rxBufferAddr := r.rxBufferAddr +1;
569 v.rxBufferAddr := (others => '0');
573 v.rxBufferAddr := r.rxBufferAddr;
574 v.inOrderSeqN := r.inOrderSeqN;
577 -- Get ready to receive new packet 578 v.tspState := WAIT_SOF_S;
580 ---------------------------------------------------------------------- 590 v.tspSsiSlave := SSI_SLAVE_NOTRDY_C;
592 -- Get ready to receive new packet 593 v.tspState := WAIT_SOF_S;
595 ---------------------------------------------------------------------- 600 ---------------------------------------------------------------------- 603 ------------------------------------------------------------ 604 -- TX Application side FSM: 605 -- Transmit the segments in correct order 606 -- Check the buffer if the next slot is available and send the buffer to APP 607 ------------------------------------------------------------ 610 -- These flags will hold if not overridden 611 v.appSsiMaster:= SSI_MASTER_INIT_C;
613 -- Pipeline incomming slave 617 ---------------------------------------------------------------------- 618 when CHECK_BUFFER_S => 621 v.txSegmentAddr := (others => '0');
622 v.rxLastSeqN := r.rxLastSeqN;
626 v.txBufferAddr := (others => '0');
627 v.rxLastSeqN := r.inOrderSeqN;
628 -- Data segment in buffer only one word long take TKEEP and apply EOF 629 elsif (r.windowArray(conv_integer(r.txBufferAddr)).occupied = '1' and 630 r.windowArray(conv_integer(r.txBufferAddr)).segType = "001" and -- Data segment type 631 r.windowArray(conv_integer(r.txBufferAddr)).segSize = 0 634 v.txBufferAddr := r.txBufferAddr;
638 v.appSsiMaster.sof := '1';
639 v.appSsiMaster.valid := '1';
640 v.appSsiMaster.strb := (others => '1');
641 v.appSsiMaster.dest := (others => '0');
642 v.appSsiMaster.keep := r.windowArray(conv_integer(r.txBufferAddr)).keep;
643 v.appSsiMaster.eof := '1';
644 v.appSsiMaster.eofe := '0';
646 v.txSegmentAddr := r.txSegmentAddr;
648 v.appState := SENT_S;
650 -- Data segment in buffer longer than one word go to DATA_S 651 elsif (r.windowArray(conv_integer(r.txBufferAddr)).occupied = '1' and 652 r.windowArray(conv_integer(r.txBufferAddr)).segType = "001" -- Data segment type 655 v.txBufferAddr := r.txBufferAddr;
659 v.appSsiMaster.sof := '1';
660 v.appSsiMaster.valid := '1';
661 v.appSsiMaster.strb := (others => '1');
662 v.appSsiMaster.dest := (others => '0');
663 v.appSsiMaster.eof := '0';
664 v.appSsiMaster.eofe := '0';
666 v.txSegmentAddr := r.txSegmentAddr + 1;
668 v.appState := DATA_S;
670 -- None data segment type (Go directly to SENT_S) 671 elsif (r.windowArray(conv_integer(r.txBufferAddr)).occupied = '1') then 673 v.txBufferAddr := r.txBufferAddr;
674 v.appState := SENT_S;
678 v.txBufferAddr := r.txBufferAddr;
679 v.appSsiMaster.valid := '0';
680 v.appState := CHECK_BUFFER_S;
682 ---------------------------------------------------------------------- 686 v.txBufferAddr := r.txBufferAddr;
687 v.rxLastSeqN := r.rxLastSeqN;
690 v.appSsiMaster.sof := '0';
691 v.appSsiMaster.strb := (others => '1');
692 v.appSsiMaster.dest := (others => '0');
693 v.appSsiMaster.eof := '0';
694 v.appSsiMaster.eofe := '0';
697 -- Next state condition 698 -- When segment address reaches segment size then go to SENT_S 699 if (r.txSegmentAddr >= r.windowArray(conv_integer(r.txBufferAddr)).segSize) then 701 -- Send EOF at the end of the segment 702 v.appSsiMaster.valid := '1';
703 v.appSsiMaster.eof := '1';
704 v.appSsiMaster.keep := r.windowArray(conv_integer(r.txBufferAddr)).keep;
705 v.appSsiMaster.eofe := '0';
706 v.txSegmentAddr := r.txSegmentAddr;
708 v.appState := SENT_S;
710 -- Increment segment address only when not pausing 712 v.appSsiMaster.valid := '1';
713 v.txSegmentAddr := r.txSegmentAddr + 1;
715 v.appSsiMaster.valid := '0';
716 v.appSsiMaster.eof := '1';
717 v.appState := CHECK_BUFFER_S;
719 v.appSsiMaster.valid := '0';
720 v.txSegmentAddr := r.txSegmentAddr;
722 ---------------------------------------------------------------------- 725 -- Register the sent SeqN (this means that the place has been freed and the SeqN can be Acked) 726 v.rxLastSeqN := r.windowArray(conv_integer(r.txBufferAddr)).seqN;
730 v.txBufferAddr := r.txBufferAddr+1;
-- Increment once 732 v.txBufferAddr := (others => '0');
735 v.windowArray(conv_integer(r.txBufferAddr)).occupied := '0';
-- Release buffer 737 v.txSegmentAddr := (others => '0');
741 -- Init the master no SSI communication 742 v.appSsiMaster := SSI_MASTER_INIT_C;
744 -- Next state immediately 745 v.appState := CHECK_BUFFER_S;
747 ---------------------------------------------------------------------- 752 ---------------------------------------------------------------------- 756 if (rst_i = '1') then 762 --------------------------------------------------------------------- 763 -- Write and read ports 781 -- Transport side SSI output 784 -- Application side SSI output 786 ----------------------------------------------------------- 789 seq :
process (
clk_i)
is 791 if (rising_edge(clk_i)) then 792 r <= rin after TPD_G;
795 --------------------------------------------------------------------- 796 end architecture rtl;
out appSsiMaster_oSsiMasterType
in appSsiSlave_iSsiSlaveType
out wrBuffData_oslv( RSSI_WORD_WIDTH_C* 8- 1 downto 0)
out rxSeqN_oslv( 7 downto 0)
in lastAckN_islv( 7 downto 0)
out chksumLength_opositive
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
in txWindowSize_iinteger range 1 to 2**( WINDOW_ADDR_SIZE_G)
WINDOW_ADDR_SIZE_Gpositive := 7
in rxWindowSize_iinteger range 1 to 2**( WINDOW_ADDR_SIZE_G)
out rxLastSeqN_oslv( 7 downto 0)
in rdBuffData_islv( RSSI_WORD_WIDTH_C* 8- 1 downto 0)
HEADER_CHKSUM_EN_Gboolean := true
out rdBuffAddr_oslv(( SEGMENT_ADDR_SIZE_G+ WINDOW_ADDR_SIZE_G)- 1 downto 0)
AxiStreamSlaveType :=(tReady => '0') AXI_STREAM_SLAVE_INIT_C
out tspSsiSlave_oSsiSlaveType
SEGMENT_ADDR_SIZE_Gpositive := 3
in tspSsiMaster_iSsiMasterType
slv( SSI_TDEST_BITS_C- 1 downto 0) dest
in rxBufferSize_iinteger range 1 to 2**( SEGMENT_ADDR_SIZE_G)
AxiStreamCtrlType :=(pause => '0',overflow => '0',idle => '1') AXI_STREAM_CTRL_UNUSED_C
AxiStreamSlaveType :=(tReady => '1') AXI_STREAM_SLAVE_FORCE_C
out rxParam_oRssiParamType
out rxAckN_oslv( 7 downto 0)
out wrBuffAddr_oslv(( SEGMENT_ADDR_SIZE_G+ WINDOW_ADDR_SIZE_G)- 1 downto 0)