Commit a7afca0e authored by mcattin's avatar mcattin

Add signed version of offset gain module, to be used with tow's complement data from ADC.

git-svn-id: http://svn.ohwr.org/fmc-adc-100m14b4cha/trunk@103 ddd67a1a-c8ad-4635-afe9-0b8a11d8f8e4
parent 3642c1a7
--------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- Offset and gain correction, signed data input and output (two's complement)
-- http://www.ohwr.org/projects/fmc-adc-100m14b4cha
--------------------------------------------------------------------------------
--
-- unit name: offset_gain_corr_s (offset_gain_corr_s.vhd)
--
-- author: Matthieu Cattin (matthieu.cattin@cern.ch)
--
-- date: 24-11-2011
--
-- version: 1.0
--
-- description: Offset and gain correction with saturation.
-- Latency = 2
--
-- ___ ___ ________
-- | | offset_data | | product | |
-- data_i ---->| + |------------>| X |-------->|saturate|--> data_o
-- |___| |___| |________|
-- ^ ^
-- | |
-- offset_i gain_i
--
--
-- dependencies:
--
--------------------------------------------------------------------------------
-- last changes: see svn log.
--------------------------------------------------------------------------------
-- TODO: -
--------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
library UNISIM;
use UNISIM.vcomponents.all;
library UNIMACRO;
use UNIMACRO.vcomponents.all;
------------------------------------------------------------------------------
-- Entity declaration
------------------------------------------------------------------------------
entity offset_gain_s is
port (
rst_n_i : in std_logic; --! Reset (active low)
clk_i : in std_logic; --! Clock
offset_i : in std_logic_vector(15 downto 0); --! Signed offset input (two's complement)
gain_i : in std_logic_vector(15 downto 0); --! Unsigned gain input
data_i : in std_logic_vector(15 downto 0); --! Signed data input (two's complement)
data_o : out std_logic_vector(15 downto 0) --! Signed data output (two's complement)
);
end entity offset_gain_s;
------------------------------------------------------------------------------
-- Architecture declaration
------------------------------------------------------------------------------
architecture rtl of offset_gain_s is
------------------------------------------------------------------------------
-- Signals declaration
------------------------------------------------------------------------------
signal rst : std_logic := '0';
signal data_in_d : std_logic_vector(15 downto 0) := (others => '0');
signal data_offset : std_logic_vector(17 downto 0) := (others => '0');
signal gain : std_logic_vector(17 downto 0) := (others => '0');
signal product : std_logic_vector(35 downto 0) := (others => '0');
begin
------------------------------------------------------------------------------
-- Active high reset for MULT_MACRO
------------------------------------------------------------------------------
rst <= not(rst_n_i);
------------------------------------------------------------------------------
-- Add offset to input data
------------------------------------------------------------------------------
p_offset : process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
data_offset <= (others => '0');
gain <= (others => '0');
data_in_d <= (others => '0');
else
data_in_d <= data_i;
-- propagate sign for signed offset_i
data_offset <= std_logic_vector(signed(data_i(15) & data_i(15) & data_i) +
signed(offset_i(15) & offset_i(15) & offset_i));
gain <= "00" & gain_i;
end if;
end if;
end process p_offset;
------------------------------------------------------------------------------
-- Multiple input data + offset by gain
------------------------------------------------------------------------------
-- MULT_MACRO: Multiply Function implemented in a DSP48E
-- Xilinx HDL Libraries Guide, version 12.4
------------------------------------------------------------------------------
cmp_multiplier : MULT_MACRO
generic map (
DEVICE => "SPARTAN6", -- Target Device: "VIRTEX5", "VIRTEX6", "SPARTAN6"
LATENCY => 0, -- Desired clock cycle latency, 0-4
WIDTH_A => 18, -- Multiplier A-input bus width, 1-25
WIDTH_B => 18) -- Multiplier B-input bus width, 1-18
port map (
P => product, -- Multiplier ouput, WIDTH_A+WIDTH_B
A => gain, -- Multiplier input A, WIDTH_A
B => data_offset, -- Multiplier input B, WIDTH_B
CE => '1', -- 1-bit active high input clock enable
CLK => clk_i, -- 1-bit positive edge clock input
RST => rst -- 1-bit input active high reset
);
------------------------------------------------------------------------------
-- Saturate addition and multiplication result
------------------------------------------------------------------------------
p_saturate : process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
data_o <= (others => '0');
else
if (data_offset(15) = '1' and data_offset(16) = '0') then
data_o <= X"7FFF"; -- saturate positive
elsif (data_offset(15) = '0' and data_offset(16) = '1') then
data_o <= X"8000"; -- saturate negative
else
data_o <= product(30 downto 15);
end if;
end if;
end if;
end process p_saturate;
end architecture rtl;
--------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 11:48:27 02/05/2010
-- Design Name:
-- Module Name: offset_gain_s_tb.vhd
-- Project Name:
-- Target Device:
-- Tool versions:
-- Description:
--
-- VHDL Test Bench Created by ISE for module: offsetgain
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes:
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test. Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation
-- simulation model.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity offset_gain_s_tb is
end offset_gain_s_tb;
architecture behavior of offset_gain_s_tb is
-- Component Declaration for the Unit Under Test (UUT)
component offset_gain_s
port (
rst_n_i : in std_logic; --! Reset (active low)
clk_i : in std_logic; --! Clock
offset_i : in std_logic_vector(15 downto 0); --! Signed offset input (two's complement)
gain_i : in std_logic_vector(15 downto 0); --! Unsigned gain input
data_i : in std_logic_vector(15 downto 0); --! Unsigned data input
data_o : out std_logic_vector(15 downto 0) --! Unsigned data output
);
end component offset_gain_s;
--Inputs
signal rst_n_i : std_logic := '0';
signal clk_i : std_logic := '0';
signal offset_i : std_logic_vector(15 downto 0) := (others => '0');
signal gain_i : std_logic_vector(15 downto 0) := (others => '0');
signal data_i : std_logic_vector(15 downto 0) := (others => '0');
--Outputs
signal data_o : std_logic_vector(15 downto 0);
-- Clock period definitions
constant clk_i_period : time := 8 ns;
begin
-- Instantiate the Unit Under Test (UUT)
uut : offset_gain_s port map (
rst_n_i => rst_n_i,
clk_i => clk_i,
offset_i => offset_i,
gain_i => gain_i,
data_i => data_i,
data_o => data_o
);
-- Clock process definitions
clk_i_process : process
begin
clk_i <= '0';
wait for clk_i_period/2;
clk_i <= '1';
wait for clk_i_period/2;
end process;
-- Stimulus process
stim_proc : process
begin
-- hold reset state
rst_n_i <= '0';
wait for 10 us;
rst_n_i <= '1';
wait for clk_i_period*10;
-- insert stimulus here
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(1000, 16));
gain_i <= std_logic_vector(to_unsigned(32768, 16)); -- gain = 1
data_i <= std_logic_vector(to_signed(32700, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(-1000, 16));
gain_i <= std_logic_vector(to_unsigned(16384, 16)); -- gain = 1
data_i <= std_logic_vector(to_signed(-32700, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(10000, 16));
gain_i <= std_logic_vector(to_unsigned(16384, 16)); -- gain = 1
data_i <= std_logic_vector(to_signed(32700, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(-10000, 16));
gain_i <= std_logic_vector(to_unsigned(16384, 16)); -- gain = 1
data_i <= std_logic_vector(to_signed(-32700, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 16));
gain_i <= std_logic_vector(to_unsigned(0, 16));
data_i <= std_logic_vector(to_signed(0, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 16));
gain_i <= std_logic_vector(to_unsigned(32768, 16)); -- gain = 1
data_i <= std_logic_vector(to_signed(0, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(10, 16));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_signed(0, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(-10, 16));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_signed(0, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 16));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_signed(0, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 16));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_signed(1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 16));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_signed(-1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(10, 16));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_signed(1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(-10, 16));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_signed(1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 16));
gain_i <= std_logic_vector(to_unsigned(49152, 16)); -- gain = 1.5
data_i <= std_logic_vector(to_signed(0, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 16));
gain_i <= std_logic_vector(to_unsigned(49152, 16)); -- gain = 1.5
data_i <= std_logic_vector(to_signed(1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 16));
gain_i <= std_logic_vector(to_unsigned(49152, 16)); -- gain = 1.5
data_i <= std_logic_vector(to_signed(-1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(10, 16));
gain_i <= std_logic_vector(to_unsigned(49152, 16)); -- gain = 1.5
data_i <= std_logic_vector(to_signed(1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(10, 16));
gain_i <= std_logic_vector(to_unsigned(49152, 16)); -- gain = 1.5
data_i <= std_logic_vector(to_signed(-1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(-10, 16));
gain_i <= std_logic_vector(to_unsigned(49152, 16)); -- gain = 1.5
data_i <= std_logic_vector(to_signed(1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(-10, 16));
gain_i <= std_logic_vector(to_unsigned(49152, 16)); -- gain = 1.5
data_i <= std_logic_vector(to_signed(-1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(-10, 16));
gain_i <= std_logic_vector(to_unsigned(49152, 16)); -- gain = 1.5
data_i <= std_logic_vector(to_signed(0, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 16));
gain_i <= std_logic_vector(to_unsigned(16384, 16)); -- gain = 0.5
data_i <= std_logic_vector(to_signed(0, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 16));
gain_i <= std_logic_vector(to_unsigned(16384, 16)); -- gain = 0.5
data_i <= std_logic_vector(to_signed(1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 16));
gain_i <= std_logic_vector(to_unsigned(16384, 16)); -- gain = 0.5
data_i <= std_logic_vector(to_signed(-1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(-10, 16));
gain_i <= std_logic_vector(to_unsigned(16384, 16)); -- gain = 0.5
data_i <= std_logic_vector(to_signed(1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(-10, 16));
gain_i <= std_logic_vector(to_unsigned(16384, 16)); -- gain = 0.5
data_i <= std_logic_vector(to_signed(-1000, 16));
wait for 1 us;
wait;
end process;
end;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment