--------------------------------------------------------------------------------
-- Company: 
-- Engineer:
--
-- Create Date:    12:16:14 10/02/05
-- Design Name:    
-- Module Name:    fir_stage - Behavioral
-- Project Name:   
-- Target Device:  
-- Tool versions:  
-- Description:
--
-- Dependencies:
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
--------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.MATH_REAL.ALL;
USE ieee.numeric_std.ALL;

library ieee_proposed;
use ieee_proposed.math_utility_pkg.all;
use ieee_proposed.fixed_pkg.all;

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

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity fir_stage_sys is
Generic
(
	nbits_in		: integer := 12;
	nbits_in_frac	: integer := 12;
	nbits_out		: integer := 12;
	nbits_out_frac	: integer := 12;
	pipe_latency	: integer := 4
);
Port
(
	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
);
end fir_stage_sys;

architecture Behavioral of fir_stage_sys is

constant min_pipe_lat	: integer := 4;

subtype in_t is sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac));
subtype out_t is sfixed(shi(nbits_out, nbits_out_frac) downto slo(nbits_out, nbits_out_frac));

type input_pipe_t is array (pipe_latency-2 downto 0) of in_t;
type coef_pipe_t is array (pipe_latency-2 downto 0) of in_t;

signal yin	: in_t;
signal prod	: out_t;

------------------------------------------------------------
begin

	assert pipe_latency >= min_pipe_lat report "Pipe latency must be greater than " & natural'image(min_pipe_lat-1) & "!" severity failure;

	yin			<= resize(y_in, yin);

------------------------------------------------------------
	proc_pipe_reg: process(clk)
	variable h_pipe	: coef_pipe_t;
	variable x_pipe	: input_pipe_t;
	begin
		if rising_edge(clk) then
			if ce = '1' then
				x_pipe	:= x_pipe(x_pipe'left-1 downto 0) & resize(x_in, x_pipe(0));
				h_pipe	:= h_pipe(h_pipe'left-1 downto 0) & resize(h_in, h_pipe(0));
				prod	<= resize(x_pipe(x_pipe'left) * h_pipe(h_pipe'left), prod, fixed_wrap, fixed_truncate);
			end if;	
		end if;	
	end process;
	
------------------------------------------------------------
	proc_out_reg: process(clk)
	variable yout : out_t;
	variable xout : in_t;
	begin
		if rising_edge(clk) then
			if ce = '1' then
				yout	:= resize(yin + prod, yout, fixed_wrap, fixed_truncate);
				y_out	<= yout;
				xout	:= resize(x_in, xout, fixed_wrap, fixed_truncate);
				x_out	<= xout;
			end if;	
		end	if;
	end process;

------------------------------------------------------------
end Behavioral;
