DEVEL: First open source release
This commit is contained in:
455
hdl/psi_ms_daq_axi.vhd
Normal file
455
hdl/psi_ms_daq_axi.vhd
Normal file
@ -0,0 +1,455 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2019 by Paul Scherrer Institute, Switzerland
|
||||
-- All rights reserved.
|
||||
-- Authors: Oliver Bruendler
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Libraries
|
||||
------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.psi_common_math_pkg.all;
|
||||
use work.psi_common_array_pkg.all;
|
||||
use work.psi_ms_daq_pkg.all;
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Entity Declaration
|
||||
------------------------------------------------------------------------------
|
||||
entity psi_ms_daq_axi is
|
||||
generic (
|
||||
-- Streams
|
||||
Streams_g : positive range 1 to 32 := 2;
|
||||
StreamWidth_g : t_ainteger := (16, 16);
|
||||
StreamPrio_g : t_ainteger := (1, 1);
|
||||
StreamBuffer_g : t_ainteger := (1024, 1024);
|
||||
StreamTimeout_g : t_areal := (1.0e-3, 1.0e-3);
|
||||
StreamClkFreq_g : t_areal := (100.0e6, 100.0e6);
|
||||
StreamTsFifoDepth_g : t_ainteger := (16, 16);
|
||||
StreamUseTs_g : t_abool := (true, true);
|
||||
-- Recording
|
||||
MaxWindows_g : positive range 1 to 32 := 16;
|
||||
MinBurstSize_g : integer range 1 to 512 := 512;
|
||||
MaxBurstSize_g : integer range 1 to 512 := 512;
|
||||
-- Axi
|
||||
AxiDataWidth_g : natural range 64 to 1024 := 64;
|
||||
AxiMaxBurstBeats_g : integer range 1 to 256 := 256;
|
||||
AxiMaxOpenTrasactions_g : natural range 1 to 8 := 8;
|
||||
AxiFifoDepth_g : natural := 1024;
|
||||
-- Axi Slave
|
||||
AxiSlaveIdWidth_g : integer := 0
|
||||
);
|
||||
port (
|
||||
-- Data Stream Input
|
||||
Str_Clk : in std_logic_vector(Streams_g-1 downto 0);
|
||||
Str_Data : in t_aslv64(Streams_g-1 downto 0);
|
||||
Str_Ts : in t_aslv64(Streams_g-1 downto 0);
|
||||
Str_Vld : in std_logic_vector(Streams_g-1 downto 0);
|
||||
Str_Rdy : out std_logic_vector(Streams_g-1 downto 0);
|
||||
Str_Trig : in std_logic_vector(Streams_g-1 downto 0);
|
||||
|
||||
-- Miscellaneous
|
||||
Irq : out std_logic;
|
||||
|
||||
-- AXI Slave Interface for Register Access
|
||||
S_Axi_Aclk : in std_logic;
|
||||
S_Axi_Aresetn : in std_logic;
|
||||
S_Axi_ArId : in std_logic_vector(AxiSlaveIdWidth_g-1 downto 0);
|
||||
S_Axi_ArAddr : in std_logic_vector(15 downto 0);
|
||||
S_Axi_Arlen : in std_logic_vector(7 downto 0);
|
||||
S_Axi_ArSize : in std_logic_vector(2 downto 0);
|
||||
S_Axi_ArBurst : in std_logic_vector(1 downto 0);
|
||||
S_Axi_ArLock : in std_logic;
|
||||
S_Axi_ArCache : in std_logic_vector(3 downto 0);
|
||||
S_Axi_ArProt : in std_logic_vector(2 downto 0);
|
||||
S_Axi_ArValid : in std_logic;
|
||||
S_Axi_ArReady : out std_logic;
|
||||
S_Axi_RId : out std_logic_vector(AxiSlaveIdWidth_g-1 downto 0);
|
||||
S_Axi_RData : out std_logic_vector(31 downto 0);
|
||||
S_Axi_RResp : out std_logic_vector(1 downto 0);
|
||||
S_Axi_RLast : out std_logic;
|
||||
S_Axi_RValid : out std_logic;
|
||||
S_Axi_RReady : in std_logic;
|
||||
S_Axi_AwId : in std_logic_vector(AxiSlaveIdWidth_g-1 downto 0);
|
||||
S_Axi_AwAddr : in std_logic_vector(15 downto 0);
|
||||
S_Axi_AwLen : in std_logic_vector(7 downto 0);
|
||||
S_Axi_AwSize : in std_logic_vector(2 downto 0);
|
||||
S_Axi_AwBurst : in std_logic_vector(1 downto 0);
|
||||
S_Axi_AwLock : in std_logic;
|
||||
S_Axi_AwCache : in std_logic_vector(3 downto 0);
|
||||
S_Axi_AwProt : in std_logic_vector(2 downto 0);
|
||||
S_Axi_AwValid : in std_logic;
|
||||
S_Axi_AwReady : out std_logic;
|
||||
S_Axi_WData : in std_logic_vector(31 downto 0);
|
||||
S_Axi_WStrb : in std_logic_vector(3 downto 0);
|
||||
S_Axi_WLast : in std_logic;
|
||||
S_Axi_WValid : in std_logic;
|
||||
S_Axi_WReady : out std_logic;
|
||||
S_Axi_BId : out std_logic_vector(AxiSlaveIdWidth_g-1 downto 0);
|
||||
S_Axi_BResp : out std_logic_vector(1 downto 0);
|
||||
S_Axi_BValid : out std_logic;
|
||||
S_Axi_BReady : in std_logic;
|
||||
|
||||
-- AXI Master Interface for Memory Access
|
||||
M_Axi_Aclk : in std_logic;
|
||||
M_Axi_Aresetn : in std_logic;
|
||||
M_Axi_AwAddr : out std_logic_vector(31 downto 0);
|
||||
M_Axi_AwLen : out std_logic_vector(7 downto 0);
|
||||
M_Axi_AwSize : out std_logic_vector(2 downto 0);
|
||||
M_Axi_AwBurst : out std_logic_vector(1 downto 0);
|
||||
M_Axi_AwLock : out std_logic;
|
||||
M_Axi_AwCache : out std_logic_vector(3 downto 0);
|
||||
M_Axi_AwProt : out std_logic_vector(2 downto 0);
|
||||
M_Axi_AwValid : out std_logic;
|
||||
M_Axi_AwReady : in std_logic := '0';
|
||||
M_Axi_WData : out std_logic_vector(AxiDataWidth_g-1 downto 0);
|
||||
M_Axi_WStrb : out std_logic_vector(AxiDataWidth_g/8-1 downto 0);
|
||||
M_Axi_WLast : out std_logic;
|
||||
M_Axi_WValid : out std_logic;
|
||||
M_Axi_WReady : in std_logic := '0';
|
||||
M_Axi_BResp : in std_logic_vector(1 downto 0) := (others => '0');
|
||||
M_Axi_BValid : in std_logic := '0';
|
||||
M_Axi_BReady : out std_logic;
|
||||
M_Axi_ArAddr : out std_logic_vector(31 downto 0);
|
||||
M_Axi_ArLen : out std_logic_vector(7 downto 0);
|
||||
M_Axi_ArSize : out std_logic_vector(2 downto 0);
|
||||
M_Axi_ArBurst : out std_logic_vector(1 downto 0);
|
||||
M_Axi_ArLock : out std_logic;
|
||||
M_Axi_ArCache : out std_logic_vector(3 downto 0);
|
||||
M_Axi_ArProt : out std_logic_vector(2 downto 0);
|
||||
M_Axi_ArValid : out std_logic;
|
||||
M_Axi_ArReady : in std_logic := '0';
|
||||
M_Axi_RData : in std_logic_vector(AxiDataWidth_g-1 downto 0) := (others => '0');
|
||||
M_Axi_RResp : in std_logic_vector(1 downto 0) := (others => '0');
|
||||
M_Axi_RLast : in std_logic := '0';
|
||||
M_Axi_RValid : in std_logic := '0';
|
||||
M_Axi_RReady : out std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Architecture Declaration
|
||||
------------------------------------------------------------------------------
|
||||
architecture rtl of psi_ms_daq_axi is
|
||||
|
||||
-- Config Arrays with correct size
|
||||
constant StreamWidth_c : t_ainteger(0 to Streams_g-1) := StreamWidth_g(0 to Streams_g-1);
|
||||
constant StreamPrio_c : t_ainteger(0 to Streams_g-1) := StreamPrio_g(0 to Streams_g-1);
|
||||
constant StreamBuffer_c : t_ainteger(0 to Streams_g-1) := StreamBuffer_g(0 to Streams_g-1);
|
||||
constant StreamTimeout_c : t_areal(0 to Streams_g-1) := StreamTimeout_g(0 to Streams_g-1);
|
||||
constant StreamClkFreq_c : t_areal(0 to Streams_g-1) := StreamClkFreq_g(0 to Streams_g-1);
|
||||
constant StreamTsFifoDepth_c : t_ainteger(0 to Streams_g-1) := StreamTsFifoDepth_g(0 to Streams_g-1);
|
||||
constant StreamUseTs_c : t_abool(0 to Streams_g-1) := StreamUseTs_g(0 to Streams_g-1);
|
||||
|
||||
-- Input/Statemachine Signals
|
||||
signal InpSm_HasTlast : std_logic_vector(Streams_g-1 downto 0);
|
||||
signal InpSm_TsVld : std_logic_vector(Streams_g-1 downto 0);
|
||||
signal InpSm_TsRdy : std_logic_vector(Streams_g-1 downto 0);
|
||||
signal InpSm_Level : t_aslv16(Streams_g-1 downto 0);
|
||||
signal InpSm_TsData : t_aslv64(Streams_g-1 downto 0);
|
||||
|
||||
-- Statemachine/Dma
|
||||
signal SmDma_Cmd : DaqSm2DaqDma_Cmd_t;
|
||||
signal SmDma_CmdVld : std_logic;
|
||||
signal DmaSm_Resp : DaqDma2DaqSm_Resp_t;
|
||||
signal DmaSm_RespVld : std_logic;
|
||||
signal DmaSm_RespRdy : std_logic;
|
||||
signal DmaSm_HasLast : std_logic_vector(Streams_g-1 downto 0);
|
||||
|
||||
-- Input/Dma
|
||||
signal InpDma_Vld : std_logic_vector(Streams_g-1 downto 0);
|
||||
signal InpDma_Rdy : std_logic_vector(Streams_g-1 downto 0);
|
||||
signal InpDma_Data : Input2Daq_Data_a(Streams_g-1 downto 0);
|
||||
|
||||
-- Dma/Mem
|
||||
signal DmaMem_CmdAddr : std_logic_vector(31 downto 0);
|
||||
signal DmaMem_CmdSize : std_logic_vector(31 downto 0);
|
||||
signal DmaMem_CmdVld : std_logic;
|
||||
signal DmaMem_CmdRdy : std_logic;
|
||||
signal DmaMem_DatData : std_logic_vector(63 downto 0);
|
||||
signal DmaMem_DatVld : std_logic;
|
||||
signal DmaMem_DatRdy : std_logic;
|
||||
|
||||
-- Mem/Statemachine
|
||||
signal MemSm_Done : std_logic;
|
||||
|
||||
-- Configuration
|
||||
signal Cfg_StrEna : std_logic_vector(Streams_g-1 downto 0);
|
||||
signal Cfg_GlbEna : std_logic;
|
||||
signal Cfg_PostTrig : t_aslv32(Streams_g-1 downto 0);
|
||||
signal Cfg_Arm : std_logic_vector(Streams_g-1 downto 0);
|
||||
signal Cfg_RecMode : t_aslv2(Streams_g-1 downto 0);
|
||||
|
||||
-- Status
|
||||
signal Stat_StrIrq : std_logic_vector(Streams_g-1 downto 0);
|
||||
signal Stat_StrLastWin : WinType_a(Streams_g-1 downto 0);
|
||||
signal Stat_IsArmed : std_logic_vector(Streams_g-1 downto 0);
|
||||
signal Stat_IsRecording : std_logic_vector(Streams_g-1 downto 0);
|
||||
|
||||
-- Context Memory Connections
|
||||
signal CtxStr_Cmd : ToCtxStr_t;
|
||||
signal CtxStr_Resp : FromCtx_t;
|
||||
signal CtxWin_Cmd : ToCtxWin_t;
|
||||
signal CtxWin_Resp : FromCtx_t;
|
||||
|
||||
-- Others
|
||||
signal Sm_HasLast : std_logic_vector(Streams_g-1 downto 0);
|
||||
signal M_Axi_Areset : std_logic; -- high active reset
|
||||
signal S_Axi_Areset : std_logic; -- high active reset
|
||||
|
||||
begin
|
||||
|
||||
M_Axi_Areset <= not M_Axi_Aresetn;
|
||||
S_Axi_Areset <= not S_Axi_Aresetn;
|
||||
|
||||
--------------------------------------------
|
||||
-- Register Interface
|
||||
--------------------------------------------
|
||||
i_reg : entity work.psi_ms_daq_reg_axi
|
||||
generic map (
|
||||
Streams_g => Streams_g,
|
||||
MaxWindows_g => MaxWindows_g,
|
||||
AxiSlaveIdWidth_g => AxiSlaveIdWidth_g
|
||||
)
|
||||
port map (
|
||||
S_Axi_Aclk => S_Axi_Aclk,
|
||||
S_Axi_Aresetn => S_Axi_Aresetn,
|
||||
S_Axi_ArId => S_Axi_ArId,
|
||||
S_Axi_ArAddr => S_Axi_ArAddr,
|
||||
S_Axi_Arlen => S_Axi_Arlen,
|
||||
S_Axi_ArSize => S_Axi_ArSize,
|
||||
S_Axi_ArBurst => S_Axi_ArBurst,
|
||||
S_Axi_ArLock => S_Axi_ArLock,
|
||||
S_Axi_ArCache => S_Axi_ArCache,
|
||||
S_Axi_ArProt => S_Axi_ArProt,
|
||||
S_Axi_ArValid => S_Axi_ArValid,
|
||||
S_Axi_ArReady => S_Axi_ArReady,
|
||||
S_Axi_RId => S_Axi_RId,
|
||||
S_Axi_RData => S_Axi_RData,
|
||||
S_Axi_RResp => S_Axi_RResp,
|
||||
S_Axi_RLast => S_Axi_RLast,
|
||||
S_Axi_RValid => S_Axi_RValid,
|
||||
S_Axi_RReady => S_Axi_RReady,
|
||||
S_Axi_AwId => S_Axi_AwId,
|
||||
S_Axi_AwAddr => S_Axi_AwAddr,
|
||||
S_Axi_AwLen => S_Axi_AwLen,
|
||||
S_Axi_AwSize => S_Axi_AwSize,
|
||||
S_Axi_AwBurst => S_Axi_AwBurst,
|
||||
S_Axi_AwLock => S_Axi_AwLock,
|
||||
S_Axi_AwCache => S_Axi_AwCache,
|
||||
S_Axi_AwProt => S_Axi_AwProt,
|
||||
S_Axi_AwValid => S_Axi_AwValid,
|
||||
S_Axi_AwReady => S_Axi_AwReady,
|
||||
S_Axi_WData => S_Axi_WData,
|
||||
S_Axi_WStrb => S_Axi_WStrb,
|
||||
S_Axi_WLast => S_Axi_WLast,
|
||||
S_Axi_WValid => S_Axi_WValid,
|
||||
S_Axi_WReady => S_Axi_WReady,
|
||||
S_Axi_BId => S_Axi_BId,
|
||||
S_Axi_BResp => S_Axi_BResp,
|
||||
S_Axi_BValid => S_Axi_BValid,
|
||||
S_Axi_BReady => S_Axi_BReady,
|
||||
IrqOut => Irq,
|
||||
PostTrig => Cfg_PostTrig,
|
||||
Arm => Cfg_Arm,
|
||||
IsArmed => Stat_IsArmed,
|
||||
IsRecording => Stat_IsRecording,
|
||||
RecMode => Cfg_RecMode,
|
||||
ClkMem => M_Axi_Aclk,
|
||||
RstMem => M_Axi_Areset,
|
||||
CtxStr_Cmd => CtxStr_Cmd,
|
||||
CtxStr_Resp => CtxStr_Resp,
|
||||
CtxWin_Cmd => CtxWin_Cmd,
|
||||
CtxWin_Resp => CtxWin_Resp,
|
||||
InLevel => InpSm_Level,
|
||||
StrIrq => Stat_StrIrq,
|
||||
StrLastWin => Stat_StrLastWin,
|
||||
StrEna => Cfg_StrEna,
|
||||
GlbEna => Cfg_GlbEna
|
||||
);
|
||||
|
||||
--------------------------------------------
|
||||
-- Input Logic Instantiation
|
||||
--------------------------------------------
|
||||
g_input : for str in 0 to Streams_g-1 generate
|
||||
signal InRst : std_logic;
|
||||
signal StrInput : std_logic_vector(StreamWidth_c(str)-1 downto 0);
|
||||
begin
|
||||
-- Reset if stream is disabled
|
||||
InRst <= M_Axi_Areset or not Cfg_StrEna(str) or not Cfg_GlbEna;
|
||||
StrInput <= Str_Data(str)(StrInput'range);
|
||||
|
||||
-- Instantiation
|
||||
i_input : entity work.psi_ms_daq_input
|
||||
generic map (
|
||||
StreamWidth_g => StreamWidth_c(str),
|
||||
StreamBuffer_g => StreamBuffer_c(str),
|
||||
StreamTimeout_g => StreamTimeout_c(str),
|
||||
StreamClkFreq_g => StreamClkFreq_c(str),
|
||||
StreamTsFifoDepth_g => StreamTsFifoDepth_c(str),
|
||||
StreamUseTs_g => StreamUseTs_c(str)
|
||||
)
|
||||
port map (
|
||||
Str_Clk => Str_Clk(str),
|
||||
Str_Vld => Str_Vld(str),
|
||||
Str_Rdy => Str_Rdy(str),
|
||||
Str_Data => StrInput,
|
||||
Str_Trig => Str_Trig(str),
|
||||
Str_Ts => Str_Ts(str),
|
||||
ClkReg => S_Axi_Aclk,
|
||||
RstReg => S_Axi_Areset,
|
||||
PostTrigSpls => Cfg_PostTrig(str),
|
||||
Mode => Cfg_RecMode(str),
|
||||
Arm => Cfg_Arm(str),
|
||||
IsArmed => Stat_IsArmed(str),
|
||||
IsRecording => Stat_IsRecording(str),
|
||||
ClkMem => M_Axi_Aclk,
|
||||
RstMem => InRst,
|
||||
Daq_Vld => InpDma_Vld(str),
|
||||
Daq_Rdy => InpDma_Rdy(str),
|
||||
Daq_Data => InpDma_Data(str),
|
||||
Daq_Level => InpSm_Level(str),
|
||||
Daq_HasLast => InpSm_HasTlast(str),
|
||||
Ts_Vld => InpSm_TsVld(str),
|
||||
Ts_Rdy => InpSm_TsRdy(str),
|
||||
Ts_Data => InpSm_TsData(str)
|
||||
);
|
||||
end generate;
|
||||
|
||||
--------------------------------------------
|
||||
-- Control State Machine
|
||||
--------------------------------------------
|
||||
-- Detect end-of frame in input buffer or DMA buffer
|
||||
Sm_HasLast <= InpSm_HasTlast or DmaSm_HasLast;
|
||||
|
||||
-- Instantiation
|
||||
i_statemachine : entity work.psi_ms_daq_daq_sm
|
||||
generic map (
|
||||
Streams_g => Streams_g,
|
||||
StreamPrio_g => StreamPrio_c,
|
||||
StreamWidth_g => StreamWidth_c,
|
||||
Windows_g => MaxWindows_g,
|
||||
MinBurstSize_g => MinBurstSize_g,
|
||||
MaxBurstSize_g => MaxBurstSize_g
|
||||
)
|
||||
port map (
|
||||
Clk => M_Axi_Aclk,
|
||||
Rst => M_Axi_Areset,
|
||||
GlbEna => Cfg_GlbEna,
|
||||
StrEna => Cfg_StrEna,
|
||||
StrIrq => Stat_StrIrq,
|
||||
StrLastWin => Stat_StrLastWin,
|
||||
Inp_HasLast => Sm_HasLast,
|
||||
Inp_Level => InpSm_Level,
|
||||
Ts_Vld => InpSm_TsVld,
|
||||
Ts_Rdy => InpSm_TsRdy,
|
||||
Ts_Data => InpSm_TsData,
|
||||
Dma_Cmd => SmDma_Cmd,
|
||||
Dma_Cmd_Vld => SmDma_CmdVld,
|
||||
Dma_Resp => DmaSm_Resp,
|
||||
Dma_Resp_Vld => DmaSm_RespVld,
|
||||
Dma_Resp_Rdy => DmaSm_RespRdy,
|
||||
TfDone => MemSm_Done,
|
||||
|
||||
-- Context RAM connections
|
||||
CtxStr_Cmd => CtxStr_Cmd,
|
||||
CtxStr_Resp => CtxStr_Resp,
|
||||
CtxWin_Cmd => CtxWin_Cmd,
|
||||
CtxWin_Resp => CtxWin_Resp
|
||||
);
|
||||
|
||||
--------------------------------------------
|
||||
-- DMA Engine
|
||||
--------------------------------------------
|
||||
i_dma : entity work.psi_ms_daq_daq_dma
|
||||
generic map (
|
||||
Streams_g => Streams_g
|
||||
)
|
||||
port map (
|
||||
Clk => M_Axi_Aclk,
|
||||
Rst => M_Axi_Areset,
|
||||
DaqSm_Cmd => SmDma_Cmd,
|
||||
DaqSm_Cmd_Vld => SmDma_CmdVld,
|
||||
DaqSm_Resp => DmaSm_Resp,
|
||||
DaqSm_Resp_Vld => DmaSm_RespVld,
|
||||
DaqSm_Resp_Rdy => DmaSm_RespRdy,
|
||||
DaqSm_HasLast => DmaSm_HasLast,
|
||||
Inp_Vld => InpDma_Vld,
|
||||
Inp_Rdy => InpDma_Rdy,
|
||||
Inp_Data => InpDma_Data,
|
||||
Mem_CmdAddr => DmaMem_CmdAddr,
|
||||
Mem_CmdSize => DmaMem_CmdSize,
|
||||
Mem_CmdVld => DmaMem_CmdVld,
|
||||
Mem_CmdRdy => DmaMem_CmdRdy,
|
||||
Mem_DatData => DmaMem_DatData,
|
||||
Mem_DatVld => DmaMem_DatVld,
|
||||
Mem_DatRdy => DmaMem_DatRdy
|
||||
);
|
||||
|
||||
--------------------------------------------
|
||||
-- Memory Interface
|
||||
--------------------------------------------
|
||||
i_memif : entity work.psi_ms_daq_axi_if
|
||||
generic map (
|
||||
AxiDataWidth_g => AxiDataWidth_g,
|
||||
AxiMaxBeats_g => AxiMaxBurstBeats_g,
|
||||
AxiMaxOpenTrasactions_g => AxiMaxOpenTrasactions_g,
|
||||
MaxOpenCommands_g => Streams_g,
|
||||
DataFifoDepth_g => 1024,
|
||||
AxiFifoDepth_g => AxiFifoDepth_g,
|
||||
RamBehavior_g => "RBW" -- Okay for Xilinx chips
|
||||
)
|
||||
port map (
|
||||
Clk => M_Axi_Aclk,
|
||||
Rst_n => M_Axi_Aresetn,
|
||||
Cmd_Addr => DmaMem_CmdAddr,
|
||||
Cmd_Size => DmaMem_CmdSize,
|
||||
Cmd_Vld => DmaMem_CmdVld,
|
||||
Cmd_Rdy => DmaMem_CmdRdy,
|
||||
Dat_Data => DmaMem_DatData,
|
||||
Dat_Vld => DmaMem_DatVld,
|
||||
Dat_Rdy => DmaMem_DatRdy,
|
||||
Done => MemSm_Done,
|
||||
M_Axi_AwAddr => M_Axi_AwAddr,
|
||||
M_Axi_AwLen => M_Axi_AwLen,
|
||||
M_Axi_AwSize => M_Axi_AwSize,
|
||||
M_Axi_AwBurst => M_Axi_AwBurst,
|
||||
M_Axi_AwLock => M_Axi_AwLock,
|
||||
M_Axi_AwCache => M_Axi_AwCache,
|
||||
M_Axi_AwProt => M_Axi_AwProt,
|
||||
M_Axi_AwValid => M_Axi_AwValid,
|
||||
M_Axi_AwReady => M_Axi_AwReady,
|
||||
M_Axi_WData => M_Axi_WData,
|
||||
M_Axi_WStrb => M_Axi_WStrb,
|
||||
M_Axi_WLast => M_Axi_WLast,
|
||||
M_Axi_WValid => M_Axi_WValid,
|
||||
M_Axi_WReady => M_Axi_WReady,
|
||||
M_Axi_BResp => M_Axi_BResp,
|
||||
M_Axi_BValid => M_Axi_BValid,
|
||||
M_Axi_BReady => M_Axi_BReady,
|
||||
M_Axi_ArAddr => M_Axi_ArAddr,
|
||||
M_Axi_ArLen => M_Axi_ArLen,
|
||||
M_Axi_ArSize => M_Axi_ArSize,
|
||||
M_Axi_ArBurst => M_Axi_ArBurst,
|
||||
M_Axi_ArLock => M_Axi_ArLock,
|
||||
M_Axi_ArCache => M_Axi_ArCache,
|
||||
M_Axi_ArProt => M_Axi_ArProt,
|
||||
M_Axi_ArValid => M_Axi_ArValid,
|
||||
M_Axi_ArReady => M_Axi_ArReady,
|
||||
M_Axi_RData => M_Axi_RData,
|
||||
M_Axi_RResp => M_Axi_RResp,
|
||||
M_Axi_RLast => M_Axi_RLast,
|
||||
M_Axi_RValid => M_Axi_RValid,
|
||||
M_Axi_RReady => M_Axi_RReady
|
||||
);
|
||||
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
|
224
hdl/psi_ms_daq_axi_if.vhd
Normal file
224
hdl/psi_ms_daq_axi_if.vhd
Normal file
@ -0,0 +1,224 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2019 by Paul Scherrer Institute, Switzerland
|
||||
-- All rights reserved.
|
||||
-- Authors: Oliver Bruendler
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Libraries
|
||||
------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.psi_common_math_pkg.all;
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Entity Declaration
|
||||
------------------------------------------------------------------------------
|
||||
entity psi_ms_daq_axi_if is
|
||||
generic (
|
||||
AxiDataWidth_g : natural range 64 to 1024 := 64;
|
||||
AxiMaxBeats_g : natural range 1 to 256 := 256;
|
||||
AxiMaxOpenTrasactions_g : natural range 1 to 8 := 8;
|
||||
MaxOpenCommands_g : positive := 16;
|
||||
DataFifoDepth_g : natural := 1024;
|
||||
AxiFifoDepth_g : natural := 1024;
|
||||
RamBehavior_g : string := "RBW"
|
||||
);
|
||||
port (
|
||||
-- Control Signals
|
||||
Clk : in std_logic;
|
||||
Rst_n : in std_logic;
|
||||
|
||||
-- Write Command
|
||||
Cmd_Addr : in std_logic_vector(31 downto 0);
|
||||
Cmd_Size : in std_logic_vector(31 downto 0);
|
||||
Cmd_Vld : in std_logic;
|
||||
Cmd_Rdy : out std_logic;
|
||||
|
||||
-- Write Data
|
||||
Dat_Data : in std_logic_vector(63 downto 0);
|
||||
Dat_Vld : in std_logic;
|
||||
Dat_Rdy : out std_logic;
|
||||
|
||||
-- Response
|
||||
Done : out std_logic;
|
||||
|
||||
-- AXI Address Write Channel
|
||||
M_Axi_AwAddr : out std_logic_vector(31 downto 0);
|
||||
M_Axi_AwLen : out std_logic_vector(7 downto 0);
|
||||
M_Axi_AwSize : out std_logic_vector(2 downto 0);
|
||||
M_Axi_AwBurst : out std_logic_vector(1 downto 0);
|
||||
M_Axi_AwLock : out std_logic;
|
||||
M_Axi_AwCache : out std_logic_vector(3 downto 0);
|
||||
M_Axi_AwProt : out std_logic_vector(2 downto 0);
|
||||
M_Axi_AwValid : out std_logic;
|
||||
M_Axi_AwReady : in std_logic := '0';
|
||||
|
||||
-- AXI Write Data Channel
|
||||
M_Axi_WData : out std_logic_vector(AxiDataWidth_g-1 downto 0);
|
||||
M_Axi_WStrb : out std_logic_vector(AxiDataWidth_g/8-1 downto 0);
|
||||
M_Axi_WLast : out std_logic;
|
||||
M_Axi_WValid : out std_logic;
|
||||
M_Axi_WReady : in std_logic := '0';
|
||||
|
||||
-- AXI Write Response Channel
|
||||
M_Axi_BResp : in std_logic_vector(1 downto 0) := (others => '0');
|
||||
M_Axi_BValid : in std_logic := '0';
|
||||
M_Axi_BReady : out std_logic;
|
||||
|
||||
-- AXI Read Address Channel
|
||||
M_Axi_ArAddr : out std_logic_vector(31 downto 0);
|
||||
M_Axi_ArLen : out std_logic_vector(7 downto 0);
|
||||
M_Axi_ArSize : out std_logic_vector(2 downto 0);
|
||||
M_Axi_ArBurst : out std_logic_vector(1 downto 0);
|
||||
M_Axi_ArLock : out std_logic;
|
||||
M_Axi_ArCache : out std_logic_vector(3 downto 0);
|
||||
M_Axi_ArProt : out std_logic_vector(2 downto 0);
|
||||
M_Axi_ArValid : out std_logic;
|
||||
M_Axi_ArReady : in std_logic := '0';
|
||||
|
||||
-- AXI Read Data Channel
|
||||
M_Axi_RData : in std_logic_vector(AxiDataWidth_g-1 downto 0) := (others => '0');
|
||||
M_Axi_RResp : in std_logic_vector(1 downto 0) := (others => '0');
|
||||
M_Axi_RLast : in std_logic := '0';
|
||||
M_Axi_RValid : in std_logic := '0';
|
||||
M_Axi_RReady : out std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Architecture Declaration
|
||||
------------------------------------------------------------------------------
|
||||
architecture rtl of psi_ms_daq_axi_if is
|
||||
signal Rst : std_logic;
|
||||
|
||||
subtype CommandAddrRng_c is natural range 31 downto 0;
|
||||
subtype CommandSizeRng_c is natural range 63 downto 32;
|
||||
constant WrCmdWidth_c : integer := CommandSizeRng_c'high+1;
|
||||
signal InfoFifoIn : std_logic_vector(WrCmdWidth_c-1 downto 0);
|
||||
signal InfoFifoOut : std_logic_vector(WrCmdWidth_c-1 downto 0);
|
||||
signal WrCmdFifo_Vld : std_logic;
|
||||
signal WrCmdFifo_Rdy : std_logic;
|
||||
signal WrCmdFifo_Addr : std_logic_vector(31 downto 0);
|
||||
signal WrCmdFifo_Size : std_logic_vector(31 downto 0);
|
||||
signal DoneI : std_logic;
|
||||
signal ErrorI : std_logic;
|
||||
|
||||
begin
|
||||
Rst <= not Rst_n;
|
||||
|
||||
InfoFifoIn(CommandAddrRng_c) <= Cmd_Addr;
|
||||
InfoFifoIn(CommandSizeRng_c) <= Cmd_Size;
|
||||
|
||||
i_wrinfo_fifo : entity work.psi_common_sync_fifo
|
||||
generic map (
|
||||
Width_g => WrCmdWidth_c,
|
||||
Depth_g => MaxOpenCommands_g,
|
||||
RamStyle_g => "distributed"
|
||||
)
|
||||
port map (
|
||||
Clk => Clk,
|
||||
Rst => Rst,
|
||||
InData => InfoFifoIn,
|
||||
InVld => Cmd_Vld,
|
||||
InRdy => Cmd_Rdy,
|
||||
OutData => InfoFifoOut,
|
||||
OutVld => WrCmdFifo_Vld,
|
||||
OutRdy => WrCmdFifo_Rdy
|
||||
);
|
||||
|
||||
WrCmdFifo_Addr <= InfoFifoOut(CommandAddrRng_c);
|
||||
WrCmdFifo_Size <= InfoFifoOut(CommandSizeRng_c);
|
||||
|
||||
i_axi : entity work.psi_common_axi_master_full
|
||||
generic map (
|
||||
AxiAddrWidth_g => 32,
|
||||
AxiDataWidth_g => AxiDataWidth_g,
|
||||
AxiMaxBeats_g => AxiMaxBeats_g,
|
||||
AxiMaxOpenTrasactions_g => AxiMaxOpenTrasactions_g,
|
||||
UserTransactionSizeBits_g => 32,
|
||||
DataFifoDepth_g => DataFifoDepth_g,
|
||||
DataWidth_g => 64,
|
||||
ImplRead_g => false,
|
||||
ImplWrite_g => true,
|
||||
RamBehavior_g => RamBehavior_g
|
||||
)
|
||||
port map (
|
||||
-- Control Signals
|
||||
M_Axi_Aclk => Clk,
|
||||
M_Axi_Aresetn => Rst_n,
|
||||
-- User Command Interface Write
|
||||
CmdWr_Addr => WrCmdFifo_Addr,
|
||||
CmdWr_Size => WrCmdFifo_Size,
|
||||
CmdWr_LowLat => '0',
|
||||
CmdWr_Vld => WrCmdFifo_Vld,
|
||||
CmdWr_Rdy => WrCmdFifo_Rdy,
|
||||
-- User Command Interface Read (unused)
|
||||
CmdRd_Addr => (others => '0'),
|
||||
CmdRd_Size => (others => '0'),
|
||||
CmdRd_LowLat => '0',
|
||||
CmdRd_Vld => '0',
|
||||
CmdRd_Rdy => open,
|
||||
-- Write Data
|
||||
WrDat_Data => Dat_Data,
|
||||
WrDat_Vld => Dat_Vld,
|
||||
WrDat_Rdy => Dat_Rdy,
|
||||
-- Read Data (unused)
|
||||
RdDat_Data => open,
|
||||
RdDat_Vld => open,
|
||||
RdDat_Rdy => '0',
|
||||
-- Response
|
||||
Wr_Done => DoneI,
|
||||
Wr_Error => ErrorI,
|
||||
Rd_Done => open,
|
||||
Rd_Error => open,
|
||||
-- AXI Address Write Channel
|
||||
M_Axi_AwAddr => M_Axi_AwAddr,
|
||||
M_Axi_AwLen => M_Axi_AwLen,
|
||||
M_Axi_AwSize => M_Axi_AwSize,
|
||||
M_Axi_AwBurst => M_Axi_AwBurst,
|
||||
M_Axi_AwLock => M_Axi_AwLock,
|
||||
M_Axi_AwCache => M_Axi_AwCache,
|
||||
M_Axi_AwProt => M_Axi_AwProt,
|
||||
M_Axi_AwValid => M_Axi_AwValid,
|
||||
M_Axi_AwReady => M_Axi_AwReady,
|
||||
-- AXI Write Data Channel
|
||||
M_Axi_WData => M_Axi_WData,
|
||||
M_Axi_WStrb => M_Axi_WStrb,
|
||||
M_Axi_WLast => M_Axi_WLast,
|
||||
M_Axi_WValid => M_Axi_WValid,
|
||||
M_Axi_WReady => M_Axi_WReady,
|
||||
-- AXI Write Response Channel
|
||||
M_Axi_BResp => M_Axi_BResp,
|
||||
M_Axi_BValid => M_Axi_BValid,
|
||||
M_Axi_BReady => M_Axi_BReady,
|
||||
-- AXI Read Address Channel
|
||||
M_Axi_ArAddr => M_Axi_ArAddr,
|
||||
M_Axi_ArLen => M_Axi_ArLen,
|
||||
M_Axi_ArSize => M_Axi_ArSize,
|
||||
M_Axi_ArBurst => M_Axi_ArBurst,
|
||||
M_Axi_ArLock => M_Axi_ArLock,
|
||||
M_Axi_ArCache => M_Axi_ArCache,
|
||||
M_Axi_ArProt => M_Axi_ArProt,
|
||||
M_Axi_ArValid => M_Axi_ArValid,
|
||||
M_Axi_ArReady => M_Axi_ArReady,
|
||||
-- AXI Read Data Channel
|
||||
M_Axi_RData => M_Axi_RData,
|
||||
M_Axi_RResp => M_Axi_RResp,
|
||||
M_Axi_RLast => M_Axi_RLast,
|
||||
M_Axi_RValid => M_Axi_RValid,
|
||||
M_Axi_RReady => M_Axi_RReady
|
||||
);
|
||||
|
||||
Done <= DoneI or ErrorI;
|
||||
|
||||
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
|
396
hdl/psi_ms_daq_daq_dma.vhd
Normal file
396
hdl/psi_ms_daq_daq_dma.vhd
Normal file
@ -0,0 +1,396 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2019 by Paul Scherrer Institute, Switzerland
|
||||
-- All rights reserved.
|
||||
-- Authors: Oliver Bruendler
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Description
|
||||
------------------------------------------------------------------------------
|
||||
-- This component calculates a binary division of two fixed point values.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Libraries
|
||||
------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.psi_common_math_pkg.all;
|
||||
use work.psi_common_logic_pkg.all;
|
||||
use work.psi_common_array_pkg.all;
|
||||
use work.psi_ms_daq_pkg.all;
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Entity Declaration
|
||||
------------------------------------------------------------------------------
|
||||
-- $$ testcases=aligned,unaligned,no_data_read,input_empty,empty_timeout,cmd_full,data_full,errors $$
|
||||
-- $$ processes=control,input,mem_cmd,mem_dat $$
|
||||
-- $$ tbpkg=work.psi_tb_txt_util,work.psi_tb_compare_pkg,work.psi_tb_activity_pkg $$
|
||||
entity psi_ms_daq_daq_dma is
|
||||
generic (
|
||||
Streams_g : positive range 1 to 32 := 4 -- $$ constant=4 $$
|
||||
);
|
||||
port (
|
||||
-- Control signals
|
||||
Clk : in std_logic; -- $$ type=clk; freq=200e6; proc=control,input,mem_dat,mem_cmd $$
|
||||
Rst : in std_logic; -- $$ type=rst; clk=Clk; proc=control $$
|
||||
|
||||
-- DAQ Statemachione Connections
|
||||
DaqSm_Cmd : in DaqSm2DaqDma_Cmd_t; -- $$ proc=control $$
|
||||
DaqSm_Cmd_Vld : in std_logic; -- $$ proc=control $$
|
||||
DaqSm_Resp : out DaqDma2DaqSm_Resp_t; -- $$ proc=control $$
|
||||
DaqSm_Resp_Vld : out std_logic; -- $$ proc=control $$
|
||||
DaqSm_Resp_Rdy : in std_logic; -- $$ proc=control $$
|
||||
DaqSm_HasLast : out std_logic_vector(Streams_g-1 downto 0); -- $$ proc=control $$
|
||||
|
||||
-- Input handling connections
|
||||
Inp_Vld : in std_logic_vector(Streams_g-1 downto 0); -- $$ proc=input $$
|
||||
Inp_Rdy : out std_logic_vector(Streams_g-1 downto 0); -- $$ proc=input $$
|
||||
Inp_Data : in Input2Daq_Data_a(Streams_g-1 downto 0); -- $$ proc=input $$
|
||||
|
||||
-- Memory interface connections
|
||||
Mem_CmdAddr : out std_logic_vector(31 downto 0); -- $$ proc=mem_cmd $$
|
||||
Mem_CmdSize : out std_logic_vector(31 downto 0); -- $$ proc=mem_cmd $$
|
||||
Mem_CmdVld : out std_logic; -- $$ proc=mem_cmd $$
|
||||
Mem_CmdRdy : in std_logic; -- $$ proc=mem_cmd $$
|
||||
Mem_DatData : out std_logic_vector(63 downto 0); -- $$ proc=mem_dat $$
|
||||
Mem_DatVld : out std_logic; -- $$ proc=mem_dat $$
|
||||
Mem_DatRdy : in std_logic -- $$ proc=mem_dat $$
|
||||
);
|
||||
end entity;
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Architecture Declaration
|
||||
------------------------------------------------------------------------------
|
||||
architecture rtl of psi_ms_daq_daq_dma is
|
||||
|
||||
-- Constants
|
||||
constant BufferFifoDepth_c : integer := 32;
|
||||
|
||||
|
||||
-- Component Connection Signals
|
||||
signal CmdFifo_Level_Dbg : std_logic_vector(log2ceil(Streams_g) downto 0);
|
||||
signal CmdFifo_InData : std_logic_vector(DaqSm2DaqDma_Cmd_Size_c-1 downto 0);
|
||||
signal CmdFifo_OutData : std_logic_vector(DaqSm2DaqDma_Cmd_Size_c-1 downto 0);
|
||||
signal CmdFifo_Cmd : DaqSm2DaqDma_Cmd_t;
|
||||
signal CmdFifo_Vld : std_logic;
|
||||
signal RspFifo_Level_Dbg : std_logic_vector(log2ceil(Streams_g) downto 0);
|
||||
signal RspFifo_InData : std_logic_vector(DaqDma2DaqSm_Resp_Size_c-1 downto 0);
|
||||
signal RspFifo_OutData : std_logic_vector(DaqDma2DaqSm_Resp_Size_c-1 downto 0);
|
||||
signal DatFifo_Level_Dbg : std_logic_vector(log2ceil(BufferFifoDepth_c) downto 0);
|
||||
signal DatFifo_AlmFull : std_logic;
|
||||
signal Rem_RdBytes : std_logic_vector(2 downto 0);
|
||||
signal Rem_Data : std_logic_vector(63 downto 0);
|
||||
signal Rem_Trigger : std_logic;
|
||||
signal Rem_Last : std_logic;
|
||||
|
||||
-- Types
|
||||
type State_t is (Idle_s, RemRd1_s, RemRd2_s, Transfer_s, Done_s, Cmd_s);
|
||||
|
||||
-- Two process method
|
||||
type two_process_r is record
|
||||
CmdFifo_Rdy : std_logic;
|
||||
RspFifo_Vld : std_logic;
|
||||
RspFifo_Data : DaqDma2DaqSm_Resp_t;
|
||||
Mem_DataVld : std_logic;
|
||||
StreamStdlv : std_logic_vector(log2ceil(Streams_g)-1 downto 0);
|
||||
RemWen : std_logic;
|
||||
RemWrBytes : std_logic_vector(2 downto 0);
|
||||
RemData : std_logic_vector(63 downto 0);
|
||||
RemTrigger : std_logic;
|
||||
RemLast : std_logic;
|
||||
RemWrTrigger : std_logic;
|
||||
RemWrLast : std_logic;
|
||||
State : State_t;
|
||||
HndlMaxSize : unsigned(15 downto 0);
|
||||
RdBytes : unsigned(15 downto 0);
|
||||
WrBytes : unsigned(15 downto 0);
|
||||
HndlStream : integer range 0 to MaxStreams_c-1;
|
||||
HndlAddress : std_logic_vector(31 downto 0);
|
||||
UpdateLast : std_logic;
|
||||
HndlSft : unsigned(2 downto 0);
|
||||
FirstDma : std_logic_vector(Streams_g-1 downto 0);
|
||||
Mem_CmdVld : std_logic;
|
||||
Trigger : std_logic;
|
||||
Last : std_logic;
|
||||
DataSft : std_logic_vector(127 downto 0);
|
||||
NextDone : std_logic;
|
||||
DataWritten : std_logic;
|
||||
HasLast : std_logic_vector(Streams_g-1 downto 0);
|
||||
end record;
|
||||
signal r, r_next : two_process_r;
|
||||
|
||||
|
||||
begin
|
||||
--------------------------------------------
|
||||
-- Combinatorial Process
|
||||
--------------------------------------------
|
||||
p_comb : process( r, DaqSm_Cmd, DaqSm_Cmd_Vld, DaqSm_Resp_Rdy, Inp_Vld, Inp_Data, Mem_CmdRdy, Mem_DatRdy,
|
||||
CmdFifo_Cmd, CmdFifo_Vld, DatFifo_AlmFull, Rem_RdBytes, Rem_Data, Rem_Trigger, Rem_Last)
|
||||
variable v : two_process_r;
|
||||
variable ThisByte_v : std_logic_vector(7 downto 0);
|
||||
variable RemSft_v : integer range 0 to 7;
|
||||
begin
|
||||
-- *** Hold variables stable ***
|
||||
v := r;
|
||||
|
||||
-- *** Default Values ***
|
||||
v.CmdFifo_Rdy := '0';
|
||||
Inp_Rdy <= (others => '0');
|
||||
v.Mem_DataVld := '0';
|
||||
v.RspFifo_Vld := '0';
|
||||
v.RemWen := '0';
|
||||
v.UpdateLast := '0';
|
||||
|
||||
-- *** State Machine ***
|
||||
case r.State is
|
||||
|
||||
when Idle_s =>
|
||||
v.HndlMaxSize := unsigned(CmdFifo_Cmd.MaxSize);
|
||||
v.HndlStream := CmdFifo_Cmd.Stream;
|
||||
v.StreamStdlv := std_logic_vector(to_unsigned(CmdFifo_Cmd.Stream, v.StreamStdlv'length));
|
||||
v.HndlAddress := CmdFifo_Cmd.Address;
|
||||
v.Trigger := '0';
|
||||
v.Last := '0';
|
||||
if CmdFifo_Vld = '1' then
|
||||
v.CmdFifo_Rdy := '1';
|
||||
v.State := RemRd1_s;
|
||||
end if;
|
||||
|
||||
when RemRd1_s =>
|
||||
v.State := RemRd2_s;
|
||||
|
||||
when RemRd2_s =>
|
||||
-- Prevent RAM data from before reset to have an influence
|
||||
v.WrBytes := (others => '0');
|
||||
if r.FirstDma(r.HndlStream) = '1' then
|
||||
v.HndlSft := (others => '0');
|
||||
v.RdBytes := (others => '0');
|
||||
v.DataSft := (others => '0');
|
||||
v.RemTrigger := '0';
|
||||
v.RemLast := '0';
|
||||
else
|
||||
v.HndlSft := unsigned(Rem_RdBytes);
|
||||
v.DataSft(127 downto 64) := Rem_Data;
|
||||
v.RdBytes := resize(unsigned(Rem_RdBytes), v.RdBytes'length);
|
||||
v.RemTrigger := Rem_Trigger;
|
||||
v.RemLast := Rem_Last;
|
||||
end if;
|
||||
v.FirstDma(r.HndlStream) := '0';
|
||||
v.State := Transfer_s;
|
||||
v.NextDone := '0';
|
||||
v.DataWritten := '0';
|
||||
|
||||
when Transfer_s =>
|
||||
-- TF done because of maximum size reached
|
||||
if r.WrBytes >= r.HndlMaxSize then
|
||||
v.State := Done_s;
|
||||
elsif DatFifo_AlmFull = '0' then
|
||||
if r.NextDone = '0' and Inp_Vld(r.HndlStream) = '1' and r.RemLast = '0' then
|
||||
v.RdBytes := r.RdBytes + unsigned(Inp_Data(r.HndlStream).Bytes);
|
||||
end if;
|
||||
v.WrBytes := r.WrBytes + 8;
|
||||
-- Combinatorial handling because of fall-through interface at input
|
||||
if r.RdBytes < r.HndlMaxSize and r.NextDone = '0' and r.RemLast = '0' then
|
||||
Inp_Rdy(r.HndlStream) <= '1';
|
||||
end if;
|
||||
-- Handling of last frame
|
||||
if (Inp_Data(r.HndlStream).Last = '1') or (r.RemLast = '1') then
|
||||
-- Do one more word if not all data can be transferred in the current beat (NextDone = 1)
|
||||
if (r.HndlSft + unsigned(Inp_Data(r.HndlStream).Bytes) <= 8) or (r.RemLast = '1') then
|
||||
v.State := Done_s;
|
||||
else
|
||||
v.NextDone := '1';
|
||||
end if;
|
||||
if (Inp_Data(r.HndlStream).IsTrig = '1') or (r.RemTrigger = '1') then
|
||||
v.Trigger :='1';
|
||||
end if;
|
||||
v.Last := '1';
|
||||
end if;
|
||||
if r.NextDone = '1' or Inp_Vld(r.HndlStream) = '0' then
|
||||
v.State := Done_s;
|
||||
end if;
|
||||
-- Data handling
|
||||
v.DataSft(63 downto 0) := r.DataSft(127 downto 64);
|
||||
v.DataSft(8*to_integer(r.HndlSft)+63 downto 8*to_integer(r.HndlSft)) := Inp_Data(r.HndlStream).Data;
|
||||
if Inp_Vld(r.HndlStream) = '1' or r.HndlSft /= 0 then
|
||||
v.Mem_DataVld := '1';
|
||||
v.DataWritten := '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when Done_s =>
|
||||
RemSft_v := to_integer(resize(r.HndlMaxSize, 3));
|
||||
v.RemWrTrigger := '0';
|
||||
v.RemWrLast := '0';
|
||||
if r.HndlMaxSize < r.RdBytes then
|
||||
v.RemWrBytes := std_logic_vector(resize(r.RdBytes - r.HndlMaxSize, v.RemWrBytes'length));
|
||||
v.RdBytes := r.HndlMaxSize;
|
||||
v.RemWrTrigger := r.Trigger;
|
||||
v.RemWrLast := r.Last;
|
||||
v.HasLast(r.HndlStream) := r.Last;
|
||||
else
|
||||
v.RemWrBytes := (others => '0');
|
||||
v.HasLast(r.HndlStream) := '0';
|
||||
end if;
|
||||
v.RemData := v.DataSft(8*RemSft_v+63 downto 8*RemSft_v);
|
||||
v.State := Cmd_s;
|
||||
if r.DataWritten = '1' then
|
||||
v.Mem_CmdVld := '1';
|
||||
end if;
|
||||
v.RemWen := '1';
|
||||
|
||||
when Cmd_s =>
|
||||
if Mem_CmdRdy = '1' or r.Mem_CmdVld = '0' then
|
||||
v.State := Idle_s;
|
||||
v.Mem_CmdVld := '0';
|
||||
v.RspFifo_Vld := '1';
|
||||
v.RspFifo_Data.Size := std_logic_vector(r.RdBytes);
|
||||
-- Only mark as trigger if all samples are completely written to memory (no remaining samples in REM RAM)
|
||||
if (unsigned(r.RemWrBytes) = 0) and (r.Trigger = '1') then
|
||||
v.RspFifo_Data.Trigger := '1';
|
||||
else
|
||||
v.RspFifo_Data.Trigger := '0';
|
||||
end if;
|
||||
v.RspFifo_Data.Stream := r.HndlStream;
|
||||
end if;
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
-- *** Assign to signal ***
|
||||
r_next <= v;
|
||||
|
||||
end process;
|
||||
|
||||
-- *** Registered Outputs ***
|
||||
Mem_CmdAddr <= r.HndlAddress;
|
||||
Mem_CmdSize(r.RdBytes'range) <= std_logic_vector(r.RdBytes);
|
||||
Mem_CmdSize(Mem_CmdSize'high downto r.RdBytes'high+1) <= (others => '0');
|
||||
Mem_CmdVld <= r.Mem_CmdVld;
|
||||
DaqSm_HasLast <= r.HasLast;
|
||||
|
||||
|
||||
--------------------------------------------
|
||||
-- Sequential Process
|
||||
--------------------------------------------
|
||||
p_seq : process(Clk)
|
||||
begin
|
||||
if rising_edge(Clk) then
|
||||
r <= r_next;
|
||||
if Rst = '1' then
|
||||
r.CmdFifo_Rdy <= '0';
|
||||
r.RspFifo_Vld <= '0';
|
||||
r.Mem_DataVld <= '0';
|
||||
r.RemWen <= '0';
|
||||
r.State <= Idle_s;
|
||||
r.FirstDma <= (others => '1');
|
||||
r.Mem_CmdVld <= '0';
|
||||
r.HasLast <= (others => '0');
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--------------------------------------------
|
||||
-- Component Instantiation
|
||||
--------------------------------------------
|
||||
-- *** Command FIFO ***
|
||||
CmdFifo_InData <= DaqSm2DaqDma_Cmd_ToStdlv(DaqSm_Cmd);
|
||||
i_fifocmd : entity work.psi_common_sync_fifo
|
||||
generic map (
|
||||
Width_g => DaqSm2DaqDma_Cmd_Size_c,
|
||||
Depth_g => Streams_g,
|
||||
RamStyle_g => "distributed",
|
||||
RamBehavior_g => "RBW"
|
||||
)
|
||||
port map (
|
||||
Clk => Clk,
|
||||
Rst => Rst,
|
||||
InData => CmdFifo_InData,
|
||||
InVld => DaqSm_Cmd_Vld,
|
||||
OutData => CmdFifo_OutData,
|
||||
OutVld => CmdFifo_Vld,
|
||||
OutRdy => r.CmdFifo_Rdy,
|
||||
OutLevel => CmdFifo_Level_Dbg
|
||||
);
|
||||
CmdFifo_Cmd <= DaqSm2DaqDma_Cmd_FromStdlv(CmdFifo_OutData);
|
||||
|
||||
-- *** Response FIFO ***
|
||||
-- Ready not required for system reasons: There is never more commands open than streams.
|
||||
RspFifo_InData <= DaqDma2DaqSm_Resp_ToStdlv(r.RspFifo_Data);
|
||||
i_fiforsp : entity work.psi_common_sync_fifo
|
||||
generic map (
|
||||
Width_g => DaqDma2DaqSm_Resp_Size_c,
|
||||
Depth_g => Streams_g,
|
||||
RamStyle_g => "distributed",
|
||||
RamBehavior_g => "RBW"
|
||||
)
|
||||
port map (
|
||||
Clk => Clk,
|
||||
Rst => Rst,
|
||||
InData => RspFifo_InData,
|
||||
InVld => r.RspFifo_Vld,
|
||||
OutData => RspFifo_OutData,
|
||||
OutVld => DaqSm_Resp_Vld,
|
||||
OutRdy => DaqSm_Resp_Rdy,
|
||||
OutLevel => RspFifo_Level_Dbg
|
||||
);
|
||||
DaqSm_Resp <= DaqDme2DaqSm_Resp_FromStdlv(RspFifo_OutData);
|
||||
|
||||
-- *** Buffer FIFO ***
|
||||
-- This FIFO allows buffering data for the time the state machine requires to react on a "memory interface not ready for more data" situation.
|
||||
-- As a result, the backpressure must not handled in the complete pipeline of this block.
|
||||
-- Rdy is not required since the data pipeline is stopped based on the almost full flag
|
||||
i_fifodata : entity work.psi_common_sync_fifo
|
||||
generic map (
|
||||
Width_g => 64,
|
||||
Depth_g => BufferFifoDepth_c,
|
||||
AlmFullOn_g => true,
|
||||
AlmFullLevel_g => BufferFifoDepth_c/2,
|
||||
RamStyle_g => "distributed",
|
||||
RamBehavior_g => "RBW"
|
||||
)
|
||||
port map (
|
||||
Clk => Clk,
|
||||
Rst => Rst,
|
||||
InData => r.DataSft(63 downto 0),
|
||||
InVld => r.Mem_DataVld,
|
||||
OutData => Mem_DatData,
|
||||
OutVld => Mem_DatVld,
|
||||
OutRdy => Mem_DatRdy,
|
||||
OutLevel => DatFifo_Level_Dbg,
|
||||
AlmFull => DatFifo_AlmFull
|
||||
);
|
||||
|
||||
-- *** Remaining Data RAM ***
|
||||
i_remram : entity work.psi_common_sdp_ram
|
||||
generic map (
|
||||
Depth_g => Streams_g,
|
||||
Width_g => 1+1+3+64,
|
||||
IsAsync_g => false,
|
||||
RamStyle_g => "distributed",
|
||||
Behavior_g => "RBW"
|
||||
)
|
||||
port map (
|
||||
Clk => Clk,
|
||||
RdClk => Rst,
|
||||
WrAddr => r.StreamStdlv,
|
||||
Wr => r.RemWen,
|
||||
WrData(68) => r.RemWrLast,
|
||||
WrData(67) => r.RemWrTrigger,
|
||||
WrData(66 downto 64) => r.RemWrBytes,
|
||||
WrData(63 downto 0) => r.RemData,
|
||||
RdAddr => r.StreamStdlv,
|
||||
RdDAta(68) => Rem_Last,
|
||||
RdData(67) => Rem_Trigger,
|
||||
RdData(66 downto 64) => Rem_RdBytes,
|
||||
RdData(63 downto 0) => Rem_Data
|
||||
);
|
||||
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
|
719
hdl/psi_ms_daq_daq_sm.vhd
Normal file
719
hdl/psi_ms_daq_daq_sm.vhd
Normal file
@ -0,0 +1,719 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2019 by Paul Scherrer Institute, Switzerland
|
||||
-- All rights reserved.
|
||||
-- Authors: Oliver Bruendler
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Description
|
||||
------------------------------------------------------------------------------
|
||||
-- This component calculates a binary division of two fixed point values.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Libraries
|
||||
------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.psi_common_math_pkg.all;
|
||||
use work.psi_common_logic_pkg.all;
|
||||
use work.psi_common_array_pkg.all;
|
||||
use work.psi_ms_daq_pkg.all;
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Entity Declaration
|
||||
------------------------------------------------------------------------------
|
||||
-- $$ testcases=single_simple,priorities,single_window,multi_window,enable,irq,timestamp $$
|
||||
-- $$ processes=control,dma_cmd,dma_resp,ctx $$
|
||||
-- $$ tbpkg=work.psi_tb_txt_util,work.psi_tb_compare_pkg $$
|
||||
entity psi_ms_daq_daq_sm is
|
||||
generic (
|
||||
Streams_g : positive range 1 to 32 := 4; -- $$ constant=4 $$
|
||||
StreamPrio_g : t_ainteger := (1, 2, 3, 1); -- $$ constant=(1, 2, 3, 1) $$
|
||||
StreamWidth_g : t_ainteger := (8, 16, 32, 64); -- $$ constant=(8, 16, 32, 64) $$
|
||||
Windows_g : positive range 1 to 32 := 4; -- $$ constant=4 $$
|
||||
MinBurstSize_g : positive := 512; -- $$ constant=512 $$
|
||||
MaxBurstSize_g : positive := 512 -- $$ constant=512 $$
|
||||
);
|
||||
port (
|
||||
-- Control signals
|
||||
Clk : in std_logic; -- $$ type=clk; freq=200e6; proc=control,dma_cmd,dma_resp,ctx $$
|
||||
Rst : in std_logic; -- $$ proc=control $$
|
||||
GlbEna : in std_logic; -- $$ proc=control; lowactive=true $$
|
||||
StrEna : in std_logic_vector(Streams_g-1 downto 0); -- $$ proc=control; lowactive=true $$
|
||||
StrIrq : out std_logic_vector(Streams_g-1 downto 0); -- $$ proc=control,dma_resp,dma_cmd; $$
|
||||
StrLastWin : out WinType_a(Streams_g-1 downto 0);
|
||||
|
||||
-- Input logic Connections
|
||||
Inp_HasLast : in std_logic_vector(Streams_g-1 downto 0); -- $$ proc=control $$
|
||||
Inp_Level : in t_aslv16(Streams_g-1 downto 0); -- $$ proc=control $$
|
||||
Ts_Vld : in std_logic_vector(Streams_g-1 downto 0); -- $$ proc=control $$
|
||||
Ts_Rdy : out std_logic_vector(Streams_g-1 downto 0); -- $$ proc=control $$
|
||||
Ts_Data : in t_aslv64(Streams_g-1 downto 0); -- $$ proc=control $$
|
||||
|
||||
-- Dma Connections
|
||||
Dma_Cmd : out DaqSm2DaqDma_Cmd_t; -- $$ proc=dma_cmd,control $$
|
||||
Dma_Cmd_Vld : out std_logic; -- $$ proc=dma_cmd,control $$
|
||||
Dma_Resp : in DaqDma2DaqSm_Resp_t; -- $$ proc=dma_resp $$
|
||||
Dma_Resp_Vld : in std_logic; -- $$ proc=dma_resp $$
|
||||
Dma_Resp_Rdy : out std_logic; -- $$ proc=dma_resp $$
|
||||
|
||||
-- Memory Controller
|
||||
TfDone : in std_logic; -- $$ proc=dma_resp $$
|
||||
|
||||
-- Context RAM connections
|
||||
CtxStr_Cmd : out ToCtxStr_t; -- $$ proc=ctx $$
|
||||
CtxStr_Resp : in FromCtx_t; -- $$ proc=ctx $$
|
||||
CtxWin_Cmd : out ToCtxWin_t; -- $$ proc=ctx $$
|
||||
CtxWin_Resp : in FromCtx_t -- $$ proc=ctx $$
|
||||
);
|
||||
end entity;
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Architecture Declaration
|
||||
------------------------------------------------------------------------------
|
||||
architecture rtl of psi_ms_daq_daq_sm is
|
||||
|
||||
-- Function Definitions
|
||||
function GetBitsOfStreamPrio( InputVector : std_logic_vector;
|
||||
Prio : integer)
|
||||
return std_logic_vector is
|
||||
variable Result_v : std_logic_vector(count(StreamPrio_g, Prio)-1 downto 0) := (others => '0');
|
||||
variable OutIdx_v : integer := 0;
|
||||
begin
|
||||
for idx in InputVector'low to InputVector'high loop
|
||||
if StreamPrio_g(idx) = Prio then
|
||||
Result_v(OutIdx_v) := InputVector(idx);
|
||||
OutIdx_v := OutIdx_v + 1;
|
||||
end if;
|
||||
end loop;
|
||||
return Result_v;
|
||||
end function;
|
||||
|
||||
function GetStreamNrFromGrant( GrantVector : std_logic_vector;
|
||||
Prio : integer)
|
||||
return integer is
|
||||
variable IdxCnt_v : integer := 0;
|
||||
begin
|
||||
for idx in StreamPrio_g'low to StreamPrio_g'high loop
|
||||
if StreamPrio_g(idx) = Prio then
|
||||
if GrantVector(IdxCnt_v) = '1' then
|
||||
return idx;
|
||||
end if;
|
||||
IdxCnt_v := IdxCnt_v + 1;
|
||||
end if;
|
||||
end loop;
|
||||
return 0;
|
||||
end function;
|
||||
|
||||
-- Vivado Workarounds (Synthesis fail)
|
||||
subtype Log2Bytes_t is integer range 0 to log2(MaxStreamWidth_c/8);
|
||||
type Log2Bytes_a is array (natural range <>) of Log2Bytes_t;
|
||||
function CalcLog2Bytes return Log2Bytes_a is
|
||||
variable arr : Log2Bytes_a(0 to Streams_g-1);
|
||||
begin
|
||||
for i in 0 to Streams_g-1 loop
|
||||
arr(i) := log2(StreamWidth_g(i)/8);
|
||||
end loop;
|
||||
return arr;
|
||||
end function;
|
||||
constant Log2StrBytes_c : Log2Bytes_a(0 to Streams_g-1) := CalcLog2Bytes;
|
||||
|
||||
-- Component Connection Signals
|
||||
signal AvailPrio1 : std_logic_vector(count(StreamPrio_g, 1)-1 downto 0);
|
||||
signal AvailPrio2 : std_logic_vector(count(StreamPrio_g, 2)-1 downto 0);
|
||||
signal AvailPrio3 : std_logic_vector(count(StreamPrio_g, 3)-1 downto 0);
|
||||
signal GrantPrio1 : std_logic_vector(AvailPrio1'range);
|
||||
signal GrantPrio2 : std_logic_vector(AvailPrio2'range);
|
||||
signal GrantPrio3 : std_logic_vector(AvailPrio3'range);
|
||||
signal GrantVld : std_logic_vector(3 downto 1);
|
||||
signal IrqFifoAlmFull : std_logic;
|
||||
signal IrqFifoEmpty : std_logic;
|
||||
signal IrqFifoGenIrq : std_logic;
|
||||
signal IrqFifoStream : std_logic_vector(log2ceil(Streams_g)-1 downto 0);
|
||||
signal IrqLastWinNr : std_logic_vector(log2ceil(Windows_g)-1 downto 0);
|
||||
signal IrqFifoIn : std_logic_vector(log2ceil(Streams_g)+log2ceil(Windows_g) downto 0);
|
||||
signal IrqFifoOut : std_logic_vector(log2ceil(Streams_g)+log2ceil(Windows_g) downto 0);
|
||||
|
||||
-- Types
|
||||
type State_t is (Idle_s, CheckPrio1_s, CheckPrio2_s, CheckPrio3_s, CheckResp_s, TlastCheck_s, ReadCtxStr_s, First_s, ReadCtxWin_s, CalcAccess0_s, CalcAccess1_s, ProcResp0_s, NextWin_s, WriteCtx_s);
|
||||
|
||||
-- Two process method
|
||||
type two_process_r is record
|
||||
GlbEnaReg : std_logic;
|
||||
StrEnaReg : std_logic_vector(Streams_g-1 downto 0);
|
||||
InpDataAvail : std_logic_vector(Streams_g-1 downto 0);
|
||||
DataAvailArbIn : std_logic_vector(Streams_g-1 downto 0);
|
||||
DataPending : std_logic_vector(Streams_g-1 downto 0);
|
||||
OpenCommand : std_logic_vector(Streams_g-1 downto 0);
|
||||
WinProtected : std_logic_vector(Streams_g-1 downto 0); -- Set if the current window is not yet available
|
||||
NewBuffer : std_logic_vector(Streams_g-1 downto 0);
|
||||
FirstAfterEna : std_logic_vector(Streams_g-1 downto 0);
|
||||
FirstOngoing : std_logic_vector(Streams_g-1 downto 0);
|
||||
GrantVldReg : std_logic_vector(3 downto 1);
|
||||
State : State_t;
|
||||
GrantPrio1Reg : std_logic_vector(GrantPrio1'range);
|
||||
GrantPrio2Reg : std_logic_vector(GrantPrio2'range);
|
||||
GrantPrio3Reg : std_logic_vector(GrantPrio3'range);
|
||||
HasLastReg : std_logic_vector(Inp_HasLast'range);
|
||||
HndlAfterCtxt : State_t;
|
||||
HndlStream : integer range 0 to Streams_g;
|
||||
HndlCtxCnt : integer range 0 to 4;
|
||||
HndlRingbuf : std_logic;
|
||||
HndlOverwrite : std_logic;
|
||||
HndlWincnt : std_logic_vector(log2ceil(Windows_g)-1 downto 0);
|
||||
HndlWincur : std_logic_vector(log2ceil(Windows_g)-1 downto 0);
|
||||
HndlLastWinNr : std_logic_vector(log2ceil(Windows_g)-1 downto 0);
|
||||
HndlBufstart : std_logic_vector(31 downto 0);
|
||||
HndlWinSize : std_logic_vector(31 downto 0);
|
||||
HndlPtr0 : std_logic_vector(31 downto 0);
|
||||
HndlPtr1 : std_logic_vector(31 downto 0);
|
||||
HndlPtr2 : std_logic_vector(31 downto 0);
|
||||
HndlLevel : std_logic_vector(15 downto 0);
|
||||
Hndl4kMax : std_logic_vector(12 downto 0);
|
||||
HndlWinMax : std_logic_vector(31 downto 0);
|
||||
HndlWinEnd : std_logic_vector(31 downto 0);
|
||||
HndlWinBytes : std_logic_vector(32 downto 0);
|
||||
HndlWinLast : std_logic_vector(31 downto 0);
|
||||
HndlTs : std_logic_vector(63 downto 0);
|
||||
TfDoneCnt : std_logic_vector(log2ceil(Streams_g)-1 downto 0);
|
||||
TfDoneReg : std_logic;
|
||||
HndlWinDone : std_logic;
|
||||
CtxStr_Cmd : ToCtxStr_t;
|
||||
CtxWin_Cmd : ToCtxWin_t;
|
||||
Dma_Cmd : DaqSm2DaqDma_Cmd_t;
|
||||
Dma_Cmd_Vld : std_logic;
|
||||
Dma_Resp_Rdy : std_logic;
|
||||
Ts_Rdy : std_logic_vector(Streams_g-1 downto 0);
|
||||
ArbDelCnt : integer range 0 to 4;
|
||||
IrqFifoWrite : std_logic;
|
||||
IrqFifoRead : std_logic;
|
||||
StrIrq : std_logic_vector(Streams_g-1 downto 0);
|
||||
StrLastWin : WinType_a(Streams_g-1 downto 0);
|
||||
EndByTrig : std_logic;
|
||||
end record;
|
||||
signal r, r_next : two_process_r;
|
||||
|
||||
-- USED FOR DEBUGGING ONLY!
|
||||
-- attribute mark_debug : string;
|
||||
-- attribute mark_debug of r : signal is "true";
|
||||
|
||||
-- Todo: mask streams that already have a transfer open at the input
|
||||
|
||||
begin
|
||||
--------------------------------------------
|
||||
-- Combinatorial Process
|
||||
--------------------------------------------
|
||||
p_comb : process( r, Inp_HasLast, Inp_Level, Ts_Vld, Ts_Data, Dma_Resp, Dma_Resp_Vld, CtxStr_Resp, CtxWin_Resp, GlbEna, StrEna, TfDone, IrqFifoGenIrq, IrqFifoStream, IrqLastWinNr,
|
||||
GrantVld, GrantPrio1, GrantPrio2, GrantPrio3, IrqFifoAlmFull, IrqFifoEmpty)
|
||||
variable v : two_process_r;
|
||||
begin
|
||||
-- *** Hold variables stable ***
|
||||
v := r;
|
||||
|
||||
-- *** Default Values ***
|
||||
v.CtxStr_Cmd.WenLo := '0';
|
||||
v.CtxStr_Cmd.WenHi := '0';
|
||||
v.CtxWin_Cmd.WenLo := '0';
|
||||
v.CtxWin_Cmd.WenHi := '0';
|
||||
v.CtxStr_Cmd.Rd := '0';
|
||||
v.CtxWin_Cmd.Rd := '0';
|
||||
v.Dma_Cmd_Vld := '0';
|
||||
v.Ts_Rdy := (others => '0');
|
||||
v.Dma_Resp_Rdy := '0';
|
||||
v.CtxWin_Cmd.WdatLo := (others => '0');
|
||||
v.CtxWin_Cmd.WdatHi := (others => '0');
|
||||
v.CtxStr_Cmd.WdatLo := (others => '0');
|
||||
v.CtxStr_Cmd.WdatHi := (others => '0');
|
||||
v.IrqFifoWrite := '0';
|
||||
v.IrqFifoRead := '0';
|
||||
v.StrIrq := (others => '0');
|
||||
|
||||
|
||||
-- *** Pure Pipelining (no functional registers) ***
|
||||
v.GrantVldReg := GrantVld;
|
||||
v.GrantPrio1Reg := GrantPrio1;
|
||||
v.GrantPrio2Reg := GrantPrio2;
|
||||
v.GrantPrio3Reg := GrantPrio3;
|
||||
v.HasLastReg := Inp_HasLast;
|
||||
v.StrEnaReg := StrEna;
|
||||
v.GlbEnaReg := GlbEna;
|
||||
v.TfDoneReg := TfDone;
|
||||
|
||||
-- *** Check Availability of a full burst ***
|
||||
for str in 0 to Streams_g-1 loop
|
||||
if unsigned(Inp_Level(str)) >= MinBurstSize_g then
|
||||
v.InpDataAvail(str) := r.StrEnaReg(str) and r.GlbEnaReg;
|
||||
else
|
||||
v.InpDataAvail(str) := '0';
|
||||
end if;
|
||||
end loop;
|
||||
v.DataAvailArbIn := r.InpDataAvail and (not r.OpenCommand) and (not r.WinProtected); -- Do not arbitrate new commands on streams that already have a command
|
||||
v.DataPending := r.InpDataAvail and (not r.WinProtected); -- Do not prevent lower priority channels from access if the window of a higher priority stream is protected
|
||||
|
||||
-- *** Select level of currently handled FIFO ***
|
||||
v.HndlLevel := Inp_Level(r.HndlStream);
|
||||
|
||||
-- *** State Machine ***
|
||||
case r.State is
|
||||
-- *** Idle state ***
|
||||
when Idle_s =>
|
||||
v.HndlCtxCnt := 0;
|
||||
v.HndlWinDone := '0';
|
||||
-- check if data to write is available (only if IRQ FIFO has space for the response for sure)
|
||||
if IrqFifoAlmFull = '0' then
|
||||
v.State := CheckPrio1_s;
|
||||
v.HndlAfterCtxt := CalcAccess0_s;
|
||||
end if;
|
||||
-- Delay arbitration in simulation to allow TB to react
|
||||
if r.ArbDelCnt /= 4 then
|
||||
v.State := Idle_s;
|
||||
v.ArbDelCnt := r.ArbDelCnt + 1;
|
||||
else
|
||||
v.ArbDelCnt := 0;
|
||||
end if;
|
||||
|
||||
-- *** Check for next stream to handle ***
|
||||
when CheckPrio1_s =>
|
||||
-- Handle command if prio 1 data is available
|
||||
if r.GrantVldReg(1) = '1' then
|
||||
v.State := ReadCtxStr_s;
|
||||
v.HndlStream := GetStreamNrFromGrant(r.GrantPrio1Reg, 1);
|
||||
-- If data is still pending, check for responses to schedule next transfer
|
||||
elsif (unsigned(GetBitsOfStreamPrio(r.DataPending, 1)) /= 0) and (count(StreamPrio_g, 1) /= 0) then -- the term after the AND is required because unsigned(null-range) is not guaranteed to be zero in Vivado
|
||||
v.State := CheckResp_s;
|
||||
-- Otherwise check lower priority streams
|
||||
else
|
||||
v.State := CheckPrio2_s;
|
||||
end if;
|
||||
|
||||
when CheckPrio2_s =>
|
||||
-- Handle command if prio 2 data is available
|
||||
if r.GrantVldReg(2) = '1' then
|
||||
v.State := ReadCtxStr_s;
|
||||
v.HndlStream := GetStreamNrFromGrant(r.GrantPrio2Reg, 2);
|
||||
-- If data is still pending, check for responses to schedule next transfer
|
||||
elsif (unsigned(GetBitsOfStreamPrio(r.DataPending, 2)) /= 0) and (count(StreamPrio_g, 2) /= 0) then -- the term after the AND is required because unsigned(null-range) is not guaranteed to be zero in Vivado
|
||||
v.State := CheckResp_s;
|
||||
-- Otherwise check lower priority streams
|
||||
else
|
||||
v.State := CheckPrio3_s;
|
||||
end if;
|
||||
|
||||
when CheckPrio3_s =>
|
||||
-- Handle command if prio 2 data is available
|
||||
if r.GrantVldReg(3) = '1' then
|
||||
v.State := ReadCtxStr_s;
|
||||
v.HndlStream := GetStreamNrFromGrant(r.GrantPrio3Reg, 3);
|
||||
-- Otherwise check for frame ends
|
||||
else
|
||||
v.State := TlastCheck_s;
|
||||
end if;
|
||||
|
||||
when TlastCheck_s =>
|
||||
v.State := CheckResp_s;
|
||||
v.WinProtected := (others => '0'); -- No bursts where available on any stream, so all of them were checked and we can retry whether SW emptied a window.
|
||||
for idx in 0 to Streams_g-1 loop
|
||||
if (r.HasLastReg(idx) = '1') and (r.OpenCommand(idx) = '0') and (r.WinProtected(idx) = '0') then
|
||||
v.State := ReadCtxStr_s;
|
||||
v.HndlStream := idx;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
when CheckResp_s =>
|
||||
-- Handle response if one is pending (less important thandata transer, therefore at the end)
|
||||
if Dma_Resp_Vld = '1' then
|
||||
v.State := ReadCtxStr_s;
|
||||
v.HndlAfterCtxt := ProcResp0_s;
|
||||
v.HndlStream := Dma_Resp.Stream;
|
||||
v.EndByTrig := Dma_Resp.Trigger;
|
||||
else
|
||||
v.State := Idle_s;
|
||||
end if;
|
||||
|
||||
-- *** Read Context Memory ***
|
||||
-- Read information from stream memory
|
||||
when ReadCtxStr_s =>
|
||||
-- State handling
|
||||
if r.HndlCtxCnt = 4 then
|
||||
v.State := First_s;
|
||||
v.HndlCtxCnt := 0;
|
||||
else
|
||||
v.HndlCtxCnt := r.HndlCtxCnt + 1;
|
||||
end if;
|
||||
|
||||
-- Command Assertions
|
||||
v.CtxStr_Cmd.Stream := r.HndlStream;
|
||||
case r.HndlCtxCnt is
|
||||
when 0 => v.CtxStr_Cmd.Sel := CtxStr_Sel_Winend_c;
|
||||
v.CtxStr_Cmd.Rd := '1';
|
||||
when 1 => v.CtxStr_Cmd.Sel := CtxStr_Sel_WinsizePtr_c;
|
||||
v.CtxStr_Cmd.Rd := '1';
|
||||
when 2 => v.CtxStr_Cmd.Sel := CtxStr_Sel_ScfgBufstart_c;
|
||||
v.CtxStr_Cmd.Rd := '1';
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
-- Response handling
|
||||
case r.HndlCtxCnt is
|
||||
when 2 => v.HndlWinEnd := CtxStr_Resp.RdatLo;
|
||||
when 3 => v.HndlWinSize := CtxStr_Resp.RdatLo;
|
||||
v.HndlPtr0 := CtxStr_Resp.RdatHi;
|
||||
when 4 => v.HndlRingbuf := CtxStr_Resp.RdatLo(CtxStr_Sft_SCFG_RINGBUF_c);
|
||||
v.HndlOverwrite := CtxStr_Resp.RdatLo(CtxStr_Sft_SCFG_OVERWRITE_c);
|
||||
v.HndlWincnt := CtxStr_Resp.RdatLo(CtxStr_Sft_SCFG_WINCNT_c+v.HndlWincnt'high downto CtxStr_Sft_SCFG_WINCNT_c);
|
||||
v.HndlWincur := CtxStr_Resp.RdatLo(CtxStr_Sft_SCFG_WINCUR_c+v.HndlWincur'high downto CtxStr_Sft_SCFG_WINCUR_c);
|
||||
v.HndlBufstart := CtxStr_Resp.RdatHi;
|
||||
v.Hndl4kMax := std_logic_vector(to_unsigned(4096, 13) - unsigned(r.HndlPtr0(11 downto 0))); -- Calculate maximum size within this 4k Region
|
||||
v.HndlWinMax := std_logic_vector(unsigned(r.HndlWinEnd) - unsigned(r.HndlPtr0)); -- Calculate maximum size within this window
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
-- Handle first access after enable
|
||||
when First_s =>
|
||||
-- State handling
|
||||
v.State := ReadCtxWin_s;
|
||||
|
||||
-- Ensure that command and response are both handled as first or not
|
||||
if r.HndlAfterCtxt = ProcResp0_s then -- responses
|
||||
-- nothing to do
|
||||
else -- command
|
||||
v.FirstAfterEna(r.HndlStream) := '0';
|
||||
v.FirstOngoing(r.HndlStream) := r.FirstAfterEna(r.HndlStream);
|
||||
end if;
|
||||
|
||||
-- Update values for first access
|
||||
if v.FirstOngoing(r.HndlStream) = '1' then
|
||||
v.HndlWinEnd := std_logic_vector(unsigned(r.HndlBufstart) + unsigned(r.HndlWinSize));
|
||||
v.HndlPtr0 := r.HndlBufstart;
|
||||
v.HndlWincur := (others => '0');
|
||||
v.Hndl4kMax := std_logic_vector(to_unsigned(4096, 13) - unsigned(r.HndlBufstart(11 downto 0)));
|
||||
v.HndlWinMax := r.HndlWinSize;
|
||||
end if;
|
||||
|
||||
|
||||
-- Read information from window memory
|
||||
when ReadCtxWin_s =>
|
||||
-- State handling
|
||||
if r.HndlCtxCnt = 2 then
|
||||
v.State := r.HndlAfterCtxt; -- Goto state depends on the context of the read procedure
|
||||
else
|
||||
v.HndlCtxCnt := r.HndlCtxCnt + 1;
|
||||
end if;
|
||||
|
||||
-- Command Assertions
|
||||
v.CtxWin_Cmd.Stream := r.HndlStream;
|
||||
v.CtxWin_Cmd.Window := to_integer(unsigned(r.HndlWincur));
|
||||
case r.HndlCtxCnt is
|
||||
when 0 => v.CtxWin_Cmd.Sel := CtxWin_Sel_WincntWinlast_c;
|
||||
v.CtxWin_Cmd.Rd := '1';
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
-- Response handling
|
||||
case r.HndlCtxCnt is
|
||||
when 2 =>
|
||||
-- Workaround for Vivado (Range expression was resolved incorrectly)
|
||||
for i in 0 to Streams_g-1 loop
|
||||
if i = r.HndlStream then
|
||||
v.HndlWinBytes := '0' & ShiftLeft(CtxWin_Resp.RdatLo, Log2StrBytes_c(i)); -- guard bit required for calculations
|
||||
end if;
|
||||
end loop;
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
-- *** Calculate next access ***
|
||||
when CalcAccess0_s =>
|
||||
-- Calculate Command
|
||||
v.Dma_Cmd.Address := r.HndlPtr0;
|
||||
v.Dma_Cmd.Stream := r.HndlStream;
|
||||
v.Dma_Cmd.MaxSize := std_logic_vector(to_unsigned(MaxBurstSize_g*8, v.Dma_Cmd.MaxSize'length)); -- 8 bytes per 64-bit QWORD
|
||||
-- State update (abort if window is not free)
|
||||
if (r.HndlOverwrite = '0') and (unsigned(r.HndlWinBytes) /= 0) and (r.NewBuffer(r.HndlStream) = '1') then
|
||||
v.State := Idle_s;
|
||||
v.WinProtected(r.HndlStream) := '1';
|
||||
else
|
||||
v.State := CalcAccess1_s;
|
||||
v.NewBuffer(r.HndlStream) := '0';
|
||||
-- Mark stream as active
|
||||
v.OpenCommand(r.HndlStream) := '1';
|
||||
end if;
|
||||
|
||||
when CalcAccess1_s =>
|
||||
if unsigned(r.Hndl4kMax) < unsigned(r.HndlWinMax) then
|
||||
if unsigned(r.Dma_Cmd.MaxSize) > unsigned(r.Hndl4kMax) then
|
||||
v.Dma_Cmd.MaxSize := std_logic_vector(resize(unsigned(r.Hndl4kMax), v.dma_Cmd.MaxSize'length));
|
||||
end if;
|
||||
else
|
||||
if unsigned(r.Dma_Cmd.MaxSize) > unsigned(r.HndlWinMax) then
|
||||
v.Dma_Cmd.MaxSize := std_logic_vector(resize(unsigned(r.HndlWinMax), v.dma_Cmd.MaxSize'length));
|
||||
end if;
|
||||
end if;
|
||||
v.Dma_Cmd_Vld := '1';
|
||||
v.State := Idle_s;
|
||||
|
||||
-- *** Handle response ***
|
||||
-- Calculate next pointer
|
||||
when ProcResp0_s =>
|
||||
v.OpenCommand(r.HndlStream) := '0';
|
||||
v.FirstOngoing(r.HndlStream) := '0';
|
||||
v.HndlPtr1 := std_logic_vector(unsigned(r.HndlPtr0) + unsigned(Dma_Resp.Size));
|
||||
v.State := NextWin_s;
|
||||
-- Update window information step 1
|
||||
v.HndlWinBytes := std_logic_vector(unsigned(r.HndlWinBytes) + unsigned(Dma_Resp.Size));
|
||||
|
||||
|
||||
-- Calculate next window to use
|
||||
when NextWin_s =>
|
||||
-- Default Values
|
||||
v.HndlPtr2 := r.HndlPtr1;
|
||||
-- Do not wait for "transfer done" for zero size transfers (they are not passed to the memory interface)
|
||||
if unsigned(Dma_Resp.Size) /= 0 then
|
||||
v.IrqFifoWrite := '1';
|
||||
end if;
|
||||
-- Switch to next window if required
|
||||
v.HndlLastWinNr := r.HndlWincur;
|
||||
if ((r.HndlPtr1 = r.HndlWinEnd) and (r.HndlRingbuf = '0')) or (Dma_Resp.Trigger = '1') then
|
||||
v.HndlWinDone := '1';
|
||||
v.NewBuffer(r.HndlStream) := '1';
|
||||
if r.HndlWincur = r.HndlWincnt then
|
||||
v.HndlWincur := (others => '0');
|
||||
v.HndlPtr2 := r.HndlBufstart;
|
||||
v.HndlWinEnd := std_logic_vector(unsigned(r.HndlBufstart) + unsigned(r.HndlWinSize));
|
||||
else
|
||||
v.HndlWincur := std_logic_vector(unsigned(r.HndlWincur) + 1);
|
||||
v.HndlPtr2 := r.HndlWinEnd;
|
||||
v.HndlWinEnd := std_logic_vector(unsigned(r.HndlWinEnd) + unsigned(r.HndlWinSize));
|
||||
end if;
|
||||
end if;
|
||||
-- wraparound for ringbuffer case
|
||||
if (r.HndlPtr1 = r.HndlWinEnd) and (r.HndlRingbuf = '1') and (Dma_Resp.Trigger = '0') then
|
||||
v.HndlPtr2 := std_logic_vector(unsigned(r.HndlPtr1) - unsigned(r.HndlWinSize));
|
||||
end if;
|
||||
-- Update window information step 2 (limit to maximum value)
|
||||
if unsigned(r.HndlWinBytes) > unsigned(r.HndlWinSize) then
|
||||
v.HndlWinBytes := '0' & r.HndlWinSize; -- value has a guard bit
|
||||
end if;
|
||||
-- Store address of last sample in window
|
||||
v.HndlWinLast := std_logic_vector(unsigned(r.HndlPtr1) - StreamWidth_g(r.HndlStream)/8);
|
||||
-- Latch timestamp
|
||||
if (Dma_Resp.Trigger = '1') and (Ts_Vld(r.HndlStream) = '1') then
|
||||
v.Ts_Rdy(r.HndlStream) := '1';
|
||||
v.HndlTs := Ts_Data(r.HndlStream);
|
||||
else
|
||||
v.HndlTs := (others => '1');
|
||||
end if;
|
||||
-- Write values
|
||||
v.State := WriteCtx_s;
|
||||
v.HndlCtxCnt := 0;
|
||||
-- Response is processed
|
||||
v.Dma_Resp_Rdy := '1';
|
||||
|
||||
-- Write Context Memory Content
|
||||
when WriteCtx_s =>
|
||||
-- Update State
|
||||
if r.HndlCtxCnt = 2 then
|
||||
v.State := Idle_s;
|
||||
else
|
||||
v.HndlCtxCnt := r.HndlCtxCnt + 1;
|
||||
end if;
|
||||
-- Write Context Memory
|
||||
v.CtxStr_Cmd.Stream := v.HndlStream;
|
||||
case r.HndlCtxCnt is
|
||||
when 0 =>
|
||||
-- Stream Memory
|
||||
v.CtxStr_Cmd.Sel := CtxStr_Sel_ScfgBufstart_c;
|
||||
v.CtxStr_Cmd.WenLo := '1';
|
||||
v.CtxStr_Cmd.WdatLo(CtxStr_Sft_SCFG_RINGBUF_c) := r.HndlRingbuf;
|
||||
v.CtxStr_Cmd.WdatLo(CtxStr_Sft_SCFG_OVERWRITE_c) := r.HndlOverwrite;
|
||||
v.CtxStr_Cmd.WdatLo(CtxStr_Sft_SCFG_WINCNT_c+v.HndlWincnt'high downto CtxStr_Sft_SCFG_WINCNT_c) := r.HndlWincnt;
|
||||
v.CtxStr_Cmd.WdatLo(CtxStr_Sft_SCFG_WINCUR_c+v.HndlWincur'high downto CtxStr_Sft_SCFG_WINCUR_c) := r.HndlWincur;
|
||||
-- Window Memory
|
||||
v.CtxWin_Cmd.Sel := CtxWin_Sel_WincntWinlast_c;
|
||||
v.CtxWin_Cmd.WenLo := '1';
|
||||
v.CtxWin_Cmd.WenHi := '1';
|
||||
v.CtxWin_Cmd.WdatLo := ShiftRight(r.HndlWinBytes(31 downto 0), Log2StrBytes_c(r.HndlStream)); -- cut-off guard bit and convert bytes to samples
|
||||
v.CtxWin_Cmd.WdatLo(31) := r.EndByTrig;
|
||||
v.CtxWin_Cmd.WdatHi := r.HndlWinLast;
|
||||
when 1 =>
|
||||
-- Stream Memory
|
||||
v.CtxStr_Cmd.Sel := CtxStr_Sel_WinsizePtr_c;
|
||||
v.CtxStr_Cmd.WenHi := '1';
|
||||
v.CtxStr_Cmd.WdatHi := r.HndlPtr2;
|
||||
-- Window Memory
|
||||
if r.HndlWinDone = '1' then
|
||||
v.CtxWin_Cmd.Sel := CtxWin_Sel_WinTs_c;
|
||||
v.CtxWin_Cmd.WenHi := '1';
|
||||
v.CtxWin_Cmd.WenLo := '1';
|
||||
v.CtxWin_Cmd.WdatLo := r.HndlTs(31 downto 0);
|
||||
v.CtxWin_Cmd.WdatHi := r.HndlTs(63 downto 32);
|
||||
end if;
|
||||
when 2 =>
|
||||
-- Stream Memory
|
||||
v.CtxStr_Cmd.Sel := CtxStr_Sel_Winend_c;
|
||||
v.CtxStr_Cmd.WenLo := '1';
|
||||
v.CtxStr_Cmd.WdatLo := r.HndlWinEnd;
|
||||
when others => null;
|
||||
end case;
|
||||
end case;
|
||||
|
||||
-- *** Handle Disabled Streams ***
|
||||
for str in 0 to Streams_g-1 loop
|
||||
if (r.GlbEnaReg = '0') or (r.StrEnaReg(str) = '0') then
|
||||
v.FirstAfterEna(str) := '1';
|
||||
v.NewBuffer(str) := '1';
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
-- *** IRQ Handling ***
|
||||
-- Feedback from memory controller
|
||||
if r.TfDoneReg = '1' then
|
||||
v.TfDoneCnt := std_logic_vector(unsigned(r.TfDoneCnt) + 1);
|
||||
end if;
|
||||
|
||||
-- Process transfer completion
|
||||
if (unsigned(r.TfDoneCnt) /= 0) and (IrqFifoEmpty = '0') then
|
||||
v.IrqFifoRead := '1';
|
||||
v.TfDoneCnt := std_logic_vector(unsigned(v.TfDoneCnt) - 1);
|
||||
-- Generate IRQ if required
|
||||
if IrqFifoGenIrq = '1' then
|
||||
v.StrIrq(to_integer(unsigned(IrqFifoStream))) := '1';
|
||||
v.StrLastWin(to_integer(unsigned(IrqFifoStream))) := std_logic_vector(resize(unsigned(IrqLastWinNr), 5));
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- *** Assign to signal ***
|
||||
r_next <= v;
|
||||
|
||||
end process;
|
||||
|
||||
-- *** Registered Outputs ***
|
||||
CtxStr_Cmd <= r.CtxStr_Cmd;
|
||||
CtxWin_Cmd <= r.CtxWin_Cmd;
|
||||
Dma_Cmd_Vld <= r.Dma_Cmd_Vld;
|
||||
Dma_Cmd <= r.Dma_Cmd;
|
||||
Dma_Resp_Rdy <= r.Dma_Resp_Rdy;
|
||||
Ts_Rdy <= r.Ts_Rdy;
|
||||
StrIrq <= r.StrIrq;
|
||||
StrLastWin <= r.StrLastWin;
|
||||
|
||||
--------------------------------------------
|
||||
-- Sequential Process
|
||||
--------------------------------------------
|
||||
p_seq : process(Clk)
|
||||
begin
|
||||
if rising_edge(Clk) then
|
||||
r <= r_next;
|
||||
if Rst = '1' then
|
||||
r.ArbDelCnt <= 0;
|
||||
r.InpDataAvail <= (others => '0');
|
||||
r.DataAvailArbIn <= (others => '0');
|
||||
r.HndlStream <= 0;
|
||||
r.State <= Idle_s;
|
||||
r.CtxStr_Cmd.WenLo <= '0';
|
||||
r.CtxStr_Cmd.WenHi <= '0';
|
||||
r.CtxWin_Cmd.WenLo <= '0';
|
||||
r.CtxWin_Cmd.WenHi <= '0';
|
||||
r.Dma_Cmd_Vld <= '0';
|
||||
r.OpenCommand <= (others => '0');
|
||||
r.WinProtected <= (others => '0');
|
||||
r.Dma_Resp_Rdy <= '0';
|
||||
r.Ts_Rdy <= (others => '0');
|
||||
r.GlbEnaReg <= '0';
|
||||
r.FirstOngoing <= (others => '0');
|
||||
r.TfDoneCnt <= (others => '0');
|
||||
r.TfDoneReg <= '0';
|
||||
r.IrqFifoWrite <= '0';
|
||||
r.IrqFifoRead <= '0';
|
||||
r.StrIrq <= (others => '0');
|
||||
r.StrLastWin <= (others => (others => '0'));
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--------------------------------------------
|
||||
-- Component Instantiation
|
||||
--------------------------------------------
|
||||
-- *** Round Robin Arbiter - Prio 1 ***
|
||||
AvailPrio1 <= GetBitsOfStreamPrio(r.DataAvailArbIn, 1);
|
||||
i_rrarb_1 : entity work.psi_common_arb_priority
|
||||
generic map (
|
||||
Size_g => count(StreamPrio_g, 1)
|
||||
)
|
||||
port map (
|
||||
Clk => Clk,
|
||||
Rst => Rst,
|
||||
Request => AvailPrio1,
|
||||
Grant => GrantPrio1
|
||||
);
|
||||
GrantVld(1) <= '1' when (unsigned(GrantPrio1) /= 0) and (GrantPrio1'length > 0) else '0';
|
||||
|
||||
-- *** Round Robin Arbiter - Prio 2 ***
|
||||
AvailPrio2 <= GetBitsOfStreamPrio(r.DataAvailArbIn, 2);
|
||||
i_rrarb_2 : entity work.psi_common_arb_priority
|
||||
generic map (
|
||||
Size_g => count(StreamPrio_g, 2)
|
||||
)
|
||||
port map (
|
||||
Clk => Clk,
|
||||
Rst => Rst,
|
||||
Request => AvailPrio2,
|
||||
Grant => GrantPrio2
|
||||
);
|
||||
GrantVld(2) <= '1' when (unsigned(GrantPrio2) /= 0) and (GrantPrio2'length > 0) else '0';
|
||||
|
||||
-- *** Round Robin Arbiter - Prio 3 ***
|
||||
AvailPrio3 <= GetBitsOfStreamPrio(r.DataAvailArbIn, 3);
|
||||
i_rrarb_3 : entity work.psi_common_arb_priority
|
||||
generic map (
|
||||
Size_g => count(StreamPrio_g, 3)
|
||||
)
|
||||
port map (
|
||||
Clk => Clk,
|
||||
Rst => Rst,
|
||||
Request => AvailPrio3,
|
||||
Grant => GrantPrio3
|
||||
);
|
||||
GrantVld(3) <= '1' when (unsigned(GrantPrio3) /= 0) and (GrantPrio3'length > 0) else '0';
|
||||
|
||||
|
||||
-- *** IRQ Information FIFO ***
|
||||
-- input assembly
|
||||
IrqFifoIn(log2ceil(Streams_g)-1 downto 0) <= std_logic_vector(to_unsigned(r.HndlStream, log2ceil(Streams_g)));
|
||||
IrqFifoIn(log2ceil(Streams_g)+log2ceil(Windows_g)-1 downto log2ceil(Streams_g)) <= r.HndlLastWinNr;
|
||||
IrqFifoIn(IrqFifoIn'high) <= r.HndlWinDone;
|
||||
|
||||
-- Instantiation
|
||||
i_irq_fifo : entity work.psi_common_sync_fifo
|
||||
generic map (
|
||||
Width_g => log2ceil(Streams_g)+log2ceil(Windows_g)+1,
|
||||
Depth_g => Streams_g*4,
|
||||
AlmFullOn_g => true,
|
||||
AlmFullLevel_g => Streams_g*3,
|
||||
RamStyle_g => "distributed"
|
||||
)
|
||||
port map (
|
||||
Clk => Clk,
|
||||
Rst => Rst,
|
||||
InData => IrqFifoIn,
|
||||
InVld => r.IrqFifoWrite,
|
||||
OutData => IrqFifoOut,
|
||||
OutRdy => r.IrqFifoRead,
|
||||
AlmFull => IrqFifoAlmFull,
|
||||
Empty => IrqFifoEmpty
|
||||
);
|
||||
|
||||
-- Output disassembly
|
||||
IrqFifoStream <= IrqFifoOut(log2ceil(Streams_g)-1 downto 0);
|
||||
IrqLastWinNr <= IrqFifoOut(log2ceil(Streams_g)+log2ceil(Windows_g)-1 downto log2ceil(Streams_g));
|
||||
IrqFifoGenIrq <= IrqFifoOut(IrqFifoOut'high);
|
||||
|
||||
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
|
547
hdl/psi_ms_daq_input.vhd
Normal file
547
hdl/psi_ms_daq_input.vhd
Normal file
@ -0,0 +1,547 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2019 by Paul Scherrer Institute, Switzerland
|
||||
-- All rights reserved.
|
||||
-- Authors: Oliver Bruendler
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Description
|
||||
------------------------------------------------------------------------------
|
||||
-- This component calculates a binary division of two fixed point values.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Libraries
|
||||
------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.psi_common_math_pkg.all;
|
||||
use work.psi_ms_daq_pkg.all;
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Entity Declaration
|
||||
------------------------------------------------------------------------------
|
||||
-- $$ testcases=single_frame,multi_frame,timeout,ts_overflow,trig_in_posttrig,always_trig,backpressure,modes $$
|
||||
-- $$ processes=stream,daq $$
|
||||
-- $$ tbpkg=work.psi_tb_txt_util $$
|
||||
entity psi_ms_daq_input is
|
||||
generic (
|
||||
StreamWidth_g : positive range 8 to 64 := 16; -- Must be 8, 16, 32 or 64 $$ export=true $$
|
||||
StreamBuffer_g : positive range 1 to 65535 := 1024; -- Buffer depth in QWORDs $$ constant=32 $$
|
||||
StreamTimeout_g : real := 1.0e-3; -- Timeout in seconds $$ constant=10.0e-6 $$
|
||||
StreamClkFreq_g : real := 125.0e6; -- Input clock frequency in Hz $$ constant=125.0e6 $$
|
||||
StreamTsFifoDepth_g : positive := 16; -- Timestamp FIFO depth $$ constant=3 $$
|
||||
StreamUseTs_g : boolean := true -- Enable/Disable the timestamp acquisition $$ constant=true $$
|
||||
);
|
||||
port (
|
||||
-- Data Stream Input
|
||||
Str_Clk : in std_logic; -- $$ type=clk; freq=125e6; proc=stream $$
|
||||
Str_Vld : in std_logic; -- $$ proc=stream $$
|
||||
Str_Rdy : out std_logic; -- $$ proc=stream $$
|
||||
Str_Data : in std_logic_vector(StreamWidth_g-1 downto 0); -- $$ proc=stream $$
|
||||
Str_Trig : in std_logic; -- $$ proc=stream $$
|
||||
Str_Ts : in std_logic_vector(63 downto 0); -- $$ proc=stream $$
|
||||
|
||||
-- Configuration Signals
|
||||
ClkReg : in std_logic;
|
||||
RstReg : in std_logic;
|
||||
PostTrigSpls : in std_logic_vector(31 downto 0); -- $$ proc=daq $$
|
||||
Mode : in RecMode_t; -- $$ proc=daq $$
|
||||
Arm : in std_logic; -- $$ proc=stream $$
|
||||
IsArmed : out std_logic; -- $$ proc=stream $$
|
||||
IsRecording : out std_logic; -- $$ proc=stream $$
|
||||
|
||||
-- DAQ control signals
|
||||
ClkMem : in std_logic; -- $$ type=clk; freq=200e6; proc=daq,stream $$
|
||||
RstMem : in std_logic; -- $$ type=rst; clk=Clk $$
|
||||
|
||||
-- DAQ logic Connections
|
||||
Daq_Vld : out std_logic; -- $$ proc=daq $$
|
||||
Daq_Rdy : in std_logic; -- $$ proc=daq $$
|
||||
Daq_Data : out Input2Daq_Data_t; -- $$ proc=daq $$
|
||||
Daq_Level : out std_logic_vector(15 downto 0); -- $$ proc=daq $$
|
||||
Daq_HasLast : out std_logic; -- $$ proc=daq $$
|
||||
|
||||
-- Timestamp connections
|
||||
Ts_Vld : out std_logic; -- $$ proc=daq $$
|
||||
Ts_Rdy : in std_logic; -- $$ proc=daq $$
|
||||
Ts_Data : out std_logic_vector(63 downto 0) -- $$ proc=daq $$
|
||||
);
|
||||
end entity;
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Architecture Declaration
|
||||
------------------------------------------------------------------------------
|
||||
architecture rtl of psi_ms_daq_input is
|
||||
|
||||
-- Use distributed RAM for small Timstamp FIFOs (< 64 entries)
|
||||
constant TsFifoStyle_c : string := choose(StreamTsFifoDepth_g <= 64, "distributed", "block");
|
||||
|
||||
-- Constants
|
||||
constant TimeoutLimit_c : integer := integer(StreamClkFreq_g*StreamTimeout_g)-1;
|
||||
constant WconvFactor_c : positive := 64/StreamWidth_g;
|
||||
constant TlastCntWidth_c : positive := log2ceil(StreamBuffer_g) + 1;
|
||||
|
||||
-- Two process method
|
||||
type two_process_r is record
|
||||
ModeReg : RecMode_t;
|
||||
ArmReg : std_logic;
|
||||
DataSftReg : std_logic_vector(63 downto 0);
|
||||
WordCnt : unsigned(log2ceil(WconvFactor_c) downto 0);
|
||||
DataFifoBytes : unsigned(3 downto 0);
|
||||
TrigLatch : std_logic;
|
||||
DataFifoVld : std_logic;
|
||||
DataFifoIsTo : std_logic;
|
||||
DataFifoIsTrig : std_logic;
|
||||
TimeoutCnt : integer range 0 to TimeoutLimit_c;
|
||||
Timeout : std_logic;
|
||||
PostTrigCnt : unsigned(31 downto 0);
|
||||
TLastCnt : std_logic_vector(TlastCntWidth_c-1 downto 0);
|
||||
TsLatch : std_logic_vector(63 downto 0);
|
||||
TsOverflow : std_logic;
|
||||
HasTlastSync : std_logic_vector(0 to 1);
|
||||
IsArmed : std_logic;
|
||||
RecEna : std_logic;
|
||||
end record;
|
||||
signal r, r_next : two_process_r;
|
||||
|
||||
-- General Instantiation signals
|
||||
signal Str_Rst : std_logic;
|
||||
|
||||
-- Data FIFO signals
|
||||
signal DataFifo_InRdy : std_logic;
|
||||
signal DataFifo_InData : std_logic_vector(69 downto 0);
|
||||
signal DataFifo_OutData : std_logic_vector(69 downto 0);
|
||||
|
||||
-- Internally reused signals
|
||||
signal Daq_Data_I : Input2Daq_Data_t;
|
||||
signal Daq_Vld_I : std_logic;
|
||||
signal Daq_HasLast_I : std_logic;
|
||||
signal Ts_Vld_I : std_logic;
|
||||
|
||||
-- Signal output side TLAST handling
|
||||
signal OutTlastCnt : std_logic_vector(TlastCntWidth_c-1 downto 0);
|
||||
signal InTlastCnt : std_logic_vector(TlastCntWidth_c-1 downto 0);
|
||||
|
||||
-- Timestamp FIFO signals
|
||||
signal TsFifo_InRdy : std_logic;
|
||||
signal TsFifo_InVld : std_logic;
|
||||
signal TsFifo_RdData : std_logic_vector(63 downto 0);
|
||||
signal TsFifo_AlmFull : std_logic;
|
||||
signal TsFifo_Empty : std_logic;
|
||||
|
||||
-- Clock Crossing Signals
|
||||
signal PostTrigSpls_Sync : std_logic_vector(PostTrigSpls'range);
|
||||
signal Mode_Sync : RecMode_t;
|
||||
signal Arm_Sync : std_logic;
|
||||
signal RstReg_Sync : std_logic;
|
||||
signal RstAcq_Sync : std_logic;
|
||||
|
||||
begin
|
||||
--------------------------------------------
|
||||
-- Combinatorial Process
|
||||
--------------------------------------------
|
||||
p_comb : process( r,
|
||||
Str_Vld, Str_Data, Str_Trig, Str_Ts, PostTrigSpls_Sync, Daq_Rdy, Ts_Rdy, Mode_Sync, Arm_Sync,
|
||||
DataFifo_InRdy, DataFifo_InData, DataFifo_OutData, Daq_Vld_I, Daq_Data_I, Daq_HasLast_I, Ts_Vld_I, OutTlastCnt, TsFifo_AlmFull, TsFifo_Empty,
|
||||
InTlastCnt, TsFifo_InRdy, TsFifo_RdData)
|
||||
variable v : two_process_r;
|
||||
variable ProcessSample_v : boolean;
|
||||
variable TriggerSample_v : boolean;
|
||||
variable AddSamples_v : integer range 0 to 1;
|
||||
variable TrigMasked_v : std_logic;
|
||||
begin
|
||||
-- *** Hold variables stable ***
|
||||
v := r;
|
||||
|
||||
-- *** Simplification Variables ***
|
||||
ProcessSample_v := (DataFifo_InRdy = '1') and (Str_Vld = '1');
|
||||
|
||||
-- *** Input Logic Stage ***
|
||||
-- Default values
|
||||
v.DataFifoIsTo := '0';
|
||||
v.DataFifoIsTrig := '0';
|
||||
v.ModeReg := Mode_Sync;
|
||||
v.ArmReg := Arm_Sync;
|
||||
|
||||
-- Masking trigger according to recording mode
|
||||
case r.ModeReg is
|
||||
when RecMode_Continuous_c =>
|
||||
TrigMasked_v := Str_Trig;
|
||||
when RecMode_TriggerMask_c |
|
||||
RecMode_SingleShot_c =>
|
||||
TrigMasked_v := Str_Trig and r.IsArmed;
|
||||
when RecMode_ManuelMode_c =>
|
||||
TrigMasked_v := r.ArmReg;
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
|
||||
-- Keep FifoVld high until data is written
|
||||
v.DataFifoVld := r.DataFifoVld and not DataFifo_InRdy;
|
||||
|
||||
-- Trigger Latching
|
||||
if ProcessSample_v then
|
||||
v.TrigLatch := '0';
|
||||
else
|
||||
v.TrigLatch := r.TrigLatch or TrigMasked_v;
|
||||
end if;
|
||||
|
||||
-- Detect timestamp FIFO overflows
|
||||
if StreamUseTs_g then
|
||||
v.HasTlastSync(0) := Daq_HasLast_I;
|
||||
v.HasTlastSync(1) := r.HasTlastSync(0);
|
||||
if (TsFifo_AlmFull = '1' ) and (r.DataFifoVld = '1') then
|
||||
v.TsOverflow := '1';
|
||||
elsif (r.HasTlastSync(1) = '0') and (TsFifo_Empty = '1' ) then
|
||||
v.TsOverflow := '0';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Timestamp latching
|
||||
if StreamUseTs_g then
|
||||
if (TrigMasked_v = '1') and (unsigned(r.PostTrigCnt) = 0) then
|
||||
if (TsFifo_AlmFull = '1') or (r.TsOverflow = '1') then
|
||||
v.TsLatch := (others => '1');
|
||||
else
|
||||
v.TsLatch := Str_Ts;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Trigger handling and post trigger counter
|
||||
if ProcessSample_v and r.RecEna = '1' then
|
||||
if r.PostTrigCnt /= 0 then
|
||||
v.PostTrigCnt := r.PostTrigCnt - 1;
|
||||
if r.PostTrigCnt = 1 then
|
||||
v.DataFifoIsTrig := '1';
|
||||
v.DataFifoVld := r.DataFifoVld or r.RecEna;
|
||||
v.RecEna := '0'; -- stop recording after frame
|
||||
end if;
|
||||
elsif (r.TrigLatch = '1') or (TrigMasked_v = '1') then
|
||||
-- Handle incoming trigger sample
|
||||
if unsigned(PostTrigSpls_Sync) = 0 then
|
||||
v.DataFifoIsTrig := '1';
|
||||
v.DataFifoVld := r.DataFifoVld or r.RecEna;
|
||||
v.RecEna := '0'; -- stop recording after frame
|
||||
else
|
||||
v.PostTrigCnt := unsigned(PostTrigSpls_Sync);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Detect Timeout
|
||||
if Str_Vld = '1' then
|
||||
v.TimeoutCnt := 0;
|
||||
else
|
||||
if r.TimeoutCnt = TimeoutLimit_c then
|
||||
v.TimeoutCnt := 0;
|
||||
v.Timeout := '1';
|
||||
else
|
||||
v.TimeoutCnt := r.TimeoutCnt + 1;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- TLast counter
|
||||
if (r.DataFifoVld = '1') and ((r.DataFifoIsTo = '1') or (r.DataFifoIsTrig = '1')) then
|
||||
v.TLastCnt := std_logic_vector(unsigned(r.TLastCnt) + 1);
|
||||
end if;
|
||||
|
||||
-- Write because timeout occured (only if data is stuck in conversion)
|
||||
if r.Timeout = '1' then
|
||||
v.DataFifoVld := r.DataFifoVld or r.RecEna;
|
||||
v.DataFifoIsTo := '1';
|
||||
v.Timeout := '0'; -- reser timeout after data was flushed to the FIFO
|
||||
end if;
|
||||
-- Process input data
|
||||
if ProcessSample_v and r.RecEna = '1' then
|
||||
v.WordCnt := r.WordCnt + 1;
|
||||
-- Write because 64-bits are ready
|
||||
if r.WordCnt = WconvFactor_c-1 then
|
||||
v.DataFifoVld := r.DataFifoVld or r.RecEna;
|
||||
end if;
|
||||
v.DataSftReg((to_integer(r.WordCnt)+1)*StreamWidth_g-1 downto to_integer(r.WordCnt)*StreamWidth_g) := Str_Data;
|
||||
end if;
|
||||
-- Reset counter if data is being written to FIFO
|
||||
if v.DataFifoVld = '1' then
|
||||
v.WordCnt := (others => '0');
|
||||
end if;
|
||||
|
||||
-- Convert word counter to byte counter
|
||||
v.DataFifoBytes := (others => '0');
|
||||
if r.Timeout = '1' then
|
||||
AddSamples_v := 0;
|
||||
else
|
||||
AddSamples_v := 1;
|
||||
end if;
|
||||
case StreamWidth_g is
|
||||
when 8 => v.DataFifoBytes := r.WordCnt + AddSamples_v;
|
||||
when 16 => v.DataFifoBytes := (r.WordCnt + AddSamples_v) & "0";
|
||||
when 32 => v.DataFifoBytes := (r.WordCnt + AddSamples_v) & "00";
|
||||
when 64 => v.DataFifoBytes := (r.WordCnt + AddSamples_v) & "000";
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
-- Handle Arming Logic
|
||||
if (r.ModeReg /= Mode_Sync) or (r.ModeReg = RecMode_Continuous_c) or (r.ModeReg = RecMode_ManuelMode_c) then -- reset on mode change!
|
||||
v.IsArmed := '0';
|
||||
elsif r.ArmReg = '1' then
|
||||
v.IsArmed := '1';
|
||||
elsif TrigMasked_v = '1' then
|
||||
v.IsArmed := '0';
|
||||
end if;
|
||||
|
||||
-- Enable Recording Logic
|
||||
case r.ModeReg is
|
||||
when RecMode_Continuous_c |
|
||||
RecMode_TriggerMask_c =>
|
||||
-- always enabled
|
||||
v.RecEna := '1';
|
||||
when RecMode_SingleShot_c |
|
||||
RecMode_ManuelMode_c =>
|
||||
-- enable on arming (disable happens after recording)
|
||||
if v.ArmReg = '1' then
|
||||
v.RecEna := '1';
|
||||
end if;
|
||||
when others => null;
|
||||
end case;
|
||||
if r.ModeReg /= Mode_Sync then
|
||||
v.RecEna := '0';
|
||||
end if;
|
||||
|
||||
-- *** Assign to signal ***
|
||||
r_next <= v;
|
||||
|
||||
end process;
|
||||
|
||||
--------------------------------------------
|
||||
-- Sequential Process
|
||||
--------------------------------------------
|
||||
p_seq : process(Str_Clk)
|
||||
begin
|
||||
if rising_edge(Str_Clk) then
|
||||
r <= r_next;
|
||||
if Str_Rst = '1' then
|
||||
r.WordCnt <= (others => '0');
|
||||
r.TrigLatch <= '0';
|
||||
r.TimeoutCnt <= 0;
|
||||
r.Timeout <= '0';
|
||||
r.PostTrigCnt <= (others => '0');
|
||||
r.TLastCnt <= (others => '0');
|
||||
r.TsOverflow <= '0';
|
||||
r.HasTlastSync <= (others => '0');
|
||||
r.IsArmed <= '0';
|
||||
r.RecEna <= '0';
|
||||
r.ArmReg <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--------------------------------------------
|
||||
-- Output Side TLAST handling
|
||||
--------------------------------------------
|
||||
p_outlast : process(ClkMem)
|
||||
begin
|
||||
if rising_edge(ClkMem) then
|
||||
-- Default Value
|
||||
Daq_HasLast_I <= '0';
|
||||
|
||||
-- Count TLAST read from output buffer
|
||||
if (Daq_Vld_I = '1') and (Daq_Rdy = '1') and (Daq_Data_I.Last = '1') then
|
||||
OutTlastCnt <= std_logic_vector(unsigned(OutTlastCnt) + 1);
|
||||
end if;
|
||||
|
||||
-- Detect if there are TLASTs in the buffer
|
||||
if OutTlastCnt /= InTlastCnt then
|
||||
Daq_HasLast_I <= '1';
|
||||
end if;
|
||||
|
||||
-- Reset
|
||||
if RstMem = '1' then
|
||||
OutTlastCnt <= (others => '0');
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
Daq_HasLast <= Daq_HasLast_I;
|
||||
|
||||
--------------------------------------------
|
||||
-- Component Instantiation
|
||||
--------------------------------------------
|
||||
-- *** Register Interface clock crossings ***
|
||||
i_cc_reg_status : entity work.psi_common_status_cc
|
||||
generic map (
|
||||
DataWidth_g => 34
|
||||
)
|
||||
port map (
|
||||
ClkA => ClkReg,
|
||||
RstInA => '0',
|
||||
DataA(31 downto 0) => PostTrigSpls,
|
||||
DataA(33 downto 32) => Mode,
|
||||
ClkB => Str_Clk,
|
||||
RstInB => Str_Rst,
|
||||
DataB(31 downto 0) => PostTrigSpls_Sync,
|
||||
DataB(33 downto 32) => Mode_Sync
|
||||
);
|
||||
|
||||
i_cc_status : entity work.psi_common_bit_cc
|
||||
generic map (
|
||||
NumBits_g => 2
|
||||
)
|
||||
port map (
|
||||
BitsA(0) => r.IsArmed,
|
||||
BitsA(1) => r.RecEna,
|
||||
ClkB => ClkReg,
|
||||
BitsB(0) => IsArmed,
|
||||
BitsB(1) => IsRecording
|
||||
);
|
||||
|
||||
i_cc_reg_pulse : entity work.psi_common_pulse_cc
|
||||
generic map (
|
||||
NumPulses_g => 1
|
||||
)
|
||||
port map (
|
||||
ClkA => ClkReg,
|
||||
RstInA => '0',
|
||||
PulseA(0) => Arm,
|
||||
ClkB => Str_Clk,
|
||||
RstInB => Str_Rst,
|
||||
RstOutB => open,
|
||||
PulseB(0) => Arm_Sync
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- *** Reset Handling ***
|
||||
icc_reg_rst : entity work.psi_common_bit_cc
|
||||
generic map (
|
||||
NumBits_g => 1
|
||||
)
|
||||
port map (
|
||||
BitsA(0) => RstReg,
|
||||
ClkB => Str_Clk,
|
||||
BitsB(0) => RstReg_Sync
|
||||
);
|
||||
|
||||
icc_mem_rst : entity work.psi_common_bit_cc
|
||||
generic map (
|
||||
NumBits_g => 1
|
||||
)
|
||||
port map (
|
||||
BitsA(0) => RstMem,
|
||||
ClkB => Str_Clk,
|
||||
BitsB(0) => RstAcq_Sync
|
||||
);
|
||||
Str_Rst <= RstReg_Sync or RstAcq_Sync;
|
||||
|
||||
-- *** Acquisition Clock Crossing ***
|
||||
-- Clock crossing for reset and TLAST counter
|
||||
i_cc : entity work.psi_common_status_cc
|
||||
generic map (
|
||||
DataWidth_g => TlastCntWidth_c
|
||||
)
|
||||
port map (
|
||||
ClkA => Str_Clk,
|
||||
RstInA => Str_Rst,
|
||||
RstOutA => open,
|
||||
DataA => r.TLastCnt,
|
||||
ClkB => ClkMem,
|
||||
RstInB => '0',
|
||||
DataB => InTlastCnt
|
||||
);
|
||||
|
||||
|
||||
-- Data FIFO
|
||||
DataFifo_InData(63 downto 0) <= r.DataSftReg;
|
||||
DataFifo_InData(67 downto 64) <= std_logic_vector(r.DataFifoBytes);
|
||||
DataFifo_InData(68) <= r.DataFifoIsTo;
|
||||
DataFifo_InData(69) <= r.DataFifoIsTrig;
|
||||
|
||||
|
||||
i_dfifo : entity work.psi_common_async_fifo
|
||||
generic map (
|
||||
Width_g => 70,
|
||||
Depth_g => StreamBuffer_g,
|
||||
AlmFullOn_g => false,
|
||||
AlmEmptyOn_g => false
|
||||
)
|
||||
port map (
|
||||
InClk => Str_Clk,
|
||||
InRst => Str_Rst,
|
||||
OutClk => ClkMem,
|
||||
OutRst => '0',
|
||||
InData => DataFifo_InData,
|
||||
InVld => r.DataFifoVld,
|
||||
InRdy => DataFifo_InRdy,
|
||||
OutData => DataFifo_OutData,
|
||||
OutVld => Daq_Vld_I,
|
||||
OutRdy => Daq_Rdy,
|
||||
OutLevel => Daq_Level(log2ceil(StreamBuffer_g) downto 0)
|
||||
);
|
||||
Daq_Level(Daq_Level'high downto log2ceil(StreamBuffer_g)+1) <= (others => '0');
|
||||
Str_Rdy <= DataFifo_InRdy;
|
||||
|
||||
Daq_Data_I.Data <= DataFifo_OutData(63 downto 0);
|
||||
Daq_Data_I.Bytes <= DataFifo_OutData(67 downto 64);
|
||||
Daq_Data_I.IsTo <= DataFifo_OutData(68);
|
||||
Daq_Data_I.IsTrig <= DataFifo_OutData(69);
|
||||
Daq_Data_I.Last <= Daq_Data_I.IsTo or Daq_Data_I.IsTrig;
|
||||
Daq_Data <= Daq_Data_I;
|
||||
Daq_Vld <= Daq_Vld_I;
|
||||
|
||||
|
||||
-- Timestamp FIFO
|
||||
g_timestamp : if StreamUseTs_g generate
|
||||
TsFifo_InVld <= r.DataFifoVld and r.DataFifoIsTrig;
|
||||
|
||||
i_tsfifo : entity work.psi_common_async_fifo
|
||||
generic map (
|
||||
Width_g => 64,
|
||||
Depth_g => StreamTsFifoDepth_g,
|
||||
AlmFullOn_g => True,
|
||||
AlmFullLevel_g => StreamTsFifoDepth_g-1,
|
||||
AlmEmptyOn_g => false,
|
||||
RamStyle_g => TsFifoStyle_c
|
||||
)
|
||||
port map (
|
||||
InClk => Str_Clk,
|
||||
InRst => Str_Rst,
|
||||
OutClk => ClkMem,
|
||||
OutRst => '0',
|
||||
InData => r.TsLatch,
|
||||
InVld => TsFifo_InVld,
|
||||
InRdy => TsFifo_InRdy,
|
||||
InAlmFull => TsFifo_AlmFull,
|
||||
InEmpty => TsFifo_Empty,
|
||||
OutData => TsFifo_RdData,
|
||||
OutVld => Ts_Vld_I,
|
||||
OutRdy => Ts_Rdy
|
||||
);
|
||||
Ts_Vld <= Ts_Vld_I;
|
||||
-- Replace data by 0xFF... if no valid timestamp is available
|
||||
Ts_Data <= (others => '1') when Ts_Vld_I = '0' else TsFifo_RdData;
|
||||
end generate;
|
||||
|
||||
g_ntimestamp : if not StreamUseTs_g generate
|
||||
Ts_Vld <= '0';
|
||||
Ts_Data <= (others => '1');
|
||||
end generate;
|
||||
|
||||
|
||||
--------------------------------------------
|
||||
-- Assertions
|
||||
--------------------------------------------
|
||||
p_assert : process(ClkMem)
|
||||
begin
|
||||
if rising_edge(ClkMem) then
|
||||
assert StreamWidth_g = 8 or StreamWidth_g = 16 or StreamWidth_g = 32 or StreamWidth_g = 64 report "###ERROR###: psi_ms_daq_input: StreamWidth_g must be 8, 16, 32 or 64" severity error;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
|
164
hdl/psi_ms_daq_pkg.vhd
Normal file
164
hdl/psi_ms_daq_pkg.vhd
Normal file
@ -0,0 +1,164 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2019 by Paul Scherrer Institute, Switzerland
|
||||
-- All rights reserved.
|
||||
-- Authors: Oliver Bruendler
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Libraries
|
||||
------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.psi_common_math_pkg.all;
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Package Header
|
||||
------------------------------------------------------------------------------
|
||||
package psi_ms_daq_pkg is
|
||||
|
||||
constant MaxStreams_c : integer := 32;
|
||||
constant MaxWindows_c : integer := 32;
|
||||
constant MaxStreamsBits_c : integer := log2ceil(MaxStreams_c);
|
||||
constant MaxWindowsBits_c : integer := log2ceil(MaxWindows_c);
|
||||
constant MaxStreamWidth_c : integer := 64;
|
||||
|
||||
subtype RecMode_t is std_logic_vector(1 downto 0);
|
||||
constant RecMode_Continuous_c : RecMode_t := std_logic_vector(to_unsigned(0, RecMode_t'length));
|
||||
constant RecMode_TriggerMask_c : RecMode_t := std_logic_vector(to_unsigned(1, RecMode_t'length));
|
||||
constant RecMode_SingleShot_c : RecMode_t := std_logic_vector(to_unsigned(2, RecMode_t'length));
|
||||
constant RecMode_ManuelMode_c : RecMode_t := std_logic_vector(to_unsigned(3, RecMode_t'length));
|
||||
|
||||
subtype WinType_t is std_logic_vector(MaxWindowsBits_c-1 downto 0);
|
||||
type WinType_a is array (natural range <>) of WinType_t;
|
||||
|
||||
type Input2Daq_Data_t is record
|
||||
Last : std_logic;
|
||||
Data : std_logic_vector(63 downto 0);
|
||||
Bytes : std_logic_vector(3 downto 0);
|
||||
IsTo : std_logic;
|
||||
IsTrig : std_logic;
|
||||
end record;
|
||||
type Input2Daq_Data_a is array (natural range <>) of Input2Daq_Data_t;
|
||||
|
||||
type DaqSm2DaqDma_Cmd_t is record
|
||||
Address : std_logic_vector(31 downto 0);
|
||||
MaxSize : std_logic_vector(15 downto 0);
|
||||
Stream : integer range 0 to MaxStreams_c-1;
|
||||
end record;
|
||||
constant DaqSm2DaqDma_Cmd_Size_c : integer := 32+16+MaxStreamsBits_c;
|
||||
function DaqSm2DaqDma_Cmd_ToStdlv( rec : DaqSm2DaqDma_Cmd_t) return std_logic_vector;
|
||||
function DaqSm2DaqDma_Cmd_FromStdlv( stdlv : std_logic_vector) return DaqSm2DaqDma_Cmd_t;
|
||||
|
||||
type DaqDma2DaqSm_Resp_t is record
|
||||
Size : std_logic_vector(15 downto 0);
|
||||
Trigger : std_logic;
|
||||
Stream : integer range 0 to MaxStreams_c-1;
|
||||
end record;
|
||||
constant DaqDma2DaqSm_Resp_Size_c : integer := 16+1+MaxStreamsBits_c;
|
||||
function DaqDma2DaqSm_Resp_ToStdlv( rec : DaqDma2DaqSm_Resp_t) return std_logic_vector;
|
||||
function DaqDme2DaqSm_Resp_FromStdlv( stdlv : std_logic_vector) return DaqDma2DaqSm_Resp_t;
|
||||
|
||||
type ToCtxStr_t is record
|
||||
Stream : integer range 0 to MaxStreams_c-1;
|
||||
Sel : std_logic_vector(1 downto 0);
|
||||
Rd : std_logic;
|
||||
WenLo : std_logic;
|
||||
WenHi : std_logic;
|
||||
WdatLo : std_logic_vector(31 downto 0);
|
||||
WdatHi : std_logic_vector(31 downto 0);
|
||||
end record;
|
||||
constant CtxStr_Sel_ScfgBufstart_c : std_logic_vector(1 downto 0) := "00";
|
||||
constant CtxStr_Sel_WinsizePtr_c : std_logic_vector(1 downto 0) := "01";
|
||||
constant CtxStr_Sel_Winend_c : std_logic_vector(1 downto 0) := "10";
|
||||
constant CtxStr_Sft_SCFG_RINGBUF_c : integer := 0;
|
||||
constant CtxStr_Sft_SCFG_OVERWRITE_c : integer := 8;
|
||||
constant CtxStr_Sft_SCFG_WINCNT_c : integer := 16;
|
||||
constant CtxStr_Sft_SCFG_WINCUR_c : integer := 24;
|
||||
|
||||
type ToCtxWin_t is record
|
||||
Stream : integer range 0 to MaxStreams_c-1;
|
||||
Window : integer range 0 to MaxWindows_c-1;
|
||||
Sel : std_logic_vector(0 downto 0);
|
||||
Rd : std_logic;
|
||||
WenLo : std_logic;
|
||||
WenHi : std_logic;
|
||||
WdatLo : std_logic_vector(31 downto 0);
|
||||
WdatHi : std_logic_vector(31 downto 0);
|
||||
end record;
|
||||
constant CtxWin_Sel_WincntWinlast_c : std_logic_vector(0 downto 0) := "0";
|
||||
constant CtxWin_Sel_WinTs_c : std_logic_vector(0 downto 0) := "1";
|
||||
|
||||
type FromCtx_t is record
|
||||
RdatLo : std_logic_vector(31 downto 0);
|
||||
RdatHi : std_logic_vector(31 downto 0);
|
||||
end record;
|
||||
|
||||
type TmemRqst_t is record
|
||||
ADD : std_logic_vector(23 downto 0);
|
||||
DATW : std_logic_vector(63 downto 0);
|
||||
ENA : std_logic;
|
||||
WE : std_logic_vector(7 downto 0);
|
||||
CS : std_logic_vector(1 downto 0);
|
||||
end record;
|
||||
constant TmemRqst_init_c : TmemRqst_t := ((others => '0'), (others => '0'), '0', (others => '0'), (others => '0'));
|
||||
|
||||
type TmemResp_t is record
|
||||
DATR : std_logic_vector(63 downto 0);
|
||||
BUSY : std_logic;
|
||||
PIPE : std_logic_vector(1 downto 0);
|
||||
end record;
|
||||
|
||||
end psi_ms_daq_pkg;
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Package Body
|
||||
------------------------------------------------------------------------------
|
||||
package body psi_ms_daq_pkg is
|
||||
|
||||
-- *** DaqSm2DaqDma_Cmd ***
|
||||
function DaqSm2DaqDma_Cmd_ToStdlv( rec : DaqSm2DaqDma_Cmd_t) return std_logic_vector is
|
||||
variable stdlv : std_logic_vector(DaqSm2DaqDma_Cmd_Size_c-1 downto 0);
|
||||
begin
|
||||
stdlv(31 downto 0) := rec.Address;
|
||||
stdlv(47 downto 32) := rec.MaxSize;
|
||||
stdlv(stdlv'left downto 48) := std_logic_vector(to_unsigned(rec.Stream, MaxStreamsBits_c));
|
||||
return stdlv;
|
||||
end function;
|
||||
|
||||
function DaqSm2DaqDma_Cmd_FromStdlv( stdlv : std_logic_vector) return DaqSm2DaqDma_Cmd_t is
|
||||
variable rec : DaqSm2DaqDma_Cmd_t;
|
||||
begin
|
||||
rec.Address := stdlv(31 downto 0);
|
||||
rec.MaxSize := stdlv(47 downto 32);
|
||||
rec.Stream := to_integer(unsigned(stdlv(stdlv'left downto 48)));
|
||||
return rec;
|
||||
end function;
|
||||
|
||||
-- *** DaqDma2DaqSm_Resp ***
|
||||
function DaqDma2DaqSm_Resp_ToStdlv( rec : DaqDma2DaqSm_Resp_t) return std_logic_vector is
|
||||
variable stdlv : std_logic_vector(DaqDma2DaqSm_Resp_Size_c-1 downto 0);
|
||||
begin
|
||||
stdlv(15 downto 0) := rec.Size;
|
||||
stdlv(16) := rec.Trigger;
|
||||
stdlv(stdlv'left downto 17) := std_logic_vector(to_unsigned(rec.Stream, MaxStreamsBits_c));
|
||||
return stdlv;
|
||||
end function;
|
||||
|
||||
function DaqDme2DaqSm_Resp_FromStdlv( stdlv : std_logic_vector) return DaqDma2DaqSm_Resp_t is
|
||||
variable rec : DaqDma2DaqSm_Resp_t;
|
||||
begin
|
||||
rec.Size := stdlv(15 downto 0);
|
||||
rec.Trigger := stdlv(16);
|
||||
rec.Stream := to_integer(unsigned(stdlv(stdlv'left downto 17)));
|
||||
return rec;
|
||||
end function;
|
||||
|
||||
end psi_ms_daq_pkg;
|
||||
|
||||
|
||||
|
||||
|
||||
|
562
hdl/psi_ms_daq_reg_axi.vhd
Normal file
562
hdl/psi_ms_daq_reg_axi.vhd
Normal file
@ -0,0 +1,562 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- Copyright (c) 2019 by Paul Scherrer Institute, Switzerland
|
||||
-- All rights reserved.
|
||||
-- Authors: Oliver Bruendler
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Libraries
|
||||
------------------------------------------------------------------------------
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.psi_common_math_pkg.all;
|
||||
use work.psi_common_array_pkg.all;
|
||||
use work.psi_common_logic_pkg.all;
|
||||
use work.psi_ms_daq_pkg.all;
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Entity Declaration
|
||||
------------------------------------------------------------------------------
|
||||
entity psi_ms_daq_reg_axi is
|
||||
generic (
|
||||
Streams_g : integer range 1 to 32;
|
||||
MaxWindows_g : integer range 1 to 32;
|
||||
AxiSlaveIdWidth_g : integer
|
||||
);
|
||||
port (
|
||||
-- AXI Control Signals
|
||||
S_Axi_Aclk : in std_logic;
|
||||
S_Axi_Aresetn : in std_logic;
|
||||
-- AXI Read address channel
|
||||
S_Axi_ArId : in std_logic_vector(AxiSlaveIdWidth_g-1 downto 0);
|
||||
S_Axi_ArAddr : in std_logic_vector(15 downto 0);
|
||||
S_Axi_Arlen : in std_logic_vector(7 downto 0);
|
||||
S_Axi_ArSize : in std_logic_vector(2 downto 0);
|
||||
S_Axi_ArBurst : in std_logic_vector(1 downto 0);
|
||||
S_Axi_ArLock : in std_logic;
|
||||
S_Axi_ArCache : in std_logic_vector(3 downto 0);
|
||||
S_Axi_ArProt : in std_logic_vector(2 downto 0);
|
||||
S_Axi_ArValid : in std_logic;
|
||||
S_Axi_ArReady : out std_logic;
|
||||
-- AXI Read data channel
|
||||
S_Axi_RId : out std_logic_vector(AxiSlaveIdWidth_g-1 downto 0);
|
||||
S_Axi_RData : out std_logic_vector(31 downto 0);
|
||||
S_Axi_RResp : out std_logic_vector(1 downto 0);
|
||||
S_Axi_RLast : out std_logic;
|
||||
S_Axi_RValid : out std_logic;
|
||||
S_Axi_RReady : in std_logic;
|
||||
-- AXI Write address channel
|
||||
S_Axi_AwId : in std_logic_vector(AxiSlaveIdWidth_g-1 downto 0);
|
||||
S_Axi_AwAddr : in std_logic_vector(15 downto 0);
|
||||
S_Axi_AwLen : in std_logic_vector(7 downto 0);
|
||||
S_Axi_AwSize : in std_logic_vector(2 downto 0);
|
||||
S_Axi_AwBurst : in std_logic_vector(1 downto 0);
|
||||
S_Axi_AwLock : in std_logic;
|
||||
S_Axi_AwCache : in std_logic_vector(3 downto 0);
|
||||
S_Axi_AwProt : in std_logic_vector(2 downto 0);
|
||||
S_Axi_AwValid : in std_logic;
|
||||
S_Axi_AwReady : out std_logic;
|
||||
-- AXI Write data channel
|
||||
S_Axi_WData : in std_logic_vector(31 downto 0);
|
||||
S_Axi_WStrb : in std_logic_vector(3 downto 0);
|
||||
S_Axi_WLast : in std_logic;
|
||||
S_Axi_WValid : in std_logic;
|
||||
S_Axi_WReady : out std_logic;
|
||||
-- AXI Write response channel
|
||||
S_Axi_BId : out std_logic_vector(AxiSlaveIdWidth_g-1 downto 0);
|
||||
S_Axi_BResp : out std_logic_vector(1 downto 0);
|
||||
S_Axi_BValid : out std_logic;
|
||||
S_Axi_BReady : in std_logic;
|
||||
|
||||
-- Control Signals (AXI-S Clk)
|
||||
Arm : out std_logic_vector(Streams_g-1 downto 0);
|
||||
IsArmed : in std_logic_vector(Streams_g-1 downto 0);
|
||||
IsRecording : in std_logic_vector(Streams_g-1 downto 0);
|
||||
PostTrig : out t_aslv32(Streams_g-1 downto 0);
|
||||
RecMode : out t_aslv2(Streams_g-1 downto 0);
|
||||
IrqOut : out std_logic;
|
||||
|
||||
-- Memory Interfae Clock domain control singals
|
||||
ClkMem : in std_logic;
|
||||
RstMem : in std_logic;
|
||||
|
||||
-- Context Memory Interface (MemClk)
|
||||
CtxStr_Cmd : in ToCtxStr_t;
|
||||
CtxStr_Resp : out FromCtx_t;
|
||||
CtxWin_Cmd : in ToCtxWin_t;
|
||||
CtxWin_Resp : out FromCtx_t;
|
||||
|
||||
-- Logic Interface (MemClk)
|
||||
StrIrq : in std_logic_vector(Streams_g-1 downto 0);
|
||||
StrLastWin : in WinType_a(Streams_g-1 downto 0);
|
||||
StrEna : out std_logic_vector(Streams_g-1 downto 0);
|
||||
GlbEna : out std_logic;
|
||||
InLevel : in t_aslv16(Streams_g-1 downto 0)
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture rtl of psi_ms_daq_reg_axi is
|
||||
-- Two process method
|
||||
type two_process_r is record
|
||||
Reg_Gcfg_Ena : std_logic;
|
||||
Reg_Gcfg_IrqEna : std_logic;
|
||||
Reg_IrqVec : std_logic_vector(Streams_g-1 downto 0);
|
||||
Reg_IrqEna : std_logic_vector(Streams_g-1 downto 0);
|
||||
Reg_StrEna : std_logic_vector(Streams_g-1 downto 0);
|
||||
Reg_PostTrig : t_aslv32(Streams_g-1 downto 0);
|
||||
Reg_Mode_Recm : t_aslv2(Streams_g-1 downto 0);
|
||||
Reg_Mode_Arm : std_logic_vector(Streams_g-1 downto 0);
|
||||
Irq : std_logic;
|
||||
RegRdval : std_logic_vector(31 downto 0);
|
||||
AddrReg : std_logic_vector(15 downto 0);
|
||||
MaxLvlClr : std_logic_vector(Streams_g-1 downto 0);
|
||||
end record;
|
||||
signal r, r_next : two_process_r;
|
||||
|
||||
constant DwWrite_c : std_logic_vector(3 downto 0) := "1111";
|
||||
|
||||
constant DepthCtxStr_c : integer := Streams_g*32/8;
|
||||
constant CtxStrAddrHigh_c : integer := log2ceil(Streams_g*32)-1;
|
||||
signal CtxStr_WeLo : std_logic;
|
||||
signal CtxStr_WeHi : std_logic;
|
||||
signal CtxStr_Rdval : std_logic_vector(63 downto 0);
|
||||
signal CtxStr_AddrB : std_logic_vector(log2ceil(DepthCtxStr_c)-1 downto 0);
|
||||
signal AddrCtxStr : boolean;
|
||||
|
||||
constant DepthCtxWin_c : integer := Streams_g*MaxWindows_g*16/8;
|
||||
constant CtxWinAddrHigh_c : integer := log2ceil(Streams_g*MaxWindows_g*16)-1;
|
||||
signal CtxWin_WeLo : std_logic;
|
||||
signal CtxWin_WeHi : std_logic;
|
||||
signal CtxWin_Rdval : std_logic_vector(63 downto 0);
|
||||
signal CtxWin_AddrB : std_logic_vector(log2ceil(DepthCtxWin_c)-1 downto 0);
|
||||
signal AddrCtxWin : boolean;
|
||||
|
||||
-- High active reset
|
||||
signal A_Axi_Areset : std_logic;
|
||||
|
||||
-- Maximum Level Latching
|
||||
signal MaxLevel : t_aslv16(Streams_g-1 downto 0);
|
||||
|
||||
-- Clock Crossing Signals
|
||||
signal StrIrq_Sync : std_logic_vector(Streams_g-1 downto 0);
|
||||
signal StrLastWin_Sync : WinType_a(Streams_g-1 downto 0);
|
||||
signal MaxLevel_Sync : t_aslv16(Streams_g-1 downto 0);
|
||||
signal MaxLevelClr_Sync : std_logic_vector(Streams_g-1 downto 0);
|
||||
|
||||
-- Axi Accesses
|
||||
signal AccAddr : std_logic_vector(15 downto 0);
|
||||
signal AccAddrOffs : std_logic_vector(15 downto 0);
|
||||
signal AccWr : std_logic_vector(3 downto 0);
|
||||
signal AccWrData : std_logic_vector(31 downto 0);
|
||||
signal AccRdData : std_logic_vector(31 downto 0);
|
||||
signal RegWrVal : t_aslv32(0 to 15);
|
||||
signal RegRdVal : t_aslv32(0 to 15) := (others => (others => '0'));
|
||||
signal RegWr : std_logic_vector(15 downto 0);
|
||||
begin
|
||||
A_Axi_Areset <= not S_Axi_Aresetn;
|
||||
|
||||
--------------------------------------------
|
||||
-- Combinatorial Process
|
||||
--------------------------------------------
|
||||
p_comb : process( r, AccAddr, AccWr, AccWrData, StrIrq_Sync, IsArmed, IsRecording, CtxStr_Rdval, CtxWin_Rdval, MaxLevel, StrLastWin_Sync, RegWr, RegWrVal)
|
||||
variable v : two_process_r;
|
||||
variable Stream_v : integer range 0 to Streams_g-1;
|
||||
begin
|
||||
-- *** Hold variables stable ***
|
||||
v := r;
|
||||
|
||||
-- *** General Register Accesses ***
|
||||
-- GCFG
|
||||
if RegWr(16#00#/4) = '1' then
|
||||
v.Reg_Gcfg_Ena := RegWrVal(16#00#/4)(0);
|
||||
v.Reg_Gcfg_IrqEna := RegWrVal(16#00#/4)(8);
|
||||
end if;
|
||||
RegRdVal(16#00#/4)(0) <= r.Reg_Gcfg_Ena;
|
||||
RegRdVal(16#00#/4)(8) <= r.Reg_Gcfg_IrqEna;
|
||||
|
||||
-- GSTAT
|
||||
if RegWr(16#04#/4) = '1' then
|
||||
null;
|
||||
end if;
|
||||
RegRdVal(16#04#/4) <= (others => '0');
|
||||
|
||||
-- IRQVEC
|
||||
if RegWr(16#10#/4) = '1' then
|
||||
v.Reg_IrqVec := r.Reg_IrqVec and (not RegWrVal(16#10#/4)(Streams_g-1 downto 0));
|
||||
end if;
|
||||
RegRdVal(16#10#/4)(Streams_g-1 downto 0) <= r.Reg_IrqVec;
|
||||
|
||||
-- IRQENA
|
||||
if RegWr(16#14#/4) = '1' then
|
||||
v.Reg_IrqEna := RegWrVal(16#14#/4)(Streams_g-1 downto 0);
|
||||
end if;
|
||||
RegRdVal(16#14#/4)(Streams_g-1 downto 0) <= r.Reg_IrqEna;
|
||||
|
||||
-- STRENA
|
||||
if RegWr(16#20#/4) = '1' then
|
||||
v.Reg_StrEna := RegWrVal(16#20#/4)(Streams_g-1 downto 0);
|
||||
end if;
|
||||
RegRdVal(16#20#/4)(Streams_g-1 downto 0) <= r.Reg_StrEna;
|
||||
|
||||
-- *** Stream Register Accesses ***
|
||||
v.RegRdval := (others => '0');
|
||||
v.Reg_Mode_Arm := (others => '0');
|
||||
v.MaxLvlClr := (others => '0');
|
||||
if AccAddr(15 downto 9) = X"0" & "001" then
|
||||
Stream_v := to_integer(unsigned(AccAddr(8 downto 4)));
|
||||
|
||||
-- MAXLVLn
|
||||
if AccAddr(3 downto 0) = X"0" then
|
||||
if AccWr = DwWrite_c then
|
||||
v.MaxLvlClr(Stream_v) := '1';
|
||||
end if;
|
||||
v.RegRdval(15 downto 0) := MaxLevel(Stream_v);
|
||||
end if;
|
||||
|
||||
-- POSTTRIGn
|
||||
if AccAddr(3 downto 0) = X"4" then
|
||||
if AccWr = DwWrite_c then
|
||||
v.Reg_PostTrig(Stream_v) := AccWrData;
|
||||
end if;
|
||||
v.RegRdval := r.Reg_PostTrig(Stream_v);
|
||||
end if;
|
||||
|
||||
-- MODEn / LASTWINn
|
||||
if AccAddr(3 downto 0) = X"8" then
|
||||
if AccWr(0) = '1' then
|
||||
v.Reg_Mode_Recm(Stream_v) := AccWrData(1 downto 0);
|
||||
end if;
|
||||
if AccWr(1) = '1' then
|
||||
v.Reg_Mode_Arm(Stream_v) := AccWrData(8);
|
||||
end if;
|
||||
v.RegRdval(1 downto 0) := r.Reg_Mode_Recm(Stream_v);
|
||||
v.RegRdval(8) := IsArmed(Stream_v);
|
||||
v.RegRdval(16) := IsRecording(Stream_v);
|
||||
end if;
|
||||
|
||||
-- LASTWINn
|
||||
if AccAddr(3 downto 0) = X"C" then
|
||||
-- LASTWINn
|
||||
v.RegRdval(MaxWindowsBits_c-1 downto 0) := StrLastWin_Sync(Stream_v);
|
||||
end if;
|
||||
|
||||
|
||||
end if;
|
||||
|
||||
-- *** Read Data MUX ***
|
||||
v.AddrReg := AccAddr;
|
||||
AccRdData <= (others => '0');
|
||||
if r.AddrReg(15 downto 12) = X"0" then
|
||||
AccRdData <= r.RegRdval;
|
||||
elsif r.AddrReg(15 downto 12) = X"1" then
|
||||
-- High-low dword in different memories
|
||||
if r.AddrReg(2) = '0' then
|
||||
AccRdData <= CtxStr_Rdval(31 downto 0);
|
||||
else
|
||||
AccRdData <= CtxStr_Rdval(63 downto 32);
|
||||
end if;
|
||||
elsif r.AddrReg(15 downto 14) = "01" then
|
||||
-- High-low dword in different memories
|
||||
if r.AddrReg(2) = '0' then
|
||||
AccRdData <= CtxWin_Rdval(31 downto 0);
|
||||
else
|
||||
AccRdData <= CtxWin_Rdval(63 downto 32);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- *** IRQ Handling ***
|
||||
for i in 0 to Streams_g-1 loop
|
||||
if (StrIrq_Sync(i) = '1') and (r.Reg_StrEna(i) = '1') then
|
||||
v.Reg_IrqVec(i) := '1';
|
||||
end if;
|
||||
end loop;
|
||||
if ((r.Reg_IrqVec and r.Reg_IrqEna) /= ZerosVector(Streams_g)) and (r.Reg_Gcfg_IrqEna = '1') then
|
||||
v.Irq := '1';
|
||||
else
|
||||
v.Irq := '0';
|
||||
end if;
|
||||
|
||||
|
||||
|
||||
-- *** Assign to signal ***
|
||||
r_next <= v;
|
||||
|
||||
end process;
|
||||
|
||||
-- *** Registered Outputs ***
|
||||
IrqOut <= r.Irq;
|
||||
PostTrig <= r.Reg_PostTrig;
|
||||
Arm <= r.Reg_Mode_Arm;
|
||||
RecMode <= r.Reg_Mode_Recm;
|
||||
|
||||
--------------------------------------------
|
||||
-- Sequential Process
|
||||
--------------------------------------------
|
||||
p_seq : process(S_Axi_Aclk)
|
||||
begin
|
||||
if rising_edge(S_Axi_Aclk) then
|
||||
r <= r_next;
|
||||
if A_Axi_Areset = '1' then
|
||||
r.Reg_Gcfg_Ena <= '0';
|
||||
r.Reg_Gcfg_IrqEna <= '0';
|
||||
r.Reg_IrqVec <= (others => '0');
|
||||
r.Reg_IrqEna <= (others => '0');
|
||||
r.Reg_StrEna <= (others => '0');
|
||||
r.Irq <= '0';
|
||||
r.Reg_PostTrig <= (others => (others => '0'));
|
||||
r.Reg_Mode_Recm <= (others => (others => '0'));
|
||||
r.Reg_Mode_Arm <= (others => '0');
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--------------------------------------------
|
||||
-- Maximum Level Latching (MemClk)
|
||||
--------------------------------------------
|
||||
p_maxlvl : process(ClkMem)
|
||||
begin
|
||||
if rising_edge(ClkMem) then
|
||||
if RstMem = '1' then
|
||||
MaxLevel <= (others => (others => '0'));
|
||||
else
|
||||
-- Latch maximum level
|
||||
for i in 0 to Streams_g-1 loop
|
||||
if MaxLevelClr_Sync(i) = '1' then
|
||||
MaxLevel(i) <= (others => '0');
|
||||
elsif unsigned(InLevel(i)) > unsigned(MaxLevel(i)) then
|
||||
MaxLevel(i) <= InLevel(i);
|
||||
end if;
|
||||
end loop;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--------------------------------------------
|
||||
-- Component Instantiations
|
||||
--------------------------------------------
|
||||
|
||||
-- *** AXI Interface ***
|
||||
i_axi : entity work.psi_common_axi_slave_ipif
|
||||
generic map (
|
||||
NumReg_g => 16,
|
||||
ResetVal_g => (0 => (others => '0'), 1 => (others => '0'), 2 => (others => '0'), 3 => (others => '0'),
|
||||
4 => (others => '0'), 5 => (others => '0'), 6 => (others => '0'), 7 => (others => '0'),
|
||||
8 => (others => '0'), 9 => (others => '0'), 10 => (others => '0'), 11 => (others => '0'),
|
||||
12 => (others => '0'), 13 => (others => '0'), 14 => (others => '0'), 15 => (others => '0')),
|
||||
UseMem_g => true,
|
||||
AxiIdWidth_g => AxiSlaveIdWidth_g,
|
||||
AxiAddrWidth_g => 16
|
||||
)
|
||||
port map (
|
||||
s_axi_aclk => S_Axi_Aclk,
|
||||
s_axi_aresetn => S_Axi_Aresetn,
|
||||
s_axi_arid => S_Axi_ArId,
|
||||
s_axi_araddr => S_Axi_ArAddr,
|
||||
s_axi_arlen => S_Axi_Arlen,
|
||||
s_axi_arsize => S_Axi_ArSize,
|
||||
s_axi_arburst => S_Axi_ArBurst,
|
||||
s_axi_arlock => S_Axi_ArLock,
|
||||
s_axi_arcache => S_Axi_ArCache,
|
||||
s_axi_arprot => S_Axi_ArProt,
|
||||
s_axi_arvalid => S_Axi_ArValid,
|
||||
s_axi_arready => S_Axi_ArReady,
|
||||
s_axi_rid => S_Axi_RId,
|
||||
s_axi_rdata => S_Axi_RData,
|
||||
s_axi_rresp => S_Axi_RResp,
|
||||
s_axi_rlast => S_Axi_RLast,
|
||||
s_axi_rvalid => S_Axi_RValid,
|
||||
s_axi_rready => S_Axi_RReady,
|
||||
s_axi_awid => S_Axi_AwId,
|
||||
s_axi_awaddr => S_Axi_AwAddr,
|
||||
s_axi_awlen => S_Axi_AwLen,
|
||||
s_axi_awsize => S_Axi_AwSize,
|
||||
s_axi_awburst => S_Axi_AwBurst,
|
||||
s_axi_awlock => S_Axi_AwLock,
|
||||
s_axi_awcache => S_Axi_AwCache,
|
||||
s_axi_awprot => S_Axi_AwProt,
|
||||
s_axi_awvalid => S_Axi_AwValid,
|
||||
s_axi_awready => S_Axi_AwReady,
|
||||
s_axi_wdata => S_Axi_WData,
|
||||
s_axi_wstrb => S_Axi_WStrb,
|
||||
s_axi_wlast => S_Axi_WLast,
|
||||
s_axi_wvalid => S_Axi_WValid,
|
||||
s_axi_wready => S_Axi_WReady,
|
||||
s_axi_bid => S_Axi_BId,
|
||||
s_axi_bresp => S_Axi_BResp,
|
||||
s_axi_bvalid => S_Axi_BValid,
|
||||
s_axi_bready => S_Axi_BReady,
|
||||
o_reg_rd => open,
|
||||
i_reg_rdata => RegRdVal,
|
||||
o_reg_wr => RegWr,
|
||||
o_reg_wdata => RegWrVal,
|
||||
o_mem_addr => AccAddrOffs,
|
||||
o_mem_wr => AccWr,
|
||||
o_mem_wdata => AccWrData,
|
||||
i_mem_rdata => AccRdData
|
||||
);
|
||||
|
||||
AccAddr <= std_logic_vector(unsigned(AccAddrOffs) + 16*4);
|
||||
|
||||
-- *** Clock Crossings ***
|
||||
blk_cc_irq : block
|
||||
begin
|
||||
g_in : for i in 0 to Streams_g-1 generate
|
||||
|
||||
i_cc_irq : entity work.psi_common_simple_cc
|
||||
generic map (
|
||||
DataWidth_g => log2ceil(MaxWindows_c)
|
||||
)
|
||||
port map (
|
||||
ClkA => ClkMem,
|
||||
RstInA => RstMem,
|
||||
DataA => StrLastWin(i),
|
||||
VldA => StrIrq(i),
|
||||
ClkB => S_Axi_Aclk,
|
||||
RstInB => A_Axi_Areset,
|
||||
DataB => StrLastWin_Sync(i),
|
||||
VldB => StrIrq_Sync(i)
|
||||
);
|
||||
end generate;
|
||||
end block;
|
||||
|
||||
blk_cc_mem_out : block
|
||||
signal ccIn, ccOut : std_logic_vector(Streams_g downto 0);
|
||||
begin
|
||||
-- Input Assembly
|
||||
ccIn(Streams_g-1 downto 0) <= r.Reg_StrEna;
|
||||
ccIn(Streams_g) <= r.Reg_Gcfg_Ena;
|
||||
|
||||
-- Instantiation
|
||||
i_cc_mem_out : entity work.psi_common_bit_cc
|
||||
generic map (
|
||||
NumBits_g => Streams_g+1
|
||||
)
|
||||
port map (
|
||||
BitsA => ccIn,
|
||||
ClkB => ClkMem,
|
||||
BitsB => ccOut
|
||||
);
|
||||
|
||||
-- Output assembly
|
||||
StrEna <= ccOut(Streams_g-1 downto 0);
|
||||
GlbEna <= ccOut(Streams_g);
|
||||
end block;
|
||||
|
||||
i_cc_mem_out_pulse : entity work.psi_common_pulse_cc
|
||||
generic map (
|
||||
NumPulses_g => Streams_g
|
||||
)
|
||||
port map (
|
||||
ClkA => S_Axi_Aclk,
|
||||
RstInA => A_Axi_Areset,
|
||||
PulseA => r.MaxLvlClr,
|
||||
ClkB => ClkMem,
|
||||
RstInB => RstMem,
|
||||
PulseB => MaxLevelClr_Sync
|
||||
);
|
||||
|
||||
|
||||
-- *** Stream Context Memory ***
|
||||
-- Signal Assembly
|
||||
AddrCtxStr <= AccAddr(15 downto 12) = X"1";
|
||||
CtxStr_WeLo <= '1' when AccWr = DwWrite_c and AddrCtxStr and AccAddr(2) = '0' else '0';
|
||||
CtxStr_WeHi <= '1' when AccWr = DwWrite_c and AddrCtxStr and AccAddr(2) = '1' else '0';
|
||||
CtxStr_AddrB <= std_logic_vector(to_unsigned(CtxStr_Cmd.Stream, log2ceil(Streams_g))) & CtxStr_Cmd.Sel;
|
||||
|
||||
-- Memory is split organized as 64 bit memory for historical reasons (Tosca TMEM is 64-bit)
|
||||
|
||||
-- Low DWORD memory
|
||||
i_mem_ctx_lo : entity work.psi_common_tdp_ram
|
||||
generic map (
|
||||
Depth_g => DepthCtxStr_c,
|
||||
Width_g => 32,
|
||||
Behavior_g => "RBW"
|
||||
)
|
||||
port map (
|
||||
ClkA => S_Axi_Aclk,
|
||||
AddrA => AccAddr(CtxStrAddrHigh_c downto 3),
|
||||
WrA => CtxStr_WeLo,
|
||||
DinA => AccWrData,
|
||||
DoutA => CtxStr_Rdval(31 downto 0),
|
||||
ClkB => ClkMem,
|
||||
AddrB => CtxStr_AddrB,
|
||||
WrB => CtxStr_Cmd.WenLo,
|
||||
DinB => CtxStr_Cmd.WdatLo,
|
||||
DoutB => CtxStr_Resp.RdatLo
|
||||
);
|
||||
|
||||
-- High DWORD memory
|
||||
i_mem_ctx_hi : entity work.psi_common_tdp_ram
|
||||
generic map (
|
||||
Depth_g => DepthCtxStr_c,
|
||||
Width_g => 32,
|
||||
Behavior_g => "RBW"
|
||||
)
|
||||
port map (
|
||||
ClkA => S_Axi_Aclk,
|
||||
AddrA => AccAddr(CtxStrAddrHigh_c downto 3),
|
||||
WrA => CtxStr_WeHi,
|
||||
DinA => AccWrData,
|
||||
DoutA => CtxStr_Rdval(63 downto 32),
|
||||
ClkB => ClkMem,
|
||||
AddrB => CtxStr_AddrB,
|
||||
WrB => CtxStr_Cmd.WenHi,
|
||||
DinB => CtxStr_Cmd.WdatHi,
|
||||
DoutB => CtxStr_Resp.RdatHi
|
||||
);
|
||||
|
||||
-- *** Window Context Memory ***
|
||||
-- Signal Assembly
|
||||
AddrCtxWin <= AccAddr(15 downto 14) = "01";
|
||||
CtxWin_WeLo <= '1' when AccWr = DwWrite_c and AddrCtxWin and AccAddr(2) = '0' else '0';
|
||||
CtxWin_WeHi <= '1' when AccWr = DwWrite_c and AddrCtxWin and AccAddr(2) = '1' else '0';
|
||||
CtxWin_AddrB <= std_logic_vector(to_unsigned(CtxWin_Cmd.Stream, log2ceil(Streams_g))) &
|
||||
std_logic_vector(to_unsigned(CtxWin_Cmd.Window, log2ceil(MaxWindows_g))) &
|
||||
CtxWin_Cmd.Sel;
|
||||
|
||||
-- Memory is split organized as 64 bit memory for historical reasons (Tosca TMEM is 64-bit)
|
||||
|
||||
-- Low DWORD memory
|
||||
i_mem_win_lo : entity work.psi_common_tdp_ram
|
||||
generic map (
|
||||
Depth_g => DepthCtxWin_c,
|
||||
Width_g => 32,
|
||||
Behavior_g => "RBW"
|
||||
)
|
||||
port map (
|
||||
ClkA => S_Axi_Aclk,
|
||||
AddrA => AccAddr(CtxWinAddrHigh_c downto 3),
|
||||
WrA => CtxWin_WeLo,
|
||||
DinA => AccWrData,
|
||||
DoutA => CtxWin_Rdval(31 downto 0),
|
||||
ClkB => ClkMem,
|
||||
AddrB => CtxWin_AddrB,
|
||||
WrB => CtxWin_Cmd.WenLo,
|
||||
DinB => CtxWin_Cmd.WdatLo,
|
||||
DoutB => CtxWin_Resp.RdatLo
|
||||
);
|
||||
|
||||
-- High DWORD memory
|
||||
i_mem_win_hi : entity work.psi_common_tdp_ram
|
||||
generic map (
|
||||
Depth_g => DepthCtxWin_c,
|
||||
Width_g => 32,
|
||||
Behavior_g => "RBW"
|
||||
)
|
||||
port map (
|
||||
ClkA => S_Axi_Aclk,
|
||||
AddrA => AccAddr(CtxWinAddrHigh_c downto 3),
|
||||
WrA => CtxWin_WeHi,
|
||||
DinA => AccWrData,
|
||||
DoutA => CtxWin_Rdval(63 downto 32),
|
||||
ClkB => ClkMem,
|
||||
AddrB => CtxWin_AddrB,
|
||||
WrB => CtxWin_Cmd.WenHi,
|
||||
DinB => CtxWin_Cmd.WdatHi,
|
||||
DoutB => CtxWin_Resp.RdatHi
|
||||
);
|
||||
|
||||
end architecture;
|
Reference in New Issue
Block a user