--------------------------------------------------------------------------------
-- Company: 
-- Engineer:
--
-- Create Date:   17:16:42 13.05.2007
-- Design Name:   tb_fir_stage
-- Module Name:   tb_fir_stage.vhd
-- Project Name:  fir_stage
-- Target Device:  
-- Tool versions:  
-- Description:   
-- 
--------------------------------------------------------------------------------
LIBRARY ieee;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.MATH_REAL.ALL;
USE ieee.numeric_std.ALL;
use std.textio.all; --  Imports the standard textio package.

library ieee_proposed;
use ieee_proposed.fixed_float_types.all;
use ieee_proposed.fixed_pkg.all;

library work;
use work.fixed_util_pkg.all;
use work.fir_pkg.all;
use work.filter_pkg.all;

use work.PCK_FIO.all;

ENTITY tb_fir_stage_sys IS
	Generic
	(
		ntaps				: integer := 33;
		nbits_in			: integer := 24;
		nbits_in_frac		: integer := 23;
		nbits_stages		: integer := 25;
		nbits_stages_frac	: integer := 23;
		nbits_out			: integer := 24;
		nbits_out_frac		: integer := 22
        );
END tb_fir_stage_sys;

ARCHITECTURE behavior OF tb_fir_stage_sys IS 

	-- Component Declaration for the Unit Under Test (UUT)
	COMPONENT fir_stage_sys
	GENERIC
	(
		nbits_in		: integer;
		nbits_in_frac	: integer;
		nbits_out		: integer;
		nbits_out_frac	: integer;
		pipe_latency	: integer
	);
	PORT
	(
		rst			: in std_logic;
		clk			: in std_logic;
		ce			: in std_logic;
		x_in		: in sfixed;
		y_in		: in sfixed;
		h_in		: in sfixed;
		x_out		: out sfixed;
		y_out		: out sfixed;
		vld_out		: out std_logic
	);
	END COMPONENT;

	type stages_t is array (natural range <>) of sfixed(shi(nbits_stages, nbits_stages_frac) downto slo(nbits_stages, nbits_stages_frac)); 

	--Constants
	constant PERIOD : time := 10 ns;
	constant zero_in : sfixed := to_sfixed(0, nbits_in, nbits_in_frac);

	--Inputs
	SIGNAL rst         : std_logic := '1';
	SIGNAL ce          : std_logic := '1';
	SIGNAL clk         : std_logic := '0';
	SIGNAL x_in        : sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac));

	--Outputs
	SIGNAL x_out       : sfixed(shi(nbits_out, nbits_out_frac) downto slo(nbits_out, nbits_out_frac));
	SIGNAL y_out       : sfixed(shi(nbits_out, nbits_out_frac) downto slo(nbits_out, nbits_out_frac));
	SIGNAL vld_out     : std_logic;

	SIGNAL x    	   : stages_t(0 to ntaps-2);
	SIGNAL y           : stages_t(0 to ntaps-2);
	SIGNAL vld         : unsigned(0 to ntaps-2);
	
	SIGNAL fileout_enable   : std_logic := '1';
	signal hr 			: real_array_t(ntaps-1 downto 0);
	
	-- Test coefficients
	function to_sfixed(x_real : real_array_t) return stages_t is
	variable res : stages_t(x_real'range); 
	begin
		for i in x_real'range loop
			res(i) := to_sfixed(x_real(i), res(i), fixed_wrap, fixed_round);
		end loop;
		
		return res;
	end to_sfixed;
	
	function to_real(x_fixed : stages_t) return real_array_t is
	variable res : real_array_t(x_fixed'range); 
	begin
		for i in x_fixed'range loop
			res(i) := to_real(x_fixed(i));
		end loop;
		
		return res;
	end to_real;

	signal h : stages_t(0 to ntaps-1) := to_sfixed(FilterCoef_Lowpass(ntaps, 0.25, 1.0));
	
	SIGNAL xi, yo : real := 0.0;
	
BEGIN

	xi <= to_real(x_in);
	yo <= to_real(y_out);
	hr <= to_real(h);
	
	----------------------------------------
	-- Instantiate the Unit Under Test (UUT)
	----------------------------------------
		uut_first_stage_sys: fir_stage_sys 
		GENERIC MAP
		(
			nbits_in		=> nbits_in,
			nbits_in_frac	=> nbits_in_frac,
			nbits_out		=> nbits_stages,
			nbits_out_frac	=> nbits_stages_frac,
			pipe_latency	=> 2
		)
		PORT MAP
		(
			rst			=> rst,
			clk			=> clk,
			ce			=> ce,
			x_in		=> x_in,
			y_in		=> zero_in,
			h_in		=> h(ntaps-1),
			x_out		=> x(0),
			y_out		=> y(0),
			vld_out		=> vld(0)
		);

	----------------------------------------
    gen_stages:
	for i in 1 to ntaps-2 generate
		uut_stages: fir_stage_sys 
		GENERIC MAP
		(
			nbits_in		=> nbits_stages,
			nbits_in_frac	=> nbits_stages_frac,
			nbits_out		=> nbits_stages,
			nbits_out_frac	=> nbits_stages_frac,
			pipe_latency	=> 2
		)
		PORT MAP
		(
			rst			=> rst,
			clk			=> clk,
			ce			=> vld(i-1),
			x_in		=> x(i-1),
			y_in		=> y(i-1),
			h_in		=> h(ntaps-i-1),
			x_out		=> x(i),
			y_out		=> y(i),
			vld_out		=> vld(i)
		);
	end generate;
	
	----------------------------------------
		uut_last_stage: fir_stage_sys 
		GENERIC MAP
		(
			nbits_in		=> nbits_stages,
			nbits_in_frac	=> nbits_stages_frac,
			nbits_out		=> nbits_out,
			nbits_out_frac	=> nbits_out_frac,
			pipe_latency	=> 2
		)
		PORT MAP
		(
			rst			=> rst,
			clk			=> clk,
			ce			=> vld(ntaps-2),
			x_in		=> x(ntaps-2),
			y_in		=> y(ntaps-2),
			h_in		=> h(0),
			x_out		=> x_out,
			y_out		=> y_out,
			vld_out		=> vld_out
		);

	----------------------------------------
	-- Finished instantiation
	----------------------------------------
	tb_clk : PROCESS
	BEGIN
		clk <= not clk;
		wait for PERIOD/2;
	END PROCESS;

	tb : PROCESS

	BEGIN

		-- Wait 100 ns for global reset to finish
		wait for 4*PERIOD;
		rst	<= '0';

		wait until rising_edge(clk);
		x_in <= to_sfixed(0.0, x_in);

		wait for 40*PERIOD;
		wait until rising_edge(clk);
		x_in <= to_sfixed(0.0, x_in);
		wait until rising_edge(clk);
		x_in <= to_sfixed(1.0, x_in);
		wait until rising_edge(clk);
		x_in <= to_sfixed(0.0, x_in);
		wait until rising_edge(clk);
		x_in <= to_sfixed(0.0, x_in);
		wait until rising_edge(clk);
		x_in <= to_sfixed(0.0, x_in);

		wait for 150*PERIOD;
		
		assert false report "Test finished" severity error;
		wait; 
	END PROCESS;
	
	tb_fo : PROCESS(clk, fileout_enable)
	file RESULT_FIR:      text open write_mode is "fir.txt"; 
	variable L:         line;

	BEGIN
		if rising_edge(clk) and fileout_enable = '1' then
			fprint(RESULT_FIR, L,"%s\n", REAL'image(yo));
		end if;

	END PROCESS;
	
END;
