-- -- Format analog acquisition data into a stream of 64-bit words. -- -- Joris van Rantwijk 2024 -- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.puzzlefw_pkg.all; entity acquisition_stream is generic ( -- Number of analog input channels. It should be either 2 or 4. num_channels: integer range 2 to 4 ); port ( -- Main clock, active on rising edge. clk: in std_logic; -- Reset, active high, synchronous to main clock. reset: in std_logic; -- High to enable 4-channel mode. -- Ignored if num_channels == 2. ch4_mode: in std_logic; -- Global timestamp counter. timestamp_in: in std_logic_vector(timestamp_bits - 1 downto 0); -- High for one cycle when a trigger occurs. trig_ack: in std_logic; -- Decimated sample stream. sample_valid: in std_logic; sample_data: in sample_data_array(0 to num_channels - 1); -- Output data stream. out_valid: out std_logic; out_ready: in std_logic; out_empty: in std_logic; out_data: out dma_data_type ); end entity; architecture arch of acquisition_stream is type regs_type is record overflow: std_logic; trig_pending: std_logic; trig_timestamp: std_logic_vector(timestamp_bits - 1 downto 0); sample_pending: std_logic; sample_data: sample_data_array(0 to num_channels - 3); out_valid: std_logic; out_data: dma_data_type; end record; constant regs_init: regs_type := ( overflow => '0', trig_pending => '0', trig_timestamp => (others => '0'), sample_pending => '0', sample_data => (others => (others => '0')), out_valid => '0', out_data => (others => '0') ); signal r: regs_type := regs_init; signal rnext: regs_type; begin -- Drive output ports. out_valid <= r.out_valid; out_data <= r.out_data; -- -- Combinatorial process. -- process (all) is variable v: regs_type; begin -- Load current register values. v := r; -- By default, do not emit data. v.out_valid := '0'; if sample_valid = '1' then -- Emit first sample data word. v.out_valid := '1'; v.out_data(63 downto 56) := msg_adc_data; v.out_data(55 downto 48) := x"10"; v.out_data(23 downto 0) := sample_data(0); v.out_data(47 downto 24) := sample_data(1); -- Detect internal overflow. if (r.sample_pending = '1') or (r.trig_pending = '1') then v.overflow := '1'; end if; elsif r.sample_pending = '1' then -- Emit second sample data word. v.sample_pending := '0'; v.out_valid := '1'; v.out_data(63 downto 56) := msg_adc_data; v.out_data(55 downto 48) := x"32"; v.out_data(47 downto 0) := (others => '0'); if num_channels > 2 then v.out_data(23 downto 0) := r.sample_data(0); end if; if num_channels > 3 then v.out_data(47 downto 24) := r.sample_data(1); end if; elsif r.trig_pending = '1' then -- Emit pending trigger record. v.trig_pending := '0'; v.out_valid := '1'; v.out_data(63 downto 56) := msg_trigger; v.out_data(55 downto 48) := x"00"; v.out_data(47 downto 0) := r.trig_timestamp; elsif trig_ack = '1' then -- Emit trigger record. v.out_valid := '1'; v.out_data(63 downto 56) := msg_trigger; v.out_data(55 downto 48) := x"00"; v.out_data(47 downto 0) := timestamp_in; end if; -- Latch second sample data word. if (num_channels > 2) and (sample_valid = '1') then v.sample_pending := ch4_mode; v.sample_data := sample_data(2 to num_channels - 1); end if; -- Latch timestamp when a trigger occurs. if trig_ack = '1' then v.trig_timestamp := timestamp_in; if (sample_valid = '1') or (r.sample_pending = '1') then v.trig_pending := '1'; end if; -- Detect internal overflow. if r.trig_pending = '1' then v.overflow := '1'; end if; end if; -- Detect overflow of external data buffer. if (r.out_valid = '1') and (out_ready = '0') then v.overflow := '1'; v.out_valid := '0'; end if; -- If there is a pending overflow, discard data until the buffer -- is empty, then emit an overflow record. if r.overflow = '1' then v.sample_pending := '0'; v.trig_pending := '0'; v.out_valid := '0'; v.out_data(63 downto 56) := msg_overflow; v.out_data(55 downto 0) := (others => '0'); if out_empty = '1' then v.out_valid := '1'; v.overflow := '0'; end if; end if; -- Synchronous reset. if reset = '1' then v := regs_init; end if; -- Drive new register values to synchronous process. rnext <= v; end process; -- -- Synchronous process. -- process (clk) is begin if rising_edge(clk) then r <= rnext; end if; end process; end architecture;