-- -- Decimation or averaging of ADC samples. -- -- Joris van Rantwijk 2024 -- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity sample_decimation is generic ( -- Input word length. -- This is also the word length of the internal accumulator. input_data_bits: integer range 4 to 64; -- Output word length. -- If the output has fewer bits than the input, it represents the -- most significant bits of the accumulator, rounded to the -- nearest integer. output_data_bits: integer range 4 to 64 ); port ( -- Main clock, active on rising edge. clk: in std_logic; -- Reset, active high, synchronous to main clock. reset: in std_logic; -- High to initialize the accumulator to the input word plus rounding bias. start: in std_logic; -- High to add the input word to the accumulator. integrate: in std_logic; -- Input data word. in_data: in std_logic_vector(input_data_bits - 1 downto 0); -- Output data word. -- Results from input signals appear on the output after 1 clock cycle. out_data: out std_logic_vector(output_data_bits - 1 downto 0) ); end entity; architecture arch of sample_decimation is -- Return the rounding bias to add to the accumulator before truncating -- the least significant bits. function rounding_bias return unsigned is begin if output_data_bits < input_data_bits then -- Set the most significant truncated bit to '1'. return shift_left(to_unsigned(1, input_data_bits), input_data_bits - output_data_bits - 1); else -- No truncation. return to_unsigned(0, input_data_bits); end if; end function; type regs_type is record accumulator: std_logic_vector(input_data_bits - 1 downto 0); end record; constant regs_init: regs_type := ( accumulator => (others => '0') ); signal r: regs_type := regs_init; signal rnext: regs_type; begin -- Drive output from accumulator. out_data <= r.accumulator(input_data_bits - 1 downto input_data_bits - output_data_bits) when (output_data_bits <= input_data_bits) else r.accumulator & std_logic_vector(to_unsigned(0, output_data_bits - input_data_bits)); -- -- Combinatorial process. -- process (all) is variable v: regs_type; begin -- Load current register values. v := r; if start = '1' then -- Initialize accumulator and add input word. v.accumulator := std_logic_vector(rounding_bias + unsigned(in_data)); elsif integrate = '1' then -- Add input word to the accumulator. v.accumulator := std_logic_vector(unsigned(r.accumulator) + unsigned(in_data)); 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;