diff --git a/axi/axi-lite/rtl/AxiDualPortRam.vhd b/axi/axi-lite/rtl/AxiDualPortRam.vhd index d0d187d743..c6f1bbbbee 100644 --- a/axi/axi-lite/rtl/AxiDualPortRam.vhd +++ b/axi/axi-lite/rtl/AxiDualPortRam.vhd @@ -23,12 +23,11 @@ use work.StdRtlPkg.all; use work.AxiLitePkg.all; entity AxiDualPortRam is - generic ( TPD_G : time := 1 ns; - BRAM_EN_G : boolean := false; - REG_EN_G : boolean := true; - MODE_G : string := "read-first"; + SYNTH_MODE_G : string := "inferred"; + MEMORY_TYPE_G : string := "block"; + READ_LATENCY_G : natural range 0 to 3 := 2; AXI_WR_EN_G : boolean := true; SYS_WR_EN_G : boolean := false; SYS_BYTE_WR_EN_G : boolean := false; @@ -44,34 +43,32 @@ entity AxiDualPortRam is axiReadSlave : out AxiLiteReadSlaveType; axiWriteMaster : in AxiLiteWriteMasterType; axiWriteSlave : out AxiLiteWriteSlaveType; - -- Standard Port - clk : in sl := '0'; - en : in sl := '1'; - we : in sl := '0'; - weByte : in slv(wordCount(DATA_WIDTH_G, 8)-1 downto 0) := (others => '0'); - rst : in sl := '0'; - addr : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); - din : in slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); - dout : out slv(DATA_WIDTH_G-1 downto 0); - axiWrValid : out sl; - axiWrStrobe : out slv(wordCount(DATA_WIDTH_G, 8)-1 downto 0); - axiWrAddr : out slv(ADDR_WIDTH_G-1 downto 0); - axiWrData : out slv(DATA_WIDTH_G-1 downto 0)); - + clk : in sl := '0'; + en : in sl := '1'; + we : in sl := '0'; + weByte : in slv(wordCount(DATA_WIDTH_G, 8)-1 downto 0) := (others => '0'); + rst : in sl := '0'; + addr : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); + din : in slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); + dout : out slv(DATA_WIDTH_G-1 downto 0); + axiWrValid : out sl; + axiWrStrobe : out slv(wordCount(DATA_WIDTH_G, 8)-1 downto 0); + axiWrAddr : out slv(ADDR_WIDTH_G-1 downto 0); + axiWrData : out slv(DATA_WIDTH_G-1 downto 0)); end entity AxiDualPortRam; architecture rtl of AxiDualPortRam is -- Number of Axi address bits that need to be manually decoded - constant AXI_DEC_BITS_C : integer := ite(DATA_WIDTH_G <= 32, 0, log2((DATA_WIDTH_G-1)/32)); - + constant AXI_DEC_BITS_C : integer := ite(DATA_WIDTH_G <= 32, 0, log2((DATA_WIDTH_G-1)/32)); + constant AXI_DEC_ADDR_HIGH_C : integer := 1+AXI_DEC_BITS_C; constant AXI_DEC_ADDR_LOW_C : integer := 2; subtype AXI_DEC_ADDR_RANGE_C is integer range AXI_DEC_ADDR_HIGH_C downto AXI_DEC_ADDR_LOW_C; - + constant AXI_RAM_ADDR_HIGH_C : integer := ADDR_WIDTH_G+AXI_DEC_ADDR_RANGE_C'high; - constant AXI_RAM_ADDR_LOW_C : integer := AXI_DEC_ADDR_RANGE_C'high+1; + constant AXI_RAM_ADDR_LOW_C : integer := AXI_DEC_ADDR_RANGE_C'high+1; subtype AXI_RAM_ADDR_RANGE_C is integer range AXI_RAM_ADDR_HIGH_C downto AXI_RAM_ADDR_LOW_C; constant ADDR_AXI_WORDS_C : natural := wordCount(DATA_WIDTH_G, 32); @@ -110,111 +107,175 @@ architecture rtl of AxiDualPortRam is signal axiSyncIn : slv(DATA_WIDTH_G + ADDR_WIDTH_G + ADDR_AXI_BYTES_C - 1 downto 0); signal axiSyncOut : slv(DATA_WIDTH_G + ADDR_WIDTH_G + ADDR_AXI_BYTES_C - 1 downto 0); -begin + signal weByteMask : slv(wordCount(DATA_WIDTH_G, 8)-1 downto 0); + signal doutInt : slv(DATA_WIDTH_G-1 downto 0); +begin - -- AXI read only, sys writable or read only (rom) - AXI_R0_SYS_RW : if (not AXI_WR_EN_G and SYS_WR_EN_G) generate - DualPortRam_1 : entity work.DualPortRam + GEN_XPM : if (SYNTH_MODE_G = "xpm") generate + U_RAM : entity work.TrueDualPortRamXpm generic map ( - TPD_G => TPD_G, - BRAM_EN_G => BRAM_EN_G, - REG_EN_G => REG_EN_G, - DOA_REG_G => REG_EN_G, - DOB_REG_G => REG_EN_G, - MODE_G => MODE_G, - BYTE_WR_EN_G => SYS_BYTE_WR_EN_G, - DATA_WIDTH_G => DATA_WIDTH_G, - ADDR_WIDTH_G => ADDR_WIDTH_G, - INIT_G => INIT_G) + TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, + MEMORY_TYPE_G => MEMORY_TYPE_G, + READ_LATENCY_G => READ_LATENCY_G, + DATA_WIDTH_G => DATA_WIDTH_G, + BYTE_WR_EN_G => true, + BYTE_WIDTH_G => 8, + ADDR_WIDTH_G => ADDR_WIDTH_G) port map ( - clka => clk, - ena => en, - wea => we, - weaByte => weByte, - rsta => rst, - addra => addr, - dina => din, - douta => dout, - - clkb => axiClk, - enb => '1', - rstb => '0', - addrb => r.axiAddr, - doutb => axiDout(DATA_WIDTH_G-1 downto 0)); + -- Port A + clka => axiClk, + ena => '1', + wea => r.axiWrStrobe(ADDR_AXI_BYTES_C-1 downto 0), + rsta => '0', + addra => r.axiAddr, + dina => axiWrDataFanout(DATA_WIDTH_G-1 downto 0), + douta => axiDout(DATA_WIDTH_G-1 downto 0), + -- Port B + clkb => clk, + enb => en, + web => weByteMask, + rstb => rst, + addrb => addr, + dinb => din, + doutb => doutInt); end generate; - -- System Read only, Axi writable or read only (ROM) - -- Logic disables axi writes if AXI_WR_EN_G=false - AXI_RW_SYS_RO : if (not SYS_WR_EN_G) generate - DualPortRam_1 : entity work.DualPortRam + GEN_ALTERA : if (SYNTH_MODE_G = "altera_mf") generate + U_RAM : entity work.TrueDualPortRamAlteraMf generic map ( - TPD_G => TPD_G, - BRAM_EN_G => BRAM_EN_G, - REG_EN_G => REG_EN_G, - DOA_REG_G => REG_EN_G, - DOB_REG_G => REG_EN_G, - MODE_G => MODE_G, - BYTE_WR_EN_G => true, - DATA_WIDTH_G => DATA_WIDTH_G, - BYTE_WIDTH_G => 8, - ADDR_WIDTH_G => ADDR_WIDTH_G, - INIT_G => INIT_G) + TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, + MEMORY_TYPE_G => MEMORY_TYPE_G, + READ_LATENCY_G => READ_LATENCY_G, + DATA_WIDTH_G => DATA_WIDTH_G, + BYTE_WR_EN_G => true, + BYTE_WIDTH_G => 8, + ADDR_WIDTH_G => ADDR_WIDTH_G) port map ( - clka => axiClk, - ena => '1', - weaByte => r.axiWrStrobe(ADDR_AXI_BYTES_C-1 downto 0), - rsta => '0', - addra => r.axiAddr, - dina => axiWrDataFanout(DATA_WIDTH_G-1 downto 0), - douta => axiDout(DATA_WIDTH_G-1 downto 0), - clkb => clk, - enb => en, - rstb => rst, - addrb => addr, - doutb => dout); + -- Port A + clka => axiClk, + ena => '1', + wea => r.axiWrStrobe(ADDR_AXI_BYTES_C-1 downto 0), + rsta => '0', + addra => r.axiAddr, + dina => axiWrDataFanout(DATA_WIDTH_G-1 downto 0), + douta => axiDout(DATA_WIDTH_G-1 downto 0), + -- Port B + clkb => clk, + enb => en, + web => weByteMask, + rstb => rst, + addrb => addr, + dinb => din, + doutb => doutInt); end generate; --- -- Both sides writable, true dual port ram - AXI_RW_SYS_RW : if (AXI_WR_EN_G and SYS_WR_EN_G) generate - U_TrueDualPortRam_1 : entity work.TrueDualPortRam - generic map ( - TPD_G => TPD_G, - MODE_G => MODE_G, - BYTE_WR_EN_G => true, - DOA_REG_G => REG_EN_G, - DOB_REG_G => REG_EN_G, - DATA_WIDTH_G => DATA_WIDTH_G, - BYTE_WIDTH_G => 8, - ADDR_WIDTH_G => ADDR_WIDTH_G, - INIT_G => INIT_G) - port map ( - clka => axiClk, -- [in] - ena => '1', -- [in] - wea => '1', - weaByte => r.axiWrStrobe(ADDR_AXI_BYTES_C-1 downto 0), - rsta => '0', -- [in] - addra => r.axiAddr, -- [in] - dina => axiWrDataFanout(DATA_WIDTH_G-1 downto 0), -- [in] - douta => axiDout(DATA_WIDTH_G-1 downto 0), -- [out] - clkb => clk, -- [in] - enb => en, -- [in] - web => we, -- [in] - webByte => weByte, -- [in] - rstb => rst, -- [in] - addrb => addr, -- [in] - dinb => din, -- [in] - doutb => dout); -- [out] - + GEN_INFERRED : if (SYNTH_MODE_G = "inferred") generate + + -- AXI read only, sys writable or read only (rom) + AXI_R0_SYS_RW : if (not AXI_WR_EN_G and SYS_WR_EN_G) generate + DualPortRam_1 : entity work.DualPortRam + generic map ( + TPD_G => TPD_G, + BRAM_EN_G => ite(MEMORY_TYPE_G = "block", true, false), + REG_EN_G => ite(READ_LATENCY_G >= 1, true, false), + DOA_REG_G => ite(READ_LATENCY_G >= 2, true, false), + DOB_REG_G => ite(READ_LATENCY_G >= 2, true, false), + BYTE_WR_EN_G => SYS_BYTE_WR_EN_G, + DATA_WIDTH_G => DATA_WIDTH_G, + ADDR_WIDTH_G => ADDR_WIDTH_G, + INIT_G => INIT_G) + port map ( + clka => clk, + ena => en, + wea => we, + weaByte => weByte, + rsta => rst, + addra => addr, + dina => din, + douta => doutInt, + + clkb => axiClk, + enb => '1', + rstb => '0', + addrb => r.axiAddr, + doutb => axiDout(DATA_WIDTH_G-1 downto 0)); + end generate; + + -- System Read only, Axi writable or read only (ROM) + -- Logic disables axi writes if AXI_WR_EN_G=false + AXI_RW_SYS_RO : if (not SYS_WR_EN_G) generate + DualPortRam_1 : entity work.DualPortRam + generic map ( + TPD_G => TPD_G, + BRAM_EN_G => ite(MEMORY_TYPE_G = "block", true, false), + REG_EN_G => ite(READ_LATENCY_G >= 1, true, false), + DOA_REG_G => ite(READ_LATENCY_G >= 2, true, false), + DOB_REG_G => ite(READ_LATENCY_G >= 2, true, false), + BYTE_WR_EN_G => true, + DATA_WIDTH_G => DATA_WIDTH_G, + BYTE_WIDTH_G => 8, + ADDR_WIDTH_G => ADDR_WIDTH_G, + INIT_G => INIT_G) + port map ( + clka => axiClk, + ena => '1', + weaByte => r.axiWrStrobe(ADDR_AXI_BYTES_C-1 downto 0), + rsta => '0', + addra => r.axiAddr, + dina => axiWrDataFanout(DATA_WIDTH_G-1 downto 0), + douta => axiDout(DATA_WIDTH_G-1 downto 0), + clkb => clk, + enb => en, + rstb => rst, + addrb => addr, + doutb => doutInt); + end generate; + + -- Both sides writable, true dual port ram + AXI_RW_SYS_RW : if (AXI_WR_EN_G and SYS_WR_EN_G) generate + U_TrueDualPortRam_1 : entity work.TrueDualPortRam + generic map ( + TPD_G => TPD_G, + BYTE_WR_EN_G => true, + DOA_REG_G => ite(READ_LATENCY_G >= 2, true, false), + DOB_REG_G => ite(READ_LATENCY_G >= 2, true, false), + DATA_WIDTH_G => DATA_WIDTH_G, + BYTE_WIDTH_G => 8, + ADDR_WIDTH_G => ADDR_WIDTH_G, + INIT_G => INIT_G) + port map ( + clka => axiClk, -- [in] + ena => '1', -- [in] + wea => '1', + weaByte => r.axiWrStrobe(ADDR_AXI_BYTES_C-1 downto 0), + rsta => '0', -- [in] + addra => r.axiAddr, -- [in] + dina => axiWrDataFanout(DATA_WIDTH_G-1 downto 0), -- [in] + douta => axiDout(DATA_WIDTH_G-1 downto 0), -- [out] + clkb => clk, -- [in] + enb => en, -- [in] + web => we, -- [in] + webByte => weByte, -- [in] + rstb => rst, -- [in] + addrb => addr, -- [in] + dinb => din, -- [in] + doutb => doutInt); -- [out] + + end generate; + end generate; - axiSyncIn(DATA_WIDTH_G-1 downto 0) - <= axiWrDataFanout(DATA_WIDTH_G-1 downto 0); - axiSyncIn(ADDR_WIDTH_G+DATA_WIDTH_G-1 downto DATA_WIDTH_G) - <= r.axiAddr; + weByteMask <= (others => '0') when(not SYS_WR_EN_G) else weByte when(SYS_BYTE_WR_EN_G) else (others => we); + + axiSyncIn(DATA_WIDTH_G-1 downto 0) <= axiWrDataFanout(DATA_WIDTH_G-1 downto 0); + axiSyncIn(ADDR_WIDTH_G+DATA_WIDTH_G-1 downto DATA_WIDTH_G) <= r.axiAddr; axiSyncIn(ADDR_WIDTH_G+DATA_WIDTH_G+ADDR_AXI_BYTES_C-1 downto ADDR_WIDTH_G+DATA_WIDTH_G) <= r.axiWrStrobe(ADDR_AXI_BYTES_C-1 downto 0); axiSyncWrEn <= uOr(r.axiWrStrobe(ADDR_AXI_BYTES_C-1 downto 0)); + U_SynchronizerFifo_1 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, @@ -235,7 +296,6 @@ begin axiWrAddr <= axiSyncOut(ADDR_WIDTH_G+DATA_WIDTH_G-1 downto DATA_WIDTH_G); axiWrStrobe <= axiSyncOut(ADDR_WIDTH_G+DATA_WIDTH_G+ADDR_AXI_BYTES_C-1 downto ADDR_WIDTH_G+DATA_WIDTH_G); - axiWrMap : for i in 0 to ADDR_AXI_WORDS_C-1 generate axiWrDataFanout((i+1)*32-1 downto i*32) <= axiWriteMaster.wdata; end generate axiWrMap; @@ -273,7 +333,7 @@ begin -- Check for write transaction if (axiStatus.writeEnable = '1') then if (AXI_WR_EN_G) then - v.axiAddr := axiWriteMaster.awaddr(AXI_RAM_ADDR_HIGH_C downto AXI_RAM_ADDR_LOW_C); + v.axiAddr := axiWriteMaster.awaddr(AXI_RAM_ADDR_HIGH_C downto AXI_RAM_ADDR_LOW_C); if (DATA_WIDTH_G <= 32) then decAddrInt := conv_integer(axiWriteMaster.awaddr(AXI_RAM_ADDR_LOW_C-1 downto 0)); else @@ -286,19 +346,8 @@ begin elsif (axiStatus.readEnable = '1') then -- Set the address bus v.axiAddr := axiReadMaster.araddr(AXI_RAM_ADDR_HIGH_C downto AXI_RAM_ADDR_LOW_C); - -- Check for registered BRAM - if (BRAM_EN_G = true) and (REG_EN_G = true) then - v.rdLatecy := 3; -- read in 3 cycles - -- Check for non-registered BRAM - elsif (BRAM_EN_G = true) and (REG_EN_G = false) then - v.rdLatecy := 2; -- read in 2 cycles - -- Check for registered LUTRAM - elsif (BRAM_EN_G = false) and (REG_EN_G = true) then - v.rdLatecy := 2; -- read in 2 cycles - -- Else non-registered LUTRAM - else - v.rdLatecy := 1; -- read on next cycle - end if; + -- Arm the wait + v.rdLatecy := 4; -- Next state v.state := RD_S; end if; @@ -337,4 +386,21 @@ begin end if; end process seq; + OUT_REG : if((READ_LATENCY_G = 3) AND (SYNTH_MODE_G /= "xpm")) generate + REG : process (clk) is + begin + if(rising_edge(clk)) then + if (rst = '1') then + dout <= (others => '0'); + else + dout <= doutInt; + end if; + end if; + end process REG; + end generate OUT_REG; + + NO_OUT_REG : if ((READ_LATENCY_G <= 2) OR (SYNTH_MODE_G = "xpm")) generate + dout <= doutInt; + end generate NO_OUT_REG; + end architecture rtl; diff --git a/axi/axi-lite/tb/AxiLiteAsyncTb.vhd b/axi/axi-lite/tb/AxiLiteAsyncTb.vhd index 9f2048daa2..8dd2de6843 100644 --- a/axi/axi-lite/tb/AxiLiteAsyncTb.vhd +++ b/axi/axi-lite/tb/AxiLiteAsyncTb.vhd @@ -101,9 +101,6 @@ begin U_AxiDualPortRam_1 : entity work.AxiDualPortRam generic map ( TPD_G => TPD_G, - BRAM_EN_G => true, - REG_EN_G => true, --- MODE_G => MODE_G, AXI_WR_EN_G => true, SYS_WR_EN_G => false, SYS_BYTE_WR_EN_G => false, diff --git a/axi/axi-lite/tb/AxiLiteWriteFilterTb.vhd b/axi/axi-lite/tb/AxiLiteWriteFilterTb.vhd index 371b65c98c..d8e432a72e 100644 --- a/axi/axi-lite/tb/AxiLiteWriteFilterTb.vhd +++ b/axi/axi-lite/tb/AxiLiteWriteFilterTb.vhd @@ -131,8 +131,6 @@ begin U_Mem : entity work.AxiDualPortRam generic map ( TPD_G => TPD_G, - BRAM_EN_G => true, - REG_EN_G => true, AXI_WR_EN_G => true, SYS_WR_EN_G => false, COMMON_CLK_G => false, diff --git a/axi/dma/rtl/AxiStreamDmaRingWrite.vhd b/axi/dma/rtl/AxiStreamDmaRingWrite.vhd index 0192bd44a8..dc1094559a 100644 --- a/axi/dma/rtl/AxiStreamDmaRingWrite.vhd +++ b/axi/dma/rtl/AxiStreamDmaRingWrite.vhd @@ -257,8 +257,9 @@ begin U_AxiDualPortRam_Start : entity work.AxiDualPortRam generic map ( TPD_G => TPD_G, - BRAM_EN_G => false, - REG_EN_G => false, + SYNTH_MODE_G => "inferred", + MEMORY_TYPE_G=> "distributed", + READ_LATENCY_G => 0, AXI_WR_EN_G => true, SYS_WR_EN_G => false, ADDR_WIDTH_G => RAM_ADDR_WIDTH_C, @@ -279,8 +280,9 @@ begin U_AxiDualPortRam_End : entity work.AxiDualPortRam generic map ( TPD_G => TPD_G, - BRAM_EN_G => false, - REG_EN_G => false, + SYNTH_MODE_G => "inferred", + MEMORY_TYPE_G=> "distributed", + READ_LATENCY_G => 0, AXI_WR_EN_G => true, SYS_WR_EN_G => false, ADDR_WIDTH_G => RAM_ADDR_WIDTH_C, @@ -302,8 +304,9 @@ begin U_AxiDualPortRam_Next : entity work.AxiDualPortRam generic map ( TPD_G => TPD_G, - BRAM_EN_G => false, - REG_EN_G => false, + SYNTH_MODE_G => "inferred", + MEMORY_TYPE_G=> "distributed", + READ_LATENCY_G => 0, AXI_WR_EN_G => false, SYS_WR_EN_G => true, ADDR_WIDTH_G => RAM_ADDR_WIDTH_C, @@ -325,8 +328,9 @@ begin U_AxiDualPortRam_Trigger : entity work.AxiDualPortRam generic map ( TPD_G => TPD_G, - BRAM_EN_G => false, - REG_EN_G => false, + SYNTH_MODE_G => "inferred", + MEMORY_TYPE_G=> "distributed", + READ_LATENCY_G => 0, AXI_WR_EN_G => false, SYS_WR_EN_G => true, ADDR_WIDTH_G => RAM_ADDR_WIDTH_C, @@ -349,8 +353,9 @@ begin U_AxiDualPortRam_Mode : entity work.AxiDualPortRam generic map ( TPD_G => TPD_G, - BRAM_EN_G => false, - REG_EN_G => false, + SYNTH_MODE_G => "inferred", + MEMORY_TYPE_G=> "distributed", + READ_LATENCY_G => 0, AXI_WR_EN_G => true, SYS_WR_EN_G => false, COMMON_CLK_G => false, @@ -375,8 +380,9 @@ begin U_AxiDualPortRam_Status : entity work.AxiDualPortRam generic map ( TPD_G => TPD_G, - BRAM_EN_G => false, - REG_EN_G => false, + SYNTH_MODE_G => "inferred", + MEMORY_TYPE_G=> "distributed", + READ_LATENCY_G => 0, AXI_WR_EN_G => false, SYS_WR_EN_G => true, ADDR_WIDTH_G => RAM_ADDR_WIDTH_C, diff --git a/axi/dma/rtl/AxiStreamDmaV2Desc.vhd b/axi/dma/rtl/AxiStreamDmaV2Desc.vhd index 510efc61f2..59ba3596dd 100644 --- a/axi/dma/rtl/AxiStreamDmaV2Desc.vhd +++ b/axi/dma/rtl/AxiStreamDmaV2Desc.vhd @@ -361,8 +361,6 @@ begin U_AddrRam : entity work.AxiDualPortRam generic map ( TPD_G => TPD_G, - REG_EN_G => true, - BRAM_EN_G => true, COMMON_CLK_G => true, ADDR_WIDTH_G => DESC_AWIDTH_G, DATA_WIDTH_G => 32) diff --git a/axi/dma/rtl/AxiStreamDmaWrite.vhd b/axi/dma/rtl/AxiStreamDmaWrite.vhd index 7dc11aefb6..5aad36f51c 100644 --- a/axi/dma/rtl/AxiStreamDmaWrite.vhd +++ b/axi/dma/rtl/AxiStreamDmaWrite.vhd @@ -33,6 +33,7 @@ entity AxiStreamDmaWrite is AXI_CONFIG_G : AxiConfigType := AXI_CONFIG_INIT_C; AXI_BURST_G : slv(1 downto 0) := "01"; AXI_CACHE_G : slv(3 downto 0) := "1111"; + BURST_BYTES_G : positive range 1 to 4096 := 4096; SW_CACHE_EN_G : boolean := false; ACK_WAIT_BVALID_G : boolean := true; PIPE_STAGES_G : natural := 1; @@ -68,7 +69,7 @@ architecture rtl of AxiStreamDmaWrite is constant DATA_BYTES_C : integer := LOC_AXIS_CONFIG_C.TDATA_BYTES_C; constant ADDR_LSB_C : integer := bitSize(DATA_BYTES_C-1); - constant AWLEN_C : slv(7 downto 0) := getAxiLen(AXI_CONFIG_G, 4096); + constant AWLEN_C : slv(7 downto 0) := getAxiLen(AXI_CONFIG_G, BURST_BYTES_G); constant FIFO_ADDR_WIDTH_C : natural := ite((AXI_CONFIG_G.LEN_BITS_C<3),4,(AXI_CONFIG_G.LEN_BITS_C+1)); type StateType is ( diff --git a/axi/simlink/src/RogueTcpMemory.c b/axi/simlink/src/RogueTcpMemory.c index 4f242715df..53d4b3fa68 100755 --- a/axi/simlink/src/RogueTcpMemory.c +++ b/axi/simlink/src/RogueTcpMemory.c @@ -259,9 +259,9 @@ void RogueTcpMemoryUpdate ( void *userPtr ) { if ( getInt(s_reset) == 1 ) { data->state = ST_IDLE; setInt(s_arvalid,0); - setInt(s_rready,0); + setInt(s_rready,1); setInt(s_awvalid,0); - setInt(s_bready,0); + setInt(s_bready,1); } // Data movement @@ -306,7 +306,7 @@ void RogueTcpMemoryUpdate ( void *userPtr ) { setInt(s_araddr,(data->addr+data->curr)); setInt(s_arprot,0); setInt(s_arvalid,1); - setInt(s_arready,0); + setInt(s_rready,1); data->state = ST_RADDR; } break; @@ -318,7 +318,7 @@ void RogueTcpMemoryUpdate ( void *userPtr ) { if ( getInt(s_wready) ) setInt(s_wvalid,0); if ( getInt(s_bvalid) ) { - setInt(s_bready,0); + //setInt(s_bready,0); data->result = getInt(s_bresp); if (data->curr == data->size) { @@ -348,7 +348,7 @@ void RogueTcpMemoryUpdate ( void *userPtr ) { data->data[data->curr++] = (data32 >> 16) & 0xFF; data->data[data->curr++] = (data32 >> 24) & 0xFF; - setInt(s_rready,0); + //setInt(s_rready,0); if (data->curr == data->size) { RogueTcpMemorySend(data,portData); // state goes to idle @@ -357,10 +357,12 @@ void RogueTcpMemoryUpdate ( void *userPtr ) { } break; - // One clock idle + // Wait for RVALID and BVALID to fall case ST_PAUSE: - data->state = ST_START; - break; + if ( getInt(s_rvalid) == 0 && getInt(s_bvalid) == 0 ) { + data->state = ST_START; + break; + } } } } diff --git a/base/fifo/ruckus.tcl b/base/fifo/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/base/fifo/ruckus.tcl +++ b/base/fifo/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/base/general/ruckus.tcl b/base/general/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/base/general/ruckus.tcl +++ b/base/general/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/base/ram/xilinx/SimpleDualPortRamAlteraMfDummy.vhd b/base/ram/xilinx/SimpleDualPortRamAlteraMfDummy.vhd index 0375fd9b9b..c8f0d8d248 100644 --- a/base/ram/xilinx/SimpleDualPortRamAlteraMfDummy.vhd +++ b/base/ram/xilinx/SimpleDualPortRamAlteraMfDummy.vhd @@ -26,7 +26,7 @@ entity SimpleDualPortRamAlteraMf is COMMON_CLK_G : boolean := false; RST_POLARITY_G : sl := '1'; -- '1' for active high rst, '0' for active low MEMORY_TYPE_G : string := "block"; - READ_LATENCY_G : natural range 0 to 2 := 1; + READ_LATENCY_G : natural range 0 to 100 := 1; DATA_WIDTH_G : integer range 1 to (2**24) := 16; BYTE_WR_EN_G : boolean := false; BYTE_WIDTH_G : integer range 8 to 9 := 8; -- If BRAM, should be multiple or 8 or 9 diff --git a/base/ram/xilinx/SimpleDualPortRamXpm.vhd b/base/ram/xilinx/SimpleDualPortRamXpm.vhd index 92d89423be..f115b60065 100644 --- a/base/ram/xilinx/SimpleDualPortRamXpm.vhd +++ b/base/ram/xilinx/SimpleDualPortRamXpm.vhd @@ -2,7 +2,7 @@ -- File : SimpleDualPortRamXpm.vhd -- Company : SLAC National Accelerator Laboratory ------------------------------------------------------------------------------- --- Description: Wrapper for XPM Simple Dual Port RAM +-- Description: Wrapper for XPM True Dual Port RAM ------------------------------------------------------------------------------- -- This file is part of 'SLAC Firmware Standard Library'. -- It is subject to the license terms in the LICENSE.txt file found in the @@ -29,7 +29,7 @@ entity SimpleDualPortRamXpm is COMMON_CLK_G : boolean := false; RST_POLARITY_G : sl := '1'; -- '1' for active high rst, '0' for active low MEMORY_TYPE_G : string := "block"; - READ_LATENCY_G : natural range 0 to 2 := 1; + READ_LATENCY_G : natural range 0 to 100 := 1; DATA_WIDTH_G : integer range 1 to (2**24) := 16; BYTE_WR_EN_G : boolean := false; BYTE_WIDTH_G : integer range 8 to 9 := 8; -- If BRAM, should be multiple or 8 or 9 @@ -74,7 +74,7 @@ begin USE_MEM_INIT => 1, -- Default value = 1 WAKEUP_TIME => "disable_sleep", -- "disable_sleep" to disable dynamic power saving option WRITE_DATA_WIDTH_A => DATA_WIDTH_G, - WRITE_MODE_B => ite(READ_LATENCY_G = 0, "read_first", "no_change")) -- Default value = no_change + WRITE_MODE_B => ite(READ_LATENCY_G = 0, "read_first", ite(MEMORY_TYPE_G="block","no_change","read_first"))) -- Default value = no_change port map ( -- Write Interface ena => ena, diff --git a/base/ram/xilinx/TrueDualPortRamXpm.vhd b/base/ram/xilinx/TrueDualPortRamXpm.vhd new file mode 100644 index 0000000000..5f32f4ac58 --- /dev/null +++ b/base/ram/xilinx/TrueDualPortRamXpm.vhd @@ -0,0 +1,122 @@ +------------------------------------------------------------------------------- +-- File : TrueDualPortRamXpm.vhd +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: Wrapper for XPM True Dual Port RAM +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +use work.StdRtlPkg.all; + +library xpm; +use xpm.vcomponents.all; + +entity TrueDualPortRamXpm is + generic ( + TPD_G : time := 1 ns; + COMMON_CLK_G : boolean := false; + RST_POLARITY_G : sl := '1'; -- '1' for active high rst, '0' for active low + MEMORY_TYPE_G : string := "block"; + READ_LATENCY_G : natural range 0 to 100 := 1; + DATA_WIDTH_G : integer range 1 to (2**24) := 16; + BYTE_WR_EN_G : boolean := false; + BYTE_WIDTH_G : integer range 8 to 9 := 8; -- If BRAM, should be multiple or 8 or 9 + ADDR_WIDTH_G : integer range 1 to (2**24) := 4); + port ( + -- Port A + clka : in sl := '0'; + ena : in sl := '1'; + wea : in slv(ite(BYTE_WR_EN_G, wordCount(DATA_WIDTH_G, BYTE_WIDTH_G), 1)-1 downto 0) := (others => '0'); + regcea : in sl := '1'; + rsta : in sl := not(RST_POLARITY_G); + addra : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); + dina : in slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); + douta : out slv(DATA_WIDTH_G-1 downto 0); + -- Port B + clkb : in sl := '0'; + enb : in sl := '1'; + web : in slv(ite(BYTE_WR_EN_G, wordCount(DATA_WIDTH_G, BYTE_WIDTH_G), 1)-1 downto 0) := (others => '0'); + regceb : in sl := '1'; + rstb : in sl := not(RST_POLARITY_G); + addrb : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); + dinb : in slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); + doutb : out slv(DATA_WIDTH_G-1 downto 0) := (others => '0')); +end TrueDualPortRamXpm; + +architecture rtl of TrueDualPortRamXpm is + + signal resetA : sl; + signal resetB : sl; + +begin + + U_RAM : xpm_memory_tdpram + generic map ( + ADDR_WIDTH_A => ADDR_WIDTH_G, + ADDR_WIDTH_B => ADDR_WIDTH_G, + AUTO_SLEEP_TIME => 0, -- 0 - Disable auto-sleep feature + BYTE_WRITE_WIDTH_A => ite(BYTE_WR_EN_G, BYTE_WIDTH_G, DATA_WIDTH_G), + BYTE_WRITE_WIDTH_B => ite(BYTE_WR_EN_G, BYTE_WIDTH_G, DATA_WIDTH_G), + CLOCKING_MODE => ite(COMMON_CLK_G, "common_clock", "independent_clock"), + ECC_MODE => "no_ecc", -- Default value = no_ecc + MEMORY_OPTIMIZATION => "true", -- Default value = true + MEMORY_PRIMITIVE => MEMORY_TYPE_G, + MEMORY_SIZE => (DATA_WIDTH_G*(2**ADDR_WIDTH_G)), + MESSAGE_CONTROL => 0, -- Default value = 0 + READ_DATA_WIDTH_A => DATA_WIDTH_G, + READ_DATA_WIDTH_B => DATA_WIDTH_G, + READ_LATENCY_A => READ_LATENCY_G, + READ_LATENCY_B => READ_LATENCY_G, + USE_EMBEDDED_CONSTRAINT => 0, -- Default value = 0 + USE_MEM_INIT => 1, -- Default value = 1 + WAKEUP_TIME => "disable_sleep", -- "disable_sleep" to disable dynamic power saving option + WRITE_DATA_WIDTH_A => DATA_WIDTH_G, + WRITE_DATA_WIDTH_B => DATA_WIDTH_G, + WRITE_MODE_A => ite(READ_LATENCY_G = 0, "read_first", "no_change"), -- Default value = no_change + WRITE_MODE_B => ite(READ_LATENCY_G = 0, "read_first", "no_change")) -- Default value = no_change + port map ( + -- Port A + clka => clka, + ena => ena, + wea => wea, + regcea => regcea, + rsta => resetA, + addra => addra, + dina => dina, + douta => douta, + -- Port B + clkb => clkb, + enb => enb, + web => web, + regceb => regceb, + rstb => resetB, + addrb => addrb, + dinb => dinb, + doutb => doutb, + -- Misc.Interface + dbiterra => open, + dbiterrb => open, + sbiterra => open, + sbiterrb => open, + injectdbiterra => '0', + injectdbiterrb => '0', + injectsbiterra => '0', + injectsbiterrb => '0', + sleep => '0'); + + resetA <= rsta when(RST_POLARITY_G = '1') else not(rsta); + resetB <= rstb when(RST_POLARITY_G = '1') else not(rstb); + +end rtl; diff --git a/base/ram/xilinx/TrueDualPortRamXpmAlteraMfDummy.vhd b/base/ram/xilinx/TrueDualPortRamXpmAlteraMfDummy.vhd new file mode 100644 index 0000000000..60ce25b5a2 --- /dev/null +++ b/base/ram/xilinx/TrueDualPortRamXpmAlteraMfDummy.vhd @@ -0,0 +1,59 @@ +------------------------------------------------------------------------------- +-- File : TrueDualPortRamXpmAlteraMfDummy.vhd +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: Wrapper for XPM Simple Dual Port RAM +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +use work.StdRtlPkg.all; + +entity TrueDualPortRamAlteraMf is + generic ( + TPD_G : time := 1 ns; + COMMON_CLK_G : boolean := false; + RST_POLARITY_G : sl := '1'; -- '1' for active high rst, '0' for active low + MEMORY_TYPE_G : string := "block"; + READ_LATENCY_G : natural range 0 to 100 := 1; + DATA_WIDTH_G : integer range 1 to (2**24) := 16; + BYTE_WR_EN_G : boolean := false; + BYTE_WIDTH_G : integer range 8 to 9 := 8; -- If BRAM, should be multiple or 8 or 9 + ADDR_WIDTH_G : integer range 1 to (2**24) := 4); + port ( + -- Port A + clka : in sl := '0'; + ena : in sl := '1'; + wea : in slv(ite(BYTE_WR_EN_G, wordCount(DATA_WIDTH_G, BYTE_WIDTH_G), 1)-1 downto 0) := (others => '0'); + regcea : in sl := '1'; + rsta : in sl := not(RST_POLARITY_G); + addra : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); + dina : in slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); + douta : out slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); + -- Port B + clkb : in sl := '0'; + enb : in sl := '1'; + web : in slv(ite(BYTE_WR_EN_G, wordCount(DATA_WIDTH_G, BYTE_WIDTH_G), 1)-1 downto 0) := (others => '0'); + regceb : in sl := '1'; + rstb : in sl := not(RST_POLARITY_G); + addrb : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0'); + dinb : in slv(DATA_WIDTH_G-1 downto 0) := (others => '0'); + doutb : out slv(DATA_WIDTH_G-1 downto 0) := (others => '0')); +end TrueDualPortRamAlteraMf; + +architecture rtl of TrueDualPortRamAlteraMf is + +begin + +end rtl; diff --git a/base/sync/ruckus.tcl b/base/sync/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/base/sync/ruckus.tcl +++ b/base/sync/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/devices/AnalogDevices/ad5780/ruckus.tcl b/devices/AnalogDevices/ad5780/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/AnalogDevices/ad5780/ruckus.tcl +++ b/devices/AnalogDevices/ad5780/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/devices/AnalogDevices/ad9467/ruckus.tcl b/devices/AnalogDevices/ad9467/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/AnalogDevices/ad9467/ruckus.tcl +++ b/devices/AnalogDevices/ad9467/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/devices/AnalogDevices/general/ruckus.tcl b/devices/AnalogDevices/general/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/AnalogDevices/general/ruckus.tcl +++ b/devices/AnalogDevices/general/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/devices/Linear/lct2270/ruckus.tcl b/devices/Linear/lct2270/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/Linear/lct2270/ruckus.tcl +++ b/devices/Linear/lct2270/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/devices/Microchip/sy56040/ruckus.tcl b/devices/Microchip/sy56040/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/Microchip/sy56040/ruckus.tcl +++ b/devices/Microchip/sy56040/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/devices/Micron/ddr3/ruckus.tcl b/devices/Micron/ddr3/ruckus.tcl index 9948281464..61b69b80db 100644 --- a/devices/Micron/ddr3/ruckus.tcl +++ b/devices/Micron/ddr3/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load target's source code and constraints -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" # Vivado Verilog bug fix (https://jira.slac.stanford.edu/browse/ESCORE-261) set_property USED_IN {implementation} [get_files {ddr3.v}] diff --git a/devices/Micron/ddr4/ruckus.tcl b/devices/Micron/ddr4/ruckus.tcl index 0cd36c05c5..7c38b21431 100644 --- a/devices/Micron/ddr4/ruckus.tcl +++ b/devices/Micron/ddr4/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load target's source code and constraints -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" # Set the top-level DDR module as Verilog set_property FILE_TYPE {Verilog Header} [get_files {arch_defines.v}] diff --git a/devices/Micron/mt28ew/ruckus.tcl b/devices/Micron/mt28ew/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/Micron/mt28ew/ruckus.tcl +++ b/devices/Micron/mt28ew/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/devices/Micron/n25q/ruckus.tcl b/devices/Micron/n25q/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/Micron/n25q/ruckus.tcl +++ b/devices/Micron/n25q/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/devices/Micron/p30/ruckus.tcl b/devices/Micron/p30/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/Micron/p30/ruckus.tcl +++ b/devices/Micron/p30/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/devices/Ti/adc32rf45/ruckus.tcl b/devices/Ti/adc32rf45/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/Ti/adc32rf45/ruckus.tcl +++ b/devices/Ti/adc32rf45/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/devices/Ti/ads42lb69/ruckus.tcl b/devices/Ti/ads42lb69/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/Ti/ads42lb69/ruckus.tcl +++ b/devices/Ti/ads42lb69/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/devices/Ti/ads54j60/ruckus.tcl b/devices/Ti/ads54j60/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/Ti/ads54j60/ruckus.tcl +++ b/devices/Ti/ads54j60/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/devices/Ti/dac7654/ruckus.tcl b/devices/Ti/dac7654/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/Ti/dac7654/ruckus.tcl +++ b/devices/Ti/dac7654/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/devices/Xilinx/xcf128/ruckus.tcl b/devices/Xilinx/xcf128/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/devices/Xilinx/xcf128/ruckus.tcl +++ b/devices/Xilinx/xcf128/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/dsp/fixed/BoxcarIntegrator.vhd b/dsp/fixed/BoxcarIntegrator.vhd index 8c1140a1d5..3042e7e87c 100644 --- a/dsp/fixed/BoxcarIntegrator.vhd +++ b/dsp/fixed/BoxcarIntegrator.vhd @@ -35,6 +35,7 @@ entity BoxcarIntegrator is ibData : in slv(DATA_WIDTH_G-1 downto 0); -- Outbound Interface obValid : out sl; + obAck : in sl := '1'; obData : out slv(DATA_WIDTH_G+ADDR_WIDTH_G-1 downto 0); obFull : out sl; obPeriod : out sl); @@ -94,14 +95,17 @@ begin doutb => ramDout); - comb : process (ibData, ibValid, r, ramDout, rst, intCount) is + comb : process (ibData, ibValid, r, ramDout, rst, intCount, obAck) is variable v : RegType; begin -- Latch the current value v := r; - -- Clear period signal - v.obPeriod := '0'; + -- Clear the output valid and period latches + if obAck = '1' then + v.obValid := '0'; + v.obPeriod := '0'; + end if; -- Input stage, setup addresses v.ibData := ibData; @@ -138,10 +142,11 @@ begin if r.obFull = '1' then v.obData := v.obData - resize(ramDout, ACCUM_WIDTH_C); end if; - end if; - -- Output registers - v.obValid := r.ibValid; + -- Output valid latch + v.obValid := '1'; + + end if; -- Outputs obValid <= r.obValid; diff --git a/ethernet/EthMacCore/rtl/EthMacTxExportXgmii.vhd b/ethernet/EthMacCore/rtl/EthMacTxExportXgmii.vhd index b88ad12c0e..2a49b06e7b 100644 --- a/ethernet/EthMacCore/rtl/EthMacTxExportXgmii.vhd +++ b/ethernet/EthMacCore/rtl/EthMacTxExportXgmii.vhd @@ -200,15 +200,15 @@ begin -- Inter frame gap if stateCountRst = '1' then - stateCount <= (others => '0'); + stateCount <= (others => '0') after TPD_G; else - stateCount <= stateCount + 1; + stateCount <= stateCount + 1 after TPD_G; end if; if stateCountRst = '1' then - exportWordCnt <= (others => '0'); + exportWordCnt <= (others => '0') after TPD_G; elsif intAdvance = '1' and intRunt = '1' then - exportWordCnt <= exportWordCnt + 1; + exportWordCnt <= exportWordCnt + 1 after TPD_G; end if; end if; @@ -217,12 +217,24 @@ begin -- Pad runt frames intRunt <= not exportWordCnt(3); - intLastValidByte <= "111" when curState = ST_PAD_C else onesCount(macMaster.tKeep(7 downto 1)); - + process (curState, intLastLine, macMaster) + begin + if (curState = ST_PAD_C) then + if intLastLine = '0' then + intLastValidByte <= "111"; + else + -- "work around" for a Xilinx IP core bug fix??? + intLastValidByte <= "000"; + end if; + else + intLastValidByte <= onesCount(macMaster.tKeep(7 downto 1)); + end if; + end process; + -- State machine process (curState, ethRst, intError, intRunt, macMaster, phyReady, stateCount) begin - + -- Init txCountEn <= '0'; txUnderRun <= '0'; diff --git a/ethernet/EthMacCore/ruckus.tcl b/ethernet/EthMacCore/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/ethernet/EthMacCore/ruckus.tcl +++ b/ethernet/EthMacCore/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/ethernet/EthMacCore/tb/EthMacTb.vhd b/ethernet/EthMacCore/tb/EthMacTb.vhd index a3a0ae0fc6..7d8a653f45 100644 --- a/ethernet/EthMacCore/tb/EthMacTb.vhd +++ b/ethernet/EthMacCore/tb/EthMacTb.vhd @@ -31,195 +31,261 @@ end EthMacTb; architecture testbed of EthMacTb is - constant CLK_PERIOD_C : time := 6.4 ns; + constant CLK_PERIOD_C : time := 10 ns; constant TPD_G : time := (CLK_PERIOD_C/4); - constant MAC_ADDR_C : Slv48Array(1 downto 0) := (0 => x"010300564400", 1 => x"020300564400"); - constant IP_ADDR_C : Slv32Array(1 downto 0) := (0 => x"0A02A8C0", 1 => x"0B02A8C0"); - - signal clk : sl := '0'; - signal rst : sl := '0'; - signal txMaster : AxiStreamMasterType; - signal txSlave : AxiStreamSlaveType; - signal obMacMasters : AxiStreamMasterArray(1 downto 0); - signal obMacSlaves : AxiStreamSlaveArray(1 downto 0); - signal ibMacMasters : AxiStreamMasterArray(1 downto 0); - signal ibMacSlaves : AxiStreamSlaveArray(1 downto 0); - signal ethConfig : EthMacConfigArray(1 downto 0) := (others => ETH_MAC_CONFIG_INIT_C); - signal phyD : Slv64Array(1 downto 0); - signal phyC : Slv8Array(1 downto 0); - signal rxMaster : AxiStreamMasterType; - signal rxSlave : AxiStreamSlaveType; - signal phyReady : sl; - signal errorDet : sl; + constant AXIS_CONFIG_C : AxiStreamConfigType := ssiAxiStreamConfig(1); -- 1 byte wide AXI stream interface + + constant PRESET_SIZE_G : slv(7 downto 0) := toSlv(11, 8); -- Present up to the SRC MAC + DST MAC + + type RegType is record + txMaster : AxiStreamMasterType; + txSize : slv(7 downto 0); + txCnt : slv(7 downto 0); + rxSlave : AxiStreamSlaveType; + rxSize : slv(7 downto 0); + rxCnt : slv(7 downto 0); + errorDet : slv(7 downto 0); + errorDetDly : sl; + end record RegType; + + constant REG_INIT_C : RegType := ( + txMaster => AXI_STREAM_MASTER_INIT_C, + txSize => PRESET_SIZE_G, + txCnt => (others => '0'), + rxSlave => AXI_STREAM_SLAVE_INIT_C, + rxSize => PRESET_SIZE_G, + rxCnt => (others => '0'), + errorDet => (others => '0'), + errorDetDly => '0'); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; + + signal clk : sl := '0'; + signal rst : sl := '0'; + signal phyReady : sl := '0'; + + signal txMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal txSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; + + signal rxMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal rxSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; + + signal ethStatus : EthMacStatusType := ETH_MAC_STATUS_INIT_C; + signal ethConfig : EthMacConfigType := ETH_MAC_CONFIG_INIT_C; + signal phyD : slv(63 downto 0) := (others => '0'); + signal phyC : slv(7 downto 0) := (others => '0'); begin ClkRst_Inst : entity work.ClkRst generic map ( CLK_PERIOD_G => CLK_PERIOD_C, - RST_START_DELAY_G => 0 ns, -- Wait this long into simulation before asserting reset - RST_HOLD_TIME_G => 1000 ns) -- Hold reset for this long) + RST_START_DELAY_G => 0 ns, + RST_HOLD_TIME_G => 1000 ns) port map ( clkP => clk, clkN => open, rst => rst, - rstL => phyReady); - - ---------- - -- PRBS TX - ---------- - U_TX : entity work.SsiPrbsTx - generic map ( - TPD_G => TPD_G, - CASCADE_SIZE_G => 1, - FIFO_ADDR_WIDTH_G => 9, - FIFO_PAUSE_THRESH_G => 2**8, - PRBS_SEED_SIZE_G => 32, - PRBS_TAPS_G => (0 => 31, 1 => 6, 2 => 2, 3 => 1), - MASTER_AXI_STREAM_CONFIG_G => EMAC_AXIS_CONFIG_C, - MASTER_AXI_PIPE_STAGES_G => 1) - port map ( - mAxisClk => clk, - mAxisRst => rst, - mAxisMaster => txMaster, - mAxisSlave => txSlave, - locClk => clk, - locRst => rst, - trig => '1', - packetLength => X"000000ff"); - - ---------------------- - -- IPv4/ARP/UDP Engine - ---------------------- - U_UDP_Client : entity work.UdpEngineWrapper - generic map ( - TPD_G => TPD_G, - SERVER_EN_G => false, - CLIENT_EN_G => true, - CLIENT_EXT_CONFIG_G => true) - port map ( - -- Local Configurations - localMac => MAC_ADDR_C(0), - localIp => IP_ADDR_C(0), - -- Remote Configurations - clientRemotePort(0) => x"0020", -- 0x2000 - clientRemoteIp(0) => IP_ADDR_C(1), - -- Interface to Ethernet Media Access Controller (MAC) - obMacMaster => obMacMasters(0), - obMacSlave => obMacSlaves(0), - ibMacMaster => ibMacMasters(0), - ibMacSlave => ibMacSlaves(0), - -- Interface to UDP Server engine(s) - obClientMasters => open, - obClientSlaves(0) => AXI_STREAM_SLAVE_FORCE_C, - ibClientMasters(0) => txMaster, - ibClientSlaves(0) => txSlave, - -- Clock and Reset - clk => clk, - rst => rst); + rstL => phyReady); -------------------- -- Ethernet MAC core -------------------- - U_MAC0 : entity work.EthMacTop + U_MAC : entity work.EthMacTop generic map ( TPD_G => TPD_G, + PAUSE_EN_G => false, + JUMBO_G => false, PHY_TYPE_G => "XGMII", - PRIM_CONFIG_G => EMAC_AXIS_CONFIG_C) + PRIM_CONFIG_G => AXIS_CONFIG_C) port map ( -- DMA Interface primClk => clk, primRst => rst, - ibMacPrimMaster => obMacMasters(0), - ibMacPrimSlave => obMacSlaves(0), - obMacPrimMaster => ibMacMasters(0), - obMacPrimSlave => ibMacSlaves(0), + ibMacPrimMaster => txMaster, + ibMacPrimSlave => txSlave, + obMacPrimMaster => rxMaster, + obMacPrimSlave => rxSlave, -- Ethernet Interface ethClk => clk, ethRst => rst, - ethConfig => ethConfig(0), + ethConfig => ethConfig, phyReady => phyReady, -- XGMII PHY Interface - xgmiiRxd => phyD(0), - xgmiiRxc => phyC(0), - xgmiiTxd => phyD(1), - xgmiiTxc => phyC(1)); - ethConfig(0).macAddress <= MAC_ADDR_C(0); + xgmiiRxd => phyD, -- Loopback + xgmiiRxc => phyC, -- Loopback + xgmiiTxd => phyD, -- Loopback + xgmiiTxc => phyC); -- Loopback - U_MAC1 : entity work.EthMacTop - generic map ( - TPD_G => TPD_G, - PHY_TYPE_G => "XGMII", - PRIM_CONFIG_G => EMAC_AXIS_CONFIG_C) - port map ( - -- DMA Interface - primClk => clk, - primRst => rst, - ibMacPrimMaster => obMacMasters(1), - ibMacPrimSlave => obMacSlaves(1), - obMacPrimMaster => ibMacMasters(1), - obMacPrimSlave => ibMacSlaves(1), - -- Ethernet Interface - ethClk => clk, - ethRst => rst, - ethConfig => ethConfig(1), - phyReady => phyReady, - -- XGMII PHY Interface - xgmiiRxd => phyD(1), - xgmiiRxc => phyC(1), - xgmiiTxd => phyD(0), - xgmiiTxc => phyC(0)); - ethConfig(1).macAddress <= MAC_ADDR_C(1); - - ---------------------- - -- IPv4/ARP/UDP Engine - ---------------------- - U_UDP_Server : entity work.UdpEngineWrapper - generic map ( - TPD_G => TPD_G, - SERVER_EN_G => true, - CLIENT_EN_G => false) - port map ( - -- Local Configurations - localMac => MAC_ADDR_C(1), - localIp => IP_ADDR_C(1), - -- Interface to Ethernet Media Access Controller (MAC) - obMacMaster => obMacMasters(1), - obMacSlave => obMacSlaves(1), - ibMacMaster => ibMacMasters(1), - ibMacSlave => ibMacSlaves(1), - -- Interface to UDP Server engine(s) - obServerMasters(0) => rxMaster, - obServerSlaves(0) => rxSlave, - ibServerMasters(0) => AXI_STREAM_MASTER_INIT_C, - ibServerSlaves => open, - -- Clock and Reset - clk => clk, - rst => rst); - - ---------- - -- PRBS RX - ---------- - U_RX : entity work.SsiPrbsRx - generic map ( - TPD_G => TPD_G, - CASCADE_SIZE_G => 1, - FIFO_ADDR_WIDTH_G => 9, - FIFO_PAUSE_THRESH_G => 2**8, - PRBS_SEED_SIZE_G => 32, - PRBS_TAPS_G => (0 => 31, 1 => 6, 2 => 2, 3 => 1), - SLAVE_AXI_STREAM_CONFIG_G => EMAC_AXIS_CONFIG_C, - SLAVE_AXI_PIPE_STAGES_G => 0) - port map ( - errorDet => errorDet, - sAxisClk => clk, - sAxisRst => rst, - sAxisMaster => rxMaster, - sAxisSlave => rxSlave, - mAxisClk => clk, - mAxisRst => rst, - axiClk => clk, - axiRst => rst); + -- For simplicity in error checking, local MAC is a counter sequence + ethConfig.macAddress <= x"0B_0A_09_08_07_06"; + + -- Only doing RAW Ethernet communication + ethConfig.ipCsumEn <= '0'; + ethConfig.tcpCsumEn <= '0'; + ethConfig.udpCsumEn <= '0'; + + comb : process (r, rst, rxMaster, txSlave) is + variable v : RegType; + variable rxEofIdx : slv(7 downto 0); + begin + -- Latch the current value + v := r; + + ------------------ + -- TX Stream Logic + ------------------ + v.txMaster.tKeep := toSlv(1, AXI_STREAM_MAX_TKEEP_WIDTH_C); + if (txSlave.tReady = '1') then + v.txMaster.tValid := '0'; + v.txMaster.tLast := '0'; + v.txMaster.tUser := (others => '0'); + end if; + + -- Check if ready to move data + if (v.txMaster.tValid = '0') then + + -- Move data + v.txMaster.tValid := '1'; + v.txMaster.tData(7 downto 0) := r.txCnt; + + -- Check if SOF event + if (r.txCnt = 0) then + -- Set SOF flag + ssiSetUserSof(AXIS_CONFIG_C, v.txMaster, '1'); + end if; + + -- Check if EOF event + if (r.txCnt = r.txSize) then + + -- Reset the counter + v.txCnt := (others => '0'); + + -- Check for roll over + if (r.txSize = x"FF")then + v.txSize := PRESET_SIZE_G; + else + -- Increment the counter + v.txSize := r.txSize + 1; + end if; + + -- Set EOF flag + v.txMaster.tLast := '1'; + + else + -- Increment the counter + v.txCnt := r.txCnt + 1; + end if; + + end if; + + ------------------ + -- RX Stream Logic + ------------------ + v.rxSlave := AXI_STREAM_SLAVE_INIT_C; + + -- EthMacTxExportXgmii.vhd enforces a min. payload of 64 bytes + if (r.rxSize > 64) then + rxEofIdx := r.rxSize; + else + rxEofIdx := toSlv(64, 8); + end if; + + -- Check if ready to move data + if (rxMaster.tValid = '1') then + + -- Accept the data + v.rxSlave.tReady := '1'; + + -- Check for data error + if (r.rxCnt > r.rxSize) then + -- Zero padding + if (rxMaster.tData(7 downto 0) /= 0) then + -- Set the error flag + v.errorDet(0) := '1'; + end if; + else + if (rxMaster.tData(7 downto 0) /= r.rxCnt) then + -- Set the error flag + v.errorDet(1) := '1'; + end if; + end if; + + -- Check if SOF error + if (r.rxCnt = 0) and (ssiGetUserSof(AXIS_CONFIG_C, rxMaster) /= '1') then + -- Set the error flag + v.errorDet(2) := '1'; + end if; + + -- Check if EOF error + if ((r.rxCnt = rxEofIdx) and (rxMaster.tLast /= '1')) then + -- Set the error flag + v.errorDet(3) := '1'; + end if; + + -- Check if EOF error + if ((r.rxCnt /= rxEofIdx) and (rxMaster.tLast = '1')) then + -- Set the error flag + v.errorDet(3) := '1'; + end if; + + -- Check if EOF event + if (rxMaster.tLast = '1') then + + -- Reset the counter + v.rxCnt := (others => '0'); + + -- Check for roll over + if (r.rxSize = x"FF")then + v.rxSize := PRESET_SIZE_G; + else + -- Increment the counter + v.rxSize := r.rxSize + 1; + end if; + + else + -- Increment the counter + v.rxCnt := r.rxCnt + 1; + end if; + + end if; + + -- Set the error flags + v.errorDet(4) := ethStatus.rxFifoDropCnt; + v.errorDet(5) := ethStatus.rxOverFlow; + v.errorDet(6) := ethStatus.rxCrcErrorCnt; + v.errorDet(7) := ethStatus.txUnderRunCnt; + + -- Outputs + rxSlave <= v.rxSlave; + txMaster <= r.txMaster; + + -- Reset + if (rst = '1') then + v := REG_INIT_C; + end if; + + --------------------------------- + -- Simulation Error Self-checking + --------------------------------- + v.errorDetDly := uOr(r.errorDet); + if r.errorDetDly = '1' then + assert false + report "Simulation Failed!" severity failure; + end if; + + -- Register the variable for next clock cycle + rin <= v; + + end process comb; + + seq : process (clk) is + begin + if (rising_edge(clk)) then + r <= rin after TPD_G; + end if; + end process seq; end testbed; diff --git a/ethernet/GigEthCore/core/ruckus.tcl b/ethernet/GigEthCore/core/ruckus.tcl index 1bba9c850e..b61f1904f5 100644 --- a/ethernet/GigEthCore/core/ruckus.tcl +++ b/ethernet/GigEthCore/core/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/ethernet/IpV4Engine/ruckus.tcl b/ethernet/IpV4Engine/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/ethernet/IpV4Engine/ruckus.tcl +++ b/ethernet/IpV4Engine/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/ethernet/RawEthFramer/rtl/RawEthFramerWrapper.vhd b/ethernet/RawEthFramer/rtl/RawEthFramerWrapper.vhd index 8d9175946d..cc99272fd4 100644 --- a/ethernet/RawEthFramer/rtl/RawEthFramerWrapper.vhd +++ b/ethernet/RawEthFramer/rtl/RawEthFramerWrapper.vhd @@ -88,16 +88,13 @@ begin U_RemoteMacLut : entity work.AxiDualPortRam generic map ( TPD_G => TPD_G, - BRAM_EN_G => true, - REG_EN_G => false, - MODE_G => "read-first", + READ_LATENCY_G => 1, AXI_WR_EN_G => true, SYS_WR_EN_G => false, SYS_BYTE_WR_EN_G => false, COMMON_CLK_G => true, ADDR_WIDTH_G => 8, - DATA_WIDTH_G => 48, - INIT_G => "0") + DATA_WIDTH_G => 48) port map ( -- AXI-Lite Interface axiClk => clk, diff --git a/ethernet/RawEthFramer/ruckus.tcl b/ethernet/RawEthFramer/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/ethernet/RawEthFramer/ruckus.tcl +++ b/ethernet/RawEthFramer/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/ethernet/TenGigEthCore/core/rtl/TenGigEthReg.vhd b/ethernet/TenGigEthCore/core/rtl/TenGigEthReg.vhd index 69727091c3..ff42480f49 100644 --- a/ethernet/TenGigEthCore/core/rtl/TenGigEthReg.vhd +++ b/ethernet/TenGigEthCore/core/rtl/TenGigEthReg.vhd @@ -104,7 +104,7 @@ begin TPD_G => TPD_G, OUT_POLARITY_G => '1', CNT_RST_EDGE_G => false, - COMMON_CLK_G => true, + COMMON_CLK_G => false, CNT_WIDTH_G => 32, WIDTH_G => STATUS_SIZE_C) port map ( diff --git a/ethernet/TenGigEthCore/core/ruckus.tcl b/ethernet/TenGigEthCore/core/ruckus.tcl index 1bba9c850e..b61f1904f5 100644 --- a/ethernet/TenGigEthCore/core/ruckus.tcl +++ b/ethernet/TenGigEthCore/core/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/ethernet/UdpEngine/ruckus.tcl b/ethernet/UdpEngine/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/ethernet/UdpEngine/ruckus.tcl +++ b/ethernet/UdpEngine/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/ethernet/UdpEngine/tb/UdpEngineCoreTb.vhd b/ethernet/UdpEngine/tb/UdpEngineCoreTb.vhd deleted file mode 100644 index bd75574943..0000000000 --- a/ethernet/UdpEngine/tb/UdpEngineCoreTb.vhd +++ /dev/null @@ -1,250 +0,0 @@ -------------------------------------------------------------------------------- --- File : UdpEngineCoreTb.vhd --- Company : SLAC National Accelerator Laboratory -------------------------------------------------------------------------------- --- Description: Simulation Testbed for testing the UdpEngineCore module -------------------------------------------------------------------------------- --- This file is part of 'SLAC Firmware Standard Library'. --- It is subject to the license terms in the LICENSE.txt file found in the --- top-level directory of this distribution and at: --- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. --- No part of 'SLAC Firmware Standard Library', including this file, --- may be copied, modified, propagated, or distributed except according to --- the terms contained in the LICENSE.txt file. -------------------------------------------------------------------------------- - -library ieee; -use ieee.std_logic_1164.all; -use ieee.std_logic_unsigned.all; -use ieee.std_logic_arith.all; - -use work.StdRtlPkg.all; -use work.AxiStreamPkg.all; -use work.SsiPkg.all; -use work.EthMacPkg.all; - -entity UdpEngineCoreTb is - generic ( - TPD_G : time := 1 ns); - port ( - -- Interface to UDP Engine - obClientMaster : in AxiStreamMasterType; - obClientSlave : out AxiStreamSlaveType; - ibClientMaster : out AxiStreamMasterType; - ibClientSlave : in AxiStreamSlaveType; - -- Simulation Result - passed : out sl; - failed : out sl; - -- Clock and Reset - clk : in sl; - rst : in sl); -end UdpEngineCoreTb; - -architecture rtl of UdpEngineCoreTb is - - type StateType is ( - PROCESSING_S, - DONE_S); - - type RegType is record - passed : sl; - failed : slv(4 downto 0); - passedDly : sl; - failedDly : sl; - txDone : sl; - tKeep : slv(15 downto 0); - timer : slv(15 downto 0); - txWordCnt : natural range 0 to 64; - txWordSize : natural range 0 to 64; - txByteCnt : natural range 0 to 16; - rxWordCnt : natural range 0 to 64; - rxWordSize : natural range 0 to 64; - rxByteCnt : natural range 0 to 16; - ibClientMaster : AxiStreamMasterType; - obClientSlave : AxiStreamSlaveType; - state : StateType; - end record RegType; - constant REG_INIT_C : RegType := ( - passed => '0', - failed => (others => '0'), - passedDly => '0', - failedDly => '0', - txDone => '0', - tKeep => (others => '1'), - timer => (others => '0'), - txWordCnt => 0, - txWordSize => 0, - txByteCnt => 0, - rxWordCnt => 0, - rxWordSize => 0, - rxByteCnt => 0, - ibClientMaster => AXI_STREAM_MASTER_INIT_C, - obClientSlave => AXI_STREAM_SLAVE_INIT_C, - state => PROCESSING_S); - - signal r : RegType := REG_INIT_C; - signal rin : RegType; - -begin - - comb : process (ibClientSlave, obClientMaster, r, rst) is - variable v : RegType; - variable i : natural; - begin - -- Latch the current value - v := r; - - -- Reset the flags - v.obClientSlave := AXI_STREAM_SLAVE_INIT_C; - if ibClientSlave.tReady = '1' then - v.ibClientMaster.tValid := '0'; - v.ibClientMaster.tLast := '0'; - v.ibClientMaster.tUser := (others => '0'); - v.ibClientMaster.tKeep := (others => '1'); - end if; - v.tKeep := (others => '1'); - - -- Increment the timer - if r.timer /= x"FFFF" then - v.timer := r.timer + 1; - else - -- Timed out - v.failed(0) := '1'; - end if; - - -- Create a delayed copy for easier viewing in simulation GUI - v.passedDly := r.passed; - v.failedDly := uOr(r.failed); - - -- State Machine - case r.state is - ---------------------------------------------------------------------- - when PROCESSING_S => - ---------------------------------------------------------------------- - ---------------------------------------------------------------------- - ---------------------------------------------------------------------- - -- TX generate - if (v.ibClientMaster.tValid = '0') and (r.txDone = '0') then - -- Move data - v.ibClientMaster.tValid := '1'; - -- Check for SOF - if r.txWordCnt = 0 then - ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.ibClientMaster, '1'); - end if; - -- Send data - v.ibClientMaster.tdata := toSlv((r.txWordCnt*16)+r.txByteCnt+1, 128); - -- Increment the counter - v.txWordCnt := r.txWordCnt + 1; - -- Check for tLast - if r.txWordCnt = r.txWordSize then - -- Reset the counters - v.txWordCnt := 0; - -- Set EOF - v.ibClientMaster.tLast := '1'; - -- Increment the counter - v.txByteCnt := r.txByteCnt + 1; - -- Loop through the tKeep byte field - for i in 15 downto 0 loop - if (i > r.txByteCnt) then - v.ibClientMaster.tKeep(i) := '0'; - end if; - end loop; - -- Check the counter - if r.txByteCnt = 15 then - -- Reset the counter - v.txByteCnt := 0; - -- Increment the counter - v.txWordSize := r.txWordSize + 1; - -- Check if we are done - if r.txWordSize = 63 then - v.txDone := '1'; - end if; - end if; - end if; - end if; - ---------------------------------------------------------------------- - ---------------------------------------------------------------------- - ---------------------------------------------------------------------- - -- RX Comparator - if obClientMaster.tValid = '1' then - -- Accept the data - v.obClientSlave.tReady := '1'; - -- Check for SOF - if (r.rxWordCnt = 0) and (ssiGetUserSof(EMAC_AXIS_CONFIG_C, obClientMaster) = '0') then - v.failed(1) := '1'; - end if; - -- Increment the counter - v.rxWordCnt := r.rxWordCnt + 1; - -- Check for errors - if (obClientMaster.tdata /= toSlv((r.rxWordCnt*16)+r.rxByteCnt+1, 128)) then - v.failed(2) := '1'; - end if; - -- Check if done with simulation test - if (uOr(v.failed) = '0') and obClientMaster.tLast = '1' then - -- Reset the transaction timer - v.timer := x"0000"; - -- Reset the counter - v.rxWordCnt := 0; - -- Increment the counter - v.rxByteCnt := r.rxByteCnt + 1; - -- Loop through the tKeep byte field - for i in 15 downto 0 loop - if (i > r.rxByteCnt) then - v.tKeep(i) := '0'; - end if; - end loop; - -- Check for errors - if (v.tKeep /= obClientMaster.tKeep(15 downto 0)) then - v.failed(3) := '1'; - end if; - -- Check the counter - if r.rxByteCnt = 15 then - -- Reset the counter - v.rxByteCnt := 0; - -- Increment the counter - v.rxWordSize := r.rxWordSize + 1; - end if; - -- Check for errors - if (r.rxWordSize /= r.rxWordCnt) then - v.failed(4) := '1'; - end if; - -- Check for full word transfer and full size - if (obClientMaster.tKeep(15 downto 0) = x"FFFF") and (r.rxWordCnt = 63) then - -- Next state - v.state := DONE_S; - end if; - end if; - end if; - ---------------------------------------------------------------------- - when DONE_S => - v.passed := '1'; - v.timer := x"0000"; - ---------------------------------------------------------------------- - end case; - - -- Combinatorial outputs before the reset - obClientSlave <= v.obClientSlave; - - -- Reset - if (rst = '1') then - v := REG_INIT_C; - end if; - - -- Register the variable for next clock cycle - rin <= v; - - -- Registered Outputs - ibClientMaster <= r.ibClientMaster; - passed <= r.passedDly; - failed <= r.failedDly; - - end process comb; - - seq : process (clk) is - begin - if rising_edge(clk) then - r <= rin after TPD_G; - end if; - end process seq; - -end rtl; diff --git a/ethernet/UdpEngine/tb/UdpEngineTb.vhd b/ethernet/UdpEngine/tb/UdpEngineTb.vhd index 38d898c215..c881a49a03 100644 --- a/ethernet/UdpEngine/tb/UdpEngineTb.vhd +++ b/ethernet/UdpEngine/tb/UdpEngineTb.vhd @@ -2,7 +2,7 @@ -- File : UdpEngineTb.vhd -- Company : SLAC National Accelerator Laboratory ------------------------------------------------------------------------------- --- Description: Simulation Testbed for testing the UdpEngine module +-- Description: Simulation Testbed for testing the EthMac module ------------------------------------------------------------------------------- -- This file is part of 'SLAC Firmware Standard Library'. -- It is subject to the license terms in the LICENSE.txt file found in the @@ -11,331 +11,294 @@ -- No part of 'SLAC Firmware Standard Library', including this file, -- may be copied, modified, propagated, or distributed except according to -- the terms contained in the LICENSE.txt file. -------------------------------------------------------------------------------- +------------------------------------------------------------------------------ library ieee; use ieee.std_logic_1164.all; -use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +library unisim; +use unisim.vcomponents.all; use work.StdRtlPkg.all; use work.AxiStreamPkg.all; use work.SsiPkg.all; use work.EthMacPkg.all; -entity UdpEngineTb is end UdpEngineTb; +entity UdpEngineTb is +end UdpEngineTb; architecture testbed of UdpEngineTb is - constant CLK_PERIOD_C : time := 6.4 ns; - constant TPD_C : time := (CLK_PERIOD_C/4); - constant LOCAL_MAC_C : slv(47 downto 0) := x"123456789ABC"; - constant LOCAL_IP_C : slv(31 downto 0) := x"12345678"; - constant REMOTE_MAC_C : slv(47 downto 0) := x"DEADBEEFCAFE"; - constant REMOTE_IP_C : slv(31 downto 0) := x"ABCDEFFF"; - - constant VLAN_C : boolean := false; - constant VID_C : slv(15 downto 0) := x"0000"; - - constant PROTOCOL_C : Slv8Array(0 downto 0) := (0 => UDP_C); - constant SERVER_PORTS_C : PositiveArray := (0 => 8192); - constant CLIENT_PORTS_C : PositiveArray := (0 => 8193); - constant SIM_ERROR_HALT_C : boolean := true; - constant TX_CALC_CHECKSUM_C : boolean := true; - - signal clk : sl := '0'; - signal rst : sl := '0'; - signal passed : sl := '0'; - signal failed : sl := '0'; - - signal obServerMasters : AxiStreamMasterArray(1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); - signal obServerSlaves : AxiStreamSlaveArray(1 downto 0) := (others => AXI_STREAM_SLAVE_FORCE_C); - signal ibServerMasters : AxiStreamMasterArray(1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); - signal ibServerSlaves : AxiStreamSlaveArray(1 downto 0) := (others => AXI_STREAM_SLAVE_FORCE_C); - - signal obClientMasters : AxiStreamMasterArray(1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); - signal obClientSlaves : AxiStreamSlaveArray(1 downto 0) := (others => AXI_STREAM_SLAVE_FORCE_C); - signal ibClientMasters : AxiStreamMasterArray(1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); - signal ibClientSlaves : AxiStreamSlaveArray(1 downto 0) := (others => AXI_STREAM_SLAVE_FORCE_C); - - signal obProtocolMasters : AxiStreamMasterArray(1 downto 0); - signal obProtocolSlaves : AxiStreamSlaveArray(1 downto 0); - signal ibProtocolMasters : AxiStreamMasterArray(1 downto 0); - signal ibProtocolSlaves : AxiStreamSlaveArray(1 downto 0); - - signal arpReqMasters : AxiStreamMasterArray(1 downto 0); - signal arpReqSlaves : AxiStreamSlaveArray(1 downto 0); - signal arpAckMasters : AxiStreamMasterArray(1 downto 0); - signal arpAckSlaves : AxiStreamSlaveArray(1 downto 0); - - signal ibMacMasters : AxiStreamMasterArray(1 downto 0); - signal ibMacSlaves : AxiStreamSlaveArray(1 downto 0); - signal obMacMasters : AxiStreamMasterArray(1 downto 0); - signal obMacSlaves : AxiStreamSlaveArray(1 downto 0); - + constant CLK_PERIOD_C : time := 6.4 ns; + constant TPD_G : time := (CLK_PERIOD_C/4); + + constant MAC_ADDR_C : Slv48Array(1 downto 0) := ( + 0 => x"010300564400", --00:44:56:00:03:01 + 1 => x"020300564400"); --00:44:56:00:03:02 + + constant IP_ADDR_C : Slv32Array(1 downto 0) := ( + 0 => x"0A02A8C0", -- 192.168.2.10 + 1 => x"0B02A8C0"); -- 192.168.2.11 + + type RegType is record + packetLength : slv(31 downto 0); + trig : sl; + txBusy : sl; + errorDet : sl; + end record RegType; + + constant REG_INIT_C : RegType := ( + packetLength => toSlv(0, 32), + trig => '0', + txBusy => '0', + errorDet => '0'); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; + + signal clk : sl := '0'; + signal rst : sl := '0'; + + signal txMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal txSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_INIT_C; + + signal obMacMasters : AxiStreamMasterArray(1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); + signal obMacSlaves : AxiStreamSlaveArray(1 downto 0) := (others => AXI_STREAM_SLAVE_INIT_C); + + signal ibMacMasters : AxiStreamMasterArray(1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); + signal ibMacSlaves : AxiStreamSlaveArray(1 downto 0) := (others => AXI_STREAM_SLAVE_INIT_C); + + signal ethConfig : EthMacConfigArray(1 downto 0) := (others => ETH_MAC_CONFIG_INIT_C); + signal phyD : Slv64Array(1 downto 0) := (others => (others => '0')); + signal phyC : Slv8Array(1 downto 0) := (others => (others => '0')); + + signal rxMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal rxSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_INIT_C; + + signal phyReady : sl; + signal updatedResults : sl; + signal errorDet : sl; + signal rxBusy : sl; + signal txBusy : sl; + begin ClkRst_Inst : entity work.ClkRst generic map ( CLK_PERIOD_G => CLK_PERIOD_C, - RST_START_DELAY_G => 0 ns, -- Wait this long into simulation before asserting reset - RST_HOLD_TIME_G => 1000 ns) -- Hold reset for this long) + RST_START_DELAY_G => 0 ns, + RST_HOLD_TIME_G => 1000 ns) port map ( clkP => clk, clkN => open, rst => rst, - rstL => open); + rstL => phyReady); - -- Loopback the UDP datagram - ibServerMasters(1) <= obServerMasters(1); - obServerSlaves(1) <= ibServerSlaves(1); + ---------- + -- PRBS TX + ---------- + U_TX : entity work.SsiPrbsTx + generic map ( + TPD_G => TPD_G, + AXI_EN_G => '0', + MASTER_AXI_STREAM_CONFIG_G => EMAC_AXIS_CONFIG_C) + port map ( + -- Master Port (mAxisClk) + mAxisClk => clk, + mAxisRst => rst, + mAxisMaster => txMaster, + mAxisSlave => txSlave, + -- Trigger Signal (locClk domain) + locClk => clk, + locRst => rst, + packetLength => r.packetLength, + trig => r.trig, + busy => txBusy); - UdpEngine_Remote : entity work.UdpEngine + ---------------------- + -- IPv4/ARP/UDP Engine + ---------------------- + U_UDP_Client : entity work.UdpEngineWrapper generic map ( -- Simulation Generics - TPD_G => TPD_C, - SIM_ERROR_HALT_G => SIM_ERROR_HALT_C, - -- UDP General Generic - RX_FORWARD_EOFE_G => false, - TX_FORWARD_EOFE_G => false, - TX_CALC_CHECKSUM_G => TX_CALC_CHECKSUM_C, + TPD_G => TPD_G, -- UDP Server Generics - SERVER_EN_G => true, - SERVER_SIZE_G => 1, - SERVER_PORTS_G => SERVER_PORTS_C, + SERVER_EN_G => false, -- UDP Client Generics - CLIENT_EN_G => true, - CLIENT_SIZE_G => 1, - CLIENT_PORTS_G => CLIENT_PORTS_C, - -- UDP ARP Generics - CLK_FREQ_G => 156.25E+06, -- In units of Hz - COMM_TIMEOUT_EN_G => true, -- Disable the timeout by setting to false - COMM_TIMEOUT_G => 30) -- In units of seconds, Client's Communication timeout before re-ARPing + CLIENT_EN_G => true, + CLIENT_SIZE_G => 1, + CLIENT_PORTS_G => (0 => 8193), + CLIENT_EXT_CONFIG_G => true) port map ( -- Local Configurations - localIp => REMOTE_IP_C, - -- Interface to IPV4 Engine - obUdpMaster => obProtocolMasters(1), - obUdpSlave => obProtocolSlaves(1), - ibUdpMaster => ibProtocolMasters(1), - ibUdpSlave => ibProtocolSlaves(1), - -- Interface to ARP Engine - arpReqMasters(0) => arpReqMasters(1), - arpReqSlaves(0) => arpReqSlaves(1), - arpAckMasters(0) => arpAckMasters(1), - arpAckSlaves(0) => arpAckSlaves(1), + localMac => MAC_ADDR_C(0), + localIp => IP_ADDR_C(0), + -- Remote Configurations + clientRemotePort(0) => x"0020", -- PORT = 8192 = 0x2000 (0x0020 in big endianness) + clientRemoteIp(0) => IP_ADDR_C(1), + -- Interface to Ethernet Media Access Controller (MAC) + obMacMaster => obMacMasters(0), + obMacSlave => obMacSlaves(0), + ibMacMaster => ibMacMasters(0), + ibMacSlave => ibMacSlaves(0), -- Interface to UDP Server engine(s) - obServerMasters(0) => obServerMasters(1), - obServerSlaves(0) => obServerSlaves(1), - ibServerMasters(0) => ibServerMasters(1), - ibServerSlaves(0) => ibServerSlaves(1), - -- Interface to UDP Client engine(s) - clientRemotePort => (others => x"0120"), - clientRemoteIp => (others => LOCAL_IP_C), - obClientMasters(0) => obClientMasters(1), - obClientSlaves(0) => obClientSlaves(1), - ibClientMasters(0) => ibClientMasters(1), - ibClientSlaves(0) => ibClientSlaves(1), + obClientMasters => open, + obClientSlaves(0) => AXI_STREAM_SLAVE_FORCE_C, + ibClientMasters(0) => txMaster, + ibClientSlaves(0) => txSlave, -- Clock and Reset - clk => clk, - rst => rst); + clk => clk, + rst => rst); - IpV4Engine_Remote : entity work.IpV4Engine + -------------------- + -- Ethernet MAC core + -------------------- + U_MAC0 : entity work.EthMacTop generic map ( - TPD_G => TPD_C, - SIM_ERROR_HALT_G => SIM_ERROR_HALT_C, - PROTOCOL_SIZE_G => 1, - PROTOCOL_G => PROTOCOL_C, - CLIENT_SIZE_G => 1, - ARP_TIMEOUT_G => 156250000, - VLAN_G => VLAN_C) + TPD_G => TPD_G, + PHY_TYPE_G => "XGMII", + PRIM_CONFIG_G => EMAC_AXIS_CONFIG_C) port map ( - -- Local Configurations - localMac => REMOTE_MAC_C, - localIp => REMOTE_IP_C, - -- Interface to Ethernet Media Access Controller (MAC) - obMacMaster => obMacMasters(1), - obMacSlave => obMacSlaves(1), - ibMacMaster => ibMacMasters(1), - ibMacSlave => ibMacSlaves(1), - -- Interface to Protocol Engine(s) - obProtocolMasters(0) => obProtocolMasters(1), - obProtocolSlaves(0) => obProtocolSlaves(1), - ibProtocolMasters(0) => ibProtocolMasters(1), - ibProtocolSlaves(0) => ibProtocolSlaves(1), - -- Interface to Client Engine(s) - arpReqMasters(0) => arpReqMasters(1), - arpReqSlaves(0) => arpReqSlaves(1), - arpAckMasters(0) => arpAckMasters(1), - arpAckSlaves(0) => arpAckSlaves(1), - -- Clock and Reset - clk => clk, - rst => rst); + -- DMA Interface + primClk => clk, + primRst => rst, + ibMacPrimMaster => ibMacMasters(0), + ibMacPrimSlave => ibMacSlaves(0), + obMacPrimMaster => obMacMasters(0), + obMacPrimSlave => obMacSlaves(0), + -- Ethernet Interface + ethClk => clk, + ethRst => rst, + ethConfig => ethConfig(0), + phyReady => phyReady, + -- XGMII PHY Interface + xgmiiRxd => phyD(0), + xgmiiRxc => phyC(0), + xgmiiTxd => phyD(1), + xgmiiTxc => phyC(1)); + ethConfig(0).macAddress <= MAC_ADDR_C(0); - MAC_FIFO_0 : entity work.AxiStreamFifoV2 - generic map ( - -- General Configurations - TPD_G => TPD_C, - PIPE_STAGES_G => 0, - SLAVE_READY_EN_G => true, - VALID_THOLD_G => 1, - -- FIFO configurations - BRAM_EN_G => false, - USE_BUILT_IN_G => false, - GEN_SYNC_FIFO_G => true, - CASCADE_SIZE_G => 1, - FIFO_ADDR_WIDTH_G => 4, - -- AXI Stream Port Configurations - SLAVE_AXI_CONFIG_G => EMAC_AXIS_CONFIG_C, - MASTER_AXI_CONFIG_G => EMAC_AXIS_CONFIG_C) - port map ( - -- Slave Port - sAxisClk => clk, - sAxisRst => rst, - sAxisMaster => ibMacMasters(0), - sAxisSlave => ibMacSlaves(0), - -- Master Port - mAxisClk => clk, - mAxisRst => rst, - mAxisMaster => obMacMasters(1), - mAxisSlave => obMacSlaves(1)); - - MAC_FIFO_1 : entity work.AxiStreamFifoV2 - generic map ( - -- General Configurations - TPD_G => TPD_C, - PIPE_STAGES_G => 0, - SLAVE_READY_EN_G => true, - VALID_THOLD_G => 1, - -- FIFO configurations - BRAM_EN_G => false, - USE_BUILT_IN_G => false, - GEN_SYNC_FIFO_G => true, - CASCADE_SIZE_G => 1, - FIFO_ADDR_WIDTH_G => 4, - -- AXI Stream Port Configurations - SLAVE_AXI_CONFIG_G => EMAC_AXIS_CONFIG_C, - MASTER_AXI_CONFIG_G => EMAC_AXIS_CONFIG_C) - port map ( - -- Slave Port - sAxisClk => clk, - sAxisRst => rst, - sAxisMaster => ibMacMasters(1), - sAxisSlave => ibMacSlaves(1), - -- Master Port - mAxisClk => clk, - mAxisRst => rst, - mAxisMaster => obMacMasters(0), - mAxisSlave => obMacSlaves(0)); - - IpV4Engine_Local : entity work.IpV4Engine + U_MAC1 : entity work.EthMacTop generic map ( - TPD_G => TPD_C, - SIM_ERROR_HALT_G => SIM_ERROR_HALT_C, - PROTOCOL_SIZE_G => 1, - PROTOCOL_G => PROTOCOL_C, - CLIENT_SIZE_G => 1, - ARP_TIMEOUT_G => 156250000, - VLAN_G => VLAN_C) + TPD_G => TPD_G, + PHY_TYPE_G => "XGMII", + PRIM_CONFIG_G => EMAC_AXIS_CONFIG_C) port map ( - -- Local Configurations - localMac => LOCAL_MAC_C, - localIp => LOCAL_IP_C, - -- Interface to Ethernet Media Access Controller (MAC) - obMacMaster => obMacMasters(0), - obMacSlave => obMacSlaves(0), - ibMacMaster => ibMacMasters(0), - ibMacSlave => ibMacSlaves(0), - -- Interface to Protocol Engine(s) - obProtocolMasters(0) => obProtocolMasters(0), - obProtocolSlaves(0) => obProtocolSlaves(0), - ibProtocolMasters(0) => ibProtocolMasters(0), - ibProtocolSlaves(0) => ibProtocolSlaves(0), - -- Interface to Client Engine(s) - arpReqMasters(0) => arpReqMasters(0), - arpReqSlaves(0) => arpReqSlaves(0), - arpAckMasters(0) => arpAckMasters(0), - arpAckSlaves(0) => arpAckSlaves(0), - -- Clock and Reset - clk => clk, - rst => rst); + -- DMA Interface + primClk => clk, + primRst => rst, + ibMacPrimMaster => ibMacMasters(1), + ibMacPrimSlave => ibMacSlaves(1), + obMacPrimMaster => obMacMasters(1), + obMacPrimSlave => obMacSlaves(1), + -- Ethernet Interface + ethClk => clk, + ethRst => rst, + ethConfig => ethConfig(1), + phyReady => phyReady, + -- XGMII PHY Interface + xgmiiRxd => phyD(1), + xgmiiRxc => phyC(1), + xgmiiTxd => phyD(0), + xgmiiTxc => phyC(0)); + ethConfig(1).macAddress <= MAC_ADDR_C(1); - UdpEngine_Local : entity work.UdpEngine + ---------------------- + -- IPv4/ARP/UDP Engine + ---------------------- + U_UDP_Server : entity work.UdpEngineWrapper generic map ( -- Simulation Generics - TPD_G => TPD_C, - SIM_ERROR_HALT_G => SIM_ERROR_HALT_C, - -- UDP General Generic - RX_FORWARD_EOFE_G => false, - TX_FORWARD_EOFE_G => false, - TX_CALC_CHECKSUM_G => TX_CALC_CHECKSUM_C, + TPD_G => TPD_G, -- UDP Server Generics - SERVER_EN_G => true, - SERVER_SIZE_G => 1, - SERVER_PORTS_G => SERVER_PORTS_C, + SERVER_EN_G => true, + SERVER_SIZE_G => 1, + SERVER_PORTS_G => (0 => 8192), -- UDP Client Generics - CLIENT_EN_G => true, - CLIENT_SIZE_G => 1, - CLIENT_PORTS_G => CLIENT_PORTS_C, - -- UDP ARP Generics - CLK_FREQ_G => 156.25E+06, -- In units of Hz - COMM_TIMEOUT_EN_G => true, -- Disable the timeout by setting to false - COMM_TIMEOUT_G => 30) -- In units of seconds, Client's Communication timeout before re-ARPing + CLIENT_EN_G => false) port map ( -- Local Configurations - localIp => LOCAL_IP_C, - -- Interface to IPV4 Engine - obUdpMaster => obProtocolMasters(0), - obUdpSlave => obProtocolSlaves(0), - ibUdpMaster => ibProtocolMasters(0), - ibUdpSlave => ibProtocolSlaves(0), - -- Interface to ARP Engine - arpReqMasters(0) => arpReqMasters(0), - arpReqSlaves(0) => arpReqSlaves(0), - arpAckMasters(0) => arpAckMasters(0), - arpAckSlaves(0) => arpAckSlaves(0), + localMac => MAC_ADDR_C(1), + localIp => IP_ADDR_C(1), + -- Interface to Ethernet Media Access Controller (MAC) + obMacMaster => obMacMasters(1), + obMacSlave => obMacSlaves(1), + ibMacMaster => ibMacMasters(1), + ibMacSlave => ibMacSlaves(1), -- Interface to UDP Server engine(s) - obServerMasters(0) => obServerMasters(0), - obServerSlaves(0) => obServerSlaves(0), - ibServerMasters(0) => ibServerMasters(0), - ibServerSlaves(0) => ibServerSlaves(0), - -- Interface to UDP Client engine(s) - clientRemotePort => (others => x"0020"), - clientRemoteIp => (others => REMOTE_IP_C), - obClientMasters(0) => obClientMasters(0), - obClientSlaves(0) => obClientSlaves(0), - ibClientMasters(0) => ibClientMasters(0), - ibClientSlaves(0) => ibClientSlaves(0), + obServerMasters(0) => rxMaster, + obServerSlaves(0) => rxSlave, + ibServerMasters(0) => AXI_STREAM_MASTER_INIT_C, + ibServerSlaves => open, -- Clock and Reset clk => clk, - rst => rst); + rst => rst); - UdpEngineCoreTb_Inst : entity work.UdpEngineCoreTb + ---------- + -- PRBS RX + ---------- + U_RX : entity work.SsiPrbsRx generic map ( - TPD_G => TPD_C) + TPD_G => TPD_G, + SLAVE_AXI_STREAM_CONFIG_G => EMAC_AXIS_CONFIG_C) port map ( - -- Interface to UDP Engine - obClientMaster => obClientMasters(0), - obClientSlave => obClientSlaves(0), - ibClientMaster => ibClientMasters(0), - ibClientSlave => ibClientSlaves(0), - -- Simulation Result - passed => passed, - failed => failed, - -- Clock and Reset - clk => clk, - rst => rst); + -- Slave Port (sAxisClk) + sAxisClk => clk, + sAxisRst => rst, + sAxisMaster => rxMaster, + sAxisSlave => rxSlave, + -- Error Detection Signals (sAxisClk domain) + updatedResults => updatedResults, + errorDet => errorDet, + busy => rxBusy); - process(failed, passed) + comb : process (errorDet, r, rst, txBusy) is + variable v : RegType; begin - if failed = '1' then + -- Latch the current value + v := r; + + -- Keep delay copies + v.errorDet := errorDet; + v.txBusy := txBusy; + v.trig := not(r.txBusy); + + -- Check for the packet completion + if (txBusy = '1') and (r.txBusy = '0') then + -- Sweeping the packet size size + v.packetLength := r.packetLength + 1; + -- Check for Jumbo frame roll over + if (r.packetLength = (8192/4)-1) then + -- Reset the counter + v.packetLength := (others => '0'); + end if; + end if; + + -- Reset + if (rst = '1') then + v := REG_INIT_C; + end if; + + --------------------------------- + -- Simulation Error Self-checking + --------------------------------- + if r.errorDet = '1' then assert false report "Simulation Failed!" severity failure; end if; - if passed = '1' then - assert false - report "Simulation Passed!" severity failure; + + -- Register the variable for next clock cycle + rin <= v; + + end process comb; + + seq : process (clk) is + begin + if (rising_edge(clk)) then + r <= rin after TPD_G; end if; - end process; + end process seq; end testbed; diff --git a/ethernet/XauiCore/core/ruckus.tcl b/ethernet/XauiCore/core/ruckus.tcl index 1bba9c850e..b61f1904f5 100644 --- a/ethernet/XauiCore/core/ruckus.tcl +++ b/ethernet/XauiCore/core/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/protocols/batcher/rtl/AxiStreamBatcherEventBuilder.vhd b/protocols/batcher/rtl/AxiStreamBatcherEventBuilder.vhd index c0c067b0fa..9674d46c7d 100644 --- a/protocols/batcher/rtl/AxiStreamBatcherEventBuilder.vhd +++ b/protocols/batcher/rtl/AxiStreamBatcherEventBuilder.vhd @@ -69,11 +69,21 @@ architecture rtl of AxiStreamBatcherEventBuilder is MOVE_S); type RegType is record + softRst : sl; + hardRst : sl; + blowoff : sl; + timerRst : sl; + cntRst : sl; ready : sl; maxSubFrames : slv(15 downto 0); timer : slv(31 downto 0); timeout : slv(31 downto 0); + dataCnt : Slv32Array(NUM_SLAVES_G-1 downto 0); + nullCnt : Slv32Array(NUM_SLAVES_G-1 downto 0); + timeoutDropCnt : Slv32Array(NUM_SLAVES_G-1 downto 0); accept : slv(NUM_SLAVES_G-1 downto 0); + nullDet : slv(NUM_SLAVES_G-1 downto 0); + timeoutDet : slv(NUM_SLAVES_G-1 downto 0); index : natural range 0 to NUM_SLAVES_G-1; axilReadSlave : AxiLiteReadSlaveType; axilWriteSlave : AxiLiteWriteSlaveType; @@ -83,11 +93,21 @@ architecture rtl of AxiStreamBatcherEventBuilder is end record RegType; constant REG_INIT_C : RegType := ( + softRst => '0', + hardRst => '0', + blowoff => '0', + timerRst => '0', + cntRst => '0', ready => '0', maxSubFrames => toSlv(NUM_SLAVES_G, 16), timer => (others => '0'), timeout => (others => '0'), + dataCnt => (others => (others => '0')), + nullCnt => (others => (others => '0')), + timeoutDropCnt => (others => (others => '0')), accept => (others => '0'), + nullDet => (others => '0'), + timeoutDet => (others => '0'), index => 0, axilReadSlave => AXI_LITE_READ_SLAVE_INIT_C, axilWriteSlave => AXI_LITE_WRITE_SLAVE_INIT_C, @@ -104,7 +124,9 @@ architecture rtl of AxiStreamBatcherEventBuilder is signal txMaster : AxiStreamMasterType; signal txSlave : AxiStreamSlaveType; - signal batcherIdle : sl; + signal batcherIdle : sl; + signal timeoutEvent : sl; + signal axisReset : sl; begin @@ -154,26 +176,79 @@ begin mAxisSlave => rxSlaves(i)); end generate GEN_VEC; + U_DspComparator : entity work.DspComparator + generic map ( + TPD_G => TPD_G, + WIDTH_G => 32) + port map ( + clk => axisClk, + ain => r.timer, + bin => r.timeout, + gtEq => timeoutEvent); -- greater than or equal to (a >= b) + comb : process (axilReadMaster, axilWriteMaster, axisRst, batcherIdle, r, - rxMasters, txSlave) is + rxMasters, timeoutEvent, txSlave) is variable v : RegType; variable axilEp : AxiLiteEndPointType; variable i : natural; + variable dbg : slv(7 downto 0); begin -- Latch the current value v := r; + -- Update the local variable + dbg := x"00"; + if (v.state = IDLE_S) then + dbg(0) := '0'; + else + dbg(0) := '1'; + end if; + + -- Reset strobes + v.cntRst := '0'; + v.timerRst := '0'; + v.hardRst := '0'; + v.softRst := '0'; + + -- Check for hard reset or soft reset + if (r.hardRst = '1') or (r.softRst = '1') then + -- Reset the register + v := REG_INIT_C; + + -- -- Check for soft reset (unclear if we want to support a hard reset that also resets the registers. it might confuse 'novice' users who randomly hitting different resets) + -- if (r.softRst = '1') then + + -- Preserve the resister configurations + v.timeout := r.timeout; + v.blowoff := r.blowoff; + + -- end if; + + end if; + -- Determine the transaction type axiSlaveWaitTxn(axilEp, axilWriteMaster, axilReadMaster, v.axilWriteSlave, v.axilReadSlave); -- Map the registers - axiSlaveRegister(axilEp, x"00", 0, v.timeout); + for i in (NUM_SLAVES_G-1) downto 0 loop + axiSlaveRegisterR(axilEp, toSlv(4*i + 0, 12), 0, r.dataCnt(i)); + axiSlaveRegisterR(axilEp, toSlv(4*i + 256, 12), 0, r.nullCnt(i)); + axiSlaveRegisterR(axilEp, toSlv(4*i + 512, 12), 0, r.timeoutDropCnt(i)); + end loop; + axiSlaveRegister (axilEp, x"FF0", 0, v.timeout); + axiSlaveRegisterR(axilEp, x"FF4", 0, toSlv(NUM_SLAVES_G, 8)); + axiSlaveRegisterR(axilEp, x"FF4", 8, dbg); + axiSlaveRegister (axilEp, x"FF8", 0, v.blowoff); + axiSlaveRegister (axilEp, x"FFC", 0, v.cntRst); + axiSlaveRegister (axilEp, x"FFC", 1, v.timerRst); + axiSlaveRegister (axilEp, x"FFC", 2, v.hardRst); + axiSlaveRegister (axilEp, x"FFC", 3, v.softRst); -- Closeout the transaction axiSlaveDefault(axilEp, v.axilWriteSlave, v.axilReadSlave, AXI_RESP_DECERR_C); -- Check for change in configuration - if (r.timeout /= v.timeout) then + if (r.timeout /= v.timeout) or (r.timerRst = '1') then -- Reset the timer v.timer := (others => '0'); end if; @@ -190,25 +265,36 @@ begin case r.state is ---------------------------------------------------------------------- when IDLE_S => - -- Loop through RX channels + -- Arm the flag v.ready := '1'; + -- Loop through RX channels for i in (NUM_SLAVES_G-1) downto 0 loop -- Check if no data if (rxMasters(i).tValid = '0') then - -- Reset the flag - v.ready := '0'; + -- Reset the flags + v.ready := '0'; + v.accept(i) := '0'; + v.nullDet(i) := '0'; else + ---------------------------------------------------------------------------------------------------- + ---------------------------------------------------------------------------------------------------- + ---------------------------------------------------------------------------------------------------- -- Check for NULL frame (defined as a single word transaction with EOFE asserted and byte count = 1) + ---------------------------------------------------------------------------------------------------- + ---------------------------------------------------------------------------------------------------- + ---------------------------------------------------------------------------------------------------- if (rxMasters(i).tLast = '1') and -- TLAST asserted (ssiGetUserEofe(AXIS_CONFIG_G, rxMasters(i)) = '1') and -- EOFE flag set (getTKeep(rxMasters(i).tKeep(AXIS_CONFIG_G.TDATA_BYTES_C-1 downto 0), AXIS_CONFIG_G) = 1) then -- byte count = 1 -- NULL frame detected - v.accept(i) := '0'; + v.accept(i) := '0'; + v.nullDet(i) := '1'; else -- Normal frame detected - v.accept(i) := '1'; + v.accept(i) := '1'; + v.nullDet(i) := '0'; end if; end if; end loop; @@ -218,7 +304,7 @@ begin -- Check if 1 of the channels are ready if (r.accept /= 0) then -- Check for timeout - if (r.timer = r.timeout) then + if (timeoutEvent = '1') then -- Set the flag v.ready := '1'; else @@ -228,14 +314,37 @@ begin end if; end if; - -- Check if ready to move data - if (batcherIdle = '1') and (r.ready = '1') then + -- Check if ready to move data and not blowing off the data + if (batcherIdle = '1') and (r.ready = '1') and (r.blowoff = '0') then + + for i in (NUM_SLAVES_G-1) downto 0 loop + + -- Increment data counter + if (r.accept(i) = '1') then + v.dataCnt(i) := r.dataCnt(i) + 1; + end if; + + -- Increment null counter + if (r.nullDet(i) = '1') then + v.nullCnt(i) := r.nullCnt(i) + 1; + end if; + + -- Check if using timer + if (r.timeout /= 0) then + + -- Check for timeout event with respect to a channel + if (r.accept(i) = '0') and (r.nullDet(i) = '0') then + + -- Increment counter + v.timeoutDropCnt(i) := r.timeoutDropCnt(i) + 1; - -- Reset the flag - v.ready := '0'; + -- Set the flag + v.timeoutDet(i) := '1'; + end if; - -- Reset the counter - v.timer := (others => '0'); + end if; + + end loop; -- Set the sub-frame count v.maxSubFrames := resize(onesCount(r.accept), 16); @@ -243,11 +352,38 @@ begin -- Next state v.state := MOVE_S; + -- Check for blowoff flag + elsif (r.blowoff = '1') then + + -- Blow off the inbound data + for i in (NUM_SLAVES_G-1) downto 0 loop + v.rxSlaves(i).tReady := '1'; + end loop; + + -- Reset the flags + v.ready := '0'; + v.accept := (others => '0'); + v.nullDet := (others => '0'); + v.timer := (others => '0'); + v.timeoutDet := (others => '0'); + end if; ---------------------------------------------------------------------- when MOVE_S => + -- Check for timeout channel + if (r.timeoutDet(r.index) = '1') then + + -- Check for last channel + if (r.index = NUM_SLAVES_G-1) then + -- Next state + v.state := IDLE_S; + else + -- Increment the counter + v.index := r.index + 1; + end if; + -- Check if ready to move data - if (rxMasters(r.index).tValid = '1') and (v.txMaster.tValid = '0') then + elsif (rxMasters(r.index).tValid = '1') and (v.txMaster.tValid = '0') then -- Move the data v.rxSlaves(r.index).tReady := '1'; @@ -258,33 +394,48 @@ begin -- Check for the last transfer if (rxMasters(r.index).tLast = '1') then - -- Check for last channel if (r.index = NUM_SLAVES_G-1) then - - -- Reset the counter - v.index := 0; - - -- Reset the accept field (makes it easier to look at simulation) - v.accept := (others => '0'); - -- Next state v.state := IDLE_S; else -- Increment the counter v.index := r.index + 1; end if; - end if; + end if; ---------------------------------------------------------------------- end case; + -- Check for state transitioning from MOVE_S to IDLE_S + if (r.state = MOVE_S) and (v.state = IDLE_S) then + + -- Reset the index pointer + v.index := 0; + + -- Reset the flags + v.ready := '0'; + v.accept := (others => '0'); + v.nullDet := (others => '0'); + v.timer := (others => '0'); + v.timeoutDet := (others => '0'); + + end if; + + -- Check if reseting counters + if (r.cntRst = '1') then + v.dataCnt := (others => (others => '0')); + v.nullCnt := (others => (others => '0')); + v.timeoutDropCnt := (others => (others => '0')); + end if; + -- Outputs rxSlaves <= v.rxSlaves; txMaster <= r.txMaster; axilWriteSlave <= r.axilWriteSlave; axilReadSlave <= r.axilReadSlave; + axisReset <= axisRst or r.hardRst or r.softRst; -- Reset if (axisRst = '1') then @@ -318,7 +469,7 @@ begin port map ( -- Clock and Reset axisClk => axisClk, - axisRst => axisRst, + axisRst => axisReset, -- External Control Interface maxSubFrames => r.maxSubFrames, idle => batcherIdle, diff --git a/protocols/clink/hdl/ClinkCtrl.vhd b/protocols/clink/hdl/ClinkCtrl.vhd index bc8d7e077f..814c4b0621 100644 --- a/protocols/clink/hdl/ClinkCtrl.vhd +++ b/protocols/clink/hdl/ClinkCtrl.vhd @@ -125,6 +125,7 @@ begin intClk => dlyCLk, intRst => dlyRst, baud => chanConfig.serBaud, + throttle => chanConfig.serThrottle, uartClk => uartClk, uartRst => uartRst, sUartMaster => sUartMaster, diff --git a/protocols/clink/hdl/ClinkData.vhd b/protocols/clink/hdl/ClinkData.vhd index 92f6544e93..024ab1c0b8 100644 --- a/protocols/clink/hdl/ClinkData.vhd +++ b/protocols/clink/hdl/ClinkData.vhd @@ -25,93 +25,95 @@ library unisim; use unisim.vcomponents.all; entity ClinkData is - generic ( - TPD_G : time := 1 ns - ); + generic ( + TPD_G : time := 1 ns + ); port ( -- Cable Input - cblHalfP : inout slv(4 downto 0); -- 8, 10, 11, 12, 9 - cblHalfM : inout slv(4 downto 0); -- 21, 23, 24, 25, 22 + cblHalfP : inout slv(4 downto 0); -- 8, 10, 11, 12, 9 + cblHalfM : inout slv(4 downto 0); -- 21, 23, 24, 25, 22 -- Delay clock, 200Mhz - dlyClk : in sl; - dlyRst : in sl; + dlyClk : in sl; + dlyRst : in sl; -- System clock and reset, must be 100Mhz or greater - sysClk : in sl; - sysRst : in sl; + sysClk : in sl; + sysRst : in sl; -- Status and config - linkConfig : in ClLinkConfigType; - linkStatus : out ClLinkStatusType; + linkConfig : in ClLinkConfigType; + linkStatus : out ClLinkStatusType; -- Data output - parData : out slv(27 downto 0); - parValid : out sl; - parReady : in sl); + parData : out slv(27 downto 0); + parValid : out sl; + parReady : in sl); end ClinkData; architecture rtl of ClinkData is type LinkState is (RESET_S, WAIT_C_S, SHIFT_C_S, CHECK_C_S, LOAD_C_S, SHIFT_D_S, CHECK_D_S, DONE_S); - + -- Each delay tap = 1/(32 * 2 * 200Mhz) = 78ps -- Input rate = 85Mhz * 7 = 595Mhz = 1.68nS = 21.55 taps type RegType is record - state : LinkState; - lastClk : slv(6 downto 0); - delay : slv(4 downto 0); - delayLd : sl; - bitSlip : sl; - count : integer range 0 to 99; - status : ClLinkStatusType; + state : LinkState; + lastClk : slv(6 downto 0); + delay : slv(4 downto 0); + delayLd : sl; + bitSlip : sl; + count : integer range 0 to 99; + status : ClLinkStatusType; end record RegType; constant REG_INIT_C : RegType := ( - state => RESET_S, - lastClk => (others=>'0'), - delay => "01111", -- 15 taps, > 1/2 cycle - delayLd => '0', - bitSlip => '0', - count => 99, - status => CL_LINK_STATUS_INIT_C); + state => RESET_S, + lastClk => (others => '0'), + delay => "00001", + delayLd => '0', + bitSlip => '0', + count => 99, + status => CL_LINK_STATUS_INIT_C); signal r : RegType := REG_INIT_C; signal rin : RegType; + signal rstFsm : sl; signal clinkClk : sl; signal clinkRst : sl; signal intData : slv(27 downto 0); signal parClock : slv(6 downto 0); - --attribute MARK_DEBUG : string; - --attribute MARK_DEBUG of r : signal is "TRUE"; - --attribute MARK_DEBUG of parClock : signal is "TRUE"; - --attribute MARK_DEBUG of intData : signal is "TRUE"; + -- attribute MARK_DEBUG : string; + -- attribute MARK_DEBUG of r : signal is "TRUE"; + -- attribute MARK_DEBUG of parClock : signal is "TRUE"; + -- attribute MARK_DEBUG of intData : signal is "TRUE"; + -- attribute MARK_DEBUG of rstFsm : signal is "TRUE"; begin ------------------------------- -- DeSerializer ------------------------------- - U_DataShift: entity work.ClinkDataShift - generic map ( TPD_G => TPD_G ) + U_DataShift : entity work.ClinkDataShift + generic map (TPD_G => TPD_G) port map ( - cblHalfP => cblHalfP, - cblHalfM => cblHalfM, - linkRst => linkConfig.reset, - dlyClk => dlyClk, - dlyRst => dlyRst, - clinkClk => clinkClk, - clinkRst => clinkRst, - parData => intData, - parClock => parClock, - delay => r.delay, - delayLd => r.delayLd, - bitSlip => r.bitSlip); + cblHalfP => cblHalfP, + cblHalfM => cblHalfM, + linkRst => linkConfig.rstPll, + dlyClk => dlyClk, + dlyRst => dlyRst, + clinkClk => clinkClk, + clinkRst => clinkRst, + parData => intData, + parClock => parClock, + delay => r.delay, + delayLd => r.delayLd, + bitSlip => r.bitSlip); ------------------------------- -- State Machine ------------------------------- - comb : process (clinkRst, r, parClock) is - variable v : RegType; + comb : process (clinkRst, parClock, r, rstFsm) is + variable v : RegType; begin v := r; @@ -160,13 +162,13 @@ begin v.state := DONE_S; -- Check for clock change - elsif parClock /= r.lastClk and ( r.lastClk = "1100011" or - r.lastClk = "1110001" or - r.lastClk = "1111000" or - r.lastClk = "0111100" or - r.lastClk = "0011110" or - r.lastClk = "0001111" or - r.lastClk = "1000111" ) then + elsif parClock /= r.lastClk and (r.lastClk = "1100011" or + r.lastClk = "1110001" or + r.lastClk = "1111000" or + r.lastClk = "0111100" or + r.lastClk = "0011110" or + r.lastClk = "0001111" or + r.lastClk = "1000111") then v.state := LOAD_C_S; -- Shift again @@ -177,7 +179,7 @@ begin -- Load final clock shift when LOAD_C_S => - v.delay := r.delay - "01010"; -- 10 = 1/2 cycle + v.delay := r.delay - "01010"; -- 10 = 1/2 cycle v.delayLd := '1'; v.state := CHECK_D_S; @@ -191,8 +193,8 @@ begin end if; when SHIFT_D_S => - v.bitSlip := '1'; - v.state := CHECK_D_S; + v.bitSlip := '1'; + v.state := CHECK_D_S; v.status.shiftCnt := r.status.shiftCnt + 1; when DONE_S => @@ -200,7 +202,8 @@ begin if parClock = "1100011" and r.delay /= 31 then v.status.locked := '1'; else - v.status.locked := '0'; + -- Retry to lock again + v := REG_INIT_C; end if; end if; @@ -210,7 +213,7 @@ begin v.status.delay := r.delay; -- Reset - if (clinkRst = '1') then + if (clinkRst = '1') or (rstFsm = '1') then v := REG_INIT_C; end if; @@ -227,36 +230,44 @@ begin end if; end process seq; + U_RstSync : entity work.RstSync + generic map ( + TPD_G => TPD_G) + port map ( + clk => clinkClk, + asyncRst => linkConfig.rstFsm, + syncRst => rstFsm); + -------------------------------------- -- Output FIFO and status -------------------------------------- - U_DataFifo: entity work.Fifo + U_DataFifo : entity work.Fifo generic map ( - TPD_G => TPD_G, - BRAM_EN_G => false, - FWFT_EN_G => true, - DATA_WIDTH_G => 28, - ADDR_WIDTH_G => 4) + TPD_G => TPD_G, + BRAM_EN_G => false, + FWFT_EN_G => true, + DATA_WIDTH_G => 28, + ADDR_WIDTH_G => 4) port map ( - rst => clinkRst, - wr_clk => clinkClk, - wr_en => '1', - din => intData, - rd_clk => sysClk, - rd_en => parReady, - dout => parData, - valid => parValid); - - U_Locked: entity work.Synchronizer - generic map ( TPD_G => TPD_G ) + rst => clinkRst, + wr_clk => clinkClk, + wr_en => '1', + din => intData, + rd_clk => sysClk, + rd_en => parReady, + dout => parData, + valid => parValid); + + U_Locked : entity work.Synchronizer + generic map (TPD_G => TPD_G) port map ( clk => sysClk, rst => sysRst, dataIn => r.status.locked, dataOut => linkStatus.locked); - U_Delay: entity work.SynchronizerVector - generic map ( + U_Delay : entity work.SynchronizerVector + generic map ( TPD_G => TPD_G, WIDTH_G => 5) port map ( @@ -265,8 +276,8 @@ begin dataIn => r.status.delay, dataOut => linkStatus.delay); - U_ShiftCnt: entity work.SynchronizerVector - generic map ( + U_ShiftCnt : entity work.SynchronizerVector + generic map ( TPD_G => TPD_G, WIDTH_G => 3) port map ( diff --git a/protocols/clink/hdl/ClinkFraming.vhd b/protocols/clink/hdl/ClinkFraming.vhd index dbf4b8e5dc..a1bdd2e998 100644 --- a/protocols/clink/hdl/ClinkFraming.vhd +++ b/protocols/clink/hdl/ClinkFraming.vhd @@ -29,48 +29,48 @@ entity ClinkFraming is DATA_AXIS_CONFIG_G : AxiStreamConfigType := AXI_STREAM_CONFIG_INIT_C); port ( -- System clock and reset - sysClk : in sl; - sysRst : in sl; + sysClk : in sl; + sysRst : in sl; -- Config and status - chanConfig : in ClChanConfigType; - chanStatus : out ClChanStatusType; - linkStatus : in ClLinkStatusArray(2 downto 0); + chanConfig : in ClChanConfigType; + chanStatus : out ClChanStatusType; + linkStatus : in ClLinkStatusArray(2 downto 0); -- Data interface - parData : in Slv28Array(2 downto 0); - parValid : in slv(2 downto 0); - parReady : out sl; + parData : in Slv28Array(2 downto 0); + parValid : in slv(2 downto 0); + parReady : out sl; -- Camera data - dataClk : in sl; - dataRst : in sl; - dataMaster : out AxiStreamMasterType; - dataSlave : in AxiStreamSlaveType); + dataClk : in sl; + dataRst : in sl; + dataMaster : out AxiStreamMasterType; + dataSlave : in AxiStreamSlaveType); end ClinkFraming; architecture rtl of ClinkFraming is - constant SLV_CONFIG_C : AxiStreamConfigType := ssiAxiStreamConfig(dataBytes=>10,tDestBits=>0); - constant MST_CONFIG_C : AxiStreamConfigType := ssiAxiStreamConfig(dataBytes=>16,tDestBits=>0); + constant SLV_CONFIG_C : AxiStreamConfigType := ssiAxiStreamConfig(dataBytes => 10, tDestBits => 0); + constant MST_CONFIG_C : AxiStreamConfigType := ssiAxiStreamConfig(dataBytes => 16, tDestBits => 0); type RegType is record - ready : sl; - portData : ClDataType; - byteData : ClDataType; - bytes : integer range 1 to 10; - inFrame : sl; - dump : sl; - status : ClChanStatusType; - master : AxiStreamMasterType; + ready : sl; + portData : ClDataType; + byteData : ClDataType; + bytes : integer range 1 to 10; + inFrame : sl; + dump : sl; + status : ClChanStatusType; + master : AxiStreamMasterType; end record RegType; constant REG_INIT_C : RegType := ( - ready => '1', - portData => CL_DATA_INIT_C, - byteData => CL_DATA_INIT_C, - bytes => 1, - inFrame => '0', - dump => '0', - status => CL_CHAN_STATUS_INIT_C, - master => AXI_STREAM_MASTER_INIT_C); + ready => '1', + portData => CL_DATA_INIT_C, + byteData => CL_DATA_INIT_C, + bytes => 1, + inFrame => '0', + dump => '0', + status => CL_CHAN_STATUS_INIT_C, + master => AXI_STREAM_MASTER_INIT_C); signal r : RegType := REG_INIT_C; signal rin : RegType; @@ -78,15 +78,18 @@ architecture rtl of ClinkFraming is signal intCtrl : AxiStreamCtrlType; signal packMaster : AxiStreamMasterType; - --attribute MARK_DEBUG : string; - --attribute MARK_DEBUG of r : signal is "TRUE"; - --attribute MARK_DEBUG of parData : signal is "TRUE"; - --attribute MARK_DEBUG of parValid : signal is "TRUE"; - --attribute MARK_DEBUG of parReady : signal is "TRUE"; + -- attribute MARK_DEBUG : string; + -- attribute MARK_DEBUG of r : signal is "TRUE"; + -- attribute MARK_DEBUG of parData : signal is "TRUE"; + -- attribute MARK_DEBUG of parValid : signal is "TRUE"; + -- attribute MARK_DEBUG of parReady : signal is "TRUE"; + -- attribute MARK_DEBUG of intCtrl : signal is "TRUE"; + -- attribute MARK_DEBUG of packMaster : signal is "TRUE"; begin - comb : process (r, sysRst, linkStatus, intCtrl, parData, parValid, chanConfig) is + comb : process (chanConfig, intCtrl, linkStatus, parData, parValid, r, + sysRst) is variable v : RegType; begin v := r; @@ -109,47 +112,47 @@ begin -- 8-bit, cameraLink spec V2.0, page 16 if chanConfig.dataMode = CDM_8BIT_C then v.portData.lv := parData(0)(24) and parData(1)(27) and parData(2)(27); - v.portData.data(0) := parData(0)(7 downto 0); - v.portData.data(1) := parData(0)(15 downto 8); + v.portData.data(0) := parData(0)(7 downto 0); + v.portData.data(1) := parData(0)(15 downto 8); v.portData.data(2) := parData(0)(23 downto 16); v.portData.data(3)(1 downto 0) := parData(0)(27 downto 26); - v.portData.data(3)(7 downto 2) := parData(1)(5 downto 0); - v.portData.data(4) := parData(1)(13 downto 6); + v.portData.data(3)(7 downto 2) := parData(1)(5 downto 0); + v.portData.data(4) := parData(1)(13 downto 6); v.portData.data(5) := parData(1)(21 downto 14); v.portData.data(6)(4 downto 0) := parData(1)(26 downto 22); - v.portData.data(6)(7 downto 5) := parData(2)(2 downto 0); - v.portData.data(7) := parData(2)(10 downto 3); + v.portData.data(6)(7 downto 5) := parData(2)(2 downto 0); + v.portData.data(7) := parData(2)(10 downto 3); v.portData.data(8) := parData(2)(18 downto 11); v.portData.data(9) := parData(2)(26 downto 19); -- 10-bit, cameraLink spec V2.0, page 17 elsif chanConfig.dataMode = CDM_10BIT_C then v.portData.lv := parData(0)(24) and parData(1)(24) and parData(2)(24); - v.portData.data(0)(4 downto 0) := parData(0)(4 downto 0); + v.portData.data(0)(4 downto 0) := parData(0)(4 downto 0); v.portData.data(0)(5) := parData(0)(6); v.portData.data(0)(6) := parData(0)(27); v.portData.data(0)(7) := parData(0)(5); - v.portData.data(1)(2 downto 0) := parData(0)(9 downto 7); + v.portData.data(1)(2 downto 0) := parData(0)(9 downto 7); v.portData.data(1)(5 downto 3) := parData(0)(14 downto 12); v.portData.data(1)(7 downto 6) := parData(0)(11 downto 10); v.portData.data(2)(0) := parData(0)(15); v.portData.data(2)(5 downto 1) := parData(0)(22 downto 18); v.portData.data(2)(7 downto 6) := parData(0)(17 downto 16); - v.portData.data(3)(4 downto 0) := parData(1)(4 downto 0); + v.portData.data(3)(4 downto 0) := parData(1)(4 downto 0); v.portData.data(3)(5) := parData(1)(6); v.portData.data(3)(6) := parData(1)(27); v.portData.data(3)(7) := parData(1)(5); - v.portData.data(4)(2 downto 0) := parData(1)(9 downto 7); + v.portData.data(4)(2 downto 0) := parData(1)(9 downto 7); v.portData.data(4)(5 downto 3) := parData(1)(14 downto 12); v.portData.data(4)(7 downto 6) := parData(1)(11 downto 10); v.portData.data(5)(0) := parData(1)(15); v.portData.data(5)(5 downto 1) := parData(1)(22 downto 18); v.portData.data(5)(7 downto 6) := parData(1)(17 downto 16); - v.portData.data(6)(4 downto 0) := parData(2)(4 downto 0); + v.portData.data(6)(4 downto 0) := parData(2)(4 downto 0); v.portData.data(6)(5) := parData(2)(6); v.portData.data(6)(6) := parData(2)(27); v.portData.data(6)(7) := parData(2)(5); - v.portData.data(7)(2 downto 0) := parData(2)(9 downto 7); + v.portData.data(7)(2 downto 0) := parData(2)(9 downto 7); v.portData.data(7)(5 downto 3) := parData(2)(14 downto 12); v.portData.data(7)(7 downto 6) := parData(2)(11 downto 10); v.portData.data(8)(0) := parData(0)(26); @@ -172,7 +175,7 @@ begin v.portData.data(0)(5) := parData(0)(6); v.portData.data(0)(6) := parData(0)(27); v.portData.data(0)(7) := parData(0)(5); - v.portData.data(1)(2 downto 0) := parData(0)(9 downto 7); + v.portData.data(1)(2 downto 0) := parData(0)(9 downto 7); v.portData.data(1)(5 downto 3) := parData(0)(14 downto 12); v.portData.data(1)(7 downto 6) := parData(0)(11 downto 10); v.portData.data(2)(0) := parData(0)(15); @@ -184,7 +187,7 @@ begin v.portData.data(3)(5) := parData(1)(6); v.portData.data(3)(6) := parData(1)(27); v.portData.data(3)(7) := parData(1)(5); - v.portData.data(4)(2 downto 0) := parData(1)(9 downto 7); + v.portData.data(4)(2 downto 0) := parData(1)(9 downto 7); v.portData.data(4)(5 downto 3) := parData(1)(14 downto 12); v.portData.data(4)(7 downto 6) := parData(1)(11 downto 10); v.portData.data(5)(0) := parData(1)(15); @@ -196,7 +199,7 @@ begin v.portData.data(6)(5) := parData(2)(6); v.portData.data(6)(6) := parData(2)(27); v.portData.data(6)(7) := parData(2)(5); - v.portData.data(7)(2 downto 0) := parData(2)(9 downto 7); + v.portData.data(7)(2 downto 0) := parData(2)(9 downto 7); v.portData.data(7)(5 downto 3) := parData(2)(14 downto 12); v.portData.data(7)(7 downto 6) := parData(2)(11 downto 10); v.portData.data(8)(0) := parData(2)(15); @@ -204,7 +207,7 @@ begin v.portData.data(8)(7 downto 6) := parData(2)(17 downto 16); -- Determine valids based upon modes - case chanConfig.linkMode is + case chanConfig.linkMode is -- Base mode, 24 bits, cameraLink spec V2.0 page 15 when CLM_BASE_C => @@ -229,7 +232,7 @@ begin v.portData.dv := parData(0)(26) and parData(1)(26) and parData(2)(26); v.portData.fv := parData(0)(25) and parData(1)(25) and parData(2)(25); v.portData.lv := parData(0)(24) and parData(1)(24) and parData(2)(24); - + when others => end case; end if; @@ -244,11 +247,11 @@ begin -- Move only when portData is valid if r.portData.valid = '1' then v.byteData := r.portData; - v.byteData.data := (others=>(others=>'0')); - v.bytes := 1; + v.byteData.data := (others => (others => '0')); + v.bytes := 1; -- Data mode - case chanConfig.dataMode is + case chanConfig.dataMode is -- 8 bits, base, medium, full & deca when CDM_8BIT_C => @@ -261,69 +264,69 @@ begin v.byteData := r.portData; v.bytes := 10; else - v.byteData.data(0) := r.portData.data(0); -- T1, DA[07:00] - v.byteData.data(1)(1 downto 0) := r.portData.data(1)(1 downto 0); -- T1, DA[09:08] - v.byteData.data(2) := r.portData.data(2); -- T2, DB[07:00] - v.byteData.data(3)(1 downto 0) := r.portData.data(1)(5 downto 4); -- T2, DB[09:08] - v.byteData.data(4) := r.portData.data(4); -- T3, DC[07:00] - v.byteData.data(5)(1 downto 0) := r.portData.data(5)(1 downto 0); -- T3, DC[09:08] - v.byteData.data(6) := r.portData.data(3); -- T4, DD[07:00] - v.byteData.data(7)(1 downto 0) := r.portData.data(5)(5 downto 4); -- T4, DD[09:08] - - v.bytes := conv_integer(chanConfig.tapCount & "0"); -- tapCount * 2 + v.byteData.data(0) := r.portData.data(0); -- T1, DA[07:00] + v.byteData.data(1)(1 downto 0) := r.portData.data(1)(1 downto 0); -- T1, DA[09:08] + v.byteData.data(2) := r.portData.data(2); -- T2, DB[07:00] + v.byteData.data(3)(1 downto 0) := r.portData.data(1)(5 downto 4); -- T2, DB[09:08] + v.byteData.data(4) := r.portData.data(4); -- T3, DC[07:00] + v.byteData.data(5)(1 downto 0) := r.portData.data(5)(1 downto 0); -- T3, DC[09:08] + v.byteData.data(6) := r.portData.data(3); -- T4, DD[07:00] + v.byteData.data(7)(1 downto 0) := r.portData.data(5)(5 downto 4); -- T4, DD[09:08] + + v.bytes := conv_integer(chanConfig.tapCount & "0"); -- tapCount * 2 end if; - + -- 12 bits, base and medium, cameraLink spec V2.0 pages 19-20 when CDM_12BIT_C => - v.byteData.data(0) := r.portData.data(0); -- T1, DA[07:00] - v.byteData.data(1)(3 downto 0) := r.portData.data(1)(3 downto 0); -- T1, DA[11:08] - v.byteData.data(2) := r.portData.data(2); -- T2, DB[07:00] - v.byteData.data(3)(3 downto 0) := r.portData.data(1)(7 downto 4); -- T2, DB[11:08] - v.byteData.data(4) := r.portData.data(4); -- T3, DC[07:00] - v.byteData.data(5)(3 downto 0) := r.portData.data(5)(3 downto 0); -- T3, DC[11:08] - v.byteData.data(6) := r.portData.data(3); -- T4, DD[07:00] - v.byteData.data(7)(3 downto 0) := r.portData.data(5)(7 downto 4); -- T4, DD[11:08] - - v.bytes := conv_integer(chanConfig.tapCount & "0"); -- tapCount * 2 - + v.byteData.data(0) := r.portData.data(0); -- T1, DA[07:00] + v.byteData.data(1)(3 downto 0) := r.portData.data(1)(3 downto 0); -- T1, DA[11:08] + v.byteData.data(2) := r.portData.data(2); -- T2, DB[07:00] + v.byteData.data(3)(3 downto 0) := r.portData.data(1)(7 downto 4); -- T2, DB[11:08] + v.byteData.data(4) := r.portData.data(4); -- T3, DC[07:00] + v.byteData.data(5)(3 downto 0) := r.portData.data(5)(3 downto 0); -- T3, DC[11:08] + v.byteData.data(6) := r.portData.data(3); -- T4, DD[07:00] + v.byteData.data(7)(3 downto 0) := r.portData.data(5)(7 downto 4); -- T4, DD[11:08] + + v.bytes := conv_integer(chanConfig.tapCount & "0"); -- tapCount * 2 + -- 14 bits, base, cameraLink spec V2.0 page 19 when CDM_14BIT_C => - v.byteData.data(0) := r.portData.data(0); -- T1, DA[07:00] - v.byteData.data(1)(5 downto 0) := r.portData.data(1)(5 downto 0); -- T1, DA[13:08] - v.bytes := 2; + v.byteData.data(0) := r.portData.data(0); -- T1, DA[07:00] + v.byteData.data(1)(5 downto 0) := r.portData.data(1)(5 downto 0); -- T1, DA[13:08] + v.bytes := 2; -- 16 bits, base, cameraLink spec V2.0 page 19 when CDM_16BIT_C => - v.byteData.data(0) := r.portData.data(0); -- T1, DA[07:00] - v.byteData.data(1) := r.portData.data(1); -- T1, DA[15:08] - v.bytes := 2; + v.byteData.data(0) := r.portData.data(0); -- T1, DA[07:00] + v.byteData.data(1) := r.portData.data(1); -- T1, DA[15:08] + v.bytes := 2; -- 24 bits, base, cameraLink spec V2.0 page 19 when CDM_24BIT_C => - v.byteData.data(0) := r.portData.data(0); -- T1, DR[07:00] - v.byteData.data(1) := r.portData.data(1); -- T2, DG[07:08] - v.byteData.data(2) := r.portData.data(2); -- T3, DB[07:08] - v.bytes := 3; + v.byteData.data(0) := r.portData.data(0); -- T1, DR[07:00] + v.byteData.data(1) := r.portData.data(1); -- T2, DG[07:08] + v.byteData.data(2) := r.portData.data(2); -- T3, DB[07:08] + v.bytes := 3; -- 30 bits, medium, cameraLink spec V2.0 page 20 when CDM_30BIT_C => - v.byteData.data(0) := r.portData.data(0); -- T1, DR[07:00] - v.byteData.data(1)(1 downto 0) := r.portData.data(1)(1 downto 0); -- T1, DR[09:08] - v.byteData.data(2) := r.portData.data(2); -- T2, DB[07:00] - v.byteData.data(3)(1 downto 0) := r.portData.data(1)(5 downto 4); -- T2, DB[09:08] - v.byteData.data(4) := r.portData.data(4); -- T3, DG[07:00] - v.byteData.data(5)(1 downto 0) := r.portData.data(5)(1 downto 0); -- T3, DG[09:08] - v.bytes := 6; + v.byteData.data(0) := r.portData.data(0); -- T1, DR[07:00] + v.byteData.data(1)(1 downto 0) := r.portData.data(1)(1 downto 0); -- T1, DR[09:08] + v.byteData.data(2) := r.portData.data(2); -- T2, DB[07:00] + v.byteData.data(3)(1 downto 0) := r.portData.data(1)(5 downto 4); -- T2, DB[09:08] + v.byteData.data(4) := r.portData.data(4); -- T3, DG[07:00] + v.byteData.data(5)(1 downto 0) := r.portData.data(5)(1 downto 0); -- T3, DG[09:08] + v.bytes := 6; -- 36 bits, medium, cameraLink spec V2.0 pages 20 when CDM_36BIT_C => - v.byteData.data(0) := r.portData.data(0); -- T1, DR[07:00] - v.byteData.data(1)(3 downto 0) := r.portData.data(1)(3 downto 0); -- T1, DR[11:08] - v.byteData.data(2) := r.portData.data(2); -- T2, DB[07:00] - v.byteData.data(3)(3 downto 0) := r.portData.data(1)(7 downto 4); -- T2, DB[11:08] - v.byteData.data(4) := r.portData.data(4); -- T3, DG[07:00] - v.byteData.data(5)(3 downto 0) := r.portData.data(5)(3 downto 0); -- T3, DG[11:08] - v.bytes := 6; + v.byteData.data(0) := r.portData.data(0); -- T1, DR[07:00] + v.byteData.data(1)(3 downto 0) := r.portData.data(1)(3 downto 0); -- T1, DR[11:08] + v.byteData.data(2) := r.portData.data(2); -- T2, DB[07:00] + v.byteData.data(3)(3 downto 0) := r.portData.data(1)(7 downto 4); -- T2, DB[11:08] + v.byteData.data(4) := r.portData.data(4); -- T3, DG[07:00] + v.byteData.data(5)(3 downto 0) := r.portData.data(5)(3 downto 0); -- T3, DG[11:08] + v.bytes := 6; when others => end case; @@ -333,23 +336,23 @@ begin -- Frame Generation --------------------------------- v.master := AXI_STREAM_MASTER_INIT_C; - v.master.tKeep := (others=>'0'); + v.master.tKeep := (others => '0'); -- Setup output data for i in 0 to SLV_CONFIG_C.TDATA_BYTES_C-1 loop if i < r.bytes then v.master.tData((i*8)+7 downto i*8) := r.byteData.data(i); - v.master.tKeep(i) := '1'; + v.master.tKeep(i) := '1'; end if; end loop; -- Set start of frame - ssiSetUserSof ( SLV_CONFIG_C, v.master, not r.inFrame ); + ssiSetUserSof (SLV_CONFIG_C, v.master, not r.inFrame); -- Move data if r.portData.valid = '1' and r.byteData.valid = '1' and ( - ( chanConfig.frameMode = CFM_FRAME_C and r.byteData.fv = '1') or -- Frame mode - ( chanConfig.frameMode = CFM_LINE_C and r.byteData.lv = '1') ) then -- Line mode + (chanConfig.frameMode = CFM_FRAME_C and r.byteData.fv = '1') or -- Frame mode + (chanConfig.frameMode = CFM_LINE_C and r.byteData.lv = '1')) then -- Line mode -- Valid data in byte record if r.dump = '0' and r.byteData.dv = '1' and r.byteData.lv = '1' then @@ -363,12 +366,12 @@ begin end if; -- End of frame or line depending on mode - if (chanConfig.frameMode = CFM_FRAME_C and r.byteData.fv = '1' and r.portData.fv = '0') or -- Frame mode - (chanConfig.frameMode = CFM_LINE_C and r.byteData.lv = '1' and r.portData.lv = '0') then -- Line mode + if (chanConfig.frameMode = CFM_FRAME_C and r.byteData.fv = '1' and r.portData.fv = '0') or -- Frame mode + (chanConfig.frameMode = CFM_LINE_C and r.byteData.lv = '1' and r.portData.lv = '0') then -- Line mode -- Frame was dumped, or bad end markers - if r.dump = '1' or r.inFrame = '0' or r.byteData.dv = '0' or r.byteData.lv = '0' then - ssiSetUserEofe ( SLV_CONFIG_C, v.master, '1' ); + if (r.dump = '1' or r.inFrame = '0' or r.byteData.dv = '0') then + ssiSetUserEofe (SLV_CONFIG_C, v.master, '1'); v.status.dropCount := r.status.dropCount + 1; else v.status.frameCount := r.status.frameCount + 1; @@ -382,22 +385,34 @@ begin end if; end if; - parReady <= v.ready; + -- Check if we need to blow off the streaming data for debugging + if (chanConfig.blowoff = '1') then + v.master.tValid := '0'; + end if; - --------------------------------- - -- Reset and outputs - --------------------------------- + -- Check for counter reset + if (chanConfig.cntRst = '1') then + v.status.frameCount := (others => '0'); + v.status.dropCount := (others => '0'); + end if; + + -- Outputs + parReady <= v.ready; + chanStatus <= r.status; + + -- Reset if (sysRst = '1' or chanConfig.dataEn = '0') then v := REG_INIT_C; end if; - rin <= v; - chanStatus <= r.status; + -- Register the variable for next clock cycle + rin <= v; + end process; seq : process (sysClk) is - begin + begin if (rising_edge(sysClk)) then r <= rin; end if; @@ -406,7 +421,7 @@ begin --------------------------------- -- Frame Packing --------------------------------- - U_Pack: entity work.AxiStreamBytePacker + U_Pack : entity work.AxiStreamBytePacker generic map ( TPD_G => TPD_G, SLAVE_CONFIG_G => SLV_CONFIG_C, @@ -420,7 +435,7 @@ begin --------------------------------- -- Data FIFO --------------------------------- - U_DataFifo: entity work.AxiStreamFifoV2 + U_DataFifo : entity work.AxiStreamFifoV2 generic map ( TPD_G => TPD_G, SLAVE_READY_EN_G => false, diff --git a/protocols/clink/hdl/ClinkPkg.vhd b/protocols/clink/hdl/ClinkPkg.vhd index 0e0df76676..043a781c7e 100644 --- a/protocols/clink/hdl/ClinkPkg.vhd +++ b/protocols/clink/hdl/ClinkPkg.vhd @@ -55,11 +55,15 @@ package ClinkPkg is -- Link Configuration Record ------------------------------------ type ClLinkConfigType is record - reset : sl; + cntRst : sl; + rstFsm : sl; + rstPll : sl; end record ClLinkConfigType; constant CL_LINK_CONFIG_INIT_C : ClLinkConfigType := ( - reset => '0'); + cntRst => '0', + rstFsm => '0', + rstPll => '0'); type ClLinkConfigArray is array (natural range<>) of ClLinkConfigType; @@ -67,15 +71,15 @@ package ClinkPkg is -- Link Status Record ------------------------------------ type ClLinkStatusType is record - locked : sl; - delay : slv(4 downto 0); - shiftCnt : slv(2 downto 0); + locked : sl; + delay : slv(4 downto 0); + shiftCnt : slv(2 downto 0); end record ClLinkStatusType; constant CL_LINK_STATUS_INIT_C : ClLinkStatusType := ( - locked => '0', - delay => (others=>'0'), - shiftCnt => (others=>'0')); + locked => '0', + delay => (others => '0'), + shiftCnt => (others => '0')); type ClLinkStatusArray is array (natural range<>) of ClLinkStatusType; @@ -86,21 +90,27 @@ package ClinkPkg is swCamCtrl : slv(3 downto 0); swCamCtrlEn : slv(3 downto 0); serBaud : slv(23 downto 0); + serThrottle : slv(15 downto 0); linkMode : slv(3 downto 0); dataMode : slv(3 downto 0); tapCount : slv(3 downto 0); frameMode : slv(3 downto 0); + cntRst : sl; + blowoff : sl; dataEn : sl; end record ClChanConfigType; constant CL_CHAN_CONFIG_INIT_C : ClChanConfigType := ( - swCamCtrl => (others=>'0'), - swCamCtrlEn => (others=>'0'), - serBaud => (others=>'0'), - linkMode => (others=>'0'), - dataMode => (others=>'0'), - tapCount => (others=>'0'), - frameMode => (others=>'0'), + swCamCtrl => (others => '0'), + swCamCtrlEn => (others => '0'), + serBaud => toSlv(57600, 24), -- Default of 57600 baud + serThrottle => (others => '1'), -- Default of 65ms per byte throttle rate + linkMode => (others => '0'), + dataMode => (others => '0'), + tapCount => (others => '0'), + frameMode => (others => '0'), + cntRst => '0', + blowoff => '0', dataEn => '0'); type ClChanConfigArray is array (natural range<>) of ClChanConfigType; @@ -116,8 +126,8 @@ package ClinkPkg is constant CL_CHAN_STATUS_INIT_C : ClChanStatusType := ( running => '0', - frameCount => (others=>'0'), - dropCount => (others=>'0')); + frameCount => (others => '0'), + dropCount => (others => '0')); type ClChanStatusArray is array (natural range<>) of ClChanStatusType; @@ -125,19 +135,19 @@ package ClinkPkg is -- Data Type ------------------------------------ type ClDataType is record - valid : sl; - data : Slv8Array(9 downto 0); - dv : sl; - fv : sl; - lv : sl; + valid : sl; + data : Slv8Array(9 downto 0); + dv : sl; + fv : sl; + lv : sl; end record ClDataType; constant CL_DATA_INIT_C : ClDataType := ( - valid => '0', - data => (others=>(others=>'0')), - dv => '0', - fv => '0', - lv => '0'); + valid => '0', + data => (others => (others => '0')), + dv => '0', + fv => '0', + lv => '0'); end package ClinkPkg; diff --git a/protocols/clink/hdl/ClinkTop.vhd b/protocols/clink/hdl/ClinkTop.vhd index 82ee68f88f..ef7ec383fc 100644 --- a/protocols/clink/hdl/ClinkTop.vhd +++ b/protocols/clink/hdl/ClinkTop.vhd @@ -34,68 +34,72 @@ entity ClinkTop is UART_AXIS_CONFIG_G : AxiStreamConfigType := AXI_STREAM_CONFIG_INIT_C); port ( -- Connector 0, Half 0, Control for Base,Medium,Full,Deca - cbl0Half0P : inout slv(4 downto 0); -- 15, 17, 5, 6, 3 - cbl0Half0M : inout slv(4 downto 0); -- 2, 4, 18, 19, 16 + cbl0Half0P : inout slv(4 downto 0); -- 15, 17, 5, 6, 3 + cbl0Half0M : inout slv(4 downto 0); -- 2, 4, 18, 19, 16 -- Connector 0, Half 1, Data X for Base,Medium,Full,Deca - cbl0Half1P : inout slv(4 downto 0); -- 8, 10, 11, 12, 9 - cbl0Half1M : inout slv(4 downto 0); -- 21, 23, 24, 25, 22 + cbl0Half1P : inout slv(4 downto 0); -- 8, 10, 11, 12, 9 + cbl0Half1M : inout slv(4 downto 0); -- 21, 23, 24, 25, 22 -- Connector 0, Serial out - cbl0SerP : out sl; -- 20 - cbl0SerM : out sl; -- 7 + cbl0SerP : out sl; -- 20 + cbl0SerM : out sl; -- 7 -- Connector 1, Half 0, Control Base, Data Z for Med, Full, Deca - cbl1Half0P : inout slv(4 downto 0); -- 2, 4, 5, 6, 3 - cbl1Half0M : inout slv(4 downto 0); -- 15, 17, 18, 19 16 + cbl1Half0P : inout slv(4 downto 0); -- 2, 4, 5, 6, 3 + cbl1Half0M : inout slv(4 downto 0); -- 15, 17, 18, 19 16 -- Connector 1, Half 1, Data X for Base, Data Y for Med, Full, Deca - cbl1Half1P : inout slv(4 downto 0); -- 8, 10, 11, 12, 9 - cbl1Half1M : inout slv(4 downto 0); -- 21, 23, 24, 25, 22 + cbl1Half1P : inout slv(4 downto 0); -- 8, 10, 11, 12, 9 + cbl1Half1M : inout slv(4 downto 0); -- 21, 23, 24, 25, 22 -- Connector 1, Serial out - cbl1SerP : out sl; -- 20 - cbl1SerM : out sl; -- 7 + cbl1SerP : out sl; -- 20 + cbl1SerM : out sl; -- 7 -- Delay clock and reset, 200Mhz - dlyClk : in sl; - dlyRst : in sl; + dlyClk : in sl; + dlyRst : in sl; -- System clock and reset, > 100 Mhz - sysClk : in sl; - sysRst : in sl; + sysClk : in sl; + sysRst : in sl; -- Camera Control Bits & status, async - camCtrl : in Slv4Array(CHAN_COUNT_G-1 downto 0); - camStatus : out ClChanStatusArray(1 downto 0); + camCtrl : in Slv4Array(CHAN_COUNT_G-1 downto 0); + camStatus : out ClChanStatusArray(1 downto 0); -- Camera data - dataClk : in sl; - dataRst : in sl; - dataMasters : out AxiStreamMasterArray(CHAN_COUNT_G-1 downto 0); - dataSlaves : in AxiStreamSlaveArray(CHAN_COUNT_G-1 downto 0); + dataClk : in sl; + dataRst : in sl; + dataMasters : out AxiStreamMasterArray(CHAN_COUNT_G-1 downto 0); + dataSlaves : in AxiStreamSlaveArray(CHAN_COUNT_G-1 downto 0); -- UART data - uartClk : in sl; - uartRst : in sl; - sUartMasters : in AxiStreamMasterArray(CHAN_COUNT_G-1 downto 0); - sUartSlaves : out AxiStreamSlaveArray(CHAN_COUNT_G-1 downto 0); - sUartCtrls : out AxiStreamCtrlArray(CHAN_COUNT_G-1 downto 0); - mUartMasters : out AxiStreamMasterArray(CHAN_COUNT_G-1 downto 0); - mUartSlaves : in AxiStreamSlaveArray(CHAN_COUNT_G-1 downto 0); + uartClk : in sl; + uartRst : in sl; + sUartMasters : in AxiStreamMasterArray(CHAN_COUNT_G-1 downto 0); + sUartSlaves : out AxiStreamSlaveArray(CHAN_COUNT_G-1 downto 0); + sUartCtrls : out AxiStreamCtrlArray(CHAN_COUNT_G-1 downto 0); + mUartMasters : out AxiStreamMasterArray(CHAN_COUNT_G-1 downto 0); + mUartSlaves : in AxiStreamSlaveArray(CHAN_COUNT_G-1 downto 0); -- Axi-Lite Interface - axilClk : in sl; - axilRst : in sl; - axilReadMaster : in AxiLiteReadMasterType; - axilReadSlave : out AxiLiteReadSlaveType; - axilWriteMaster : in AxiLiteWriteMasterType; - axilWriteSlave : out AxiLiteWriteSlaveType); + axilClk : in sl; + axilRst : in sl; + axilReadMaster : in AxiLiteReadMasterType; + axilReadSlave : out AxiLiteReadSlaveType; + axilWriteMaster : in AxiLiteWriteMasterType; + axilWriteSlave : out AxiLiteWriteSlaveType); end ClinkTop; architecture rtl of ClinkTop is type RegType is record - chanConfig : ClChanConfigArray(1 downto 0); - linkConfig : ClLinkConfigType; - axilReadSlave : AxiLiteReadSlaveType; - axilWriteSlave : AxiLiteWriteSlaveType; + locked : slv(2 downto 0); + lockCnt : Slv8Array(2 downto 0); + chanConfig : ClChanConfigArray(1 downto 0); + linkConfig : ClLinkConfigType; + axilReadSlave : AxiLiteReadSlaveType; + axilWriteSlave : AxiLiteWriteSlaveType; end record RegType; constant REG_INIT_C : RegType := ( - chanConfig => (others=>CL_CHAN_CONFIG_INIT_C), - linkConfig => CL_LINK_CONFIG_INIT_C, - axilReadSlave => AXI_LITE_READ_SLAVE_INIT_C, - axilWriteSlave => AXI_LITE_WRITE_SLAVE_INIT_C); + locked => "000", + lockCnt => (others=>x"00"), + chanConfig => (others => CL_CHAN_CONFIG_INIT_C), + linkConfig => CL_LINK_CONFIG_INIT_C, + axilReadSlave => AXI_LITE_READ_SLAVE_INIT_C, + axilWriteSlave => AXI_LITE_WRITE_SLAVE_INIT_C); signal r : RegType := REG_INIT_C; signal rin : RegType; @@ -125,39 +129,39 @@ begin ---------------------------------------- U_IdelayCtrl : IDELAYCTRL port map ( - RDY => open, -- 1-bit output: Ready output - REFCLK => dlyClk, -- 1-bit input: Reference clock input - RST => dlyRst); -- 1-bit input: Active high reset input + RDY => open, -- 1-bit output: Ready output + REFCLK => dlyClk, -- 1-bit input: Reference clock input + RST => dlyRst); -- 1-bit input: Active high reset input -- Connector 0, Half 0, Control for Base,Medium,Full,Deca - U_Cbl0Half0: entity work.ClinkCtrl + U_Cbl0Half0 : entity work.ClinkCtrl generic map ( TPD_G => TPD_G, INV_34_G => false, UART_READY_EN_G => UART_READY_EN_G, UART_AXIS_CONFIG_G => UART_AXIS_CONFIG_G) port map ( - cblHalfP => cbl0Half0P, - cblHalfM => cbl0Half0M, - cblSerP => cbl0SerP, - cblSerM => cbl0SerM, - dlyClk => dlyClk, - dlyRst => dlyRst, - sysClk => sysClk, - sysRst => sysRst, - camCtrl => camCtrl(0), - chanConfig => r.chanConfig(0), - uartClk => uartClk, - uartRst => uartRst, - sUartMaster => sUartMasters(0), - sUartSlave => sUartSlaves(0), - sUartCtrl => sUartCtrls(0), - mUartMaster => mUartMasters(0), - mUartSlave => mUartSlaves(0)); + cblHalfP => cbl0Half0P, + cblHalfM => cbl0Half0M, + cblSerP => cbl0SerP, + cblSerM => cbl0SerM, + dlyClk => dlyClk, + dlyRst => dlyRst, + sysClk => sysClk, + sysRst => sysRst, + camCtrl => camCtrl(0), + chanConfig => r.chanConfig(0), + uartClk => uartClk, + uartRst => uartRst, + sUartMaster => sUartMasters(0), + sUartSlave => sUartSlaves(0), + sUartCtrl => sUartCtrls(0), + mUartMaster => mUartMasters(0), + mUartSlave => mUartSlaves(0)); -- Connector 0, Half 1, Data X for Base,Medium,Full,Deca - U_Cbl0Half1: entity work.ClinkData - generic map ( TPD_G => TPD_G) + U_Cbl0Half1 : entity work.ClinkData + generic map (TPD_G => TPD_G) port map ( cblHalfP => cbl0Half1P, cblHalfM => cbl0Half1M, @@ -172,47 +176,47 @@ begin parReady => frameReady(0)); -- Dual channel enable - U_DualCtrlEn: if CHAN_COUNT_G = 2 generate + U_DualCtrlEn : if CHAN_COUNT_G = 2 generate -- Connector 1, Half 0, Control Base, Data Z for Med, Full, Deca - U_Cbl1Half0: entity work.ClinkCtrl + U_Cbl1Half0 : entity work.ClinkCtrl generic map ( TPD_G => TPD_G, INV_34_G => true, UART_READY_EN_G => UART_READY_EN_G, UART_AXIS_CONFIG_G => UART_AXIS_CONFIG_G) port map ( - cblHalfP => cbl1Half0P, - cblHalfM => cbl1Half0M, - cblSerP => cbl1SerP, - cblSerM => cbl1SerM, - dlyClk => dlyClk, - dlyRst => dlyRst, - sysClk => sysClk, - sysRst => sysRst, - camCtrl => camCtrl(1), - chanConfig => r.chanConfig(1), - uartClk => uartClk, - uartRst => uartRst, - sUartMaster => sUartMasters(1), - sUartSlave => sUartSlaves(1), - sUartCtrl => sUartCtrls(1), - mUartMaster => mUartMasters(1), - mUartSlave => mUartSlaves(1)); + cblHalfP => cbl1Half0P, + cblHalfM => cbl1Half0M, + cblSerP => cbl1SerP, + cblSerM => cbl1SerM, + dlyClk => dlyClk, + dlyRst => dlyRst, + sysClk => sysClk, + sysRst => sysRst, + camCtrl => camCtrl(1), + chanConfig => r.chanConfig(1), + uartClk => uartClk, + uartRst => uartRst, + sUartMaster => sUartMasters(1), + sUartSlave => sUartSlaves(1), + sUartCtrl => sUartCtrls(1), + mUartMaster => mUartMasters(1), + mUartSlave => mUartSlaves(1)); -- Unused signals linkStatus(2) <= CL_LINK_STATUS_INIT_C; - parData(2) <= (others=>'0'); + parData(2) <= (others => '0'); parValid(2) <= '0'; end generate; -- Dual channel disable - U_DualCtrlDis: if CHAN_COUNT_G = 1 generate + U_DualCtrlDis : if CHAN_COUNT_G = 1 generate -- Connector 1, Half 0, Control Base, Data Z for Med, Full, Deca - U_Cbl1Half0: entity work.ClinkData - generic map ( TPD_G => TPD_G ) + U_Cbl1Half0 : entity work.ClinkData + generic map (TPD_G => TPD_G) port map ( cblHalfP => cbl1Half0P, cblHalfM => cbl1Half0M, @@ -226,7 +230,7 @@ begin parValid => parValid(2), parReady => frameReady(0)); - U_SerOut: OBUFDS + U_SerOut : OBUFDS port map ( I => '0', O => cbl1SerP, @@ -235,8 +239,8 @@ begin end generate; -- Connector 1, Half 1, Data X for Base, Data Y for Med, Full, Deca - U_Cbl1Half1: entity work.ClinkData - generic map ( TPD_G => TPD_G ) + U_Cbl1Half1 : entity work.ClinkData + generic map (TPD_G => TPD_G) port map ( cblHalfP => cbl1Half1P, cblHalfM => cbl1Half1M, @@ -258,21 +262,21 @@ begin TPD_G => TPD_G, DATA_AXIS_CONFIG_G => DATA_AXIS_CONFIG_G) port map ( - sysClk => sysClk, - sysRst => sysRst, - chanConfig => r.chanConfig(0), - chanStatus => chanStatus(0), - linkStatus => linkStatus, - parData => parData, - parValid => parValid, - parReady => frameReady(0), - dataClk => dataClk, - dataRst => dataRst, - dataMaster => dataMasters(0), - dataSlave => dataSlaves(0)); + sysClk => sysClk, + sysRst => sysRst, + chanConfig => r.chanConfig(0), + chanStatus => chanStatus(0), + linkStatus => linkStatus, + parData => parData, + parValid => parValid, + parReady => frameReady(0), + dataClk => dataClk, + dataRst => dataRst, + dataMaster => dataMasters(0), + dataSlave => dataSlaves(0)); -- Dual data processing enable - U_DualFrameEn: if CHAN_COUNT_G = 2 generate + U_DualFrameEn : if CHAN_COUNT_G = 2 generate U_Framer1 : entity work.ClinkFraming generic map ( @@ -287,8 +291,8 @@ begin linkStatus(1) => CL_LINK_STATUS_INIT_C, linkStatus(2) => CL_LINK_STATUS_INIT_C, parData(0) => parData(1), - parData(1) => (others=>'0'), - parData(2) => (others=>'0'), + parData(1) => (others => '0'), + parData(2) => (others => '0'), parValid(0) => parValid(1), parValid(1) => '0', parValid(2) => '0', @@ -301,18 +305,18 @@ begin end generate; -- Dual data processing disable - U_DualFrameDis: if CHAN_COUNT_G = 1 generate - chanStatus(1) <= CL_CHAN_STATUS_INIT_C; - frameReady(1) <= frameReady(0); + U_DualFrameDis : if CHAN_COUNT_G = 1 generate + chanStatus(1) <= CL_CHAN_STATUS_INIT_C; + frameReady(1) <= frameReady(0); end generate; --------------------------------- -- AXIL Clock Transition --------------------------------- - U_AxilAsync: entity work.AxiLiteAsync + U_AxilAsync : entity work.AxiLiteAsync generic map ( - TPD_G => TPD_G, - COMMON_CLK_G => false) + TPD_G => TPD_G, + COMMON_CLK_G => false) port map ( sAxiClk => axilClk, sAxiClkRst => axilRst, @@ -330,15 +334,33 @@ begin --------------------------------- -- Registers --------------------------------- - comb : process (r, sysRst, intReadMaster, intWriteMaster, chanStatus, linkStatus) is + comb : process (chanStatus, intReadMaster, intWriteMaster, linkStatus, r, + sysRst) is variable v : RegType; variable axilEp : AxiLiteEndpointType; + variable i : natural; begin -- Latch the current value v := r; + -- Loop through the locking channels + for i in 2 downto 0 loop + -- Keep delayed copy of the locks + v.locked(i) := linkStatus(i).locked; + -- Check for 0->1 lock transition and not max value + if (r.locked(i) = '0') and (linkStatus(i).locked = '1') and (r.lockCnt(i) /= x"FF") then + -- Increment the counter + v.lockCnt(i) := r.lockCnt(i) + 1; + end if; + end loop; + + -- Check for counter reset + if (r.linkConfig.cntRst = '1') then + v.lockCnt := (others=>x"00"); + end if; + ------------------------ -- AXI-Lite Transactions ------------------------ @@ -347,52 +369,71 @@ begin axiSlaveWaitTxn(axilEp, intWriteMaster, intReadMaster, v.axilWriteSlave, v.axilReadSlave); -- Common Config - axiSlaveRegisterR(axilEp, x"000", 0, toSlv(CHAN_COUNT_G,4)); - axiSlaveRegister (axilEp, x"004", 0, v.linkConfig.reset); + axiSlaveRegisterR(axilEp, x"000", 0, toSlv(CHAN_COUNT_G, 4)); + axiSlaveRegister (axilEp, x"004", 0, v.linkConfig.rstPll); + axiSlaveRegister (axilEp, x"004", 1, v.linkConfig.rstFsm); + axiSlaveRegister (axilEp, x"004", 2, v.linkConfig.cntRst); -- Common Status - axiSlaveRegisterR(axilEp, x"010", 0, linkStatus(0).locked); - axiSlaveRegisterR(axilEp, x"010", 1, linkStatus(1).locked); - axiSlaveRegisterR(axilEp, x"010", 2, linkStatus(2).locked); - axiSlaveRegisterR(axilEp, x"014", 0, linkStatus(0).shiftCnt); - axiSlaveRegisterR(axilEp, x"014", 8, linkStatus(1).shiftCnt); + axiSlaveRegisterR(axilEp, x"010", 0, linkStatus(0).locked); + axiSlaveRegisterR(axilEp, x"010", 1, linkStatus(1).locked); + axiSlaveRegisterR(axilEp, x"010", 2, linkStatus(2).locked); + axiSlaveRegisterR(axilEp, x"010", 8, r.lockCnt(0)); + axiSlaveRegisterR(axilEp, x"010", 16, r.lockCnt(1)); + axiSlaveRegisterR(axilEp, x"010", 24, r.lockCnt(2)); + axiSlaveRegisterR(axilEp, x"014", 0, linkStatus(0).shiftCnt); + axiSlaveRegisterR(axilEp, x"014", 8, linkStatus(1).shiftCnt); axiSlaveRegisterR(axilEp, x"014", 16, linkStatus(2).shiftCnt); - axiSlaveRegisterR(axilEp, x"018", 0, linkStatus(0).delay); - axiSlaveRegisterR(axilEp, x"018", 8, linkStatus(1).delay); + axiSlaveRegisterR(axilEp, x"018", 0, linkStatus(0).delay); + axiSlaveRegisterR(axilEp, x"018", 8, linkStatus(1).delay); axiSlaveRegisterR(axilEp, x"018", 16, linkStatus(2).delay); -- Channel A Config - axiSlaveRegister (axilEp, x"100", 0, v.chanConfig(0).linkMode); - axiSlaveRegister (axilEp, x"104", 0, v.chanConfig(0).dataMode); - axiSlaveRegister (axilEp, x"108", 0, v.chanConfig(0).frameMode); - axiSlaveRegister (axilEp, x"10C", 0, v.chanConfig(0).tapCount); - axiSlaveRegister (axilEp, x"110", 0, v.chanConfig(0).dataEn); - axiSlaveRegister (axilEp, x"114", 0, v.chanConfig(0).serBaud); - axiSlaveRegister (axilEp, x"118", 0, v.chanConfig(0).swCamCtrlEn); - axiSlaveRegister (axilEp, x"11C", 0, v.chanConfig(0).swCamCtrl); + axiSlaveRegister (axilEp, x"100", 0, v.chanConfig(0).linkMode); + axiSlaveRegister (axilEp, x"104", 0, v.chanConfig(0).dataMode); + axiSlaveRegister (axilEp, x"108", 0, v.chanConfig(0).frameMode); + axiSlaveRegister (axilEp, x"10C", 0, v.chanConfig(0).tapCount); + axiSlaveRegister (axilEp, x"110", 0, v.chanConfig(0).dataEn); + axiSlaveRegister (axilEp, x"110", 1, v.chanConfig(0).blowoff); + axiSlaveRegister (axilEp, x"110", 2, v.chanConfig(0).cntRst); + axiSlaveRegister (axilEp, x"110", 16, v.chanConfig(0).serThrottle); + axiSlaveRegister (axilEp, x"114", 0, v.chanConfig(0).serBaud); + axiSlaveRegister (axilEp, x"118", 0, v.chanConfig(0).swCamCtrlEn); + axiSlaveRegister (axilEp, x"11C", 0, v.chanConfig(0).swCamCtrl); -- Channel A Status - axiSlaveRegisterR(axilEp, x"120", 0, chanStatus(0).running); - axiSlaveRegisterR(axilEp, x"124", 0, chanStatus(0).frameCount); - axiSlaveRegisterR(axilEp, x"128", 0, chanStatus(0).dropCount); + axiSlaveRegisterR(axilEp, x"120", 0, chanStatus(0).running); + axiSlaveRegisterR(axilEp, x"124", 0, chanStatus(0).frameCount); + axiSlaveRegisterR(axilEp, x"128", 0, chanStatus(0).dropCount); -- Channel B Config - axiSlaveRegister (axilEp, x"200", 0, v.chanConfig(1).linkMode); - axiSlaveRegister (axilEp, x"204", 0, v.chanConfig(1).dataMode); - axiSlaveRegister (axilEp, x"208", 0, v.chanConfig(1).frameMode); - axiSlaveRegister (axilEp, x"20C", 0, v.chanConfig(1).tapCount); - axiSlaveRegister (axilEp, x"210", 0, v.chanConfig(1).dataEn); - axiSlaveRegister (axilEp, x"214", 0, v.chanConfig(1).serBaud); - axiSlaveRegister (axilEp, x"218", 0, v.chanConfig(1).swCamCtrlEn); - axiSlaveRegister (axilEp, x"21C", 0, v.chanConfig(1).swCamCtrl); + axiSlaveRegister (axilEp, x"200", 0, v.chanConfig(1).linkMode); + axiSlaveRegister (axilEp, x"204", 0, v.chanConfig(1).dataMode); + axiSlaveRegister (axilEp, x"208", 0, v.chanConfig(1).frameMode); + axiSlaveRegister (axilEp, x"20C", 0, v.chanConfig(1).tapCount); + axiSlaveRegister (axilEp, x"210", 0, v.chanConfig(1).dataEn); + axiSlaveRegister (axilEp, x"210", 1, v.chanConfig(1).blowoff); + axiSlaveRegister (axilEp, x"210", 2, v.chanConfig(1).cntRst); + axiSlaveRegister (axilEp, x"210", 16, v.chanConfig(1).serThrottle); + axiSlaveRegister (axilEp, x"214", 0, v.chanConfig(1).serBaud); + axiSlaveRegister (axilEp, x"218", 0, v.chanConfig(1).swCamCtrlEn); + axiSlaveRegister (axilEp, x"21C", 0, v.chanConfig(1).swCamCtrl); -- Channel B Status - axiSlaveRegisterR(axilEp, x"220", 0, chanStatus(1).running); - axiSlaveRegisterR(axilEp, x"224", 0, chanStatus(1).frameCount); - axiSlaveRegisterR(axilEp, x"228", 0, chanStatus(1).dropCount); + axiSlaveRegisterR(axilEp, x"220", 0, chanStatus(1).running); + axiSlaveRegisterR(axilEp, x"224", 0, chanStatus(1).frameCount); + axiSlaveRegisterR(axilEp, x"228", 0, chanStatus(1).dropCount); axiSlaveDefault(axilEp, v.axilWriteSlave, v.axilReadSlave, AXI_RESP_DECERR_C); + -- Prevent zero baud rate + if (v.chanConfig(0).serBaud = 0) then + v.chanConfig(0).serBaud := toSlv(1, 24); + end if; + if (v.chanConfig(1).serBaud = 0) then + v.chanConfig(1).serBaud := toSlv(1, 24); + end if; + ------------- -- Reset ------------- @@ -416,5 +457,4 @@ begin end if; end process seq; -end architecture rtl; - +end rtl; diff --git a/protocols/clink/hdl/ClinkUart.vhd b/protocols/clink/hdl/ClinkUart.vhd index 80cd573f88..dc8b2d3850 100644 --- a/protocols/clink/hdl/ClinkUart.vhd +++ b/protocols/clink/hdl/ClinkUart.vhd @@ -29,60 +29,61 @@ entity ClinkUart is UART_AXIS_CONFIG_G : AxiStreamConfigType := AXI_STREAM_CONFIG_INIT_C); port ( -- Clock and reset, 200Mhz - intClk : in sl; - intRst : in sl; - -- Baud rate - baud : in slv(23 downto 0); + intClk : in sl; + intRst : in sl; + -- Configurations + baud : in slv(23 downto 0); -- Baud rate (units of bps) + throttle : in slv(15 downto 0); -- TX Throttle (units of us) -- Data In/Out - uartClk : in sl; - uartRst : in sl; - sUartMaster : in AxiStreamMasterType; - sUartSlave : out AxiStreamSlaveType; - sUartCtrl : out AxiStreamCtrlType; - mUartMaster : out AxiStreamMasterType; - mUartSlave : in AxiStreamSlaveType; + uartClk : in sl; + uartRst : in sl; + sUartMaster : in AxiStreamMasterType; + sUartSlave : out AxiStreamSlaveType; + sUartCtrl : out AxiStreamCtrlType; + mUartMaster : out AxiStreamMasterType; + mUartSlave : in AxiStreamSlaveType; -- Serial data - rxIn : in sl; - txOut : out sl); + rxIn : in sl; + txOut : out sl); end ClinkUart; architecture rtl of ClinkUart is constant INT_FREQ_C : integer := 200000000; - constant INT_CONFIG_C : AxiStreamConfigType := ssiAxiStreamConfig(dataBytes=>4,tDestBits=>0); + constant INT_CONFIG_C : AxiStreamConfigType := ssiAxiStreamConfig(dataBytes => 4, tDestBits => 0); - type RegType is record - count : integer; - clkEn : sl; + type RegType is record + count : integer; + clkEn : sl; end record RegType; constant REG_INIT_C : RegType := ( - count => 0, - clkEn => '0'); + count => 0, + clkEn => '0'); signal r : RegType := REG_INIT_C; signal rin : Regtype; - signal rdData : slv(7 downto 0); - signal rdValid : sl; + signal rdData : slv(7 downto 0); + signal rdValid : sl; - signal txMaster : AxiStreamMasterType; - signal txSlave : AxiStreamSlaveType; - signal rxMaster : AxiStreamMasterType; + signal txMasters : AxiStreamMasterArray(1 downto 0); + signal txSlaves : AxiStreamSlaveArray(1 downto 0); + signal rxMaster : AxiStreamMasterType; begin ----------------------------------- -- Baud rate generation ----------------------------------- - comb : process (r, intRst, baud) is + comb : process (baud, intRst, r) is variable v : RegType; begin v := r; -- 16x (add min of 1 to ensure data moves when baud=0) - v.count := r.count + conv_integer(baud & x"1"); + v.count := r.count + conv_integer(baud & x"1"); v.clkEn := '0'; if r.count >= INT_FREQ_C then @@ -94,11 +95,11 @@ begin v := REG_INIT_C; end if; - rin <= v; + rin <= v; end process; seq : process (intClk) is - begin + begin if (rising_edge(intClk)) then r <= rin; end if; @@ -107,7 +108,7 @@ begin ------------------------------------------------------------------------------------------------- -- Transmit FIFO ------------------------------------------------------------------------------------------------- - U_TxFifo: entity work.AxiStreamFifoV2 + U_TxFifo : entity work.AxiStreamFifoV2 generic map ( TPD_G => TPD_G, GEN_SYNC_FIFO_G => false, @@ -118,13 +119,28 @@ begin port map ( sAxisClk => uartClk, sAxisRst => uartRst, - sAxisMaster => sUartMaster, + sAxisMaster => sUartMaster, sAxisSlave => sUartSlave, sAxisCtrl => sUartCtrl, mAxisClk => intClk, mAxisRst => intRst, - mAxisMaster => txMaster, - mAxisSlave => txSlave); + mAxisMaster => txMasters(0), + mAxisSlave => txSlaves(0)); + + U_TxThrottle : entity work.ClinkUartThrottle + generic map ( + TPD_G => TPD_G) + port map ( + -- Clock and reset, 200Mhz + intClk => intClk, + intRst => intRst, + -- Throttle Config (units of us) + throttle => throttle, + -- Data In/Out + sUartMaster => txMasters(0), + sUartSlave => txSlaves(0), + mUartMaster => txMasters(1), + mUartSlave => txSlaves(1)); ------------------------------------------------------------------------------------------------- -- UART transmitter @@ -133,13 +149,13 @@ begin generic map ( TPD_G => TPD_G) port map ( - clk => intClk, -- [in] - rst => intRst, -- [in] - baud16x => r.clkEn, -- [in] - wrData => txMaster.tData(7 downto 0), -- [in] - wrValid => txMaster.tValid, -- [in] - wrReady => txSlave.tReady, -- [out] - tx => txOut); -- [out] + clk => intClk, -- [in] + rst => intRst, -- [in] + baud16x => r.clkEn, -- [in] + wrData => txMasters(1).tData(7 downto 0), -- [in] + wrValid => txMasters(1).tValid, -- [in] + wrReady => txSlaves(1).tReady, -- [out] + tx => txOut); -- [out] ------------------------------------------------------------------------------------------------- -- UART Receiver @@ -148,13 +164,13 @@ begin generic map ( TPD_G => TPD_G) port map ( - clk => intClk, -- [in] - rst => intRst, -- [in] - baud16x => r.clkEn, -- [in] - rdData => rdData, -- [out] - rdValid => rdValid, -- [out] - rdReady => '1', -- [in] - rx => rxIn); -- [in] + clk => intClk, -- [in] + rst => intRst, -- [in] + baud16x => r.clkEn, -- [in] + rdData => rdData, -- [out] + rdValid => rdValid, -- [out] + rdReady => '1', -- [in] + rx => rxIn); -- [in] process (rdData, rdValid) is variable mst : AxiStreamMasterType; @@ -176,7 +192,7 @@ begin ------------------------------------------------------------------------------------------------- -- Receive FIFO ------------------------------------------------------------------------------------------------- - U_RxFifo: entity work.AxiStreamFifoV2 + U_RxFifo : entity work.AxiStreamFifoV2 generic map ( TPD_G => TPD_G, GEN_SYNC_FIFO_G => false, diff --git a/protocols/clink/hdl/ClinkUartThrottle.vhd b/protocols/clink/hdl/ClinkUartThrottle.vhd new file mode 100644 index 0000000000..8ec9d6dae6 --- /dev/null +++ b/protocols/clink/hdl/ClinkUartThrottle.vhd @@ -0,0 +1,137 @@ +------------------------------------------------------------------------------- +-- File : ClinkUartThrottle.vhd +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: CameraLink UART TX Throttle +-- Used when the camera cannot accept new bytes until the previous command processed +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; +use work.StdRtlPkg.all; +use work.AxiStreamPkg.all; +use work.SsiPkg.all; + +entity ClinkUartThrottle is + generic ( + TPD_G : time := 1 ns); + port ( + -- Clock and reset, 200Mhz + intClk : in sl; + intRst : in sl; + -- Throttle Config (units of us) + throttle : in slv(15 downto 0); + -- Data In/Out + sUartMaster : in AxiStreamMasterType; + sUartSlave : out AxiStreamSlaveType; + mUartMaster : out AxiStreamMasterType; + mUartSlave : in AxiStreamSlaveType); +end ClinkUartThrottle; + +architecture rtl of ClinkUartThrottle is + + constant TIMEOUT_C : integer := 199; -- (200 MHz x 1 us) - 1 + + constant INT_CONFIG_C : AxiStreamConfigType := ssiAxiStreamConfig(dataBytes => 4, tDestBits => 0); + + type RegType is record + heartbeat : sl; + cnt : natural range 0 to TIMEOUT_C; + timeout : sl; + timer : slv(15 downto 0); + sUartSlave : AxiStreamSlaveType; + mUartMaster : AxiStreamMasterType; + end record RegType; + + constant REG_INIT_C : RegType := ( + heartbeat => '0', + cnt => 0, + timeout => '0', + timer => (others => '0'), + sUartSlave => AXI_STREAM_SLAVE_INIT_C, + mUartMaster => AXI_STREAM_MASTER_INIT_C); + + signal r : RegType := REG_INIT_C; + signal rin : Regtype; + +begin + + comb : process (intRst, mUartSlave, r, sUartMaster, throttle) is + variable v : RegType; + begin + -- Latch the current value + v := r; + + -- Reset the flags + v.heartbeat := '0'; + v.timeout := '0'; + v.sUartSlave := AXI_STREAM_SLAVE_INIT_C; + if mUartSlave.tReady = '1' then + v.mUartMaster.tValid := '0'; + end if; + + -- Update the 1us heartbeat timer + if r.cnt = 0 then + -- Set the flag + v.heartbeat := '1'; + -- Reset the timer + v.cnt := TIMEOUT_C; + else + -- Decrement the counter + v.cnt := r.cnt -1; + end if; + + -- Check the heartbeat + if (r.heartbeat = '1') then + -- Check for timeout + if (r.timer = 0) then + -- Set the flag + v.timeout := '1'; + -- Reset the timer + v.timer := throttle; + else + -- Decrement the counter + v.timer := r.timer - 1; + end if; + end if; + + -- Check if ready to move data and timeout + if (v.mUartMaster.tValid = '0') and (sUartMaster.tValid = '1') and (r.timeout = '1') then + -- Accept the data + v.sUartSlave.tReady := '1'; + -- Move the data + v.mUartMaster := sUartMaster; + end if; + + -- Outputs + sUartSlave <= v.sUartSlave; + mUartMaster <= r.mUartMaster; + + -- Reset + if (intRst = '1') then + v := REG_INIT_C; + end if; + + -- Register the variable for next clock cycle + rin <= v; + + end process comb; + + seq : process (intClk) is + begin + if rising_edge(intClk) then + r <= rin after TPD_G; + end if; + end process seq; + +end rtl; diff --git a/protocols/clink/ruckus.tcl b/protocols/clink/ruckus.tcl index 3c7df20d8e..6c97733ef6 100644 --- a/protocols/clink/ruckus.tcl +++ b/protocols/clink/ruckus.tcl @@ -10,10 +10,10 @@ if { ${family} == "artix7" || ${family} == "zynq" } { # Load Source Code - loadSource -dir "$::DIR_PATH/hdl/" + loadSource -dir "$::DIR_PATH/hdl" # Load Simulation - loadSource -sim_only -dir "$::DIR_PATH/sim/" + loadSource -sim_only -dir "$::DIR_PATH/sim" } diff --git a/protocols/glink/core/ruckus.tcl b/protocols/glink/core/ruckus.tcl index 1bba9c850e..b61f1904f5 100644 --- a/protocols/glink/core/ruckus.tcl +++ b/protocols/glink/core/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/protocols/glink/gtp7/ruckus.tcl b/protocols/glink/gtp7/ruckus.tcl index 1bba9c850e..b61f1904f5 100644 --- a/protocols/glink/gtp7/ruckus.tcl +++ b/protocols/glink/gtp7/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/protocols/glink/gtx7/ruckus.tcl b/protocols/glink/gtx7/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/protocols/glink/gtx7/ruckus.tcl +++ b/protocols/glink/gtx7/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/protocols/i2c/ruckus.tcl b/protocols/i2c/ruckus.tcl index aaae5950ca..87b4cc5447 100644 --- a/protocols/i2c/ruckus.tcl +++ b/protocols/i2c/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/sim/" +loadSource -sim_only -dir "$::DIR_PATH/sim" diff --git a/protocols/jesd204b/ruckus.tcl b/protocols/jesd204b/ruckus.tcl index aaae5950ca..87b4cc5447 100644 --- a/protocols/jesd204b/ruckus.tcl +++ b/protocols/jesd204b/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/sim/" +loadSource -sim_only -dir "$::DIR_PATH/sim" diff --git a/protocols/jtag/ruckus.tcl b/protocols/jtag/ruckus.tcl index 70d50f6386..ab0dc04958 100644 --- a/protocols/jtag/ruckus.tcl +++ b/protocols/jtag/ruckus.tcl @@ -11,6 +11,6 @@ if { $::env(VIVADO_VERSION) >= 2016.4 } { set_property -dict [list CONFIG.C_DEBUG_MODE {4}] [get_ips DebugBridgeJtag] } - loadSource -dir "$::DIR_PATH/rtl/" + loadSource -dir "$::DIR_PATH/rtl" } \ No newline at end of file diff --git a/protocols/mdio/ruckus.tcl b/protocols/mdio/ruckus.tcl index 1bba9c850e..b61f1904f5 100644 --- a/protocols/mdio/ruckus.tcl +++ b/protocols/mdio/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/protocols/packetizer/ruckus.tcl b/protocols/packetizer/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/protocols/packetizer/ruckus.tcl +++ b/protocols/packetizer/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/protocols/pgp/pgp2b/core/ruckus.tcl b/protocols/pgp/pgp2b/core/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/protocols/pgp/pgp2b/core/ruckus.tcl +++ b/protocols/pgp/pgp2b/core/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/protocols/pgp/pgp2b/gth7/ruckus.tcl b/protocols/pgp/pgp2b/gth7/ruckus.tcl index 1bba9c850e..b61f1904f5 100644 --- a/protocols/pgp/pgp2b/gth7/ruckus.tcl +++ b/protocols/pgp/pgp2b/gth7/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/protocols/pgp/pgp2b/gthUltraScale/ruckus.tcl b/protocols/pgp/pgp2b/gthUltraScale/ruckus.tcl index 5198ee3fdd..3d4cb0ea68 100644 --- a/protocols/pgp/pgp2b/gthUltraScale/ruckus.tcl +++ b/protocols/pgp/pgp2b/gthUltraScale/ruckus.tcl @@ -4,7 +4,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load local source Code and constraints if { $::env(VIVADO_VERSION) >= 2017.3 } { - loadSource -dir "$::DIR_PATH/rtl/" + loadSource -dir "$::DIR_PATH/rtl" loadSource -path "$::DIR_PATH/ip/PgpGthCore.dcp" # loadIpCore -path "$::DIR_PATH/ip/PgpGthCore.xci" diff --git a/protocols/pgp/pgp2b/gtp7/rtl/Pgp2bGtp7FixedLatWrapper.vhd b/protocols/pgp/pgp2b/gtp7/rtl/Pgp2bGtp7FixedLatWrapper.vhd index 70b8f3b4a8..c61cba3920 100644 --- a/protocols/pgp/pgp2b/gtp7/rtl/Pgp2bGtp7FixedLatWrapper.vhd +++ b/protocols/pgp/pgp2b/gtp7/rtl/Pgp2bGtp7FixedLatWrapper.vhd @@ -272,7 +272,6 @@ begin clkIn => pgpTxClkBase, rstIn => pgpTxMmcmReset, clkOut(0) => pgpTxClk, - rstOut(0) => open, locked => pgpTxMmcmLocked); pgpTxReset <= extRst; diff --git a/protocols/pgp/pgp2b/gtp7/rtl/Pgp2bGtp7VarLatWrapper.vhd b/protocols/pgp/pgp2b/gtp7/rtl/Pgp2bGtp7VarLatWrapper.vhd index 23d8f65826..45ed421398 100644 --- a/protocols/pgp/pgp2b/gtp7/rtl/Pgp2bGtp7VarLatWrapper.vhd +++ b/protocols/pgp/pgp2b/gtp7/rtl/Pgp2bGtp7VarLatWrapper.vhd @@ -161,7 +161,6 @@ begin clkIn => pgpTxRecClk, rstIn => pgpTxMmcmReset, clkOut(0) => pgpClock, - rstOut(0) => open, locked => pgpTxMmcmLocked); -- PLL0 Port Mapping diff --git a/protocols/pgp/pgp2b/gtp7/ruckus.tcl b/protocols/pgp/pgp2b/gtp7/ruckus.tcl index 1bba9c850e..b61f1904f5 100644 --- a/protocols/pgp/pgp2b/gtp7/ruckus.tcl +++ b/protocols/pgp/pgp2b/gtp7/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/protocols/pgp/pgp2b/gtx7/ruckus.tcl b/protocols/pgp/pgp2b/gtx7/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/protocols/pgp/pgp2b/gtx7/ruckus.tcl +++ b/protocols/pgp/pgp2b/gtx7/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/protocols/pgp/pgp3/core/ruckus.tcl b/protocols/pgp/pgp3/core/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/protocols/pgp/pgp3/core/ruckus.tcl +++ b/protocols/pgp/pgp3/core/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/protocols/pgp/pgp3/gthUs/ruckus.tcl b/protocols/pgp/pgp3/gthUs/ruckus.tcl index 0a55cb1e7b..c790e2c243 100644 --- a/protocols/pgp/pgp3/gthUs/ruckus.tcl +++ b/protocols/pgp/pgp3/gthUs/ruckus.tcl @@ -5,7 +5,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl if { $::env(VIVADO_VERSION) >= 2017.3 } { # Load Source Code - loadSource -dir "$::DIR_PATH/rtl/" + loadSource -dir "$::DIR_PATH/rtl" loadSource -path "$::DIR_PATH/ip/Pgp3GthUsIp10G/Pgp3GthUsIp10G.dcp" # loadIpCore -path "$::DIR_PATH/ip/Pgp3GthUsIp10G/Pgp3GthUsIp10G.xci" diff --git a/protocols/rssi/ruckus.tcl b/protocols/rssi/ruckus.tcl index aaae5950ca..6d35d730ab 100644 --- a/protocols/rssi/ruckus.tcl +++ b/protocols/rssi/ruckus.tcl @@ -1,8 +1,5 @@ # Load RUCKUS library source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl -# Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" - -# Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/sim/" +loadRuckusTcl "$::DIR_PATH/v1" +loadRuckusTcl "$::DIR_PATH/v1b" diff --git a/protocols/rssi/rtl/RssiAxiLiteRegItf.vhd b/protocols/rssi/v1/rtl/RssiAxiLiteRegItf.vhd similarity index 95% rename from protocols/rssi/rtl/RssiAxiLiteRegItf.vhd rename to protocols/rssi/v1/rtl/RssiAxiLiteRegItf.vhd index 3234dacc8b..406f68dd1c 100644 --- a/protocols/rssi/rtl/RssiAxiLiteRegItf.vhd +++ b/protocols/rssi/v1/rtl/RssiAxiLiteRegItf.vhd @@ -76,6 +76,7 @@ entity RssiAxiLiteRegItf is generic ( -- General Configurations TPD_G : time := 1 ns; + COMMON_CLK_G : boolean := false; -- true if axiClk_i = devClk_i SEGMENT_ADDR_SIZE_G : positive := 7; -- 2^SEGMENT_ADDR_SIZE_G = Number of 64 bit wide data words -- Defaults form generics TIMEOUT_UNIT_G : real := 1.0E-6; @@ -325,6 +326,7 @@ begin SyncFifo_IN0 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => status_i'length ) port map ( @@ -337,6 +339,7 @@ begin SyncFifo_IN1 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => validCnt_i'length ) port map ( @@ -349,6 +352,7 @@ begin SyncFifo_IN2 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => dropCnt_i'length ) port map ( @@ -361,6 +365,7 @@ begin SyncFifo_IN3 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => resendCnt_i'length ) port map ( @@ -373,6 +378,7 @@ begin SyncFifo_IN4 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => reconCnt_i'length ) port map ( @@ -385,8 +391,8 @@ begin -- Output assignment and synchronization Sync_OUT0 : entity work.Synchronizer generic map ( - TPD_G => TPD_G - ) + TPD_G => TPD_G, + BYPASS_SYNC_G => COMMON_CLK_G) port map ( dataIn => r.control(0), clk => devClk_i, @@ -395,8 +401,8 @@ begin Sync_OUT1 : entity work.Synchronizer generic map ( - TPD_G => TPD_G - ) + TPD_G => TPD_G, + BYPASS_SYNC_G => COMMON_CLK_G) port map ( dataIn => r.control(1), clk => devClk_i, @@ -405,8 +411,8 @@ begin Sync_OUT2 : entity work.Synchronizer generic map ( - TPD_G => TPD_G - ) + TPD_G => TPD_G, + BYPASS_SYNC_G => COMMON_CLK_G) port map ( dataIn => r.control(2), clk => devClk_i, @@ -415,8 +421,8 @@ begin Sync_OUT3 : entity work.Synchronizer generic map ( - TPD_G => TPD_G - ) + TPD_G => TPD_G, + BYPASS_SYNC_G => COMMON_CLK_G) port map ( dataIn => r.control(3), clk => devClk_i, @@ -425,8 +431,8 @@ begin Sync_OUT4 : entity work.Synchronizer generic map ( - TPD_G => TPD_G - ) + TPD_G => TPD_G, + BYPASS_SYNC_G => COMMON_CLK_G) port map ( dataIn => r.control(4), clk => devClk_i, @@ -436,6 +442,7 @@ begin SyncFifo_OUT5 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => 8 ) port map ( @@ -448,6 +455,7 @@ begin SyncFifo_OUT6 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => 4 ) port map ( @@ -460,6 +468,7 @@ begin SyncFifo_OUT7 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => 8 ) port map ( @@ -472,6 +481,7 @@ begin SyncFifo_OUT8 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => 16 ) port map ( @@ -484,6 +494,7 @@ begin SyncFifo_OUT9 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => 16 ) port map ( @@ -496,6 +507,7 @@ begin SyncFifo_OUT10 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => 16 ) port map ( @@ -508,6 +520,7 @@ begin SyncFifo_OUT11 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => 16 ) port map ( @@ -520,6 +533,7 @@ begin SyncFifo_OUT12 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => 8 ) port map ( @@ -532,6 +546,7 @@ begin SyncFifo_OUT13 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => 8 ) port map ( @@ -544,6 +559,7 @@ begin SyncFifo_OUT14 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => 8 ) port map ( @@ -556,6 +572,7 @@ begin SyncFifo_OUT15 : entity work.SynchronizerFifo generic map ( TPD_G => TPD_G, + COMMON_CLK_G => COMMON_CLK_G, DATA_WIDTH_G => 32 ) port map ( diff --git a/protocols/rssi/rtl/RssiChksum.vhd b/protocols/rssi/v1/rtl/RssiChksum.vhd similarity index 100% rename from protocols/rssi/rtl/RssiChksum.vhd rename to protocols/rssi/v1/rtl/RssiChksum.vhd diff --git a/protocols/rssi/rtl/RssiConnFsm.vhd b/protocols/rssi/v1/rtl/RssiConnFsm.vhd similarity index 100% rename from protocols/rssi/rtl/RssiConnFsm.vhd rename to protocols/rssi/v1/rtl/RssiConnFsm.vhd diff --git a/protocols/rssi/rtl/RssiCore.vhd b/protocols/rssi/v1/rtl/RssiCore.vhd similarity index 87% rename from protocols/rssi/rtl/RssiCore.vhd rename to protocols/rssi/v1/rtl/RssiCore.vhd index 9a9231144b..c0f197e89e 100644 --- a/protocols/rssi/rtl/RssiCore.vhd +++ b/protocols/rssi/v1/rtl/RssiCore.vhd @@ -65,6 +65,9 @@ entity RssiCore is BYP_TX_BUFFER_G : boolean := false; BYP_RX_BUFFER_G : boolean := false; + SYNTH_MODE_G : string := "inferred"; + MEMORY_TYPE_G : string := "block"; + -- Version and connection ID INIT_SEQ_N_G : natural := 16#80#; CONN_ID_G : positive := 16#12345678#; @@ -640,23 +643,69 @@ begin ----------------------------------------------- -- Tx buffer RAM - GEN_TX : if (BYP_TX_BUFFER_G = false) generate - U_Buffer : entity work.SimpleDualPortRam - generic map ( - TPD_G => TPD_G, - DATA_WIDTH_G => RSSI_WORD_WIDTH_C*8, - ADDR_WIDTH_G => BUFFER_ADDR_WIDTH_C) - port map ( - -- Port A - Write only - clka => clk_i, - wea => s_txWrBuffWe, - addra => s_txWrBuffAddr, - dina => s_txWrBuffData, - -- Port B - Read only - clkb => clk_i, - rstb => rst_i, - addrb => s_txRdBuffAddr, - doutb => s_txRdBuffData); + GEN_TX : if (BYP_TX_BUFFER_G = false) generate + + GEN_XPM : if (SYNTH_MODE_G = "xpm") generate + U_RAM : entity work.SimpleDualPortRamXpm + generic map ( + TPD_G => TPD_G, + COMMON_CLK_G => true, + MEMORY_TYPE_G => MEMORY_TYPE_G, + DATA_WIDTH_G => RSSI_WORD_WIDTH_C*8, + ADDR_WIDTH_G => BUFFER_ADDR_WIDTH_C) + port map ( + -- Port A - Write only + clka => clk_i, + wea(0) => s_txWrBuffWe, + addra => s_txWrBuffAddr, + dina => s_txWrBuffData, + -- Port B - Read only + clkb => clk_i, + rstb => rst_i, + addrb => s_txRdBuffAddr, + doutb => s_txRdBuffData); + end generate; + + GEN_ALTERA : if (SYNTH_MODE_G = "altera_mf") generate + U_RAM : entity work.SimpleDualPortRamAlteraMf + generic map ( + TPD_G => TPD_G, + COMMON_CLK_G => true, + MEMORY_TYPE_G => MEMORY_TYPE_G, + DATA_WIDTH_G => RSSI_WORD_WIDTH_C*8, + ADDR_WIDTH_G => BUFFER_ADDR_WIDTH_C) + port map ( + -- Port A - Write only + clka => clk_i, + wea(0) => s_txWrBuffWe, + addra => s_txWrBuffAddr, + dina => s_txWrBuffData, + -- Port B - Read only + clkb => clk_i, + rstb => rst_i, + addrb => s_txRdBuffAddr, + doutb => s_txRdBuffData); + end generate; + + GEN_INFERRED : if (SYNTH_MODE_G = "inferred") generate + U_RAM : entity work.SimpleDualPortRam + generic map ( + TPD_G => TPD_G, + DATA_WIDTH_G => RSSI_WORD_WIDTH_C*8, + ADDR_WIDTH_G => BUFFER_ADDR_WIDTH_C) + port map ( + -- Port A - Write only + clka => clk_i, + wea => s_txWrBuffWe, + addra => s_txWrBuffAddr, + dina => s_txWrBuffData, + -- Port B - Read only + clkb => clk_i, + rstb => rst_i, + addrb => s_txRdBuffAddr, + doutb => s_txRdBuffData); + end generate; + end generate; tx_Chksum_INST : entity work.RssiChksum @@ -720,23 +769,69 @@ begin appSsiSlave_i => s_mAppSsiSlave); -- Rx buffer RAM - GEN_RX : if (BYP_RX_BUFFER_G = false) generate - U_Buffer : entity work.SimpleDualPortRam - generic map ( - TPD_G => TPD_G, - DATA_WIDTH_G => RSSI_WORD_WIDTH_C*8, - ADDR_WIDTH_G => BUFFER_ADDR_WIDTH_C) - port map ( - -- Port A - Write only - clka => clk_i, - wea => s_rxWrBuffWe, - addra => s_rxWrBuffAddr, - dina => s_rxWrBuffData, - -- Port B - Read only - clkb => clk_i, - rstb => rst_i, - addrb => s_rxRdBuffAddr, - doutb => s_rxRdBuffData); + GEN_RX : if (BYP_RX_BUFFER_G = false) generate + + GEN_XPM : if (SYNTH_MODE_G = "xpm") generate + U_RAM : entity work.SimpleDualPortRamXpm + generic map ( + TPD_G => TPD_G, + COMMON_CLK_G => true, + MEMORY_TYPE_G => MEMORY_TYPE_G, + DATA_WIDTH_G => RSSI_WORD_WIDTH_C*8, + ADDR_WIDTH_G => BUFFER_ADDR_WIDTH_C) + port map ( + -- Port A - Write only + clka => clk_i, + wea(0) => s_rxWrBuffWe, + addra => s_rxWrBuffAddr, + dina => s_rxWrBuffData, + -- Port B - Read only + clkb => clk_i, + rstb => rst_i, + addrb => s_rxRdBuffAddr, + doutb => s_rxRdBuffData); + end generate; + + GEN_ALTERA : if (SYNTH_MODE_G = "altera_mf") generate + U_RAM : entity work.SimpleDualPortRamAlteraMf + generic map ( + TPD_G => TPD_G, + COMMON_CLK_G => true, + MEMORY_TYPE_G => MEMORY_TYPE_G, + DATA_WIDTH_G => RSSI_WORD_WIDTH_C*8, + ADDR_WIDTH_G => BUFFER_ADDR_WIDTH_C) + port map ( + -- Port A - Write only + clka => clk_i, + wea(0) => s_rxWrBuffWe, + addra => s_rxWrBuffAddr, + dina => s_rxWrBuffData, + -- Port B - Read only + clkb => clk_i, + rstb => rst_i, + addrb => s_rxRdBuffAddr, + doutb => s_rxRdBuffData); + end generate; + + GEN_INFERRED : if (SYNTH_MODE_G = "inferred") generate + U_RAM : entity work.SimpleDualPortRam + generic map ( + TPD_G => TPD_G, + DATA_WIDTH_G => RSSI_WORD_WIDTH_C*8, + ADDR_WIDTH_G => BUFFER_ADDR_WIDTH_C) + port map ( + -- Port A - Write only + clka => clk_i, + wea => s_rxWrBuffWe, + addra => s_rxWrBuffAddr, + dina => s_rxWrBuffData, + -- Port B - Read only + clkb => clk_i, + rstb => rst_i, + addrb => s_rxRdBuffAddr, + doutb => s_rxRdBuffData); + end generate; + end generate; -- Acknowledge valid packet diff --git a/protocols/rssi/rtl/RssiCoreWrapper.vhd b/protocols/rssi/v1/rtl/RssiCoreWrapper.vhd similarity index 98% rename from protocols/rssi/rtl/RssiCoreWrapper.vhd rename to protocols/rssi/v1/rtl/RssiCoreWrapper.vhd index d54c0bb1b1..90e9e46b71 100644 --- a/protocols/rssi/rtl/RssiCoreWrapper.vhd +++ b/protocols/rssi/v1/rtl/RssiCoreWrapper.vhd @@ -39,6 +39,8 @@ entity RssiCoreWrapper is APP_ILEAVE_EN_G : boolean := false; BYP_TX_BUFFER_G : boolean := false; BYP_RX_BUFFER_G : boolean := false; + SYNTH_MODE_G : string := "inferred"; + MEMORY_TYPE_G : string := "block"; ILEAVE_ON_NOTVALID_G : boolean := false; -- AXIS Configurations APP_AXIS_CONFIG_G : AxiStreamConfigArray := (0 => ssiAxiStreamConfig(8, TKEEP_NORMAL_C)); @@ -229,6 +231,8 @@ begin SEGMENT_ADDR_SIZE_G => SEGMENT_ADDR_SIZE_G, BYP_TX_BUFFER_G => BYP_TX_BUFFER_G, BYP_RX_BUFFER_G => BYP_RX_BUFFER_G, + SYNTH_MODE_G => SYNTH_MODE_G, + MEMORY_TYPE_G => MEMORY_TYPE_G, -- AXIS Configurations APP_AXIS_CONFIG_G => CONV_AXIS_CONFIG_C, TSP_AXIS_CONFIG_G => TSP_AXIS_CONFIG_G, diff --git a/protocols/rssi/rtl/RssiHeaderReg.vhd b/protocols/rssi/v1/rtl/RssiHeaderReg.vhd similarity index 100% rename from protocols/rssi/rtl/RssiHeaderReg.vhd rename to protocols/rssi/v1/rtl/RssiHeaderReg.vhd diff --git a/protocols/rssi/rtl/RssiMonitor.vhd b/protocols/rssi/v1/rtl/RssiMonitor.vhd similarity index 100% rename from protocols/rssi/rtl/RssiMonitor.vhd rename to protocols/rssi/v1/rtl/RssiMonitor.vhd diff --git a/protocols/rssi/rtl/RssiPkg.vhd b/protocols/rssi/v1/rtl/RssiPkg.vhd similarity index 100% rename from protocols/rssi/rtl/RssiPkg.vhd rename to protocols/rssi/v1/rtl/RssiPkg.vhd diff --git a/protocols/rssi/rtl/RssiRxFsm.vhd b/protocols/rssi/v1/rtl/RssiRxFsm.vhd similarity index 100% rename from protocols/rssi/rtl/RssiRxFsm.vhd rename to protocols/rssi/v1/rtl/RssiRxFsm.vhd diff --git a/protocols/rssi/rtl/RssiTxFsm.vhd b/protocols/rssi/v1/rtl/RssiTxFsm.vhd similarity index 100% rename from protocols/rssi/rtl/RssiTxFsm.vhd rename to protocols/rssi/v1/rtl/RssiTxFsm.vhd diff --git a/protocols/rssi/v1/ruckus.tcl b/protocols/rssi/v1/ruckus.tcl new file mode 100644 index 0000000000..87b4cc5447 --- /dev/null +++ b/protocols/rssi/v1/ruckus.tcl @@ -0,0 +1,8 @@ +# Load RUCKUS library +source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl + +# Load Source Code +loadSource -dir "$::DIR_PATH/rtl" + +# Load Simulation +loadSource -sim_only -dir "$::DIR_PATH/sim" diff --git a/protocols/rssi/sim/Chksum_tb.vhd b/protocols/rssi/v1/sim/Chksum_tb.vhd similarity index 100% rename from protocols/rssi/sim/Chksum_tb.vhd rename to protocols/rssi/v1/sim/Chksum_tb.vhd diff --git a/protocols/rssi/sim/RssiCoreTb.vhd b/protocols/rssi/v1/sim/RssiCoreTb.vhd similarity index 100% rename from protocols/rssi/sim/RssiCoreTb.vhd rename to protocols/rssi/v1/sim/RssiCoreTb.vhd diff --git a/protocols/rssi/v1b/rtl/AxiRssiCore.vhd b/protocols/rssi/v1b/rtl/AxiRssiCore.vhd new file mode 100644 index 0000000000..62f598910b --- /dev/null +++ b/protocols/rssi/v1b/rtl/AxiRssiCore.vhd @@ -0,0 +1,680 @@ +------------------------------------------------------------------------------- +-- File : AxiRssiCore.vhd +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: The module is based upon RUDP (Cisco implementation) RFC-908, RFC-1151, draft-ietf-sigtran-reliable-udp-00. +-- The specifications in the drafts are modified by internal simplifications and improvements. +-- +-- Interfaces to transport and application side through AxiStream ports +-- The AxiStream IO port widths can be adjusted (AxiStream FIFOs added to IO) +-- Optional AxiLite Register interface. More info on registers is in RssiAxiLiteRegItf.vhd +-- The module can act as Server or Client: +-- - Server: - Passively listens for connection request from client, +-- - Monitors connection activity NULL segment timeouts +-- - Client: - Actively requests connection +-- - Sends NULL packages if there is no incoming data +-- Status register: +-- statusReg_o(0) : Connection Active +-- statusReg_o(1) : Maximum retransmissions exceeded r.retransMax and +-- statusReg_o(2) : Null timeout reached (server) r.nullTout; +-- statusReg_o(3) : Error in acknowledgment mechanism +-- statusReg_o(4) : SSI Frame length too long +-- statusReg_o(5) : Connection to peer timed out +-- statusReg_o(6) : Client rejected the connection (parameters out of range) +-- Server proposed new parameters (parameters out of range) +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; +use ieee.math_real.all; + +use work.StdRtlPkg.all; +use work.AxiPkg.all; +use work.AxiStreamPkg.all; +use work.AxiLitePkg.all; +use work.AxiRssiPkg.all; +use work.RssiPkg.all; +use work.SsiPkg.all; + +entity AxiRssiCore is + generic ( + TPD_G : time := 1 ns; + SERVER_G : boolean := true; --! Module is server or client + -- AXI Configurations + MAX_SEG_SIZE_G : positive := 1024; --! max. payload size (units of bytes) + AXI_CONFIG_G : AxiConfigType := RSSI_AXI_CONFIG_C; --! Defines the AXI configuration but ADDR_WIDTH_C should be defined as the space for RSSI and maybe not the entire memory address space + -- AXIS Configurations + APP_AXIS_CONFIG_G : AxiStreamConfigType := ssiAxiStreamConfig(8, TKEEP_NORMAL_C); + TSP_AXIS_CONFIG_G : AxiStreamConfigType := ssiAxiStreamConfig(16, TKEEP_NORMAL_C); + -- RSSI Timeouts + CLK_FREQUENCY_G : real := 156.25E+6; --! In units of Hz + TIMEOUT_UNIT_G : real := 1.0E-3; --! In units of seconds + ACK_TOUT_G : positive := 25; --! unit depends on TIMEOUT_UNIT_G + RETRANS_TOUT_G : positive := 50; --! unit depends on TIMEOUT_UNIT_G (Recommended >= MAX_NUM_OUTS_SEG_C*Data segment transmission time) + NULL_TOUT_G : positive := 200; --! unit depends on TIMEOUT_UNIT_G (Recommended >= 4*RETRANS_TOUT_G) + RETRANSMIT_ENABLE_G : boolean := true; --! Enable/Disable retransmissions in tx module + -- Version and connection ID + INIT_SEQ_N_G : natural := 16#80#; + CONN_ID_G : positive := 16#12345678#; + VERSION_G : positive := 1; + HEADER_CHKSUM_EN_G : boolean := true; + -- Counters + MAX_RETRANS_CNT_G : positive := 8; + MAX_CUM_ACK_CNT_G : positive := 3); + port ( + clk : in sl; + rst : in sl; + -- AXI TX Segment Buffer Interface + txAxiOffset : in slv(63 downto 0); --! Used to apply an address offset to the master AXI transactions + txAxiWriteMaster : out AxiWriteMasterType; + txAxiWriteSlave : in AxiWriteSlaveType; + txAxiReadMaster : out AxiReadMasterType; + txAxiReadSlave : in AxiReadSlaveType; + -- AXI RX Segment Buffer Interface + rxAxiOffset : in slv(63 downto 0); --! Used to apply an address offset to the master AXI transactions + rxAxiWriteMaster : out AxiWriteMasterType; + rxAxiWriteSlave : in AxiWriteSlaveType; + rxAxiReadMaster : out AxiReadMasterType; + rxAxiReadSlave : in AxiReadSlaveType; + -- High level Application side interface + openRq : in sl := '0'; + closeRq : in sl := '0'; + inject : in sl := '0'; + -- SSI Application side + sAppAxisMaster : in AxiStreamMasterType; + sAppAxisSlave : out AxiStreamSlaveType; + mAppAxisMaster : out AxiStreamMasterType; + mAppAxisSlave : in AxiStreamSlaveType; + -- SSI Transport side + sTspAxisMaster : in AxiStreamMasterType; + sTspAxisSlave : out AxiStreamSlaveType; + mTspAxisMaster : out AxiStreamMasterType; + mTspAxisSlave : in AxiStreamSlaveType; + -- AXI-Lite Register Interface + sAxilReadMaster : in AxiLiteReadMasterType := AXI_LITE_READ_MASTER_INIT_C; + sAxilReadSlave : out AxiLiteReadSlaveType; + sAxilWriteMaster : in AxiLiteWriteMasterType := AXI_LITE_WRITE_MASTER_INIT_C; + sAxilWriteSlave : out AxiLiteWriteSlaveType; + -- Internal statuses + statusReg : out slv(6 downto 0); + maxSegSize : out slv(15 downto 0)); +end entity AxiRssiCore; + +architecture rtl of AxiRssiCore is + + constant MAX_SEGS_BITS_C : positive := bitSize(MAX_SEG_SIZE_G-1); + constant SEGMENT_ADDR_SIZE_C : positive := (MAX_SEGS_BITS_C-3); --! 2^SEGMENT_ADDR_SIZE_C = Number of 64 bit wide data words + constant WINDOW_ADDR_SIZE_C : positive := (AXI_CONFIG_G.ADDR_WIDTH_C-MAX_SEGS_BITS_C); --! 2^WINDOW_ADDR_SIZE_C = Max number of segments in buffer + constant MAX_NUM_OUTS_SEG_C : positive := (2**WINDOW_ADDR_SIZE_C); --! MAX_NUM_OUTS_SEG_C=(2**WINDOW_ADDR_SIZE_C) + constant AXI_BURST_BYTES_C : positive := ite((MAX_SEG_SIZE_G > 4096), 4096, 2**MAX_SEGS_BITS_C); -- Enforce power of 2 and up to 4kB AXI burst + + -- RSSI Parameters + signal s_appRssiParam : RssiParamType; + signal s_rxRssiParam : RssiParamType; + signal s_rssiParam : RssiParamType; + + -- Monitor input signals + signal s_txBufferEmpty : sl; + signal s_lenErr : sl; + signal s_ackErr : sl; + signal s_peerConnTout : sl; + signal s_paramReject : sl; + + -- Connection control and parameters + signal s_initSeqN : slv(7 downto 0); + signal s_connActive : sl; + signal s_closeRq : sl; + signal s_closed : sl; + signal s_openRq : sl; + signal s_intCloseRq : sl; + signal s_txAckF : sl; + + -- Fault injection + signal s_injectFaultReg : sl; + signal s_injectFault : sl; + + -- Header states + signal s_synHeadSt : sl; + signal s_rstHeadSt : sl; + signal s_dataHeadSt : sl; + signal s_nullHeadSt : sl; + signal s_ackHeadSt : sl; + + -- Tx Segment requests + signal s_sndResend : sl; + signal s_sndSyn : sl; + signal s_sndAck : sl; + signal s_sndAckMon : sl; + signal s_sndAckCon : sl; + signal s_sndRst : sl; + signal s_sndNull : sl; + + -- Current transmitted or received SeqN and AckN + signal s_txSeqN : slv(7 downto 0); + signal s_txAckN : slv(7 downto 0); + signal s_rxSeqN : slv(7 downto 0); + signal s_rxLastSeqN : slv(7 downto 0); + signal s_rxAckN : slv(7 downto 0); + signal s_rxLastAckN : slv(7 downto 0); + + -- Tx Header Interface + signal s_headerAddr : slv(7 downto 0); + signal s_headerData : slv(RSSI_WORD_WIDTH_C*8-1 downto 0); + signal s_headerRdy : sl; + signal s_headerLength : positive; + + -- Rx Statuses + signal s_rxValidSeg : sl; + signal s_rxDropSeg : sl; + signal s_rxFlags : flagsType; + signal s_rxAck : sl; -- Acknowledge pulse when valid segment with acknowledge flag received + signal s_rxBuffBusy : sl; + + -- Rx segment buffer + signal s_rxBufferSize : integer range 1 to 2 ** (SEGMENT_ADDR_SIZE_C); + signal s_rxWindowSize : integer range 1 to 2 ** (WINDOW_ADDR_SIZE_C); + + -- Tx segment buffer + signal s_txBufferSize : integer range 1 to 2 ** (SEGMENT_ADDR_SIZE_C); + signal s_txWindowSize : integer range 1 to 2 ** (WINDOW_ADDR_SIZE_C); + + -- AXIS Application Interface + signal s_sAppAxisMaster : AxiStreamMasterType; + signal s_sAppAxisSlave : AxiStreamSlaveType; + signal s_mAppAxisMaster : AxiStreamMasterType; + signal s_mAppAxisSlave : AxiStreamSlaveType; + + -- AXIS Transport Interface + signal s_sTspAxisMaster : AxiStreamMasterType; + signal s_sTspAxisSlave : AxiStreamSlaveType; + signal s_mTspAxisMaster : AxiStreamMasterType; + signal s_mTspAxisSlave : AxiStreamSlaveType; + + -- AXI-Lite Control/Config Interface + signal s_openRqReg : sl; + signal s_closeRqReg : sl; + signal s_modeReg : sl; -- '0': Use internal parameters from generics, '1': Use parameters from Axil + signal s_initSeqNReg : slv(7 downto 0); + signal s_appRssiParamReg : RssiParamType; + + -- AXI-Lite Status/Monitoring Interface + signal s_statusReg : slv(statusReg'range); + signal s_dropCntReg : slv(31 downto 0); + signal s_validCntReg : slv(31 downto 0); + signal s_reconCntReg : slv(31 downto 0); + signal s_resendCntReg : slv(31 downto 0); + signal s_monMasters : AxiStreamMasterArray(1 downto 0); + signal s_monSlaves : AxiStreamSlaveArray(1 downto 0); + signal s_frameRate : Slv32Array(1 downto 0); + signal s_bandwidth : Slv64Array(1 downto 0); + +begin + + assert (MAX_NUM_OUTS_SEG_C <= 256) + report "AxiRssiCore: MAX_NUM_OUTS_SEG_C must be <= 256" severity failure; + + statusReg <= s_statusReg; + maxSegSize <= s_rxRssiParam.maxSegSize; + + --------------------- + -- Register interface + --------------------- + U_Reg : entity work.RssiAxiLiteRegItf + generic map ( + TPD_G => TPD_G, + COMMON_CLK_G => true, + TIMEOUT_UNIT_G => TIMEOUT_UNIT_G, + SEGMENT_ADDR_SIZE_G => SEGMENT_ADDR_SIZE_C, + INIT_SEQ_N_G => INIT_SEQ_N_G, + CONN_ID_G => CONN_ID_G, + VERSION_G => VERSION_G, + HEADER_CHKSUM_EN_G => HEADER_CHKSUM_EN_G, + MAX_NUM_OUTS_SEG_G => MAX_NUM_OUTS_SEG_C, + MAX_SEG_SIZE_G => MAX_SEG_SIZE_G, + RETRANS_TOUT_G => RETRANS_TOUT_G, + ACK_TOUT_G => ACK_TOUT_G, + NULL_TOUT_G => NULL_TOUT_G, + MAX_RETRANS_CNT_G => MAX_RETRANS_CNT_G, + MAX_CUM_ACK_CNT_G => MAX_CUM_ACK_CNT_G, + MAX_OUT_OF_SEQUENCE_G => 0) + port map ( + axiClk_i => clk, + axiRst_i => rst, + axilReadMaster => sAxilReadMaster, + axilReadSlave => sAxilReadSlave, + axilWriteMaster => sAxilWriteMaster, + axilWriteSlave => sAxilWriteSlave, + -- DevClk domain + devClk_i => clk, + devRst_i => rst, + -- Control + openRq_o => s_openRqReg, + closeRq_o => s_closeRqReg, + mode_o => s_modeReg, + initSeqN_o => s_initSeqNReg, + appRssiParam_o => s_appRssiParamReg, + injectFault_o => s_injectFaultReg, + -- Status (RO) + frameRate_i => s_frameRate, + bandwidth_i => s_bandwidth, + status_i => s_statusReg, + dropCnt_i => s_dropCntReg, + validCnt_i => s_validCntReg, + resendCnt_i => s_resendCntReg, + reconCnt_i => s_reconCntReg); + + s_injectFault <= s_injectFaultReg or inject; + + PACKET_RATE : + for i in 1 downto 0 generate + U_AxiStreamMon : entity work.AxiStreamMon + generic map ( + TPD_G => TPD_G, + COMMON_CLK_G => true, + AXIS_CLK_FREQ_G => CLK_FREQUENCY_G, + AXIS_CONFIG_G => APP_AXIS_CONFIG_G) + port map ( + -- AXIS Stream Interface + axisClk => clk, + axisRst => rst, + axisMaster => s_monMasters(i), + axisSlave => s_monSlaves(i), + -- Status Interface + statusClk => clk, + statusRst => rst, + frameRate => s_frameRate(i), + bandwidth => s_bandwidth(i)); + end generate PACKET_RATE; + + ---------------------------------------------------------------------------- + -- Connection, Auto Negotiation and Monitoring -- + ---------------------------------------------------------------------------- + + ----------------------- + -- Parameter assignment + ----------------------- + process (closeRq, openRq, s_appRssiParamReg, s_closeRqReg, s_initSeqNReg, + s_intCloseRq, s_modeReg, s_openRqReg) is + begin + if (s_modeReg = '0') then + + -- Use external requests + s_closeRq <= s_closeRqReg or closeRq or s_intCloseRq; + s_openRq <= s_openRqReg or openRq; + + -- Assign application side RSSI parameters from generics + s_appRssiParam.maxOutsSeg <= toSlv(MAX_NUM_OUTS_SEG_C, 8); + s_appRssiParam.maxSegSize <= toSlv(MAX_SEG_SIZE_G, 16); + s_appRssiParam.retransTout <= toSlv(RETRANS_TOUT_G, 16); + s_appRssiParam.cumulAckTout <= toSlv(ACK_TOUT_G, 16); + s_appRssiParam.nullSegTout <= toSlv(NULL_TOUT_G, 16); + s_appRssiParam.maxRetrans <= toSlv(MAX_RETRANS_CNT_G, 8); + s_appRssiParam.maxCumAck <= toSlv(MAX_CUM_ACK_CNT_G, 8); + s_appRssiParam.maxOutofseq <= toSlv(0, 8); + s_appRssiParam.version <= toSlv(VERSION_G, 4); + s_appRssiParam.connectionId <= toSlv(CONN_ID_G, 32); + s_appRssiParam.chksumEn <= ite(HEADER_CHKSUM_EN_G, "1", "0"); + s_appRssiParam.timeoutUnit <= toSlv(integer(0.0 - (ieee.math_real.log(TIMEOUT_UNIT_G)/ieee.math_real.log(10.0))), 8); + s_initSeqN <= toSlv(INIT_SEQ_N_G, 8); + + else + + -- Use AXI-Lite register requests + s_closeRq <= s_closeRqReg or s_intCloseRq; + s_openRq <= s_openRqReg; + + -- Assign application side RSSI parameters from AXI-Lite registers + s_appRssiParam <= s_appRssiParamReg; + s_initSeqN <= s_initSeqNReg; + + end if; + end process; + + ---------------------------------- + -- Connection Finite State Machine + ---------------------------------- + U_ConnFSM : entity work.RssiConnFsm + generic map ( + TPD_G => TPD_G, + SERVER_G => SERVER_G, + TIMEOUT_UNIT_G => TIMEOUT_UNIT_G, + CLK_FREQUENCY_G => CLK_FREQUENCY_G, + RETRANS_TOUT_G => RETRANS_TOUT_G, + MAX_RETRANS_CNT_G => MAX_RETRANS_CNT_G, + WINDOW_ADDR_SIZE_G => WINDOW_ADDR_SIZE_C, + SEGMENT_ADDR_SIZE_G => SEGMENT_ADDR_SIZE_C) + port map ( + clk_i => clk, + rst_i => rst, + connRq_i => s_openRq, + closeRq_i => s_closeRq, + closed_o => s_closed, + rxRssiParam_i => s_rxRssiParam, + appRssiParam_i => s_appRssiParam, + rssiParam_o => s_rssiParam, + rxFlags_i => s_rxFlags, + rxValid_i => s_rxValidSeg, + synHeadSt_i => s_synHeadSt, + ackHeadSt_i => s_ackHeadSt, + rstHeadSt_i => s_rstHeadSt, + connActive_o => s_connActive, + sndSyn_o => s_sndSyn, + sndAck_o => s_sndAckCon, + sndRst_o => s_sndRst, + txAckF_o => s_txAckF, + rxBufferSize_o => s_rxBufferSize, + rxWindowSize_o => s_rxWindowSize, + txBufferSize_o => s_txBufferSize, + txWindowSize_o => s_txWindowSize, + peerTout_o => s_peerConnTout, + paramReject_o => s_paramReject); + + ------------------------------- + -- Connection Monitoring Module + ------------------------------- + U_Monitor : entity work.RssiMonitor + generic map ( + TPD_G => TPD_G, + CLK_FREQUENCY_G => CLK_FREQUENCY_G, + TIMEOUT_UNIT_G => TIMEOUT_UNIT_G, + SERVER_G => SERVER_G, + WINDOW_ADDR_SIZE_G => WINDOW_ADDR_SIZE_C, + RETRANSMIT_ENABLE_G => RETRANSMIT_ENABLE_G) + port map ( + clk_i => clk, + rst_i => rst, + connActive_i => s_connActive, + rxBuffBusy_i => s_rxBuffBusy, + rssiParam_i => s_rssiParam, + rxFlags_i => s_rxFlags, + rxValid_i => s_rxValidSeg, + rxDrop_i => s_rxDropSeg, + ackHeadSt_i => s_ackHeadSt, + rstHeadSt_i => s_rstHeadSt, + dataHeadSt_i => s_dataHeadSt, + nullHeadSt_i => s_nullHeadSt, + rxLastSeqN_i => s_rxLastSeqN, + rxWindowSize_i => s_rxWindowSize, + lenErr_i => s_lenErr, + ackErr_i => s_ackErr, + peerConnTout_i => s_peerConnTout, + paramReject_i => s_paramReject, + txBufferEmpty_i => s_txBufferEmpty, + sndResend_o => s_sndResend, + sndAck_o => s_sndAckMon, + sndNull_o => s_sndNull, + closeRq_o => s_intCloseRq, + statusReg_o => s_statusReg, + dropCnt_o => s_dropCntReg, + validCnt_o => s_validCntReg, + resendCnt_o => s_resendCntReg, + reconCnt_o => s_reconCntReg); + + ------------------------------------ + -- Outbound Header Generation Module + ------------------------------------ + U_HeaderReg : entity work.RssiHeaderReg + generic map ( + TPD_G => TPD_G, + SYN_HEADER_SIZE_G => SYN_HEADER_SIZE_C, + ACK_HEADER_SIZE_G => ACK_HEADER_SIZE_C, + EACK_HEADER_SIZE_G => EACK_HEADER_SIZE_C, + RST_HEADER_SIZE_G => RST_HEADER_SIZE_C, + NULL_HEADER_SIZE_G => NULL_HEADER_SIZE_C, + DATA_HEADER_SIZE_G => DATA_HEADER_SIZE_C) + port map ( + clk_i => clk, + rst_i => rst, + synHeadSt_i => s_synHeadSt, + rstHeadSt_i => s_rstHeadSt, + dataHeadSt_i => s_dataHeadSt, + nullHeadSt_i => s_nullHeadSt, + ackHeadSt_i => s_ackHeadSt, + busyHeadSt_i => s_rxBuffBusy, + ack_i => s_txAckF, -- Connected to ConnectFSM + txSeqN_i => s_txSeqN, + rxAckN_i => s_rxLastSeqN, + headerValues_i => s_rssiParam, + addr_i => s_headerAddr, + headerData_o => s_headerData, + ready_o => s_headerRdy, + headerLength_o => s_headerLength); + + s_sndAck <= s_sndAckCon or s_sndAckMon; + + ---------------------------------------------------------------------------- + -- From Application layer to Transport Layer -- + ---------------------------------------------------------------------------- + + -------------------- + -- Application Layer + -------------------- + U_AppIn : entity work.AxiStreamResize + generic map ( + -- General Configurations + TPD_G => TPD_G, + READY_EN_G => true, + -- AXI Stream Port Configurations + SLAVE_AXI_CONFIG_G => APP_AXIS_CONFIG_G, + MASTER_AXI_CONFIG_G => RSSI_AXIS_CONFIG_C) + port map ( + -- Clock and reset + axisClk => clk, + axisRst => rst, + -- Slave Port + sAxisMaster => s_monMasters(0), + sAxisSlave => s_monSlaves(0), + -- Master Port + mAxisMaster => s_mAppAxisMaster, + mAxisSlave => s_mAppAxisSlave); + + s_monMasters(0) <= sAppAxisMaster; + sAppAxisSlave <= s_monSlaves(0); + + ----------------------------------- + -- Transmitter Finite State Machine + ----------------------------------- + U_TxFSM : entity work.AxiRssiTxFsm + generic map ( + TPD_G => TPD_G, + AXI_CONFIG_G => AXI_CONFIG_G, + BURST_BYTES_G => AXI_BURST_BYTES_C, + WINDOW_ADDR_SIZE_G => WINDOW_ADDR_SIZE_C, + SEGMENT_ADDR_SIZE_G => SEGMENT_ADDR_SIZE_C, + HEADER_CHKSUM_EN_G => HEADER_CHKSUM_EN_G) + port map ( + clk_i => clk, + rst_i => rst, + -- AXI Segment Buffer Interface + axiOffset_i => txAxiOffset, + mAxiWriteMaster_o => txAxiWriteMaster, + mAxiWriteSlave_i => txAxiWriteSlave, + mAxiReadMaster_o => txAxiReadMaster, + mAxiReadSlave_i => txAxiReadSlave, + -- Inbound Application Interface + appMaster_i => s_mAppAxisMaster, + appSlave_o => s_mAppAxisSlave, + -- Outbound Transport Interface + tspMaster_o => s_sTspAxisMaster, + tspSlave_i => s_sTspAxisSlave, + -- Connection FSM indicating active connection + connActive_i => s_connActive, + -- Closed state in connFSM (initialize seqN) + closed_i => s_closed, + -- Fault injection corrupts header checksum + injectFault_i => s_injectFault, + -- Various segment requests + sndSyn_i => s_sndSyn, + sndAck_i => s_sndAck, + sndRst_i => s_sndRst, + sndResend_i => s_sndResend, + sndNull_i => s_sndNull, + -- Window buff size (Depends on the number of outstanding segments) + windowSize_i => s_txWindowSize, + bufferSize_i => s_txBufferSize, + -- Header read + rdHeaderAddr_o => s_headerAddr, + rdHeaderData_i => s_headerData, + -- Initial sequence number + initSeqN_i => s_initSeqN, + -- Tx data (input to header decoder module) + txSeqN_o => s_txSeqN, + -- FSM outs for header and data flow control + synHeadSt_o => s_synHeadSt, + ackHeadSt_o => s_ackHeadSt, + dataHeadSt_o => s_dataHeadSt, + dataSt_o => open, -- may be used in the future otherwise remove + rstHeadSt_o => s_rstHeadSt, + nullHeadSt_o => s_nullHeadSt, + -- Last acked number (Used in Rx FSM to determine if AcnN is valid) + lastAckN_o => s_rxLastAckN, + -- Acknowledge mechanism + ack_i => s_rxAck, + ackN_i => s_rxAckN, + ---------------------------------- + --eack_i => s_rxEack_i, -- From receiver module when a segment with valid EACK is received + --eackSeqnArr_i => s_rxEackSeqnArr, -- Array of sequence numbers received out of order + ---------------------------------- + -- Errors (1 cc pulse) + lenErr_o => s_lenErr, + ackErr_o => s_ackErr, + -- Segment buffer indicator + bufferEmpty_o => s_txBufferEmpty); + + ------------------ + -- Transport Layer + ------------------ + U_TspOut : entity work.AxiStreamResize + generic map ( + -- General Configurations + TPD_G => TPD_G, + READY_EN_G => true, + -- AXI Stream Port Configurations + SLAVE_AXI_CONFIG_G => RSSI_AXIS_CONFIG_C, + MASTER_AXI_CONFIG_G => TSP_AXIS_CONFIG_G) + port map ( + -- Clock and reset + axisClk => clk, + axisRst => rst, + -- Slave Port + sAxisMaster => s_sTspAxisMaster, + sAxisSlave => s_sTspAxisSlave, + -- Master Port + mAxisMaster => mTspAxisMaster, + mAxisSlave => mTspAxisSlave); + + ---------------------------------------------------------------------------- + -- From Transport layer to Application Layer -- + ---------------------------------------------------------------------------- + + ------------------ + -- Transport Layer + ------------------ + U_TspIn : entity work.AxiStreamResize + generic map ( + -- General Configurations + TPD_G => TPD_G, + READY_EN_G => true, + -- AXI Stream Port Configurations + SLAVE_AXI_CONFIG_G => TSP_AXIS_CONFIG_G, + MASTER_AXI_CONFIG_G => RSSI_AXIS_CONFIG_C) + port map ( + -- Clock and reset + axisClk => clk, + axisRst => rst, + -- Slave Port + sAxisMaster => sTspAxisMaster, + sAxisSlave => sTspAxisSlave, + -- Master Port + mAxisMaster => s_mTspAxisMaster, + mAxisSlave => s_mTspAxisSlave); + + -------------------------------- + -- Receiver Finite State Machine + -------------------------------- + U_RxFSM : entity work.AxiRssiRxFsm + generic map ( + TPD_G => TPD_G, + AXI_CONFIG_G => AXI_CONFIG_G, + BURST_BYTES_G => AXI_BURST_BYTES_C, + WINDOW_ADDR_SIZE_G => WINDOW_ADDR_SIZE_C, + HEADER_CHKSUM_EN_G => HEADER_CHKSUM_EN_G, + SEGMENT_ADDR_SIZE_G => SEGMENT_ADDR_SIZE_C) + port map ( + clk_i => clk, + rst_i => rst, + -- AXI Segment Buffer Interface + axiOffset_i => rxAxiOffset, + mAxiWriteMaster_o => rxAxiWriteMaster, + mAxiWriteSlave_i => rxAxiWriteSlave, + mAxiReadMaster_o => rxAxiReadMaster, + mAxiReadSlave_i => rxAxiReadSlave, + -- Inbound Transport Interface + tspMaster_i => s_mTspAxisMaster, + tspSlave_o => s_mTspAxisSlave, + -- Outbound Application Interface + appMaster_o => s_sAppAxisMaster, + appSlave_i => s_sAppAxisSlave, + -- RX Buffer Full + rxBuffBusy_o => s_rxBuffBusy, + -- Connection FSM indicating active connection + connActive_i => s_connActive, + -- Window size different for Rx and Tx + rxWindowSize_i => s_rxWindowSize, + rxBufferSize_i => s_rxBufferSize, + txWindowSize_i => s_txWindowSize, + -- Last acknowledged Sequence number connected to TX module + lastAckN_i => s_rxLastAckN, + -- Current received seqN + rxSeqN_o => s_rxSeqN, + -- Current received ackN + rxLastSeqN_o => s_rxLastSeqN, + -- Last seqN received and sent to application (this is the ackN transmitted) + rxAckN_o => s_rxAckN, + -- Valid Segment received (1 c-c) + rxValidSeg_o => s_rxValidSeg, + -- Segment dropped (1 c-c) + rxDropSeg_o => s_rxDropSeg, + -- Last segment received flags (active until next segment is received) + rxFlags_o => s_rxFlags, + -- Parameters received from peer SYN packet + rxParam_o => s_rxRssiParam); + + s_rxAck <= s_rxValidSeg and s_rxFlags.ack and s_connActive; -- Acknowledge valid packet + + -------------------- + -- Application Layer + -------------------- + U_AppOut : entity work.AxiStreamResize + generic map ( + -- General Configurations + TPD_G => TPD_G, + READY_EN_G => true, + -- AXI Stream Port Configurations + SLAVE_AXI_CONFIG_G => RSSI_AXIS_CONFIG_C, + MASTER_AXI_CONFIG_G => APP_AXIS_CONFIG_G) + port map ( + -- Clock and reset + axisClk => clk, + axisRst => rst, + -- Slave Port + sAxisMaster => s_sAppAxisMaster, + sAxisSlave => s_sAppAxisSlave, + -- Master Port + mAxisMaster => s_monMasters(1), + mAxisSlave => s_monSlaves(1)); + + mAppAxisMaster <= s_monMasters(1); + s_monSlaves(1) <= mAppAxisSlave; + +end architecture rtl; diff --git a/protocols/rssi/v1b/rtl/AxiRssiCoreWrapper.vhd b/protocols/rssi/v1b/rtl/AxiRssiCoreWrapper.vhd new file mode 100644 index 0000000000..e7f1eae0d9 --- /dev/null +++ b/protocols/rssi/v1b/rtl/AxiRssiCoreWrapper.vhd @@ -0,0 +1,315 @@ +------------------------------------------------------------------------------- +-- File : AxiRssiCoreWrapper.vhd +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: Wrapper for RSSI + AXIS packetizer +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.StdRtlPkg.all; +use work.AxiPkg.all; +use work.AxiStreamPkg.all; +use work.AxiLitePkg.all; +use work.AxiRssiPkg.all; +use work.RssiPkg.all; +use work.SsiPkg.all; + +entity AxiRssiCoreWrapper is + generic ( + TPD_G : time := 1 ns; + SERVER_G : boolean := true; --! Module is server or client + JUMBO_G : boolean := false; --! true=8192 byte payload, false=1024 byte payload + AXI_CONFIG_G : AxiConfigType := RSSI_AXI_CONFIG_C; --! Defines the AXI configuration but ADDR_WIDTH_C should be defined as the space for RSSI and "maybe" not the entire memory address space available + -- AXIS Configurations + APP_STREAMS_G : positive := 1; + APP_STREAM_ROUTES_G : Slv8Array := (0 => "--------"); + ILEAVE_ON_NOTVALID_G : boolean := true; + APP_AXIS_CONFIG_G : AxiStreamConfigArray := (0 => ssiAxiStreamConfig(8, TKEEP_NORMAL_C)); + TSP_AXIS_CONFIG_G : AxiStreamConfigType := ssiAxiStreamConfig(16, TKEEP_NORMAL_C); + -- RSSI Timeouts + CLK_FREQUENCY_G : real := 156.25E+6; -- In units of Hz + TIMEOUT_UNIT_G : real := 1.0E-3; -- In units of seconds + ACK_TOUT_G : positive := 25; -- unit depends on TIMEOUT_UNIT_G + RETRANS_TOUT_G : positive := 50; -- unit depends on TIMEOUT_UNIT_G (Recommended >= MAX_NUM_OUTS_SEG_G*Data segment transmission time) + NULL_TOUT_G : positive := 200; -- unit depends on TIMEOUT_UNIT_G (Recommended >= 4*RETRANS_TOUT_G) + -- Counters + MAX_RETRANS_CNT_G : positive := 8; + MAX_CUM_ACK_CNT_G : positive := 3); + port ( + -- Clock and Reset + clk : in sl; + rst : in sl; + -- AXI TX Segment Buffer Interface + txAxiOffset : in slv(63 downto 0); --! Used to apply an address offset to the master AXI transactions + txAxiWriteMaster : out AxiWriteMasterType; + txAxiWriteSlave : in AxiWriteSlaveType; + txAxiReadMaster : out AxiReadMasterType; + txAxiReadSlave : in AxiReadSlaveType; + -- AXI RX Segment Buffer Interface + rxAxiOffset : in slv(63 downto 0); --! Used to apply an address offset to the master AXI transactions + rxAxiWriteMaster : out AxiWriteMasterType; + rxAxiWriteSlave : in AxiWriteSlaveType; + rxAxiReadMaster : out AxiReadMasterType; + rxAxiReadSlave : in AxiReadSlaveType; + -- SSI Application side + sAppAxisMasters : in AxiStreamMasterArray(APP_STREAMS_G-1 downto 0); + sAppAxisSlaves : out AxiStreamSlaveArray(APP_STREAMS_G-1 downto 0); + mAppAxisMasters : out AxiStreamMasterArray(APP_STREAMS_G-1 downto 0); + mAppAxisSlaves : in AxiStreamSlaveArray(APP_STREAMS_G-1 downto 0); + -- SSI Transport side + sTspAxisMaster : in AxiStreamMasterType; + sTspAxisSlave : out AxiStreamSlaveType; + mTspAxisMaster : out AxiStreamMasterType; + mTspAxisSlave : in AxiStreamSlaveType; + -- High level Application side interface + openRq : in sl := '0'; + closeRq : in sl := '0'; + inject : in sl := '0'; + linkUp : out sl; + -- Optional AXI-Lite Register Interface + sAxilReadMaster : in AxiLiteReadMasterType := AXI_LITE_READ_MASTER_INIT_C; + sAxilReadSlave : out AxiLiteReadSlaveType; + sAxilWriteMaster : in AxiLiteWriteMasterType := AXI_LITE_WRITE_MASTER_INIT_C; + sAxilWriteSlave : out AxiLiteWriteSlaveType); +end entity AxiRssiCoreWrapper; + +architecture mapping of AxiRssiCoreWrapper is + + constant PACKETIZER_AXIS_CONFIG_C : AxiStreamConfigType := ( + TSTRB_EN_C => false, + TDATA_BYTES_C => 8, + TDEST_BITS_C => 8, + TID_BITS_C => 8, + TKEEP_MODE_C => TKEEP_COMP_C, + TUSER_BITS_C => 8, + TUSER_MODE_C => TUSER_FIRST_LAST_C); + + constant MAX_SEG_SIZE_C : positive := ite(JUMBO_G, 8192, 1024); + constant MAX_SEGS_BITS_C : positive := bitSize(MAX_SEG_SIZE_C); + + signal maxSegs : slv(MAX_SEGS_BITS_C-1 downto 0) := toSlv(MAX_SEG_SIZE_C, MAX_SEGS_BITS_C); + signal maxObSegSize : slv(15 downto 0) := toSlv(MAX_SEG_SIZE_C, 16); + + signal status : slv(6 downto 0) := (others => '0'); + signal rssiNotConnected : sl := '1'; + signal rssiConnected : sl := '1'; + + signal rxMasters : AxiStreamMasterArray(APP_STREAMS_G-1 downto 0); + signal rxSlaves : AxiStreamSlaveArray(APP_STREAMS_G-1 downto 0); + + signal depacketizerMasters : AxiStreamMasterArray(1 downto 0); + signal depacketizerSlaves : AxiStreamSlaveArray(1 downto 0); + + signal packetizerMasters : AxiStreamMasterArray(1 downto 0); + signal packetizerSlaves : AxiStreamSlaveArray(1 downto 0); + + signal txMasters : AxiStreamMasterArray(APP_STREAMS_G-1 downto 0); + signal txSlaves : AxiStreamSlaveArray(APP_STREAMS_G-1 downto 0); + +begin + + -- Register to help with timing + process(clk) + begin + if rising_edge(clk) then + linkUp <= status(0) after TPD_G; + rssiConnected <= status(0) after TPD_G; + rssiNotConnected <= not(rssiConnected) after TPD_G; + if (unsigned(maxObSegSize) >= MAX_SEG_SIZE_C) then + maxSegs <= slv(to_unsigned(MAX_SEG_SIZE_C, maxSegs'length)) after TPD_G; + else + maxSegs <= maxObSegSize(maxSegs'range) after TPD_G; + end if; + end if; + end process; + + GEN_RX : + for i in (APP_STREAMS_G-1) downto 0 generate + U_Rx : entity work.AxiStreamResize + generic map ( + -- General Configurations + TPD_G => TPD_G, + READY_EN_G => true, + -- AXI Stream Port Configurations + SLAVE_AXI_CONFIG_G => APP_AXIS_CONFIG_G(i), + MASTER_AXI_CONFIG_G => PACKETIZER_AXIS_CONFIG_C) + port map ( + -- Clock and reset + axisClk => clk, + axisRst => rst, + -- Slave Port + sAxisMaster => sAppAxisMasters(i), + sAxisSlave => sAppAxisSlaves(i), + -- Master Port + mAxisMaster => rxMasters(i), + mAxisSlave => rxSlaves(i)); + end generate GEN_RX; + + U_AxiStreamMux : entity work.AxiStreamMux + generic map ( + TPD_G => TPD_G, + NUM_SLAVES_G => APP_STREAMS_G, + MODE_G => "ROUTED", + TDEST_ROUTES_G => APP_STREAM_ROUTES_G, + ILEAVE_EN_G => true, + ILEAVE_ON_NOTVALID_G => ILEAVE_ON_NOTVALID_G, + ILEAVE_REARB_G => (MAX_SEG_SIZE_C/PACKETIZER_AXIS_CONFIG_C.TDATA_BYTES_C), + PIPE_STAGES_G => 1) + port map ( + -- Clock and reset + axisClk => clk, + axisRst => rst, + -- Slaves + sAxisMasters => rxMasters, + sAxisSlaves => rxSlaves, + -- Master + mAxisMaster => packetizerMasters(0), + mAxisSlave => packetizerSlaves(0)); + + U_Packetizer : entity work.AxiStreamPacketizer2 + generic map ( + TPD_G => TPD_G, + BRAM_EN_G => true, + CRC_MODE_G => "FULL", + CRC_POLY_G => x"04C11DB7", + TDEST_BITS_G => 8, + MAX_PACKET_BYTES_G => MAX_SEG_SIZE_C, + INPUT_PIPE_STAGES_G => 0, + OUTPUT_PIPE_STAGES_G => 1) + port map ( + axisClk => clk, + axisRst => rst, + maxPktBytes => maxSegs, + sAxisMaster => packetizerMasters(0), + sAxisSlave => packetizerSlaves(0), + mAxisMaster => packetizerMasters(1), + mAxisSlave => packetizerSlaves(1)); + + U_RssiCore : entity work.AxiRssiCore + generic map ( + TPD_G => TPD_G, + SERVER_G => SERVER_G, + -- AXI Configurations + MAX_SEG_SIZE_G => MAX_SEG_SIZE_C, + AXI_CONFIG_G => AXI_CONFIG_G, + -- AXIS Configurations + APP_AXIS_CONFIG_G => PACKETIZER_AXIS_CONFIG_C, + TSP_AXIS_CONFIG_G => TSP_AXIS_CONFIG_G, + -- RSSI Timeouts + CLK_FREQUENCY_G => CLK_FREQUENCY_G, + TIMEOUT_UNIT_G => TIMEOUT_UNIT_G, + ACK_TOUT_G => ACK_TOUT_G, + RETRANS_TOUT_G => RETRANS_TOUT_G, + NULL_TOUT_G => NULL_TOUT_G, + -- Counters + MAX_RETRANS_CNT_G => MAX_RETRANS_CNT_G, + MAX_CUM_ACK_CNT_G => MAX_CUM_ACK_CNT_G) + port map ( + -- Clock and Reset + clk => clk, + rst => rst, + -- AXI TX Segment Buffer Interface + txAxiOffset => txAxiOffset, + txAxiWriteMaster => txAxiWriteMaster, + txAxiWriteSlave => txAxiWriteSlave, + txAxiReadMaster => txAxiReadMaster, + txAxiReadSlave => txAxiReadSlave, + -- AXI RX Segment Buffer Interface + rxAxiOffset => rxAxiOffset, + rxAxiWriteMaster => rxAxiWriteMaster, + rxAxiWriteSlave => rxAxiWriteSlave, + rxAxiReadMaster => rxAxiReadMaster, + rxAxiReadSlave => rxAxiReadSlave, + -- SSI Application side + sAppAxisMaster => packetizerMasters(1), + sAppAxisSlave => packetizerSlaves(1), + mAppAxisMaster => depacketizerMasters(1), + mAppAxisSlave => depacketizerSlaves(1), + -- SSI Transport side + sTspAxisMaster => sTspAxisMaster, + sTspAxisSlave => sTspAxisSlave, + mTspAxisMaster => mTspAxisMaster, + mTspAxisSlave => mTspAxisSlave, + -- High level Application side interface + openRq => openRq, + closeRq => closeRq, + inject => inject, + -- AXI-Lite Register Interface + sAxilReadMaster => sAxilReadMaster, + sAxilReadSlave => sAxilReadSlave, + sAxilWriteMaster => sAxilWriteMaster, + sAxilWriteSlave => sAxilWriteSlave, + -- Internal statuses + statusReg => status, + maxSegSize => maxObSegSize); + + U_Depacketizer : entity work.AxiStreamDepacketizer2 + generic map ( + TPD_G => TPD_G, + BRAM_EN_G => true, + CRC_MODE_G => "FULL", + CRC_POLY_G => x"04C11DB7", + TDEST_BITS_G => 8, + INPUT_PIPE_STAGES_G => 0, -- No need for input stage, RSSI output is already pipelined + OUTPUT_PIPE_STAGES_G => 1) + port map ( + axisClk => clk, + axisRst => rst, + linkGood => rssiConnected, + sAxisMaster => depacketizerMasters(1), + sAxisSlave => depacketizerSlaves(1), + mAxisMaster => depacketizerMasters(0), + mAxisSlave => depacketizerSlaves(0)); + + U_AxiStreamDeMux : entity work.AxiStreamDeMux + generic map ( + TPD_G => TPD_G, + PIPE_STAGES_G => 1, + NUM_MASTERS_G => APP_STREAMS_G, + MODE_G => "ROUTED", + TDEST_ROUTES_G => APP_STREAM_ROUTES_G) + port map ( + -- Clock and reset + axisClk => clk, + axisRst => rst, + -- Slaves + sAxisMaster => depacketizerMasters(0), + sAxisSlave => depacketizerSlaves(0), + -- Master + mAxisMasters => txMasters, + mAxisSlaves => txSlaves); + + GEN_TX : + for i in (APP_STREAMS_G-1) downto 0 generate + U_Tx : entity work.AxiStreamResize + generic map ( + -- General Configurations + TPD_G => TPD_G, + READY_EN_G => true, + -- AXI Stream Port Configurations + SLAVE_AXI_CONFIG_G => PACKETIZER_AXIS_CONFIG_C, + MASTER_AXI_CONFIG_G => APP_AXIS_CONFIG_G(i)) + port map ( + -- Clock and reset + axisClk => clk, + axisRst => rst, + -- Slave Port + sAxisMaster => txMasters(i), + sAxisSlave => txSlaves(i), + -- Master Port + mAxisMaster => mAppAxisMasters(i), + mAxisSlave => mAppAxisSlaves(i)); + end generate GEN_TX; + +end architecture mapping; diff --git a/protocols/rssi/v1b/rtl/AxiRssiPkg.vhd b/protocols/rssi/v1b/rtl/AxiRssiPkg.vhd new file mode 100644 index 0000000000..77fe6a8195 --- /dev/null +++ b/protocols/rssi/v1b/rtl/AxiRssiPkg.vhd @@ -0,0 +1,92 @@ +------------------------------------------------------------------------------- +-- File : AxiRssiPkg.vhd +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: RSSI Package File +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; + +use work.StdRtlPkg.all; +use work.AxiPkg.all; + +package AxiRssiPkg is + + --! Default RSSI AXI configuration + constant RSSI_AXI_CONFIG_C : AxiConfigType := ( + ADDR_WIDTH_C => 13, -- 2^13 = 8kB buffer + DATA_BYTES_C => 8, -- 8 bytes = 64-bits + ID_BITS_C => 2, + LEN_BITS_C => 7); -- Up to 1kB bursting + + procedure GetRssiCsum ( -- 2 clock cycle latency calculation + -- Input + init : in sl; + header : in slv(63 downto 0); + accumReg : in slv(20 downto 0); + -- Results + accumVar : inout slv(20 downto 0); + chksumOk : inout sl; + checksum : inout slv(15 downto 0)); + +end AxiRssiPkg; + + +package body AxiRssiPkg is + + procedure GetRssiCsum ( + -- Input + init : in sl; + header : in slv(63 downto 0); + accumReg : in slv(20 downto 0); + -- Results + accumVar : inout slv(20 downto 0); + chksumOk : inout sl; + checksum : inout slv(15 downto 0)) is + variable hdrSum : slv(20 downto 0); + variable summ0 : slv(16 downto 0); + variable summ1 : slv(15 downto 0); + begin + + -- Summation of the header + hdrSum := resize(header(63 downto 48), 21) + + resize(header(47 downto 32), 21) + + resize(header(31 downto 16), 21) + + resize(header(15 downto 0), 21); + + -- Check for initializing + if (init = '1') then + accumVar := hdrSum; + else + -- Add new word sum + accumVar := hdrSum + accumReg; + end if; + + -- Add the sum carry bits + summ0 := resize(accumReg(15 downto 0), 17) + resize(accumReg(20 downto 16), 17); + summ1 := summ0(15 downto 0) + resize(summ0(16 downto 16), 16); + + -- Checksum's Ones complement output (only used in TX FSM) + checksum := not(summ1); + + -- Output the checksum status (only used in RX FSM) + if (checksum = 0) then + chksumOk := '1'; + else + chksumOk := '0'; + end if; + + end procedure; + +end package body AxiRssiPkg; diff --git a/protocols/rssi/v1b/rtl/AxiRssiRxFsm.vhd b/protocols/rssi/v1b/rtl/AxiRssiRxFsm.vhd new file mode 100644 index 0000000000..f20e2e09f5 --- /dev/null +++ b/protocols/rssi/v1b/rtl/AxiRssiRxFsm.vhd @@ -0,0 +1,763 @@ +------------------------------------------------------------------------------- +-- File : AxiRssiRxFsm.vhd +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: Receiver FSM +-- Receiver has the following functionality: +-- Transport side FSM. Receive check and save segments to RX buffer. +-- - WAIT_SOF Waits for Transport side SOF, +-- - CHECK Determines the segment type and checks: +-- ACK, NULL, DATA, or RST segment +-- 1. Validates checksum (when valid), +-- 2. Header length (number of bytes), +-- 3. Sequence number (Only current seqN or lastSeqN+1 allowed) +-- 4. Acknowledgment number (Valid range is lastAckN to lastAckN + txWindowSize) +-- - CHECK_SYN Toggles through SYN header addresses and saves the RSSI parameters +-- Checks the following: +-- 1. Validates checksum (when valid), +-- 2. Validates Ack number if the ack is sent with the SYN segment +-- - DATA Receives the payload part of the DATA segment +-- - VALID Checks if next valid SEQn is received. If yes: +-- 1. increment the in order SEQn +-- 2. save seqN, type, and occupied to the window buffer at current rxBufferAddr +-- 3. increment rxBufferAddr +-- - DROP Just report dropped packet and got back to WAIT_SOF +-- Receiver side FSM. Send data to App side. +-- - CHECK_BUFFER and DATA Send the data frame to the Application +-- when the data at the next txSegmentAddr is ready. +-- - SENT Release the windowbuffer at txBufferAddr. +-- Increment txBufferAddr. +-- Register the received SeqN for acknowledgment. +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; + +use work.StdRtlPkg.all; +use work.AxiStreamPkg.all; +use work.AxiPkg.all; +use work.AxiDmaPkg.all; +use work.AxiRssiPkg.all; +use work.RssiPkg.all; +use work.SsiPkg.all; + +entity AxiRssiRxFsm is + generic ( + TPD_G : time := 1 ns; + AXI_CONFIG_G : AxiConfigType := RSSI_AXI_CONFIG_C; + BURST_BYTES_G : positive := 1024; + WINDOW_ADDR_SIZE_G : positive := 7; -- 2^WINDOW_ADDR_SIZE_G = Number of segments + HEADER_CHKSUM_EN_G : boolean := true; + SEGMENT_ADDR_SIZE_G : positive := 3); -- 2^SEGMENT_ADDR_SIZE_G = Number of 64 bit wide data words + port ( + clk_i : in sl; + rst_i : in sl; + -- AXI Segment Buffer Interface + axiOffset_i : in slv(63 downto 0); + mAxiWriteMaster_o : out AxiWriteMasterType; + mAxiWriteSlave_i : in AxiWriteSlaveType; + mAxiReadMaster_o : out AxiReadMasterType; + mAxiReadSlave_i : in AxiReadSlaveType; + -- Inbound Transport Interface + tspMaster_i : in AxiStreamMasterType; + tspSlave_o : out AxiStreamSlaveType; + -- Outbound Application Interface + appMaster_o : out AxiStreamMasterType; + appSlave_i : in AxiStreamSlaveType; + -- RX Buffer Full + rxBuffBusy_o : out sl; + -- Connection FSM indicating active connection + connActive_i : in sl; + -- Window size different for Rx and Tx + rxWindowSize_i : in integer range 1 to 2 ** (WINDOW_ADDR_SIZE_G); + rxBufferSize_i : in integer range 1 to 2 ** (SEGMENT_ADDR_SIZE_G); -- Units of 64-bit words + txWindowSize_i : in integer range 1 to 2 ** (WINDOW_ADDR_SIZE_G); + -- Last acknowledged Sequence number connected to TX module + lastAckN_i : in slv(7 downto 0); + -- Current received seqN + rxSeqN_o : out slv(7 downto 0); + -- Current received ackN + rxAckN_o : out slv(7 downto 0); + -- Last seqN received and sent to application (this is the ackN transmitted) + rxLastSeqN_o : out slv(7 downto 0); + -- Valid Segment received (1 c-c) + rxValidSeg_o : out sl; + -- Segment dropped (1 c-c) + rxDropSeg_o : out sl; + -- Last segment received flags (active until next segment is received) + rxFlags_o : out flagsType; + -- Parameters received from peer SYN packet + rxParam_o : out RssiParamType); +end entity AxiRssiRxFsm; + +architecture rtl of AxiRssiRxFsm is + + type tspStateType is ( + IDLE_S, + SYN_WAIT0_S, + SYN_WAIT1_S, + SYN_CHECK_S, + NSYN_CHECK_S, + DATA_S, + VALID_S); + + type AppStateType is ( + IDLE_S, + DATA_S, + SENT_S); + + type RegType is record + -- Reception buffer window + windowArray : WindowTypeArray(0 to 2 ** WINDOW_ADDR_SIZE_G-1); + pending : slv(WINDOW_ADDR_SIZE_G downto 0); + -------------------------------------------------- + -- Transport side FSM (Receive and check segments) + -------------------------------------------------- + wrReq : AxiWriteDmaReqType; + -- Counters + inorderSeqN : slv(7 downto 0); -- Next expected seqN + rxBufferAddr : slv(WINDOW_ADDR_SIZE_G-1 downto 0); + -- Packet flags + rxF : flagsType; + -- Received RSSI parameters + rxParam : RssiParamType; + rxHeadLen : slv(7 downto 0); + rxSeqN : slv(7 downto 0); -- Received seqN + rxAckN : slv(7 downto 0); -- Received ackN + -- Checksum Calculation + csumAccum : slv(20 downto 0); + chksumOk : sl; + chksumRdy : sl; + checksum : slv(15 downto 0); + -- Strobing status flags + segValid : sl; + segDrop : sl; + simErrorDet : sl; + -- Inbound Transport Interface + tspSlave : AxiStreamSlaveType; + -- State Machine + tspState : TspStateType; + -- Application side FSM (Send segments when next in order received) + ----------------------------------------------------------- + rdReq : AxiReadDmaReqType; + txBufferAddr : slv(WINDOW_ADDR_SIZE_G-1 downto 0); + rxLastSeqN : slv(7 downto 0); + -- State Machine + appState : AppStateType; + end record RegType; + + constant REG_INIT_C : RegType := ( + -- Rx buffer window + windowArray => (0 to 2 ** WINDOW_ADDR_SIZE_G-1 => WINDOW_INIT_C), + pending => (others => '0'), + -------------------------------------------------- + -- Transport side FSM (Receive and check segments) + -------------------------------------------------- + wrReq => AXI_WRITE_DMA_REQ_INIT_C, + -- Counters + inorderSeqN => (others => '0'), -- Next expected seqN + rxBufferAddr => (others => '0'), + -- Packet flags + rxF => (others => ('0')), + -- Received RSSI parameters + rxParam => RSSI_PARAM_INIT_C, + rxHeadLen => (others => '0'), -- Received seqN + rxSeqN => (others => '0'), -- Received seqN + rxAckN => (others => '0'), -- Received ackN + -- Checksum Calculation + csumAccum => (others => '0'), + chksumOk => '0', + chksumRdy => '0', + checksum => (others => '0'), + -- Strobing status flags + segValid => '0', + segDrop => '0', + simErrorDet => '0', + -- Inbound Transport Interface + tspSlave => AXI_STREAM_SLAVE_INIT_C, + -- Transport side state + tspState => IDLE_S, + ---------------------------------------------------------------------------- + -- Application side FSM (Send segments when received next in order received) + ---------------------------------------------------------------------------- + rdReq => AXI_READ_DMA_REQ_INIT_C, + txBufferAddr => (others => '0'), + rxLastSeqN => (others => '0'), + -- Application side state + appState => IDLE_S); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; + + signal wrAck : AxiWriteDmaAckType; + signal rdAck : AxiReadDmaAckType; + + signal wrDmaMaster : AxiStreamMasterType; + signal wrDmaSlave : AxiStreamSlaveType; + + -- attribute dont_touch : string; + -- attribute dont_touch of r : signal is "TRUE"; + +begin + + U_DmaWrite : entity work.AxiStreamDmaWrite + generic map ( + TPD_G => TPD_G, + AXI_READY_EN_G => true, + AXIS_CONFIG_G => RSSI_AXIS_CONFIG_C, + AXI_CONFIG_G => AXI_CONFIG_G, + BURST_BYTES_G => BURST_BYTES_G, + AXI_BURST_G => "01", -- INCR + AXI_CACHE_G => "0011", -- Cacheable + SW_CACHE_EN_G => false, + ACK_WAIT_BVALID_G => true, + PIPE_STAGES_G => 0, + BYP_SHIFT_G => true, + BYP_CACHE_G => true) + port map ( + -- Clock/Reset + axiClk => clk_i, + axiRst => rst_i, + -- DMA Control Interface + dmaReq => r.wrReq, + dmaAck => wrAck, + -- Streaming Interface + axisMaster => wrDmaMaster, + axisSlave => wrDmaSlave, + -- AXI Interface + axiWriteMaster => mAxiWriteMaster_o, + axiWriteSlave => mAxiWriteSlave_i); + + U_DmaRead : entity work.AxiStreamDmaRead + generic map ( + TPD_G => TPD_G, + AXIS_READY_EN_G => true, + AXIS_CONFIG_G => RSSI_AXIS_CONFIG_C, + AXI_CONFIG_G => AXI_CONFIG_G, + AXI_BURST_G => "01", -- INCR + AXI_CACHE_G => "0011", -- Cacheable + SW_CACHE_EN_G => false, + PIPE_STAGES_G => 0, + PEND_THRESH_G => 0, -- In units of bytes + BYP_SHIFT_G => true) + port map ( + -- Clock/Reset + axiClk => clk_i, + axiRst => rst_i, + -- DMA Control Interface + dmaReq => r.rdReq, + dmaAck => rdAck, + -- Streaming Interface + axisMaster => appMaster_o, + axisSlave => appSlave_i, + axisCtrl => AXI_STREAM_CTRL_UNUSED_C, + -- AXI Interface + axiReadMaster => mAxiReadMaster_o, + axiReadSlave => mAxiReadSlave_i); + + ----------------------------------------------------------------------------------------------- + comb : process (axiOffset_i, connActive_i, lastAckN_i, r, rdAck, rst_i, + rxBufferSize_i, rxWindowSize_i, tspMaster_i, txWindowSize_i, + wrAck, wrDmaSlave) is + + variable v : RegType; + variable headerData : slv(63 downto 0); + variable maxSegSize : natural; + variable rxBufIdx : natural; + variable txBufIdx : natural; + begin + -- Latch the current value + v := r; + + -- Reset strobes + v.tspSlave := AXI_STREAM_SLAVE_INIT_C; + v.segValid := '0'; + v.segDrop := '0'; + v.chksumRdy := '0'; + + -- Endian swap the header + headerData := endianSwap64(tspMaster_i.tData(63 downto 0)); + + -- Convert to bytes + maxSegSize := 8*rxBufferSize_i; + + -- Calculate the next DMA write transaction + rxBufIdx := conv_integer(r.rxBufferAddr); + v.wrReq.address := axiOffset_i + toSlv((rxBufIdx*maxSegSize), 64); + v.wrReq.maxSize := toSlv(maxSegSize, 32); + + ------------------------------------------------------------ + -- RX Transport side FSM: + -- Receive the segment from the peer + -- Check the segment: + -- register the parameters from SYN header + -- seqN, ackN + -- check header checksum + -- increment in order received SeqN + ------------------------------------------------------------ + case r.tspState is + ---------------------------------------------------------------------- + when IDLE_S => + + -- Calculate the checksum + GetRssiCsum( + -- Input + '1', -- init + headerData, -- header + r.csumAccum, -- accumReg + -- Results + v.csumAccum, -- accumVar + v.chksumOk, -- chksumOk + v.checksum); -- checksum + + -- Check for data + if (tspMaster_i.tValid = '1') then + + -- Accept the data + v.tspSlave.tReady := '1'; + + -- Check if SOF + if (ssiGetUserSof(RSSI_AXIS_CONFIG_C, tspMaster_i) = '1') then + + -- Register flags, header length and SEQn + v.rxF.syn := headerData(63); + v.rxF.ack := headerData(62); + v.rxF.eack := headerData(61); + v.rxF.rst := headerData(60); + v.rxF.nul := headerData(59); + v.rxF.busy := headerData(56); + v.rxHeadLen := headerData(55 downto 48); + v.rxSeqN := headerData(47 downto 40); + v.rxAckN := headerData(39 downto 32); + + -- Syn header received (header is 3 c-c long) + if (v.rxF.syn = '1') then + + -- Register SYN header word 0 parameters + v.rxParam.version := headerData(31 downto 28); + v.rxParam.chksumEn := headerData(26 downto 26); + v.rxParam.maxOutsSeg := headerData(23 downto 16); + v.rxParam.maxSegSize := headerData(15 downto 0); + + -- Check for early EOF + if (tspMaster_i.tLast = '1') then + -- Set the flag + v.segDrop := '1'; + else + -- Next State + v.tspState := SYN_WAIT0_S; + end if; + + else + -- Set the flag + v.rxF.data := not(tspMaster_i.tLast); + -- Next State + v.tspState := NSYN_CHECK_S; + end if; + + end if; + + end if; + ---------------------------------------------------------------------- + when SYN_WAIT0_S => + -- Check for data + if (tspMaster_i.tValid = '1') then + + -- Accept the data + v.tspSlave.tReady := '1'; + + -- Calculate the checksum + GetRssiCsum( + -- Input + '0', -- init + headerData, -- header + r.csumAccum, -- accumReg + -- Results + v.csumAccum, -- accumVar + v.chksumOk, -- chksumOk + v.checksum); -- checksum + + -- Syn parameters + v.rxParam.retransTout := headerData(63 downto 48); + v.rxParam.cumulAckTout := headerData(47 downto 32); + v.rxParam.nullSegTout := headerData(31 downto 16); + v.rxParam.maxRetrans := headerData(15 downto 8); + v.rxParam.maxCumAck := headerData(7 downto 0); + + -- Check for early EOF + if (tspMaster_i.tLast = '1') then + -- Set the flag + v.segDrop := '1'; + -- Next State + v.tspState := IDLE_S; + else + -- Next State + v.tspState := SYN_WAIT1_S; + end if; + + end if; + + ---------------------------------------------------------------------- + when SYN_WAIT1_S => + -- Check for data + if (tspMaster_i.tValid = '1') then + + -- Accept the data + v.tspSlave.tReady := '1'; + + -- Calculate the checksum + GetRssiCsum( + -- Input + '0', -- init + headerData, -- header + r.csumAccum, -- accumReg + -- Results + v.csumAccum, -- accumVar + v.chksumOk, -- chksumOk + v.checksum); -- checksum + + -- Syn parameters + v.rxParam.maxOutofseq := headerData(63 downto 56); + v.rxParam.timeoutUnit := headerData(55 downto 48); + v.rxParam.connectionId(31 downto 0) := headerData(47 downto 16); + + -- Check for no EOF + if (tspMaster_i.tLast = '0') then + -- Set the flag + v.segDrop := '1'; + -- Next State + v.tspState := IDLE_S; + else + -- Next State + v.tspState := SYN_CHECK_S; + end if; + + end if; + ---------------------------------------------------------------------- + when SYN_CHECK_S => + + -- Last cycle of pipeline + v.chksumRdy := '1'; + GetRssiCsum( + -- Input + '0', -- init + (others => '0'), -- header + r.csumAccum, -- accumReg + -- Results + v.csumAccum, -- accumVar + v.chksumOk, -- chksumOk + v.checksum); -- checksum + + if (r.chksumRdy = '1') then + + -- Check the header + if ((HEADER_CHKSUM_EN_G = false) or (r.chksumOk = '1')) and (r.rxHeadLen = toSlv(24, 8)) then + -- Next State + v.tspState := VALID_S; + else + + -- Set the flag + v.segDrop := '1'; + + -- Next State + v.tspState := IDLE_S; + + end if; + + end if; + ---------------------------------------------------------------------- + when NSYN_CHECK_S => + -- Last cycle of pipeline + v.chksumRdy := '1'; + GetRssiCsum( + -- Input + '0', -- init + (others => '0'), -- header + r.csumAccum, -- accumReg + -- Results + v.csumAccum, -- accumVar + v.chksumOk, -- chksumOk + v.checksum); -- checksum + + if (r.chksumRdy = '1') then + + -- Check the header + if ( + ((HEADER_CHKSUM_EN_G = false) or (r.chksumOk = '1')) and + -- Check length + r.rxHeadLen = toSlv(8, 8) and + -- Check SeqN range + (r.rxSeqN - r.inOrderSeqN) <= 1 and + -- Check AckN range + (r.rxAckN - lastAckN_i) <= txWindowSize_i + ) then + + -- Valid data segment + if (r.rxF.data = '1' and v.rxF.nul = '0' and v.rxF.rst = '0') then + + -- Wait if the buffer full + -- Note: Deadlock possibility! If the peer is not accepting data! + if (r.windowArray(rxBufIdx).occupied = '0') then + -- Start the DMA write transaction + v.wrReq.request := '1'; + -- Next State + v.tspState := DATA_S; + + -- Buffer is full -> drop segment + else + -- Set the flag + v.segDrop := '1'; + -- Next State + v.tspState := IDLE_S; + end if; + + -- Valid non data segment + elsif (r.rxF.data = '0') then + -- Next State + v.tspState := VALID_S; + + -- Undefined condition + else + -- Set the flag + v.segDrop := '1'; + -- Next State + v.tspState := IDLE_S; + end if; + + -- Else failed header checking + else + -- Set the flag + v.segDrop := '1'; + -- Next State + v.tspState := IDLE_S; + end if; + + end if; + ---------------------------------------------------------------------- + when DATA_S => + -- Latch the segment size + v.windowArray(rxBufIdx).segSize := conv_integer(wrAck.size); + + -- Check if DMA write completed + if (wrAck.done = '1') then + + -- Reset the flag + v.wrReq.request := '0'; + + -- Check for error + if (wrAck.writeError = '1') or (wrAck.overflow = '1') then + -- Set the flag + v.segDrop := '1'; + -- Next State + v.tspState := IDLE_S; + else + -- Next State + v.tspState := VALID_S; + end if; + + end if; + ---------------------------------------------------------------------- + when VALID_S => + -- Set the flag + v.segValid := '1'; + + -- Initialize when valid SYN segment received + -- 1. Set the initial SeqN + -- 2. Initialize the buffer address + -- 3. Initialize window + if (connActive_i = '0') and (r.rxF.syn = '1') then + + -- Initialize for FSM internal signals + v.rxF.ack := r.rxF.ack; + v.inOrderSeqN := r.rxSeqN; + v.rxBufferAddr := (others => '0'); + v.windowArray := REG_INIT_C.windowArray; + v.pending := (others => '0'); + + -- Check if next valid SEQn is received. If yes: + -- 1. increment the in order SEQn + -- 2. save seqN, type, and occupied to the current buffer address + -- 3. increase buffer + elsif ((r.rxF.data = '1' or r.rxF.nul = '1' or r.rxF.rst = '1') and + -- Next seqN absolute difference is one + r.rxSeqN - r.inOrderSeqN = 1 + ) then + + -- Fill in the window array buffer + v.windowArray(rxBufIdx).seqN := r.rxSeqN; + v.windowArray(rxBufIdx).segType(0) := r.rxF.data; + v.windowArray(rxBufIdx).segType(1) := r.rxF.nul; + v.windowArray(rxBufIdx).segType(2) := r.rxF.rst; + v.windowArray(rxBufIdx).occupied := '1'; + + -- Update the in-order sequence index + v.inOrderSeqN := r.rxSeqN; + + -- Increment the RX buffer index + if r.rxBufferAddr < (rxWindowSize_i-1) then + v.rxBufferAddr := r.rxBufferAddr +1; + else + v.rxBufferAddr := (others => '0'); + end if; + + -- Increment the pending counter + if v.pending < rxWindowSize_i then + v.pending := v.pending + 1; + end if; + + end if; + + -- Next State + v.tspState := IDLE_S; + ---------------------------------------------------------------------- + end case; + + -- Calculate the next DMA read transaction + txBufIdx := conv_integer(r.txBufferAddr); + v.rdReq.address := axiOffset_i + toSlv((txBufIdx*maxSegSize), 64); + v.rdReq.size := toSlv(r.windowArray(txBufIdx).segSize, 32); + v.rdReq.firstUser(SSI_SOF_C) := '1'; -- SOF + + ---------------------------------------------------------------------------- + -- TX Application side FSM: + -- Transmit the segments in correct order + -- Check the buffer if the next slot is available and send the buffer to APP + ---------------------------------------------------------------------------- + case r.appState is + ---------------------------------------------------------------------- + when IDLE_S => + -- Check if not connected + if (connActive_i = '0') then + -- Reset the index pointers + v.txBufferAddr := (others => '0'); + v.rxLastSeqN := r.inOrderSeqN; + + -- Check for occupied buffer + elsif (r.windowArray(txBufIdx).occupied = '1') then + + -- Check for a data segment + if (r.windowArray(txBufIdx).segType(0) = '1') then + + -- Check if ready to move data + if (rdAck.idle = '1') then + -- Start the DMA read transaction + v.rdReq.request := '1'; + + -- Next State + v.appState := DATA_S; + end if; + + else + -- Next State + v.appState := SENT_S; + end if; + + end if; + ---------------------------------------------------------------------- + when DATA_S => + -- Check if DMA write completed + if (rdAck.done = '1') then + + -- Reset the flag + v.rdReq.request := '0'; + + -- Next State + v.appState := SENT_S; + + end if; + ---------------------------------------------------------------------- + when SENT_S => + -- Register the sent SeqN (this means that the place has been freed and the SeqN can be Acked) + v.rxLastSeqN := r.windowArray(txBufIdx).seqN; + + -- Release buffer + v.windowArray(txBufIdx).occupied := '0'; + + -- Increment the TX buffer index + if r.txBufferAddr < (rxWindowSize_i-1) then + v.txBufferAddr := r.txBufferAddr+1; -- Increment once + else + v.txBufferAddr := (others => '0'); + end if; + + -- Decrement the pending counter + if v.pending /= 0 then + v.pending := v.pending - 1; + end if; + + -- Next State + v.appState := IDLE_S; + ---------------------------------------------------------------------- + end case; + + v.simErrorDet := (r.segDrop or wrAck.overflow or wrAck.writeError or rdAck.readError); + -- if r.simErrorDet = '1' then + -- assert false + -- report "Simulation Failed!" severity failure; + -- end if; + + ---------------------------------------------------------------------- + -- Outputs -- + ---------------------------------------------------------------------- + + -- Inbound Transport Interface + wrDmaMaster <= tspMaster_i; + wrDmaMaster.tValid <= tspMaster_i.tValid and r.wrReq.request; + tspSlave_o.tReady <= v.tspSlave.tReady or wrDmaSlave.tReady; + + -- RX Buffer Full + if (r.pending > 1) then + rxBuffBusy_o <= '1'; + else + rxBuffBusy_o <= '0'; + end if; + + -- Current received seqN + rxSeqN_o <= r.rxSeqN; + + -- Current received ackN + rxAckN_o <= r.rxAckN; + + -- Last seqN received and sent to application (this is the ackN transmitted) + rxLastSeqN_o <= r.rxLastSeqN; + + -- Valid Segment received (1 c-c) + rxValidSeg_o <= r.segValid; + + -- Segment dropped (1 c-c) + rxDropSeg_o <= r.segDrop; + + -- Last segment received flags (active until next segment is received) + rxFlags_o <= r.rxF; + + -- Parameters received from peer SYN packet + rxParam_o <= r.rxParam; + + -- Reset + if (rst_i = '1') then + v := REG_INIT_C; + end if; + + -- Register the variable for next clock cycle + rin <= v; + + end process comb; + + seq : process (clk_i) is + begin + if (rising_edge(clk_i)) then + r <= rin after TPD_G; + end if; + end process seq; + +end architecture rtl; diff --git a/protocols/rssi/v1b/rtl/AxiRssiTxFsm.vhd b/protocols/rssi/v1b/rtl/AxiRssiTxFsm.vhd new file mode 100644 index 0000000000..cf289e1366 --- /dev/null +++ b/protocols/rssi/v1b/rtl/AxiRssiTxFsm.vhd @@ -0,0 +1,1160 @@ +------------------------------------------------------------------------------- +-- File : AxiRssiTxFsm.vhd +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: Transmitter FSM +-- Transmitter has the following functionality: +-- Handle buffer addresses and buffer window (firstUnackAddr,nextSentAddr,lastSentAddr, bufferFull, bufferEmpty) +-- Application side FSM. Receive SSI frame and store into TX data buffer. +-- - IDLE Waits until buffer window is free (not bufferFull), +-- - Waits for Application side SOF, +-- - Save the segment to Rx buffer at nextSentAddr. Disable sending of NULL segments with appBusy flag, +-- - When EOF received save segment length and keep flags. Check length error, +-- - Request data send at Transport side FSM and increment nextSentAddr +-- - Wait until the data is processed and data segment sent by Transport side FSM +-- - Release appBusy flag and go back to INIT. +-- Acknowledgment FSM. +-- - IDLE Waits for ack_i (ack request) and ackN_i(ack number)(from RxFSM), +-- - Increments firstUnackAddr until the ackN_i is found in Window buffer, +-- - If it does not find the SEQ number it reports Ack Error, +-- - Goes back to IDLE. +-- Transport side FSM. Send and resend various segments to Transport side. +-- - INIT Initializes seqN to initSeqN. Waits until new connection requested. ConnFSM goin out od Closed state. +-- - DISS_CONN allows sending SYN, ACK, or RST segments. Goes to CONN when connection becomes active. +-- - CONN allows sending DATA, NULL, ACK, or RST segments. +-- In Resend procedure the FSM resends all the unacknowledged (DATA, NULL, RST) segments in the buffer window. +-- +-- Note:Sequence number is incremented with sending SYN, DATA, NULL, and RST segments. +-- Note:Only the following segments are saved into Tx buffer DATA, NULL, and RST. +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; + +use work.StdRtlPkg.all; +use work.AxiStreamPkg.all; +use work.AxiPkg.all; +use work.AxiDmaPkg.all; +use work.AxiRssiPkg.all; +use work.RssiPkg.all; +use work.SsiPkg.all; + +entity AxiRssiTxFsm is + generic ( + TPD_G : time := 1 ns; + AXI_CONFIG_G : AxiConfigType := RSSI_AXI_CONFIG_C; + BURST_BYTES_G : positive := 1024; + WINDOW_ADDR_SIZE_G : positive := 3; -- 2^WINDOW_ADDR_SIZE_G = Number of segments + SEGMENT_ADDR_SIZE_G : positive := 7; -- 2^SEGMENT_ADDR_SIZE_G = Number of 64 bit wide data words + HEADER_CHKSUM_EN_G : boolean := true); + port ( + clk_i : in sl; + rst_i : in sl; + -- AXI Segment Buffer Interface + axiOffset_i : in slv(63 downto 0); + mAxiWriteMaster_o : out AxiWriteMasterType; + mAxiWriteSlave_i : in AxiWriteSlaveType; + mAxiReadMaster_o : out AxiReadMasterType; + mAxiReadSlave_i : in AxiReadSlaveType; + -- Inbound Application Interface + appMaster_i : in AxiStreamMasterType; + appSlave_o : out AxiStreamSlaveType; + -- Outbound Transport Interface + tspMaster_o : out AxiStreamMasterType; + tspSlave_i : in AxiStreamSlaveType; + -- Connection FSM indicating active connection + connActive_i : in sl; + -- Closed state in connFSM (initialize seqN) + closed_i : in sl; + -- Fault injection corrupts header checksum + injectFault_i : in sl; + -- Various segment requests + sndSyn_i : in sl; + sndAck_i : in sl; + sndRst_i : in sl; + sndResend_i : in sl; + sndNull_i : in sl; + -- Window buff size (Depends on the number of outstanding segments) + windowSize_i : in integer range 1 to 2 ** (WINDOW_ADDR_SIZE_G); + bufferSize_i : in integer range 1 to 2 ** (SEGMENT_ADDR_SIZE_G); + -- Header read + rdHeaderAddr_o : out slv(7 downto 0); + rdHeaderData_i : in slv(RSSI_WORD_WIDTH_C*8-1 downto 0); + -- Initial sequence number + initSeqN_i : in slv(7 downto 0); + -- Tx data (input to header decoder module) + txSeqN_o : out slv(7 downto 0); + -- FSM outs for header and data flow control + synHeadSt_o : out sl; + ackHeadSt_o : out sl; + dataHeadSt_o : out sl; + dataSt_o : out sl; + rstHeadSt_o : out sl; + nullHeadSt_o : out sl; + -- Last acked number (Used in Rx FSM to determine if AcnN is valid) + lastAckN_o : out slv(7 downto 0); + -- Acknowledge mechanism + ack_i : in sl; -- From receiver module when a segment with valid ACK is received + ackN_i : in slv(7 downto 0); -- Number being ACKed + --eack_i : in sl; -- From receiver module when a segment with valid EACK is received + --eackSeqnArr_i : in Slv8Array(0 to MAX_RX_NUM_OUTS_SEG_G-1); -- Array of sequence numbers received out of order + -- Errors (1 cc pulse) + lenErr_o : out sl; + ackErr_o : out sl; + -- Segment buffer indicator + bufferEmpty_o : out sl); +end entity AxiRssiTxFsm; + +architecture rtl of AxiRssiTxFsm is + + type TspStateType is ( + -- + INIT_S, + DISS_CONN_S, + CONN_S, + -- + SYN_H_S, + SYN_XSUM_S, + NSYN_H_S, + NSYN_XSUM_S, + DATA_H_S, + DATA_XSUM_S, + DATA_S, + -- + RESEND_INIT_S, + RESEND_H_S, + RESEND_XSUM_S, + RESEND_PP_S); + + type AppStateType is ( + IDLE_S, + WAIT_SOF_S, + DATA_S, + SEG_RDY_S); + + type AckStateType is ( + IDLE_S, + ERR_S, + -- EACK_S, + ACK_S); + + type RegType is record + ---------------------------------------------------- + -- Buffer window handling and acknowledgment control + ---------------------------------------------------- + windowArray : WindowTypeArray(0 to 2 ** WINDOW_ADDR_SIZE_G-1); + firstUnackAddr : slv(WINDOW_ADDR_SIZE_G-1 downto 0); + nextSentAddr : slv(WINDOW_ADDR_SIZE_G-1 downto 0); + lastSentAddr : slv(WINDOW_ADDR_SIZE_G-1 downto 0); + lastAckSeqN : slv(7 downto 0); + --eackAddr : slv(WINDOW_ADDR_SIZE_G-1 downto 0); + --eackIndex : integer; + bufferFull : sl; + bufferEmpty : sl; + ackErr : sl; + -- State Machine + ackState : AckStateType; + ----------------------- + -- Application side FSM + ----------------------- + wrReq : AxiWriteDmaReqType; + rxBufferAddr : slv(WINDOW_ADDR_SIZE_G-1 downto 0); + rxSegmentWe : sl; + sndData : sl; + lenErr : sl; + appBusy : sl; + appSlave : AxiStreamSlaveType; + appState : AppStateType; + --------------------- + -- Transport side FSM + --------------------- + rdReq : AxiReadDmaReqType; + -- Checksum Calculation + csumAccum : slv(20 downto 0); + chksumOk : sl; + checksum : slv(15 downto 0); + -- Counters + nextSeqN : slv(7 downto 0); + seqN : slv(7 downto 0); + txHeaderAddr : slv(7 downto 0); + txBufferAddr : slv(WINDOW_ADDR_SIZE_G-1 downto 0); + -- Data mux flags + synH : sl; + ackH : sl; + rstH : sl; + nullH : sl; + dataH : sl; + dataD : sl; + resend : sl; + ackSndData : sl; + hdrAmrmed : sl; + simErrorDet : sl; + -- Various controls + buffWe : sl; + buffSent : sl; + -- Fault injection + injectFaultD1 : sl; + injectFaultReg : sl; + -- Transport Interface + rdDmaSlave : AxiStreamSlaveType; + tspMaster : AxiStreamMasterType; + -- State Machine + tspState : tspStateType; + end record RegType; + + constant REG_INIT_C : RegType := ( + ---------------------------------------------------- + -- Buffer window handling and acknowledgment control + ---------------------------------------------------- + -- Window control + firstUnackAddr => (others => '0'), + lastSentAddr => (others => '0'), + nextSentAddr => (others => '0'), + lastAckSeqN => (others => '0'), + --eackAddr => (others => '0'), + --eackIndex => 0, + bufferFull => '0', + bufferEmpty => '1', + windowArray => (0 to 2 ** WINDOW_ADDR_SIZE_G-1 => WINDOW_INIT_C), + ackErr => '0', + ackState => IDLE_S, + ----------------------- + -- Application side FSM + ----------------------- + wrReq => AXI_WRITE_DMA_REQ_INIT_C, + rxSegmentWe => '0', + rxBufferAddr => (others => '0'), + sndData => '0', + lenErr => '0', + appBusy => '0', + appSlave => AXI_STREAM_SLAVE_INIT_C, + appState => IDLE_S, + ---------------------- + -- Transport side FSM + ---------------------- + rdReq => AXI_READ_DMA_REQ_INIT_C, + -- + csumAccum => (others => '0'), + chksumOk => '0', + checksum => (others => '0'), + -- + nextSeqN => (others => '0'), + seqN => (others => '0'), + txHeaderAddr => (others => '0'), + txBufferAddr => (others => '0'), + -- + synH => '0', + ackH => '0', + rstH => '0', + nullH => '0', + dataH => '0', + dataD => '0', + resend => '0', + ackSndData => '0', + hdrAmrmed => '0', + simErrorDet => '0', + -- + buffWe => '0', + buffSent => '0', + -- Fault injection + injectFaultD1 => '0', + injectFaultReg => '0', + -- Transport Interface + rdDmaSlave => AXI_STREAM_SLAVE_INIT_C, + tspMaster => AXI_STREAM_MASTER_INIT_C, + -- State Machine + tspState => INIT_S); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; + + signal wrAck : AxiWriteDmaAckType; + signal rdAck : AxiReadDmaAckType; + + signal wrDmaMaster : AxiStreamMasterType; + signal wrDmaSlave : AxiStreamSlaveType; + + signal rdDmaMaster : AxiStreamMasterType; + signal rdDmaSlave : AxiStreamSlaveType; + + -- attribute dont_touch : string; + -- attribute dont_touch of r : signal is "TRUE"; + +begin + + U_DmaWrite : entity work.AxiStreamDmaWrite + generic map ( + TPD_G => TPD_G, + AXI_READY_EN_G => true, + AXIS_CONFIG_G => RSSI_AXIS_CONFIG_C, + AXI_CONFIG_G => AXI_CONFIG_G, + BURST_BYTES_G => BURST_BYTES_G, + AXI_BURST_G => "01", -- INCR + AXI_CACHE_G => "0011", -- Cacheable + SW_CACHE_EN_G => false, + ACK_WAIT_BVALID_G => true, + PIPE_STAGES_G => 0, + BYP_SHIFT_G => true, + BYP_CACHE_G => true) + port map ( + -- Clock/Reset + axiClk => clk_i, + axiRst => rst_i, + -- DMA Control Interface + dmaReq => r.wrReq, + dmaAck => wrAck, + -- Streaming Interface + axisMaster => wrDmaMaster, + axisSlave => wrDmaSlave, + -- AXI Interface + axiWriteMaster => mAxiWriteMaster_o, + axiWriteSlave => mAxiWriteSlave_i); + + U_DmaRead : entity work.AxiStreamDmaRead + generic map ( + TPD_G => TPD_G, + AXIS_READY_EN_G => true, + AXIS_CONFIG_G => RSSI_AXIS_CONFIG_C, + AXI_CONFIG_G => AXI_CONFIG_G, + AXI_BURST_G => "01", -- INCR + AXI_CACHE_G => "0011", -- Cacheable + SW_CACHE_EN_G => false, + PIPE_STAGES_G => 0, + PEND_THRESH_G => 0, -- In units of bytes + BYP_SHIFT_G => true) + port map ( + -- Clock/Reset + axiClk => clk_i, + axiRst => rst_i, + -- DMA Control Interface + dmaReq => r.rdReq, + dmaAck => rdAck, + -- Streaming Interface + axisMaster => rdDmaMaster, + axisSlave => rdDmaSlave, + axisCtrl => AXI_STREAM_CTRL_UNUSED_C, + -- AXI Interface + axiReadMaster => mAxiReadMaster_o, + axiReadSlave => mAxiReadSlave_i); + + + ----------------------------------------------------------------------------------------------- + comb : process (ackN_i, ack_i, appMaster_i, axiOffset_i, bufferSize_i, + closed_i, connActive_i, initSeqN_i, injectFault_i, r, rdAck, + rdDmaMaster, rdHeaderData_i, rst_i, sndAck_i, sndNull_i, + sndResend_i, sndRst_i, sndSyn_i, tspSlave_i, windowSize_i, + wrAck, wrDmaSlave) is + + variable v : RegType; + variable maxSegSize : natural; + variable rxBufIdx : natural; + variable txBufIdx : natural; + begin + -- Latch the current value + v := r; + + -- Convert to bytes + maxSegSize := 8*bufferSize_i; + + -- Reset strobes + v.appSlave := AXI_STREAM_SLAVE_INIT_C; + v.ackSndData := '0'; + v.sndData := '0'; + v.lenErr := '0'; + + -- ///////////////////////////////////////////////////////// + ------------------------------------------------------------ + -- Buffer window handling + ------------------------------------------------------------ + -- ///////////////////////////////////////////////////////// + + ------------------------------------------------------------ + -- Buffer full if next slot is occupied + if (r.windowArray(conv_integer(v.rxBufferAddr)).occupied = '1') then + v.bufferFull := '1'; + else + v.bufferFull := '0'; + end if; + + ------------------------------------------------------------ + -- Buffer empty if next unacknowledged slot is unoccupied + if (r.windowArray(conv_integer(r.firstUnackAddr)).occupied = '0') then + v.bufferEmpty := '1'; + else + v.bufferEmpty := '0'; + end if; + + ------------------------------------------------------------ + -- Write seqN and segment type to window array + ------------------------------------------------------------ + if (r.buffWe = '1') then + v.windowArray(conv_integer(r.nextSentAddr)).seqN := r.nextSeqN; + v.windowArray(conv_integer(r.nextSentAddr)).segType := r.rstH & r.nullH & r.dataH; + v.windowArray(conv_integer(r.nextSentAddr)).occupied := '1'; + + -- Update last sent address when new segment is being sent + v.lastSentAddr := r.nextSentAddr; + else + v.windowArray := r.windowArray; + end if; + + ------------------------------------------------------------ + -- When buffer is sent increase nextSentAddr + ------------------------------------------------------------ + if (r.buffSent = '1') then + + if r.nextSentAddr < (windowSize_i-1) then + v.nextSentAddr := r.nextSentAddr +1; + else + v.nextSentAddr := (others => '0'); + end if; + + else + v.nextSentAddr := r.nextSentAddr; + end if; + + -- ///////////////////////////////////////////////////////// + ------------------------------------------------------------ + -- ACK FSM + -- Acknowledgment mechanism to increment firstUnackAddr + -- Place out of order flags from EACK table (Not in Version 1) + ------------------------------------------------------------ + -- ///////////////////////////////////////////////////////// + + case r.ackState is + ---------------------------------------------------------------------- + when IDLE_S => + + -- Hold ACK address + v.firstUnackAddr := r.firstUnackAddr; + v.lastAckSeqN := r.lastAckSeqN; + --v.eackAddr := r.firstUnackAddr; + --v.eackIndex := 0; + v.ackErr := '0'; + + -- Next state condition + if (ack_i = '1') then + v.ackState := ACK_S; + end if; + ---------------------------------------------------------------------- + when ACK_S => + + -- If the same ackN received do nothing + if (r.lastAckSeqN = ackN_i) then + v.firstUnackAddr := r.firstUnackAddr; + -- Increment ACK address until seqN is found next received + elsif r.firstUnackAddr < (windowSize_i-1) then + v.windowArray(conv_integer(r.firstUnackAddr)).occupied := '0'; + v.firstUnackAddr := r.firstUnackAddr+1; + else + v.windowArray(conv_integer(r.firstUnackAddr)).occupied := '0'; + v.firstUnackAddr := (others => '0'); + end if; + + --v.eackAddr := r.firstUnackAddr; + -- v.eackIndex := 0; + v.ackErr := '0'; + + -- Next state condition + + -- If the same ackN received + if (r.lastAckSeqN = ackN_i) then + + -- Go back to IDLE + v.ackState := IDLE_S; + + elsif (r.firstUnackAddr = r.lastSentAddr and r.windowArray(conv_integer(r.firstUnackAddr)).seqN /= ackN_i) then + -- If the acked seqN is not found go to error state + v.ackState := ERR_S; + elsif (r.windowArray(conv_integer(r.firstUnackAddr)).seqN = ackN_i) then + v.lastAckSeqN := ackN_i; -- Save the last Acked seqN + --if eack_i = '1' then + -- Go back to init when the acked seqN is found + -- v.ackState := EACK_S; + --else + -- Go back to init when the acked seqN is found + v.ackState := IDLE_S; + --end if; + end if; + ---------------------------------------------------------------------- + -- when EACK_S => + + -- -- Increment EACK address from firstUnackAddr to nextSentAddr + -- if r.eackAddr < (windowSize_i-1) then + -- v.eackAddr := r.eackAddr+1; + -- else + -- v.eackAddr := (others => '0'); + -- end if; + + -- -- For every address check if the sequence number equals value from eackSeqnArr_i array. + -- -- If it matches mark the eack field at the address and compare the next value from the table. + -- if r.windowArray(conv_integer(r.eackAddr)).seqN = eackSeqnArr_i(r.eackIndex) then + -- v.windowArray(conv_integer(r.eackAddr)).eacked := '1'; + -- v.eackIndex := r.eackIndex + 1; + -- end if; + + -- v.firstUnackAddr := r.firstUnackAddr; + -- v.ackErr := '0'; + + -- -- Next state condition + -- if (r.eackAddr = r.nextSentAddr) then + -- -- If the acked seqN is not found go to error state + -- v.ackState := IDLE_S; + -- end if; + ---------------------------------------------------------------------- + when ERR_S => + -- Outputs + v.firstUnackAddr := r.firstUnackAddr; + --v.eackAddr := r.firstUnackAddr; + --v.eackIndex := 0; + v.ackErr := '1'; + + -- Next state condition + v.ackState := IDLE_S; + ---------------------------------------------------------------------- + end case; + + -- ///////////////////////////////////////////////////////// + ------------------------------------------------------------ + -- Application side FSM + ------------------------------------------------------------ + -- ///////////////////////////////////////////////////////// + + -- Calculate the next DMA write transaction + rxBufIdx := conv_integer(r.rxBufferAddr); + v.wrReq.address := axiOffset_i + toSlv((rxBufIdx*maxSegSize), 64); + v.wrReq.maxSize := toSlv(maxSegSize, 32); + + ------------------------------------------------------------ + case r.appState is + ---------------------------------------------------------------------- + when IDLE_S => + -- Set the flag + v.appBusy := '1'; + -- Check if buffer if not full + if (v.bufferFull = '0') then + -- Next state + v.appState := WAIT_SOF_S; + end if; + ---------------------------------------------------------------------- + when WAIT_SOF_S => + -- Set the flag + v.appBusy := '0'; + -- If other segment (NULL, or RST) is requested return to IDLE_S to + -- check if buffer is still available (not full) + if (r.buffWe = '1') then + -- Increment the buffer window address because a NULL segment has filled the current spot + if r.rxBufferAddr < (windowSize_i-1) then + v.rxBufferAddr := r.rxBufferAddr+1; + else + v.rxBufferAddr := (others => '0'); + end if; + -- Set the flag + v.appBusy := '1'; + -- Next state + v.appState := IDLE_S; + -- Check for data + elsif (appMaster_i.tValid = '1') then + -- Check if SOF + if (ssiGetUserSof(RSSI_AXIS_CONFIG_C, appMaster_i) = '1') then + -- Set the flag + v.appBusy := '1'; + -- Start the DMA write transaction + v.wrReq.request := '1'; + -- Next State + v.appState := DATA_S; + else + -- Blow off the data + v.appSlave.tReady := '1'; + end if; + end if; + ---------------------------------------------------------------------- + when DATA_S => + -- Latch the segment size + v.windowArray(rxBufIdx).segSize := conv_integer(wrAck.size); + -- Check if DMA write completed + if (wrAck.done = '1') then + -- Reset the flag + v.wrReq.request := '0'; + -- Check for error + if (wrAck.writeError = '1') or (wrAck.overflow = '1') then + -- Set the flag + v.lenErr := '1'; + -- Next state + v.appState := IDLE_S; + else + -- Next state + v.appState := SEG_RDY_S; + end if; + end if; + ---------------------------------------------------------------------- + when SEG_RDY_S => + -- Request data transfer + v.sndData := '1'; + -- Hold request until accepted and not in resend process + if (r.ackSndData = '1') and (v.resend = '0') then + -- Increment the rxBuffer + if r.rxBufferAddr < (windowSize_i-1) then + v.rxBufferAddr := r.rxBufferAddr+1; + else + v.rxBufferAddr := (others => '0'); + end if; + -- Next state + v.appState := IDLE_S; + end if; + ---------------------------------------------------------------------- + end case; + + + -- ///////////////////////////////////////////////////////// + ------------------------------------------------------------ + -- Initialization of the parameters when the connection is broken + if (connActive_i = '0') then + v.firstUnackAddr := REG_INIT_C.firstUnackAddr; + v.lastSentAddr := REG_INIT_C.lastSentAddr; + v.nextSentAddr := REG_INIT_C.nextSentAddr; + v.rxBufferAddr := REG_INIT_C.rxBufferAddr; + v.bufferFull := REG_INIT_C.bufferFull; + v.bufferEmpty := REG_INIT_C.bufferEmpty; + v.windowArray := REG_INIT_C.windowArray; + v.lastAckSeqN := initSeqN_i; + v.ackState := REG_INIT_C.ackState; + v.appState := REG_INIT_C.appState; + end if; + ------------------------------------------------------------ + -- ///////////////////////////////////////////////////////// + + -- ///////////////////////////////////////////////////////// + ------------------------------------------------------------ + -- Arm fault injection on rising edge of injectFault_i + ------------------------------------------------------------ + -- /// ////////////////////////////////////////////////////// + v.injectFaultD1 := injectFault_i; + + if (injectFault_i = '1' and r.injectFaultD1 = '0') then + v.injectFaultReg := '1'; + else + v.injectFaultReg := r.injectFaultReg; + end if; + + + -- ///////////////////////////////////////////////////////// + ------------------------------------------------------------ + -- Transport side FSM + ------------------------------------------------------------ + -- ///////////////////////////////////////////////////////// + + -- Reset strobes + v.buffWe := '0'; + v.buffSent := '0'; + v.rdDmaSlave := AXI_STREAM_SLAVE_INIT_C; + if (tspSlave_i.tReady = '1') then + v.tspMaster.tValid := '0'; + v.tspMaster.tLast := '0'; + v.tspMaster.tUser := (others => '0'); + v.tspMaster.tKeep := (others => '1'); + end if; + + -- Calculate the next DMA read transaction + txBufIdx := conv_integer(r.txBufferAddr); + v.rdReq.address := axiOffset_i + toSlv((txBufIdx*maxSegSize), 64); + v.rdReq.size := toSlv(r.windowArray(txBufIdx).segSize, 32); + + -- Update the pipeline + GetRssiCsum( + -- Input + '0', -- init + (others => '0'), -- header + r.csumAccum, -- accumReg + -- Results + v.csumAccum, -- accumVar + v.chksumOk, -- chksumOk + v.checksum); -- checksum + + + case r.tspState is + ---------------------------------------------------------------------- + when INIT_S => + -- Initialize all + v := REG_INIT_C; + -- Register initial sequence number + v.nextSeqN := initSeqN_i; + v.seqN := r.nextSeqN; + -- Next state condition + if (closed_i = '0') then + -- Next state + v.tspState := DISS_CONN_S; + end if; + ---------------------------------------------------------------------- + when DISS_CONN_S => + -- Update the sequence indexes + v.nextSeqN := r.nextSeqN; + v.seqN := r.nextSeqN; + -- Update TX buffer address + v.txBufferAddr := r.nextSentAddr; + -- Reset RSSI flags + v.synH := '0'; + v.ackH := '0'; + v.rstH := '0'; + v.nullH := '0'; + v.dataH := '0'; + v.dataD := '0'; + v.resend := '0'; + v.hdrAmrmed := '0'; + -- Check for SYN + if (sndSyn_i = '1') then + -- Set the flag + v.synH := '1'; + -- Next state + v.tspState := SYN_H_S; + -- Check for ACK + elsif (sndAck_i = '1') then + -- Set the flag + v.ackH := '1'; + -- Next state + v.tspState := NSYN_H_S; + -- Check for RST + elsif (sndRst_i = '1') then + -- Set the flag + v.rstH := '1'; + -- Next state + v.tspState := NSYN_H_S; + -- Check for link up + elsif (connActive_i = '1') then + -- Next state + v.tspState := CONN_S; + -- Check for link down + elsif (closed_i = '1') then + -- Next state + v.tspState := INIT_S; + end if; + ---------------------------------------------------------------------- + when CONN_S => + -- Update TX buffer address + v.txBufferAddr := r.nextSentAddr; + -- Reset RSSI flags + v.synH := '0'; + v.ackH := '0'; + v.rstH := '0'; + v.nullH := '0'; + v.dataH := '0'; + v.dataD := '0'; + v.resend := '0'; + v.hdrAmrmed := '0'; + -- Check for RST + if (sndRst_i = '1') then + -- Set the flags + v.rstH := '1'; + -- Next state + v.tspState := NSYN_H_S; + -- Check for DATA + elsif (r.sndData = '1') and (r.bufferFull = '0') then + -- Set the flags + v.ackSndData := '1'; + v.dataH := '1'; + v.buffWe := '1'; -- Update buffer seqN and Type + -- Start the DMA read transaction + v.rdReq.request := '1'; + -- Next state + v.tspState := DATA_H_S; + -- Check for RESEND + elsif (sndResend_i = '1') and (r.bufferEmpty = '0') then + -- Next state + v.tspState := RESEND_INIT_S; + -- Check for ACK + elsif (sndAck_i = '1') then + -- Set the flag + v.ackH := '1'; + -- Next state + v.tspState := NSYN_H_S; + -- Check for NULL + elsif (sndNull_i = '1') and (r.bufferFull = '0') and (r.appBusy = '0') then + -- Set flags + v.nullH := '1'; + v.buffWe := '1'; -- Update buffer seqN and Type + -- Next state + v.tspState := NSYN_H_S; + -- Check for link down + elsif (connActive_i = '0') then + -- Next state + v.tspState := INIT_S; + end if; + ---------------------------------------------------------------------- + when SYN_H_S => + -- Set the flag + v.hdrAmrmed := '1'; + -- Check if ready to move data + if (r.tspMaster.tValid = '0') and (r.hdrAmrmed = '1') then -- Using registered value to help relax timing + -- Move the data + v.tspMaster.tValid := '1'; + v.tspMaster.tData(63 downto 0) := endianSwap64(rdHeaderData_i); + -- Increment the counter + v.txHeaderAddr := r.txHeaderAddr + 1; + -- Check for SOF + if (r.txHeaderAddr = 0) then + -- Set the SOF flag + ssiSetUserSof(RSSI_AXIS_CONFIG_C, v.tspMaster, '1'); + -- Calculate the checksum + GetRssiCsum( + -- Input + '1', -- init + rdHeaderData_i, -- header + r.csumAccum, -- accumReg + -- Results + v.csumAccum, -- accumVar + v.chksumOk, -- chksumOk + v.checksum); -- checksum + elsif (r.txHeaderAddr = 1) or (r.txHeaderAddr = 2) then + -- Calculate the checksum + GetRssiCsum( + -- Input + '0', -- init + rdHeaderData_i, -- header + r.csumAccum, -- accumReg + -- Results + v.csumAccum, -- accumVar + v.chksumOk, -- chksumOk + v.checksum); -- checksum + if (r.txHeaderAddr = 2) then + -- Keep counter value + v.txHeaderAddr := r.txHeaderAddr; + -- Hold off write + v.tspMaster.tValid := '0'; + -- Reset the flag + v.hdrAmrmed := '0'; + -- Next state + v.tspState := SYN_XSUM_S; + end if; + end if; + end if; + ---------------------------------------------------------------------- + when SYN_XSUM_S => + -- Set the flag + v.hdrAmrmed := '1'; + -- Check if ready to move data (r.tspMaster.tValid already '0' from previous state) + if (r.hdrAmrmed = '1') then -- Using registered value to help relax timing + -- Reset counter + v.txHeaderAddr := (others => '0'); + -- Move the data + v.tspMaster.tValid := '1'; + -- Set EOF flag + v.tspMaster.tLast := '1'; + -- Check if header checksum enable generic set + if (HEADER_CHKSUM_EN_G) then + -- Insert the checksum + v.tspMaster.tData(63 downto 56) := r.checksum(7 downto 0); + v.tspMaster.tData(55 downto 48) := r.checksum(15 downto 8); + end if; + -- Increment SEQ number at the end of segment transmission + v.nextSeqN := r.nextSeqN+1; + v.seqN := r.nextSeqN+1; + -- Next state + v.tspState := DISS_CONN_S; + end if; + ---------------------------------------------------------------------- + when NSYN_H_S => -- RST/ACK/NULL messages + -- Set the flag + v.hdrAmrmed := '1'; + -- Check if ready to move data + if (r.tspMaster.tValid = '0') and (r.hdrAmrmed = '1') then -- Using registered value to help relax timing + -- Set the data + v.tspMaster.tData(63 downto 0) := endianSwap64(rdHeaderData_i); + -- Calculate the checksum + GetRssiCsum( + -- Input + '1', -- init + rdHeaderData_i, -- header + r.csumAccum, -- accumReg + -- Results + v.csumAccum, -- accumVar + v.chksumOk, -- chksumOk + v.checksum); -- checksum + -- Reset the flag + v.hdrAmrmed := '0'; + -- Next state + v.tspState := NSYN_XSUM_S; + end if; + ---------------------------------------------------------------------- + when NSYN_XSUM_S => + -- Set the flag + v.hdrAmrmed := '1'; + -- Check if ready to move data (r.tspMaster.tValid already '0' from previous state) + if (r.hdrAmrmed = '1') then -- Using registered value to help relax timing + -- Move the data + v.tspMaster.tValid := '1'; + -- Set the SOF flag + ssiSetUserSof(RSSI_AXIS_CONFIG_C, v.tspMaster, '1'); + -- Set EOF flag + v.tspMaster.tLast := '1'; + -- Check if header checksum enable generic set + if (HEADER_CHKSUM_EN_G) then + -- Insert the checksum + v.tspMaster.tData(63 downto 56) := r.checksum(7 downto 0); + v.tspMaster.tData(55 downto 48) := r.checksum(15 downto 8); + end if; + -- Check for RST or NULL + if (r.rstH = '1') or (r.nullH = '1') then + -- Increment seqN + v.nextSeqN := r.nextSeqN+1; -- Increment SEQ number at the end of segment transmission + v.seqN := r.nextSeqN+1; + end if; + -- Increment the sent buffer + v.buffSent := r.nullH; + -- Check if link up + if connActive_i = '0' then + -- Next state + v.tspState := DISS_CONN_S; + else + -- Next state + v.tspState := CONN_S; + end if; + end if; + ---------------------------------------------------------------------- + when DATA_H_S => + -- Set the flag + v.hdrAmrmed := '1'; + -- Check if ready to move data + if (r.tspMaster.tValid = '0') and (r.hdrAmrmed = '1') then -- Using registered value to help relax timing + -- Set the data + v.tspMaster.tData(63 downto 0) := endianSwap64(rdHeaderData_i); + -- Calculate the checksum + GetRssiCsum( + -- Input + '1', -- init + rdHeaderData_i, -- header + r.csumAccum, -- accumReg + -- Results + v.csumAccum, -- accumVar + v.chksumOk, -- chksumOk + v.checksum); -- checksum + -- Reset the flag + v.hdrAmrmed := '0'; + -- Next state + v.tspState := DATA_XSUM_S; + end if; + ---------------------------------------------------------------------- + when DATA_XSUM_S => + -- Set the flag + v.hdrAmrmed := '1'; + -- Check if ready to move data (r.tspMaster.tValid already '0' from previous state) + if (r.hdrAmrmed = '1') then -- Using registered value to help relax timing + -- Move the data + v.tspMaster.tValid := '1'; + -- Set the SOF flag + ssiSetUserSof(RSSI_AXIS_CONFIG_C, v.tspMaster, '1'); + -- Check if header checksum enable generic set + if (HEADER_CHKSUM_EN_G) then + -- Inject fault into checksum + if (r.injectFaultReg = '1') then + -- Flip bits in checksum! Point of fault injection! + v.tspMaster.tData(63 downto 56) := not(r.checksum(7 downto 0)); + v.tspMaster.tData(55 downto 48) := not(r.checksum(15 downto 8)); + else + -- Insert the checksum + v.tspMaster.tData(63 downto 56) := r.checksum(7 downto 0); + v.tspMaster.tData(55 downto 48) := r.checksum(15 downto 8); + end if; + end if; + -- Set the fault reg to 0 + v.injectFaultReg := '0'; + -- Update the flags + v.dataH := '0'; + v.dataD := '1'; -- Send data + -- Next state + v.tspState := DATA_S; + end if; + ---------------------------------------------------------------------- + when DATA_S => + -- Check if ready to move data + if (v.tspMaster.tValid = '0') and (rdDmaMaster.tValid = '1') then + -- Accept the data + v.rdDmaSlave.tReady := '1'; + -- Move the data + v.tspMaster := rdDmaMaster; + -- Check for last transfer + if (rdDmaMaster.tLast = '1') then + -- Reset the flag + v.rdReq.request := '0'; + -- Check if not resending + if (r.resend = '0') then + -- Increment SEQ number at the end of segment transmission + v.nextSeqN := r.nextSeqN+1; + v.seqN := r.nextSeqN+1; + -- Increment buffer last sent address(txBuffer) + v.buffSent := '1'; + -- Next state + v.tspState := CONN_S; + else + -- Next state + v.tspState := RESEND_PP_S; + end if; + end if; + end if; + ---------------------------------------------------------------------- + -- Resend all packets from the buffer + -- Packets between r.firstUnackAddr and r.lastSentAddr + ---------------------------------------------------------------------- + when RESEND_INIT_S => + -- Check if first segment iteration of resending + if (r.resend = '0') then + -- Start from first unack address + v.txBufferAddr := r.firstUnackAddr; + -- Update the sequence indexes + v.nextSeqN := r.nextSeqN; -- Never increment seqN while resending + v.seqN := r.windowArray(conv_integer(r.firstUnackAddr)).seqN; + end if; + -- Update the RSSI flags + v.synH := '0'; + v.ackH := '0'; + v.rstH := r.windowArray(conv_integer(r.firstUnackAddr)).segType(2); + v.nullH := r.windowArray(conv_integer(r.firstUnackAddr)).segType(1); + v.dataH := r.windowArray(conv_integer(r.firstUnackAddr)).segType(0); + v.dataD := '0'; + v.resend := '1'; + -- Reset the flag + v.hdrAmrmed := '0'; + -- Next state condition + v.tspState := RESEND_H_S; + ---------------------------------------------------------------------- + when RESEND_H_S => + -- Set the flag + v.hdrAmrmed := '1'; + -- Check if ready to move data + if (r.tspMaster.tValid = '0') and (r.hdrAmrmed = '1') then -- Using registered value to help relax timing + -- Set the data + v.tspMaster.tData(63 downto 0) := endianSwap64(rdHeaderData_i); + -- Calculate the checksum + GetRssiCsum( + -- Input + '1', -- init + rdHeaderData_i, -- header + r.csumAccum, -- accumReg + -- Results + v.csumAccum, -- accumVar + v.chksumOk, -- chksumOk + v.checksum); -- checksum + -- Reset the flag + v.hdrAmrmed := '0'; + -- Next state + v.tspState := RESEND_XSUM_S; + end if; + ---------------------------------------------------------------------- + when RESEND_XSUM_S => + -- Set the flag + v.hdrAmrmed := '1'; + -- Check if ready to move data (r.tspMaster.tValid already '0' from previous state) + if (r.hdrAmrmed = '1') then -- Using registered value to help relax timing + -- Move the data + v.tspMaster.tValid := '1'; + -- Set the SOF flag + ssiSetUserSof(RSSI_AXIS_CONFIG_C, v.tspMaster, '1'); + -- Check if header checksum enable generic set + if (HEADER_CHKSUM_EN_G) then + -- Insert the checksum + v.tspMaster.tData(63 downto 56) := r.checksum(7 downto 0); + v.tspMaster.tData(55 downto 48) := r.checksum(15 downto 8); + end if; + -- Check for a Null or Rst packet + if (r.windowArray(txBufIdx).segType(2) = '1') or (r.windowArray(txBufIdx).segType(1) = '1') then + -- Set EOF flag + v.tspMaster.tLast := '1'; + -- Next state + v.tspState := RESEND_PP_S; + -- else resend the DATA packet start sending data + else + -- Start the DMA read transaction + v.rdReq.request := '1'; + -- Next state + v.tspState := DATA_S; + end if; + end if; + ---------------------------------------------------------------------- + when RESEND_PP_S => + -- Increment buffer address (circular) + if r.txBufferAddr < (windowSize_i-1) then + v.txBufferAddr := r.txBufferAddr+1; + else + v.txBufferAddr := (others => '0'); + end if; + -- Go back to CONN_S when the last sent address reached + if (r.txBufferAddr = r.lastSentAddr) then + -- Next state + v.tspState := CONN_S; + else + -- Next state + v.tspState := RESEND_INIT_S; + end if; + ---------------------------------------------------------------------- + end case; + + v.simErrorDet := (wrAck.overflow or wrAck.writeError or rdAck.readError); + -- if r.simErrorDet = '1' then + -- assert false + -- report "Simulation Failed!" severity failure; + -- end if; + + ---------------------------------------------------------------------- + -- Outputs -- + ---------------------------------------------------------------------- + + -- Inbound Application Interface + wrDmaMaster <= appMaster_i; + wrDmaMaster.tValid <= appMaster_i.tValid and r.wrReq.request; + appSlave_o.tReady <= v.appSlave.tReady or wrDmaSlave.tReady; + + -- Outbound Transport Interface + tspMaster_o <= r.tspMaster; + + -- DMA Read Interface + rdDmaSlave <= v.rdDmaSlave; + + -- Tx data (input to header decoder module) + txSeqN_o <= r.seqN; + + -- FSM outs for header and data flow control + rdHeaderAddr_o <= v.txHeaderAddr; + synHeadSt_o <= r.synH; + ackHeadSt_o <= r.ackH; + dataHeadSt_o <= r.dataH; + dataSt_o <= r.dataD; + rstHeadSt_o <= r.rstH; + nullHeadSt_o <= r.nullH; + + -- Last acked number (Used in Rx FSM to determine if AcnN is valid) + lastAckN_o <= r.lastAckSeqN; + + -- Errors (1 cc pulse) + ackErr_o <= r.ackErr; + lenErr_o <= r.lenErr; + + -- Segment buffer indicator + bufferEmpty_o <= r.bufferEmpty; + + -- Reset + if (rst_i = '1') then + v := REG_INIT_C; + end if; + + -- Register the variable for next clock cycle + rin <= v; + + end process comb; + + seq : process (clk_i) is + begin + if (rising_edge(clk_i)) then + r <= rin after TPD_G; + end if; + end process seq; + +end architecture rtl; diff --git a/protocols/rssi/v1b/ruckus.tcl b/protocols/rssi/v1b/ruckus.tcl new file mode 100644 index 0000000000..cdcd2f7367 --- /dev/null +++ b/protocols/rssi/v1b/ruckus.tcl @@ -0,0 +1,8 @@ +# Load RUCKUS library +source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl + +# Load Source Code +loadSource -dir "$::DIR_PATH/rtl" + +# Load Simulation +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/protocols/rssi/v1b/tb/AxiRssiCoreTb.vhd b/protocols/rssi/v1b/tb/AxiRssiCoreTb.vhd new file mode 100644 index 0000000000..011c82eb12 --- /dev/null +++ b/protocols/rssi/v1b/tb/AxiRssiCoreTb.vhd @@ -0,0 +1,326 @@ +------------------------------------------------------------------------------- +-- File : AxiRssiCoreTb.vhd +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: Simulation Testbed for testing the AxiRssiCore +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; + +use work.StdRtlPkg.all; +use work.AxiPkg.all; +use work.AxiStreamPkg.all; +use work.AxiLitePkg.all; +use work.SsiPkg.all; +use work.AxiRssiPkg.all; +use work.RssiPkg.all; + +entity AxiRssiCoreTb is +end AxiRssiCoreTb; + +architecture testbed of AxiRssiCoreTb is + + constant CLK_PERIOD_C : time := 10 ns; -- 1 us makes it easy to count clock cycles in sim GUI + constant TPD_G : time := CLK_PERIOD_C/4; + + -- RSSI Timeouts + constant CLK_FREQUENCY_C : real := 100.0E+6; -- In units of Hz + constant TIMEOUT_UNIT_C : real := 1.0E-6; -- In units of seconds + constant ACK_TOUT_C : positive := 25; -- unit depends on TIMEOUT_UNIT_G + constant RETRANS_TOUT_C : positive := 50; -- unit depends on TIMEOUT_UNIT_G (Recommended >= MAX_NUM_OUTS_SEG_G*Data segment transmission time) + constant NULL_TOUT_C : positive := 200; -- unit depends on TIMEOUT_UNIT_G (Recommended >= 4*RETRANS_TOUT_G) + -- Counters + constant MAX_RETRANS_CNT_C : positive := 3; + constant MAX_CUM_ACK_CNT_C : positive := 2; + + constant JUMBO_C : boolean := true; + constant AXI_CONFIG_C : AxiConfigType := ( + ADDR_WIDTH_C => ite(JUMBO_C, 16, 13), -- (true=64kB buffer),(false=8kB buffer) + DATA_BYTES_C => 8, -- 8 bytes = 64-bits + ID_BITS_C => 2, + LEN_BITS_C => ite(JUMBO_C, 8, 7)); -- (true=2kB bursting),(false=1kB bursting) + + type RegType is record + packetLength : slv(31 downto 0); + trig : sl; + txBusy : sl; + errorDet : sl; + end record RegType; + + constant REG_INIT_C : RegType := ( + packetLength => toSlv(0, 32), + trig => '0', + txBusy => '0', + errorDet => '0'); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; + + signal clk : sl := '0'; + signal rst : sl := '0'; + + signal txMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal txSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; + + signal ibSrvMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal ibSrvSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; + signal obSrvMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal obSrvSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; + + signal ibCltMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal ibCltSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; + signal obCltMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal obCltSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; + + signal axiWriteMasters : AxiWriteMasterArray(3 downto 0); + signal axiWriteSlaves : AxiWriteSlaveArray(3 downto 0); + signal axiReadMasters : AxiReadMasterArray(3 downto 0); + signal axiReadSlaves : AxiReadSlaveArray(3 downto 0); + + signal rxMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal rxSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; + + signal linkUp : sl; + signal updatedResults : sl; + signal errorDet : sl; + signal rxBusy : sl; + signal txBusy : sl; + +begin + + --------------------------- + -- Generate clock and reset + --------------------------- + U_ClkRst : entity work.ClkRst + generic map ( + CLK_PERIOD_G => CLK_PERIOD_C, + RST_START_DELAY_G => 0 ns, + RST_HOLD_TIME_G => 1 us) + port map ( + clkP => clk, + rst => rst); + + ---------- + -- PRBS TX + ---------- + U_SsiPrbsTx : entity work.SsiPrbsTx + generic map ( + TPD_G => TPD_G, + AXI_EN_G => '0', + MASTER_AXI_STREAM_CONFIG_G => RSSI_AXIS_CONFIG_C) + port map ( + -- Master Port (mAxisClk) + mAxisClk => clk, + mAxisRst => rst, + mAxisMaster => txMaster, + mAxisSlave => txSlave, + -- Trigger Signal (locClk domain) + locClk => clk, + locRst => rst, + packetLength => r.packetLength, + -- packetLength => toSlv(800,32), + trig => r.trig, + busy => txBusy); + + -------------- + -- RSSI Server + -------------- + U_RssiServer : entity work.AxiRssiCoreWrapper + generic map ( + TPD_G => TPD_G, + JUMBO_G => JUMBO_C, + SERVER_G => true, -- Server + AXI_CONFIG_G => AXI_CONFIG_C, + -- AXIS Configurations + APP_AXIS_CONFIG_G => (0 => RSSI_AXIS_CONFIG_C), + TSP_AXIS_CONFIG_G => RSSI_AXIS_CONFIG_C, + -- RSSI Timeouts + CLK_FREQUENCY_G => CLK_FREQUENCY_C, + TIMEOUT_UNIT_G => TIMEOUT_UNIT_C, + ACK_TOUT_G => ACK_TOUT_C, + RETRANS_TOUT_G => RETRANS_TOUT_C, + NULL_TOUT_G => NULL_TOUT_C, + -- Counters + MAX_RETRANS_CNT_G => MAX_RETRANS_CNT_C, + MAX_CUM_ACK_CNT_G => MAX_CUM_ACK_CNT_C) + port map ( + clk => clk, + rst => rst, + openRq => '1', + -- AXI TX Segment Buffer Interface + txAxiOffset => (others => '0'), + txAxiWriteMaster => axiWriteMasters(0), + txAxiWriteSlave => axiWriteSlaves(0), + txAxiReadMaster => axiReadMasters(0), + txAxiReadSlave => axiReadSlaves(0), + -- AXI RX Segment Buffer Interface + rxAxiOffset => (others => '0'), + rxAxiWriteMaster => axiWriteMasters(1), + rxAxiWriteSlave => axiWriteSlaves(1), + rxAxiReadMaster => axiReadMasters(1), + rxAxiReadSlave => axiReadSlaves(1), + -- Application Layer Interface + sAppAxisMasters(0) => txMaster, + sAppAxisSlaves(0) => txSlave, + mAppAxisSlaves(0) => AXI_STREAM_SLAVE_FORCE_C, + -- Transport Layer Interface + sTspAxisMaster => ibSrvMaster, + sTspAxisSlave => ibSrvSlave, + mTspAxisMaster => obSrvMaster, + mTspAxisSlave => obSrvSlave); + + -------------- + -- RSSI Client + -------------- + U_RssiClient : entity work.AxiRssiCoreWrapper + generic map ( + TPD_G => TPD_G, + JUMBO_G => JUMBO_C, + SERVER_G => false, -- Client + AXI_CONFIG_G => AXI_CONFIG_C, + -- AXIS Configurations + APP_AXIS_CONFIG_G => (0 => RSSI_AXIS_CONFIG_C), + TSP_AXIS_CONFIG_G => RSSI_AXIS_CONFIG_C, + -- RSSI Timeouts + CLK_FREQUENCY_G => CLK_FREQUENCY_C, + TIMEOUT_UNIT_G => TIMEOUT_UNIT_C, + ACK_TOUT_G => ACK_TOUT_C, + RETRANS_TOUT_G => RETRANS_TOUT_C, + NULL_TOUT_G => NULL_TOUT_C, + -- Counters + MAX_RETRANS_CNT_G => MAX_RETRANS_CNT_C, + MAX_CUM_ACK_CNT_G => MAX_CUM_ACK_CNT_C) + port map ( + clk => clk, + rst => rst, + openRq => '1', + linkUp => linkUp, + -- AXI TX Segment Buffer Interface + txAxiOffset => (others => '0'), + txAxiWriteMaster => axiWriteMasters(2), + txAxiWriteSlave => axiWriteSlaves(2), + txAxiReadMaster => axiReadMasters(2), + txAxiReadSlave => axiReadSlaves(2), + -- AXI RX Segment Buffer Interface + rxAxiOffset => (others => '0'), + rxAxiWriteMaster => axiWriteMasters(3), + rxAxiWriteSlave => axiWriteSlaves(3), + rxAxiReadMaster => axiReadMasters(3), + rxAxiReadSlave => axiReadSlaves(3), + -- Application Layer Interface + sAppAxisMasters(0) => AXI_STREAM_MASTER_INIT_C, + mAppAxisMasters(0) => rxMaster, + mAppAxisSlaves(0) => rxSlave, + -- Transport Layer Interface + sTspAxisMaster => ibCltMaster, + sTspAxisSlave => ibCltSlave, + mTspAxisMaster => obCltMaster, + mTspAxisSlave => obCltSlave); + + ------------- + -- AXI Memory + ------------- + GEN_VEC : for i in 3 downto 0 generate + U_MEM : entity work.AxiRam + generic map ( + TPD_G => TPD_G, + SYNTH_MODE_G => "xpm", + AXI_CONFIG_G => AXI_CONFIG_C) + port map ( + -- Clock and Reset + axiClk => clk, + axiRst => rst, + -- Slave Write Interface + sAxiWriteMaster => axiWriteMasters(i), + sAxiWriteSlave => axiWriteSlaves(i), + -- Slave Read Interface + sAxiReadMaster => axiReadMasters(i), + sAxiReadSlave => axiReadSlaves(i)); + end generate GEN_VEC; + + ---------- + -- PRBS RX + ---------- + U_SsiPrbsRx : entity work.SsiPrbsRx + generic map ( + TPD_G => TPD_G, + SLAVE_AXI_STREAM_CONFIG_G => RSSI_AXIS_CONFIG_C) + port map ( + -- Slave Port (sAxisClk) + sAxisClk => clk, + sAxisRst => rst, + sAxisMaster => rxMaster, + sAxisSlave => rxSlave, + -- Error Detection Signals (sAxisClk domain) + updatedResults => updatedResults, + errorDet => errorDet, + busy => rxBusy); + + comb : process (errorDet, ibCltSlave, ibSrvSlave, linkUp, obCltMaster, + obSrvMaster, r, rst, txBusy) is + variable v : RegType; + begin + -- Latch the current value + v := r; + + -- Keep delay copies + v.errorDet := errorDet; + v.txBusy := txBusy; + v.trig := not(r.txBusy) and linkUp; + + -- Check for the packet completion + if (txBusy = '1') and (r.txBusy = '0') then + -- Sweeping the packet size size + v.packetLength := r.packetLength + 1; + end if; + + -- Reset + if (rst = '1') then + v := REG_INIT_C; + end if; + + --------------------------------- + -- Simulation Error Self-checking + --------------------------------- + if r.errorDet = '1' then + assert false + report "Simulation Failed!" severity failure; + end if; + + if (r.packetLength < 8192) then + -- if (r.packetLength < 128) then + ibSrvMaster <= obCltMaster; + obCltSlave <= ibSrvSlave; + ibCltMaster <= obSrvMaster; + obSrvSlave <= ibCltSlave; + else -- Emulation a cable being disconnected + ibSrvMaster <= AXI_STREAM_MASTER_INIT_C; + obCltSlave <= AXI_STREAM_SLAVE_FORCE_C; + ibCltMaster <= AXI_STREAM_MASTER_INIT_C; + obSrvSlave <= AXI_STREAM_SLAVE_FORCE_C; + end if; + + -- Register the variable for next clock cycle + rin <= v; + + end process comb; + + seq : process (clk) is + begin + if (rising_edge(clk)) then + r <= rin after TPD_G; + end if; + end process seq; + +end testbed; diff --git a/protocols/saci/ruckus.tcl b/protocols/saci/ruckus.tcl index aaae5950ca..87b4cc5447 100644 --- a/protocols/saci/ruckus.tcl +++ b/protocols/saci/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/sim/" +loadSource -sim_only -dir "$::DIR_PATH/sim" diff --git a/protocols/salt/core/ruckus.tcl b/protocols/salt/core/ruckus.tcl index 1bba9c850e..b61f1904f5 100644 --- a/protocols/salt/core/ruckus.tcl +++ b/protocols/salt/core/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/protocols/salt/xilinx7/ruckus.tcl b/protocols/salt/xilinx7/ruckus.tcl index 71c3ea7e32..e5941b5b76 100644 --- a/protocols/salt/xilinx7/ruckus.tcl +++ b/protocols/salt/xilinx7/ruckus.tcl @@ -10,7 +10,7 @@ if { $::env(VIVADO_VERSION) >= 2016.4 } { loadSource -path "$::DIR_PATH/ip/Salt7SeriesCore.dcp" # Load Simulation - loadSource -sim_only -dir "$::DIR_PATH/tb/" + loadSource -sim_only -dir "$::DIR_PATH/tb" } else { puts "\n\nWARNING: $::DIR_PATH requires Vivado 2016.4 (or later)\n\n" diff --git a/protocols/salt/xilinxUltraScale/ruckus.tcl b/protocols/salt/xilinxUltraScale/ruckus.tcl index bbe6122528..32a3fcc9be 100644 --- a/protocols/salt/xilinxUltraScale/ruckus.tcl +++ b/protocols/salt/xilinxUltraScale/ruckus.tcl @@ -13,7 +13,7 @@ if { $::env(VIVADO_VERSION) >= 2016.4 } { loadSource -path "$::DIR_PATH/images/SaltUltraScaleTxOnly.dcp" # Load Simulation - loadSource -sim_only -dir "$::DIR_PATH/tb/" + loadSource -sim_only -dir "$::DIR_PATH/tb" } else { puts "\n\nWARNING: $::DIR_PATH requires Vivado 2016.4 (or later)\n\n" diff --git a/protocols/spi/ruckus.tcl b/protocols/spi/ruckus.tcl index 1bba9c850e..b61f1904f5 100644 --- a/protocols/spi/ruckus.tcl +++ b/protocols/spi/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/protocols/srp/ruckus.tcl b/protocols/srp/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/protocols/srp/ruckus.tcl +++ b/protocols/srp/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/protocols/srp/tb/AxiLiteSrpV0Tb.vhd b/protocols/srp/tb/AxiLiteSrpV0Tb.vhd index 40d238cb1f..478579addb 100644 --- a/protocols/srp/tb/AxiLiteSrpV0Tb.vhd +++ b/protocols/srp/tb/AxiLiteSrpV0Tb.vhd @@ -169,8 +169,6 @@ begin U_AxiDualPortRam_1 : entity work.AxiDualPortRam generic map ( TPD_G => TPD_G, - BRAM_EN_G => true, - REG_EN_G => true, AXI_WR_EN_G => true, SYS_WR_EN_G => false, SYS_BYTE_WR_EN_G => false, diff --git a/protocols/ssi/ruckus.tcl b/protocols/ssi/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/protocols/ssi/ruckus.tcl +++ b/protocols/ssi/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/protocols/ssp/ruckus.tcl b/protocols/ssp/ruckus.tcl index 6bcb327061..cdcd2f7367 100644 --- a/protocols/ssp/ruckus.tcl +++ b/protocols/ssp/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/tb/" +loadSource -sim_only -dir "$::DIR_PATH/tb" diff --git a/protocols/uart/ruckus.tcl b/protocols/uart/ruckus.tcl index aaae5950ca..87b4cc5447 100644 --- a/protocols/uart/ruckus.tcl +++ b/protocols/uart/ruckus.tcl @@ -2,7 +2,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" # Load Simulation -loadSource -sim_only -dir "$::DIR_PATH/sim/" +loadSource -sim_only -dir "$::DIR_PATH/sim" diff --git a/protocols/uart/sim/UartAxiLiteMasterTb.vhd b/protocols/uart/sim/UartAxiLiteMasterTb.vhd index e2c272db58..e0ad80ae71 100644 --- a/protocols/uart/sim/UartAxiLiteMasterTb.vhd +++ b/protocols/uart/sim/UartAxiLiteMasterTb.vhd @@ -111,8 +111,9 @@ begin U_AxiDualPortRam_1 : entity work.AxiDualPortRam generic map ( TPD_G => TPD_G, - BRAM_EN_G => false, - REG_EN_G => false, + SYNTH_MODE_G => "xpm", + MEMORY_TYPE_G=> "distributed", + READ_LATENCY_G => 0, AXI_WR_EN_G => true, SYS_WR_EN_G => false, COMMON_CLK_G => true, diff --git a/python/surf/axi/_AxiStreamBatcherEventBuilder.py b/python/surf/axi/_AxiStreamBatcherEventBuilder.py new file mode 100644 index 0000000000..4a3a253067 --- /dev/null +++ b/python/surf/axi/_AxiStreamBatcherEventBuilder.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +#----------------------------------------------------------------------------- +# Title : PyRogue AXI-Lite Version Module +#----------------------------------------------------------------------------- +# File : AxiVersion.py +# Created : 2017-04-12 +#----------------------------------------------------------------------------- +# Description: +# PyRogue AXI-Lite Version Module +#----------------------------------------------------------------------------- +# This file is part of the rogue software platform. It is subject to +# the license terms in the LICENSE.txt file found in the top-level directory +# of this distribution and at: +# https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +# No part of the rogue software platform, including this file, may be +# copied, modified, propagated, or distributed except according to the terms +# contained in the LICENSE.txt file. +#----------------------------------------------------------------------------- + +import pyrogue as pr + +class AxiStreamBatcherEventBuilder(pr.Device): + def __init__(self, + name = "AxiStreamBatcherEventBuilder", + description = "AxiStreamBatcherEventBuilder Container", + numberSlaves = 1, + tickUnit = 'TBD', + **kwargs): + super().__init__(name=name, description=description, **kwargs) + + self.addRemoteVariables( + name = 'DataCnt', + description = 'Increments every time a data frame is received', + offset = 0x000, + bitSize = 32, + mode = 'RO', + number = numberSlaves, + stride = 4, + pollInterval = 1, + ) + + self.addRemoteVariables( + name = 'NullCnt', + description = 'Increments every time a null frame is received', + offset = 0x100, + bitSize = 32, + mode = 'RO', + number = numberSlaves, + stride = 4, + pollInterval = 1, + ) + + self.addRemoteVariables( + name = 'TimeoutDropCnt', + description = 'Increments every time a timeout slave channel drop event happens', + offset = 0x200, + bitSize = 32, + mode = 'RO', + number = numberSlaves, + stride = 4, + pollInterval = 1, + ) + + self.add(pr.RemoteVariable( + name = 'Timeout', + description = 'Sets the timer\'s timeout duration. Setting to 0x0 (default) bypasses the timeout feature', + offset = 0xFF0, + bitSize = 32, + mode = 'RW', + units = tickUnit, + )) + + self.add(pr.RemoteVariable( + name = 'NUM_SLAVES_G', + description = 'NUM_SLAVES_G generic value', + offset = 0xFF4, + bitSize = 8, + mode = 'RO', + disp = '{:d}', + )) + + self.add(pr.RemoteVariable( + name = "State", + description = "current state of FSM (for debugging)", + offset = 0xFF8, + bitSize = 1, + bitOffset = 8, + mode = "RO", + pollInterval = 1, + enum = { + 0x0: 'IDLE_S', + 0x1: 'MOVE_S', + }, + )) + + self.add(pr.RemoteVariable( + name = "Blowoff", + description = "Blows off the inbound AXIS stream (for debugging)", + offset = 0xFF8, + bitSize = 1, + bitOffset = 0, + base = pr.Bool, + mode = "RW", + )) + + self.add(pr.RemoteCommand( + name = "CntRst", + description = "", + offset = 0xFFC, + bitSize = 1, + bitOffset = 0, + function = pr.BaseCommand.toggle, + )) + + self.add(pr.RemoteCommand( + name = "TimerRst", + description = "", + offset = 0xFFC, + bitSize = 1, + bitOffset = 1, + function = pr.BaseCommand.toggle, + )) + + self.add(pr.RemoteCommand( + name = "HardRst", + description = "", + offset = 0xFFC, + bitSize = 1, + bitOffset = 2, + function = pr.BaseCommand.toggle, + )) + + self.add(pr.RemoteCommand( + name = "SoftRst", + description = "", + offset = 0xFFC, + bitSize = 1, + bitOffset = 3, + function = pr.BaseCommand.toggle, + )) + + def hardReset(self): + self.HardRst() + + def softReset(self): + self.SoftRst() + + def countReset(self): + self.CntRst() diff --git a/python/surf/axi/_AxiStreamMonitoring.py b/python/surf/axi/_AxiStreamMonitoring.py index 689ded81e1..f0fbbe0800 100644 --- a/python/surf/axi/_AxiStreamMonitoring.py +++ b/python/surf/axi/_AxiStreamMonitoring.py @@ -27,6 +27,14 @@ def __init__(self, **kwargs): super().__init__(name=name, description=description, **kwargs) + self.add(pr.RemoteVariable( + name = "CntRst", + description = "Counter Reset", + mode = 'WO', + offset = 0x0, + hidden = True, + )) + def addPair(name,offset,bitSize,units,bitOffset,description,function,pollInterval = 0,): self.add(pr.RemoteVariable( name = (name+"Raw"), @@ -121,10 +129,16 @@ def addPair(name,offset,bitSize,units,bitOffset,description,function,pollInterva units = 'Mbps', pollInterval = 1, ) - + @staticmethod def convMbps(var): return var.dependencies[0].value() * 8e-6 + def hardReset(self): + self.CntRst.set(0x1) + + def softReset(self): + self.CntRst.set(0x1) + def countReset(self): - self._rawWrite(offset=0x0,data=0x1) \ No newline at end of file + self.CntRst.set(0x1) diff --git a/python/surf/axi/_AxiVersion.py b/python/surf/axi/_AxiVersion.py index 426382509d..4eb04ff66c 100644 --- a/python/surf/axi/_AxiVersion.py +++ b/python/surf/axi/_AxiVersion.py @@ -258,13 +258,13 @@ def parseBuildStamp(var,read): def hardReset(self): - print('AxiVersion hard reset called') + print(f'{self.path} hard reset called') def softReset(self): - print('AxiVersion soft reset called') + print(f'{self.path} soft reset called') def countReset(self): - print('AxiVersion count reset called') + print(f'{self.path} count reset called') def printStatus(self): try: @@ -282,5 +282,5 @@ def printStatus(self): print("BuildDate = {}".format(self.BuildDate.value())) print("Builder = {}".format(self.Builder.value())) except Exception as e: - print("Failed to get AxiVersion status") + print("Failed to get %s status" % self) diff --git a/python/surf/axi/__init__.py b/python/surf/axi/__init__.py index ef86382067..9fc7aed71a 100644 --- a/python/surf/axi/__init__.py +++ b/python/surf/axi/__init__.py @@ -8,10 +8,11 @@ ## may be copied, modified, propagated, or distributed except according to ## the terms contained in the LICENSE.txt file. ############################################################################## -from surf.axi._AxiLiteEmpty import * -from surf.axi._AxiMemTester import * -from surf.axi._AxiStreamDmaRingWrite import * -from surf.axi._AxiStreamMonitoring import * -from surf.axi._AxiVersion import * -from surf.axi._AxiVersionLegacy import * -from surf.axi._AxiStreamDmaV2 import * +from surf.axi._AxiLiteEmpty import * +from surf.axi._AxiMemTester import * +from surf.axi._AxiStreamBatcherEventBuilder import * +from surf.axi._AxiStreamDmaRingWrite import * +from surf.axi._AxiStreamMonitoring import * +from surf.axi._AxiVersion import * +from surf.axi._AxiVersionLegacy import * +from surf.axi._AxiStreamDmaV2 import * diff --git a/python/surf/devices/ti/_Adc32Rf45.py b/python/surf/devices/ti/_Adc32Rf45.py index 1385a2397a..6035515315 100644 --- a/python/surf/devices/ti/_Adc32Rf45.py +++ b/python/surf/devices/ti/_Adc32Rf45.py @@ -557,7 +557,7 @@ def SetNLTrim(): @self.command(name = "JESD_DDC_config", description = "JESD DDC config") def JESD_DDC_config(): # JESD DIGITAL PAGE - channels = self.find(typ=Adc32Rf45Channel) + channels = self.find(typ=dev.ti.Adc32Rf45Channel) for channel in channels: channel.SCRAMBLE_EN.set(0x1, write=True) channel.node('12BIT_MODE').set(0x0, write=True) # need to use node to find variables with leading # diff --git a/python/surf/protocols/clink/_ClinkChannel.py b/python/surf/protocols/clink/_ClinkChannel.py index ace40b7c58..8394806e3f 100644 --- a/python/surf/protocols/clink/_ClinkChannel.py +++ b/python/surf/protocols/clink/_ClinkChannel.py @@ -34,13 +34,19 @@ def __init__( self, self.add(pr.RemoteVariable( name = "LinkMode", - description = "Link mode control for camera link lanes", offset = 0x00, bitSize = 3, bitOffset = 0, - base = pr.UInt, - enum = { 0 : 'Disable' , 1 : 'Base', 2 : 'Medium', 3 : 'Full', 4 : 'Deca'}, mode = "RW", + enum = { 0 : 'Disable' , 1 : 'Base', 2 : 'Medium', 3 : 'Full', 4 : 'Deca'}, + description = """ + Link mode control for camera link lanes: + Disable: Nothing connected + Base: Port Supported [A,B,C], # of chips = 1, # of connectors = 1 + Medium: Port Supported [A,B,C,D,E,F], # of chips = 2, # of connectors = 2 + Full: Port Supported [A,B,C,D,E,F,G,H], # of chips = 3, # of connectors = 3 + Deca: Refer to section /"2.2.3 Camera Link 80 bit/" CameraLink spec V2.0, page 16 + """, )) self.add(pr.RemoteVariable( @@ -49,44 +55,74 @@ def __init__( self, offset = 0x04, bitSize = 4, bitOffset = 0, - base = pr.UInt, + mode = "RW", enum = { 0 : 'None', 1 : '8Bit', 2 : '10Bit', 3 : '12Bit', 4 : '14Bit', 5 : '16Bit', 6 : '24Bit', 7 : '30Bit', 8 : '36Bit'}, - mode = "RW", )) self.add(pr.RemoteVariable( name = "FrameMode", - description = "Frame mode", offset = 0x08, bitSize = 2, bitOffset = 0, - base = pr.UInt, - enum = { 0 : 'None', 1 : 'Line', 2 : 'Frame'}, mode = "RW", + enum = { 0 : 'None', 1 : 'Line', 2 : 'Frame'}, + description = """ + None: Disables output + Line: 1D camera + Frame" 2D pixel array + """, )) self.add(pr.RemoteVariable( name = "TapCount", - description = "Frame mode", + description = "# of video output taps on the Camera Link Interface (# of individual data value channels)", offset = 0x0C, bitSize = 4, bitOffset = 0, minimum = 0, maximum = 10, - base = pr.UInt, mode = "RW", )) self.add(pr.RemoteVariable( name = "DataEn", - description = "Data enable", + description = "Data enable. When 0x0 causes reset on ClinkData\'s FSM module", offset = 0x10, bitSize = 1, bitOffset = 0, base = pr.Bool, mode = "RW", )) + + self.add(pr.RemoteVariable( + name = "Blowoff", + description = "Blows off the outbound AXIS stream (for debugging)", + offset = 0x10, + bitSize = 1, + bitOffset = 1, + base = pr.Bool, + mode = "RW", + )) + + self.add(pr.RemoteCommand( + name = "CntRst", + description = "", + offset = 0x10, + bitSize = 1, + bitOffset = 2, + function = pr.BaseCommand.toggle, + )) + + self.add(pr.RemoteVariable( + name = "SerThrottle", + description = "Throttles the UART Serial TX byte rate. Used when the camera cannot accept new bytes until the previous command processed", + offset = 0x10, + bitSize = 16, + bitOffset = 16, + mode = "RW", + units = "microsec", + )) self.add(pr.RemoteVariable( name = "BaudRate", @@ -95,17 +131,16 @@ def __init__( self, bitSize = 24, bitOffset = 0, disp = '{}', - base = pr.UInt, mode = "RW", + units = "bps", )) - + self.add(pr.RemoteVariable( name = "SwControlValue", description = "Software camera control bit values", offset = 0x18, bitSize = 4, bitOffset = 0, - base = pr.UInt, mode = "RW", )) @@ -115,7 +150,6 @@ def __init__( self, offset = 0x1C, bitSize = 4, bitOffset = 0, - base = pr.UInt, mode = "RW", )) @@ -126,8 +160,8 @@ def __init__( self, bitSize = 1, bitOffset = 0, base = pr.Bool, - pollInterval = 1, mode = "RO", + pollInterval = 1, )) self.add(pr.RemoteVariable( @@ -136,10 +170,9 @@ def __init__( self, offset = 0x24, bitSize = 32, bitOffset = 0, - base = pr.UInt, disp = '{}', - pollInterval = 1, mode = "RO", + pollInterval = 1, )) self.add(pr.RemoteVariable( @@ -148,10 +181,9 @@ def __init__( self, offset = 0x28, bitSize = 32, bitOffset = 0, - base = pr.UInt, disp = '{}', - pollInterval = 1, mode = "RO", + pollInterval = 1, )) self._rx = None @@ -179,3 +211,12 @@ def sendGcp(): if self._tx is not None: self._tx.sendString("gcp") + def hardReset(self): + self.CntRst() + + def softReset(self): + self.CntRst() + + def countReset(self): + self.CntRst() + \ No newline at end of file diff --git a/python/surf/protocols/clink/_ClinkSerialRx.py b/python/surf/protocols/clink/_ClinkSerialRx.py index 8618d4afb4..1375386b05 100644 --- a/python/surf/protocols/clink/_ClinkSerialRx.py +++ b/python/surf/protocols/clink/_ClinkSerialRx.py @@ -38,4 +38,3 @@ def _acceptFrame(self,frame): self._cur = [] elif c != '\r': self._cur.append(c) - diff --git a/python/surf/protocols/clink/_ClinkTop.py b/python/surf/protocols/clink/_ClinkTop.py index 2743eb61f8..2dda1fe329 100644 --- a/python/surf/protocols/clink/_ClinkTop.py +++ b/python/surf/protocols/clink/_ClinkTop.py @@ -39,21 +39,36 @@ def __init__( self, offset = 0x00, bitSize = 4, bitOffset = 0x00, - base = pr.UInt, mode = "RO", )) - self.add(pr.RemoteVariable( - name = "LinkReset", - description = "Camera link channel reset", + self.add(pr.RemoteCommand( + name = "ResetPll", + description = "Camera link channel PLL reset", offset = 0x04, bitSize = 1, bitOffset = 0, - base = pr.Bool, - pollInterval = 1, - mode = "RW", - )) + function = pr.BaseCommand.toggle, + )) + self.add(pr.RemoteCommand( + name = "ResetFsm", + description = "Camera link channel FSM reset", + offset = 0x04, + bitSize = 1, + bitOffset = 1, + function = pr.BaseCommand.toggle, + )) + + self.add(pr.RemoteCommand( + name = "CntRst", + description = "", + offset = 0x04, + bitSize = 1, + bitOffset = 2, + function = pr.BaseCommand.toggle, + )) + self.add(pr.RemoteVariable( name = "LinkLockedA", description = "Camera link channel locked status", @@ -86,16 +101,48 @@ def __init__( self, pollInterval = 1, mode = "RO", )) + + self.add(pr.RemoteVariable( + name = "LinkLockedCntA", + description = "Camera link channel locked status counter", + offset = 0x10, + bitSize = 8, + bitOffset = 8, + disp = '{}', + mode = "RO", + pollInterval = 1, + )) + + self.add(pr.RemoteVariable( + name = "LinkLockedCntB", + description = "Camera link channel locked status counter", + offset = 0x10, + bitSize = 8, + bitOffset = 16, + disp = '{}', + mode = "RO", + pollInterval = 1, + )) + self.add(pr.RemoteVariable( + name = "LinkLockedCntC", + description = "Camera link channel locked status counter", + offset = 0x10, + bitSize = 8, + bitOffset = 24, + disp = '{}', + mode = "RO", + pollInterval = 1, + )) + self.add(pr.RemoteVariable( name = "ShiftCountA", description = "Shift count for channel", offset = 0x14, bitSize = 3, bitOffset = 0, - base = pr.UInt, - pollInterval = 1, mode = "RO", + pollInterval = 1, )) self.add(pr.RemoteVariable( @@ -104,9 +151,8 @@ def __init__( self, offset = 0x14, bitSize = 3, bitOffset = 8, - base = pr.UInt, - pollInterval = 1, mode = "RO", + pollInterval = 1, )) self.add(pr.RemoteVariable( @@ -115,9 +161,8 @@ def __init__( self, offset = 0x14, bitSize = 3, bitOffset = 16, - base = pr.UInt, - pollInterval = 1, mode = "RO", + pollInterval = 1, )) self.add(pr.RemoteVariable( @@ -126,9 +171,8 @@ def __init__( self, offset = 0x18, bitSize = 5, bitOffset = 0, - base = pr.UInt, - pollInterval = 1, mode = "RO", + pollInterval = 1, )) self.add(pr.RemoteVariable( @@ -137,9 +181,8 @@ def __init__( self, offset = 0x18, bitSize = 5, bitOffset = 8, - base = pr.UInt, - pollInterval = 1, mode = "RO", + pollInterval = 1, )) self.add(pr.RemoteVariable( @@ -148,11 +191,18 @@ def __init__( self, offset = 0x18, bitSize = 5, bitOffset = 16, - base = pr.UInt, - pollInterval = 1, mode = "RO", + pollInterval = 1, )) - self.add(surf.protocols.clink.ClinkChannel( name = "ChannelA", serial=serialA, offset=0x100)) - self.add(surf.protocols.clink.ClinkChannel( name = "ChannelB", serial=serialB, offset=0x200)) + self.add(surf.protocols.clink.ClinkChannel( name = "Channel[0]", serial=serialA, offset=0x100)) + self.add(surf.protocols.clink.ClinkChannel( name = "Channel[1]", serial=serialB, offset=0x200)) + + def hardReset(self): + self.CntRst() + + def softReset(self): + self.CntRst() + def countReset(self): + self.CntRst() \ No newline at end of file diff --git a/python/surf/protocols/clink/_UartOpal000.py b/python/surf/protocols/clink/_UartOpal000.py new file mode 100644 index 0000000000..33c7d4d276 --- /dev/null +++ b/python/surf/protocols/clink/_UartOpal000.py @@ -0,0 +1,264 @@ +#!/usr/bin/env python +#----------------------------------------------------------------------------- +# Title : PyRogue CameraLink module +#----------------------------------------------------------------------------- +# File : _UartOpal000.py +# Created : 2017-11-21 +#----------------------------------------------------------------------------- +# Description: +# PyRogue CameraLink module +#----------------------------------------------------------------------------- +# This file is part of the rogue software platform. It is subject to +# the license terms in the LICENSE.txt file found in the top-level directory +# of this distribution and at: +# https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +# No part of the rogue software platform, including this file, may be +# copied, modified, propagated, or distributed except according to the terms +# contained in the LICENSE.txt file. +#----------------------------------------------------------------------------- + +import pyrogue as pr + +import surf.protocols.clink as clink + +import time + +class UartOpal000Tx(clink.ClinkSerialTx): + def __init__(self,**kwargs): + super().__init__(**kwargs) + +class UartOpal000Rx(clink.ClinkSerialRx): + def __init__(self,**kwargs): + super().__init__(**kwargs) + + def _acceptFrame(self,frame): + ba = bytearray(frame.getPayload()) + frame.read(ba,0) + + for i in range(0,len(ba),4): + c = chr(ba[i]) + + if c == '\n': + print("Got Response: {}".format(''.join(self._cur))) + self._cur = [] + elif ba[i] == 0x6: + print("Got ACK Response: {}".format(''.join(self._cur))) + self._cur = [] + elif ba[i] == 0x25: + print("Got NAK Response: {}".format(''.join(self._cur))) + self._cur = [] + elif c != '\r': + self._cur.append(c) + +class UartOpal000(pr.Device): + def __init__( self, + name = 'UartOpal000', + description = 'Uart Opal000 channel access', + serial = None, + **kwargs): + super().__init__(name=name, description=description, **kwargs) + + if serial is not None: + + # Attach the serial devices + self._rx = UartOpal000Rx() + pr.streamConnect(serial,self._rx) + + self._tx = UartOpal000Tx() + pr.streamConnect(self._tx,serial) + + ############################## + # Variables + ############################## + + self.add(pr.LocalVariable( + name = 'CCE[0]', + description = 'Selects the exposure control source and event selection', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@CCE{self.CCE[0].get()};{self.CCE[1].get()}\r') if (self.CCE[0].get()!='' and self.CCE[1].get()!='') else '' + )) + + self.add(pr.LocalVariable( + name = 'CCE[1]', + description = 'Selects the exposure control source and event selection', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@CCE{self.CCE[0].get()};{self.CCE[1].get()}\r') if (self.CCE[0].get()!='' and self.CCE[1].get()!='') else '' + )) + + self.add(pr.LocalVariable( + name = 'CCFS[0]', + description = 'Selects the frame start control source and event selection', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@CCFS{self.CCFS[0].get()};{self.CCFS[1].get()}\r') if (self.CCFS[0].get()!='' and self.CCFS[1].get()!='') else '' + )) + + self.add(pr.LocalVariable( + name = 'CCFS[1]', + description = 'Selects the frame start control source and event selection', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@CCFS{self.CCFS[0].get()};{self.CCFS[1].get()}\r') if (self.CCFS[0].get()!='' and self.CCFS[1].get()!='') else '' + )) + + self.add(pr.LocalVariable( + name = 'DPE', + description = 'Enables or disables the defect pixel correction.', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@DPE{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'FP', + description = 'Sets the frame period.', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@FP{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'FSM', + description = 'Selects the FSTROBE output and polarity', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@FSM{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'FST[0]', + description = 'Configures the FSTROBE, step, delay and active', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@FST{self.FST[0].get()};{self.FST[1].get()}\r') if (self.FST[0].get()!='' and self.FST[1].get()!='') else '' + )) + + self.add(pr.LocalVariable( + name = 'FST[1]', + description = 'Configures the FSTROBE, step, delay and active', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@FST{self.FST[0].get()};{self.FST[1].get()}\r') if (self.FST[0].get()!='' and self.FST[1].get()!='') else '' + )) + + self.add(pr.LocalVariable( + name = 'GA', + description = 'Sets the digital gain of the camera.', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@GA{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'IT', + description = 'Sets the integration time.', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@IT{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'MI', + description = 'Enables or disables the mirror function.', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@MI{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'MO', + description = 'Sets the operating mode of the camera.', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@MO{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'OFS', + description = 'Sets the output offset in GL at 12 bit internal resolution', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@OFS{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'OR', + description = 'Sets the output resolution of the camera.', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@OR{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'TP', + description = 'Selects display of the test pattern', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@TP{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'VBIN', + description = 'Sets the image output binning', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@VBIN{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'WB[0]', + description = 'Sets the gain for the Red, Green and Blue channel', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@WB{self.WB[0].get()};{self.WB[1].get()};{self.WB[2].get()}\r') if (self.WB[0].get()!='' and self.WB[1].get()!='' and self.WB[2].get()!='') else '' + )) + + self.add(pr.LocalVariable( + name = 'WB[1]', + description = 'Sets the gain for the Red, Green and Blue channel', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@WB{self.WB[0].get()};{self.WB[1].get()};{self.WB[2].get()}\r') if (self.WB[0].get()!='' and self.WB[1].get()!='' and self.WB[2].get()!='') else '' + )) + + self.add(pr.LocalVariable( + name = 'WB[2]', + description = 'Sets the gain for the Red, Green and Blue channel', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@WB{self.WB[0].get()};{self.WB[1].get()};{self.WB[2].get()}\r') if (self.WB[0].get()!='' and self.WB[1].get()!='' and self.WB[2].get()!='') else '' + )) + + self.add(pr.LocalVariable( + name = 'BL', + description = 'Sets the black level.', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@BL{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'VR', + description = 'Enableling and disableling the vertical remap is done by means of the vertical remap command.', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@VR{value}\r') if value!='' else '' + )) + + self.add(pr.LocalVariable( + name = 'FSP', + description = ''' + The active state of the strobe output can be inverted to adapt to the application requirements. + 0 for the reverse polarity: in this polarity configuration the phototransistor at the camera output is non-conductive during the active state of the strobe. + 1 for the normal polarity: in this polarity configuration the phototransistor at the camera output is conductive during the active state of the strobe. + ''', + mode = 'RW', + value = '', + localSet = lambda value: self._tx.sendString(f'@FSP{value}\r') if value!='' else '' + )) + + else: + raise ValueError('UartOpal000.serial=none (no streaming interface attached)' ) + \ No newline at end of file diff --git a/python/surf/protocols/clink/__init__.py b/python/surf/protocols/clink/__init__.py index b4d0f85236..298ed62fb7 100644 --- a/python/surf/protocols/clink/__init__.py +++ b/python/surf/protocols/clink/__init__.py @@ -8,7 +8,11 @@ ## may be copied, modified, propagated, or distributed except according to ## the terms contained in the LICENSE.txt file. ############################################################################## + from surf.protocols.clink._ClinkTop import * from surf.protocols.clink._ClinkSerialRx import * from surf.protocols.clink._ClinkSerialTx import * from surf.protocols.clink._ClinkChannel import * + +# Library of support Camera UART interfaces +from surf.protocols.clink._UartOpal000 import * diff --git a/python/surf/protocols/pgp/_Pgp2bAxi.py b/python/surf/protocols/pgp/_Pgp2bAxi.py index 840670ab58..b56218d76b 100644 --- a/python/surf/protocols/pgp/_Pgp2bAxi.py +++ b/python/surf/protocols/pgp/_Pgp2bAxi.py @@ -26,7 +26,9 @@ def __init__(self, description = "Configuration and status of a downstream PGP link", writeEn = True, **kwargs): - super().__init__(name=name, description=description, **kwargs) + super().__init__(name=name, description=description, **kwargs) + + self.writeEn = writeEn if writeEn: self.add(pr.RemoteVariable( @@ -324,15 +326,6 @@ def __init__(self, function = pr.BaseCommand.toggle, )) - def softReset(self): - if writeEn: - self.Flush() - - def hardReset(self): - self.ResetTxRx() - - def countReset(self): - self.CountReset() self.add(pr.RemoteVariable( name = "RxClkFreqRaw", @@ -375,3 +368,12 @@ def convtMHz(var): linkedGet = convtMHz, )) + def softReset(self): + if self.writeEn: + self.Flush() + + def hardReset(self): + self.ResetTxRx() + + def countReset(self): + self.CountReset() diff --git a/xilinx/7Series/general/ruckus.tcl b/xilinx/7Series/general/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/xilinx/7Series/general/ruckus.tcl +++ b/xilinx/7Series/general/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/xilinx/7Series/gth7/ruckus.tcl b/xilinx/7Series/gth7/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/xilinx/7Series/gth7/ruckus.tcl +++ b/xilinx/7Series/gth7/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/xilinx/7Series/gtp7/ruckus.tcl b/xilinx/7Series/gtp7/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/xilinx/7Series/gtp7/ruckus.tcl +++ b/xilinx/7Series/gtp7/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/xilinx/7Series/gtx7/ruckus.tcl b/xilinx/7Series/gtx7/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/xilinx/7Series/gtx7/ruckus.tcl +++ b/xilinx/7Series/gtx7/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/xilinx/7Series/sem/ruckus.tcl b/xilinx/7Series/sem/ruckus.tcl index 64931b7110..900e650fca 100644 --- a/xilinx/7Series/sem/ruckus.tcl +++ b/xilinx/7Series/sem/ruckus.tcl @@ -4,7 +4,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code if { $::env(VIVADO_VERSION) >= 2016.4 } { - loadSource -dir "$::DIR_PATH/rtl/" + loadSource -dir "$::DIR_PATH/rtl" # Load IP Code loadSource -path "$::DIR_PATH/ip/SemCore.dcp" diff --git a/xilinx/7Series/xadc/ruckus.tcl b/xilinx/7Series/xadc/ruckus.tcl index e0b9e2ed49..aeca4d53d0 100644 --- a/xilinx/7Series/xadc/ruckus.tcl +++ b/xilinx/7Series/xadc/ruckus.tcl @@ -4,7 +4,7 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code if { $::env(VIVADO_VERSION) >= 2015.2 } { - loadSource -dir "$::DIR_PATH/rtl/" + loadSource -dir "$::DIR_PATH/rtl" # loadIpCore -path "$::DIR_PATH/ip/AxiXadcMinimum.xci" loadSource -path "$::DIR_PATH/ip/AxiXadcMinimum.dcp" diff --git a/xilinx/UltraScale+/gthUs/ruckus.tcl b/xilinx/UltraScale+/gthUs/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/xilinx/UltraScale+/gthUs/ruckus.tcl +++ b/xilinx/UltraScale+/gthUs/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/xilinx/UltraScale/general/ruckus.tcl b/xilinx/UltraScale/general/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/xilinx/UltraScale/general/ruckus.tcl +++ b/xilinx/UltraScale/general/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl" diff --git a/xilinx/UltraScale/gthUs/ruckus.tcl b/xilinx/UltraScale/gthUs/ruckus.tcl index 6fa215e9f8..f988a4f0c1 100644 --- a/xilinx/UltraScale/gthUs/ruckus.tcl +++ b/xilinx/UltraScale/gthUs/ruckus.tcl @@ -2,4 +2,4 @@ source -quiet $::env(RUCKUS_DIR)/vivado_proc.tcl # Load Source Code -loadSource -dir "$::DIR_PATH/rtl/" +loadSource -dir "$::DIR_PATH/rtl"