DEVEL: First open source release

This commit is contained in:
Oliver Bruendler
2019-08-02 10:03:58 +02:00
commit d455112276
167 changed files with 27513 additions and 0 deletions

455
hdl/psi_ms_daq_axi.vhd Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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;