Commit 62f5c1ec authored by mcattin's avatar mcattin

Add offset_gain entity.

git-svn-id: http://svn.ohwr.org/fmc-adc-100m14b4cha/trunk@98 ddd67a1a-c8ad-4635-afe9-0b8a11d8f8e4
parent 0fb16384
--------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- Offset and gain correction
-- http://www.ohwr.org/projects/fmc-adc-100m14b4cha
--------------------------------------------------------------------------------
--
-- unit name: offset_gain_corr (offset_gain_corr.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 is
port (
rst_n_i : in std_logic; --! Reset (active low)
clk_i : in std_logic; --! Clock
offset_i : in std_logic_vector(16 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 entity offset_gain;
------------------------------------------------------------------------------
-- Architecture declaration
------------------------------------------------------------------------------
architecture rtl of offset_gain is
------------------------------------------------------------------------------
-- Signals declaration
------------------------------------------------------------------------------
signal rst : std_logic := '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');
else
-- propagate sign for signed offset_i
data_offset <= std_logic_vector(unsigned(("00" & data_i)) +
unsigned((offset_i(16) & 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 product(34) = '1' then
data_o <= (others => '0'); -- saturate negative
elsif (product(34) = '0' and product(31) = '1') then
data_o <= (others => '1'); -- saturate positive
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: C:/mcattin/fpga_design/cvorb_cvorg/sources/offsetgain_tb.vhd
-- Project Name: cvorg_v3
-- 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 offsetgain_tb is
end offsetgain_tb;
architecture behavior of offsetgain_tb is
-- Component Declaration for the Unit Under Test (UUT)
component offset_gain
port (
rst_n_i : in std_logic; --! Reset (active low)
clk_i : in std_logic; --! Clock
offset_i : in std_logic_vector(16 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;
--Inputs
signal rst_n_i : std_logic := '0';
signal clk_i : std_logic := '0';
signal offset_i : std_logic_vector(16 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 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(0, 17));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_unsigned(0, 16));
wait for 1 us;
wait until rising_edge(clk_i);
data_i <= std_logic_vector(to_unsigned(1, 16));
wait for 1 us;
wait until rising_edge(clk_i);
data_i <= std_logic_vector(to_unsigned(3, 16));
wait for 1 us;
wait until rising_edge(clk_i);
data_i <= std_logic_vector(to_unsigned(32768, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(-10, 17));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_unsigned(0, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(10, 17));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_unsigned(65535, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(-10, 17));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_unsigned(1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(10, 17));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_unsigned(1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 17));
gain_i <= std_logic_vector(to_unsigned(32000, 16));
data_i <= std_logic_vector(to_unsigned(1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(0, 17));
gain_i <= std_logic_vector(to_unsigned(34000, 16));
data_i <= std_logic_vector(to_unsigned(1000, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(32768, 17));
gain_i <= std_logic_vector(to_unsigned(32768, 16));
data_i <= std_logic_vector(to_unsigned(32768, 16));
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= std_logic_vector(to_signed(-32768, 17));
gain_i <= std_logic_vector(to_unsigned(33768, 16));
data_i <= std_logic_vector(to_unsigned(0, 16));
wait for 1 us;
wait until rising_edge(clk_i);
-- offset_i <= "010000000000000";
offset_i <= "01111111111111111";
gain_i <= X"8000";
data_i <= (others => '1');
wait for 1 us;
wait until rising_edge(clk_i);
offset_i <= "10000000000000000";
-- offset_i <= "011111111111111";
gain_i <= X"8000";
data_i <= (others => '0');
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