--------------------------------------------------------------------------------
-- Company: 
-- Engineer:
--
-- Create Date:   17:16:42 13.05.2007
-- Design Name:   tb_mix_cpx
-- Module Name:   tb_mix_cpx.vhd
-- Project Name:  mix_cpx
-- Target Device:  
-- Tool versions:  
-- Description:   
-- 
--------------------------------------------------------------------------------
LIBRARY ieee;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.MATH_REAL.ALL;
USE ieee.numeric_std.ALL;

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.utils_pkg.all;

ENTITY cic_decim_pipe IS
	Generic
	(
		nstages			: integer := 3;
		diff_delay		: integer := 1;
		ratio			: integer := 64;
		scale_nbits		: integer := 9;
		in_width		: integer := 32;
		in_width_frac	: integer := 20;
		out_width		: integer := 32;
		out_width_frac	: integer := 20
	);
	Port
	(
		clk				: in std_logic;
		rst				: in std_logic;
		vld_in			: in std_logic;
		din				: in sfixed;
		dout			: out sfixed;
		vld_out 		: out std_logic
	);
END cic_decim_pipe;

ARCHITECTURE behavior OF cic_decim_pipe IS 

	COMPONENT cic_i_pipe
	GENERIC
	(
		max_width		: integer;
		max_width_frac	: integer
	);
	PORT
	(
		clk			: in std_logic;
		rst			: in std_logic;
		vld_in		: in std_logic;
		din			: in sfixed;
		dout		: out sfixed;
		vld_out 	: out std_logic
	);
	END COMPONENT;

	COMPONENT cic_c_pipe
	GENERIC
	(
		max_diff_delay	: integer;
		max_width		: integer;
		max_width_frac	: integer
	);
	PORT
	(
		clk			: in std_logic;
		rst			: in std_logic;
		vld_in		: in std_logic;
		diff_delay	: in natural range 1 to max_diff_delay;
		din			: in sfixed;
		dout		: out sfixed;
		vld_out 	: out std_logic
	);
	END COMPONENT;

	constant max_gain_bits		: natural := natural(NextExpBaseTwo(real(ratio)**real(nstages)));

	constant integ_nbits		: natural := in_width + max_gain_bits;
	constant integ_nbits_frac	: natural := integ_nbits - (in_width - in_width_frac);
	
	constant comb_nbits			: natural := out_width+1;
	constant comb_nbits_frac	: natural := out_width_frac+1;

	subtype word_i_t is sfixed(shi(integ_nbits, integ_nbits_frac) downto slo(integ_nbits, integ_nbits_frac));
	type word_i_pipe_t is array (0 to nstages) of word_i_t;

	signal word_i_pipe	: word_i_pipe_t;
	signal vld_i_pipe	: unsigned (0 to nstages);
	signal vld_i		: std_logic;
	
	subtype word_c_t is sfixed(shi(comb_nbits, comb_nbits_frac) downto slo(comb_nbits, comb_nbits_frac));
	type word_c_pipe_t is array (0 to nstages) of word_c_t;

	signal word_c_pipe	: word_c_pipe_t;
	signal vld_c_pipe	: unsigned (0 to nstages);
	signal vld_c		: std_logic;

	signal resample_cnt	: natural range 1 to ratio;
	signal resample_vld	: std_logic;

BEGIN

	assert false report "max_gain_bits = " & natural'image(max_gain_bits) & "." severity note;
	assert false report "integ. prec. = " & natural'image(integ_nbits) & ":" & natural'image(integ_nbits_frac) & "." severity note;
	assert false report "comb prec. = " & natural'image(comb_nbits) & ":" & natural'image(comb_nbits_frac) & "." severity note;

	vld_i			<= vld_i_pipe(nstages);

input_scale:
	process(clk)
	variable x : sfixed(shi(integ_nbits, integ_nbits_frac) downto slo(integ_nbits, integ_nbits_frac));
	variable xs : sfixed(shi(integ_nbits, integ_nbits_frac) downto slo(integ_nbits, integ_nbits_frac));
	variable xsi : sfixed(shi(integ_nbits, integ_nbits_frac) downto slo(integ_nbits, integ_nbits_frac));
	begin
		if rising_edge(clk) then
			x				:= resize(din, x, fixed_wrap, fixed_truncate);
			xs				:= x sra scale_nbits;
			word_i_pipe(0)	<= xs;
			vld_i_pipe(0)	<= vld_in;
		end if;
	end process;		

	gen_i_stages:
	for i in 1 to nstages generate
	begin
		inst_cic_i_pipe: cic_i_pipe 
		GENERIC MAP
		(
			max_width		=> integ_nbits,
			max_width_frac	=> integ_nbits_frac
		)
		PORT MAP
		(
			clk				=> clk,
			rst				=> rst,
			vld_in			=> vld_i_pipe(i-1),
			din				=> word_i_pipe(i-1),
			dout			=> word_i_pipe(i),
			vld_out			=> vld_i_pipe(i)
		);
	end generate;
	
	word_c_pipe(0)	<= resize(word_i_pipe(nstages), word_c_pipe(0), fixed_wrap, fixed_truncate);
	vld_c_pipe(0)	<= resample_vld;
	vld_c			<= vld_c_pipe(nstages);

	vld_out			<= vld_c;
	
	gen_c_stages:
	for i in 1 to nstages generate
	begin
		inst_cic_c_pipe: cic_c_pipe 
		GENERIC MAP
		(
			max_diff_delay	=> diff_delay,
			max_width		=> comb_nbits,
			max_width_frac	=> comb_nbits_frac
		)
		PORT MAP
		(
			clk				=> clk,
			rst				=> rst,
			vld_in			=> vld_c_pipe(i-1),
			diff_delay		=> diff_delay,
			din				=> word_c_pipe(i-1),
			dout			=> word_c_pipe(i),
			vld_out			=> vld_c_pipe(i)
		);
	end generate;
	
resampler_proc:
	process(clk)
	begin
		if rising_edge(clk) then
			resample_vld	<= '0';
			if rst = '1' then
				resample_cnt	<= 1;
			elsif vld_i = '1' then
				if resample_cnt = ratio then
					resample_vld	<= '1';
					resample_cnt	<= 1;
				else
					resample_cnt	<= resample_cnt + 1;
				end if ;
			end if;
		end if;
	end process;		

	dout		<= resize(word_c_pipe(nstages), shi(out_width, out_width_frac), slo(out_width, out_width_frac), fixed_wrap, fixed_truncate);

END;
