125 lines
3.4 KiB
VHDL
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;
|