redpitaya-puzzlefw/fpga/rtl/sample_decimation.vhd

125 lines
3.4 KiB
VHDL

--
-- 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;