diff --git a/axi/axi-stream/rtl/AxiStreamRingBuffer.vhd b/axi/axi-stream/rtl/AxiStreamRingBuffer.vhd index 85857fa4ef..6dadeef295 100644 --- a/axi/axi-stream/rtl/AxiStreamRingBuffer.vhd +++ b/axi/axi-stream/rtl/AxiStreamRingBuffer.vhd @@ -29,7 +29,7 @@ entity AxiStreamRingBuffer is RST_ASYNC_G : boolean := false; SYNTH_MODE_G : string := "inferred"; MEMORY_TYPE_G : string := "block"; - COMMON_CLK_G : boolean := false; -- true if dataClk=axilClk + COMMON_CLK_G : boolean := false; -- true if dataClk=axilClk DATA_BYTES_G : positive := 16; RAM_ADDR_WIDTH_G : positive := 9; -- AXI Stream Configurations @@ -74,10 +74,7 @@ architecture rtl of AxiStreamRingBuffer is -- Stream clock domain signals ------------------------------ type DataRegType is record - extTrig : sl; - bufferEnable : sl; enable : sl; - cleared : sl; armed : sl; ramWrEn : sl; readReq : sl; @@ -88,10 +85,7 @@ architecture rtl of AxiStreamRingBuffer is end record; constant DATA_REG_INIT_C : DataRegType := ( - extTrig => '0', - bufferEnable => '0', - enable => '0', - cleared => '1', -- Only set HIGH after reset + enable => '1', -- Only set HIGH after reset armed => '0', ramWrEn => '0', readReq => '0', @@ -103,26 +97,26 @@ architecture rtl of AxiStreamRingBuffer is signal dataR : DataRegType := DATA_REG_INIT_C; signal dataRin : DataRegType; - signal bufferEnableSync : sl; - signal bufferClearSync : sl; + signal softTrigSync : sl; + signal bufferClearSync : sl; -------------------------------- -- AXI-Lite clock domain signals -------------------------------- type DataStateType is ( IDLE_S, - MOVE_S); + MOVE_S, + CLEARED_S); type TrigStateType is ( IDLE_S, - CLEAR_S, ARMED_S, WAIT_S); type AxilRegType is record trigCnt : slv(31 downto 0); continuous : sl; - bufferEnable : sl; + softTrig : sl; bufferClear : sl; wordCnt : slv(RAM_ADDR_WIDTH_G-1 downto 0); ramRdAddr : slv(RAM_ADDR_WIDTH_G-1 downto 0); @@ -137,7 +131,7 @@ architecture rtl of AxiStreamRingBuffer is constant AXIL_REG_INIT_C : AxilRegType := ( trigCnt => (others => '0'), continuous => '0', - bufferEnable => '0', + softTrig => '0', bufferClear => '0', wordCnt => (others => '0'), ramRdAddr => (others => '0'), @@ -159,7 +153,6 @@ architecture rtl of AxiStreamRingBuffer is signal bufferLength : slv(RAM_ADDR_WIDTH_G-1 downto 0); signal readReq : sl; - signal cleared : sl; signal armed : sl; signal txSlave : AxiStreamSlaveType; @@ -238,32 +231,24 @@ begin -------------------------------------------------- -- Synchronize AXI registers to data clock dataClk -------------------------------------------------- - U_bufferEnable : entity surf.Synchronizer + U_SyncVec_dataClk : entity surf.SynchronizerVector generic map ( TPD_G => TPD_G, - RST_ASYNC_G => RST_ASYNC_G) - port map ( - clk => dataClk, - rst => dataRst, - dataIn => axilR.bufferEnable, - dataOut => bufferEnableSync); - - U_bufferClear : entity surf.SynchronizerOneShot - generic map ( - TPD_G => TPD_G, - RST_ASYNC_G => RST_ASYNC_G, - PULSE_WIDTH_G => 10) + RST_ASYNC_G => RST_ASYNC_G, + WIDTH_G => 2) port map ( - clk => dataClk, - rst => dataRst, - dataIn => axilR.bufferClear, - dataOut => bufferClearSync); + clk => dataClk, + rst => dataRst, + dataIn(0) => axilR.softTrig, + dataIn(1) => axilR.bufferClear, + dataOut(0) => softTrigSync, + dataOut(1) => bufferClearSync); -------------------------- -- Main AXI-Stream process -------------------------- - dataComb : process (bufferClearSync, bufferEnableSync, dataR, dataRst, - dataValid, dataValue, extTrig) is + dataComb : process (bufferClearSync, dataR, dataRst, dataValid, dataValue, + extTrig, softTrigSync) is variable v : DataRegType; begin -- Latch the current value @@ -272,38 +257,43 @@ begin -- Reset strobes v.ramWrEn := '0'; v.readReq := '0'; - v.cleared := '0'; - - -- Check for external trigger - if (extTrig = '1') and (dataR.extTrig = '0') then - v.extTrig := '1'; - v.bufferEnable := '1'; - end if; - -- Default assignment + -- Register data value to help with making timing v.ramWrData := dataValue; - v.enable := bufferEnableSync or dataR.bufferEnable; - - -- Increment the addresses on each valid if logging enabled - if (dataValid = '1') and (dataR.enable = '1') then - -- Trigger a write - v.ramWrEn := '1'; - - -- Increment the address - v.nextAddr := dataR.nextAddr + 1; - -- Check if the write pointer = read pointer - if (v.nextAddr = dataR.firstAddr) then - v.firstAddr := dataR.firstAddr + 1; - v.armed := '1'; - v.bufferEnable := '0'; + + -- Check if ring buffer is logging + if (dataR.enable = '1') then + + -- Check for valid data to write + if (dataValid = '1') then + + -- Trigger a write + v.ramWrEn := '1'; + + -- Increment the address + v.nextAddr := dataR.nextAddr + 1; + -- Check if the write pointer = read pointer + if (v.nextAddr = dataR.firstAddr) then + v.firstAddr := dataR.firstAddr + 1; + v.armed := '1'; + end if; + + -- Calculate the length of the buffer + v.bufferLength := dataR.nextAddr - dataR.firstAddr; + + end if; + + -- Check for a trigger event to stop the logging + if (extTrig = '1') or (softTrigSync = '1') then + + -- Stop the logging in the ring buffer + v.enable := '0'; + + -- Make a read request event + v.readReq := '1'; + end if; - -- Calculate the length of the buffer - v.bufferLength := dataR.nextAddr - dataR.firstAddr; - end if; - -- Check for read request event - if (dataR.enable = '1') and (v.enable = '0') then - v.readReq := '1'; end if; -- Synchronous Reset @@ -354,21 +344,18 @@ begin generic map ( TPD_G => TPD_G, RST_ASYNC_G => RST_ASYNC_G, - WIDTH_G => 2) + WIDTH_G => 1) port map ( clk => axilClk, rst => axilRst, - dataIn(0) => dataR.cleared, - dataIn(1) => dataR.armed, - dataOut(0) => cleared, - dataOut(1) => armed); + dataIn(0) => dataR.armed, + dataOut(0) => armed); ------------------------ -- Main AXI-Lite process ------------------------ axiComb : process (armed, axilR, axilReadMaster, axilRst, axilWriteMaster, - bufferLength, cleared, firstAddr, ramRdData, readReq, - txSlave) is + bufferLength, firstAddr, ramRdData, readReq, txSlave) is variable v : AxilRegType; variable axilEp : AxiLiteEndpointType; begin @@ -401,44 +388,30 @@ begin case axilR.trigState is ---------------------------------------------------------------------- when IDLE_S => - -- Check for trigger request + -- Check for software trigger request if ((axilR.trigCnt /= 0) or (axilR.continuous = '1')) and (axilR.dataState = IDLE_S) then - -- Set the flags - v.bufferEnable := '1'; - v.bufferClear := '1'; + -- Check if we need to decrement the counter if (axilR.trigCnt /= 0) then -- Decrement the counter v.trigCnt := axilR.trigCnt - 1; end if; + -- Next state - v.trigState := CLEAR_S; - else - -- Reset the flag - v.bufferEnable := '0'; - end if; - ---------------------------------------------------------------------- - when CLEAR_S => - -- Check if cleared - if (cleared = '1') then - -- Set the flag - v.bufferEnable := '1'; - -- Next state - v.trigState := ARMED_S; + v.trigState := ARMED_S; + end if; ---------------------------------------------------------------------- when ARMED_S => -- Check if armed if (armed = '1') then - -- Set the flag - v.bufferEnable := '0'; -- Next state - v.trigState := WAIT_S; + v.trigState := WAIT_S; end if; ---------------------------------------------------------------------- when WAIT_S => - -- Set the flag - v.bufferEnable := '0'; + -- Hold the trigger until cleared by (axilR.dataState = IDLE_S) + v.softTrig := '1'; ---------------------------------------------------------------------- end case; @@ -465,6 +438,9 @@ begin -- Check for trigger event if (readReq = '1') then + -- Reset the flag + v.softTrig := '0'; + -- Next state v.dataState := MOVE_S; @@ -495,9 +471,8 @@ begin -- Set the clear flag v.bufferClear := '1'; - -- Next states - v.dataState := IDLE_S; - v.trigState := IDLE_S; + -- Next state + v.dataState := CLEARED_S; else -- Increment the counter @@ -505,6 +480,14 @@ begin end if; end if; + ---------------------------------------------------------------------- + when CLEARED_S => + -- Check if armed de-asserted + if (armed = '0') then + -- Next states + v.dataState := IDLE_S; + v.trigState := IDLE_S; + end if; ---------------------------------------------------------------------- end case; diff --git a/axi/axi-stream/tb/AxiStreamRingBufferTb.vhd b/axi/axi-stream/tb/AxiStreamRingBufferTb.vhd new file mode 100644 index 0000000000..05d14f35db --- /dev/null +++ b/axi/axi-stream/tb/AxiStreamRingBufferTb.vhd @@ -0,0 +1,153 @@ +------------------------------------------------------------------------------- +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: Simulation Testbed for testing the AxiStreamRingBuffer 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; + +library surf; +use surf.StdRtlPkg.all; +use surf.AxiLitePkg.all; +use surf.AxiStreamPkg.all; +use surf.SsiPkg.all; + +entity AxiStreamRingBufferTb is end AxiStreamRingBufferTb; + +architecture testbed of AxiStreamRingBufferTb is + + constant CLK_PERIOD_C : time := 10 ns; + constant TPD_C : time := CLK_PERIOD_C/4; + + constant AXIS_CONFIG_C : AxiStreamConfigType := ssiAxiStreamConfig(dataBytes => 2); + + type RegType is record + extTrig : sl; + data : slv(15 downto 0); + cnt : slv(11 downto 0); + end record; + + constant REG_INIT_C : RegType := ( + extTrig => '0', + data => (others => '0'), + cnt => (others => '0')); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; + + signal clk : sl := '0'; + signal rst : sl := '1'; + + signal axilWriteMaster : AxiLiteWriteMasterType := AXI_LITE_WRITE_MASTER_INIT_C; + signal axilWriteSlave : AxiLiteWriteSlaveType := AXI_LITE_WRITE_SLAVE_INIT_C; + signal axilReadMaster : AxiLiteReadMasterType := AXI_LITE_READ_MASTER_INIT_C; + signal axilReadSlave : AxiLiteReadSlaveType := AXI_LITE_READ_SLAVE_INIT_C; + + signal axisMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal axisSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; + +begin + + --------------------------- + -- Generate clock and reset + --------------------------- + U_ClkRst : entity surf.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) + port map ( + clkP => clk, + clkN => open, + rst => rst, + rstL => open); + + -------------------------- + -- Design Under Test (DUT) + -------------------------- + U_DUT : entity surf.AxiStreamRingBuffer + generic map ( + TPD_G => TPD_C, + COMMON_CLK_G => true, -- true if dataClk=axilClk + DATA_BYTES_G => 2, -- 16-bit data + RAM_ADDR_WIDTH_G => 10, -- 1k samples deep + -- AXI Stream Configurations + GEN_SYNC_FIFO_G => true, -- true if axisClk=axilClk + AXI_STREAM_CONFIG_G => AXIS_CONFIG_C) + port map ( + -- Data to store in ring buffer (dataClk domain) + dataClk => clk, + dataValue => r.data, + extTrig => r.extTrig, + -- AXI-Lite interface (axilClk domain) + axilClk => clk, + axilRst => rst, + axilReadMaster => axilReadMaster, + axilReadSlave => axilReadSlave, + axilWriteMaster => axilWriteMaster, + axilWriteSlave => axilWriteSlave, + -- AXI-Stream Interface (axilClk domain) + axisClk => clk, + axisRst => rst, + axisMaster => axisMaster, + axisSlave => axisSlave); + + comb : process (r, rst) is + variable v : RegType; + begin + -- Latch the current value + v := r; + + -- Reset the strobes + v.extTrig := '0'; + + -- Check if increment the counter + if (r.cnt /= x"FFF") then + + -- Increment the counter + v.cnt := r.cnt + 1; + + -- Check if making data pattern + if r.cnt < 1024 then + v.data := r.data + 1; + else + v.data := (others => '0'); + end if; + + -- check for the trigger event + if (r.cnt = 1111) then + -- Set the flag + v.extTrig := '1'; + end if; + + end if; + + -- Synchronous Reset + if (rst = '1') then + v := REG_INIT_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_C; + end if; + end process seq; + +end testbed; diff --git a/devices/AnalogDevices/ruckus.tcl b/devices/AnalogDevices/ruckus.tcl index 0e92b6ce04..b77afd7118 100644 --- a/devices/AnalogDevices/ruckus.tcl +++ b/devices/AnalogDevices/ruckus.tcl @@ -13,5 +13,5 @@ if { $::env(VIVADO_VERSION) > 0.0} { # AD9249 sim model requires ClockManager7 loadSource -lib surf -path "$::DIR_PATH/../../xilinx/7Series/general/rtl/ClockManager7.vhd" - loadSource -lib surf -path "$::DIR_PATH/../../xilinx/7Series/general/rtl/ClockManager7Pkg.vhd" + loadSource -lib surf -path "$::DIR_PATH/../../xilinx/7Series/general/rtl/ClockManager7Pkg.vhd" }