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