--------------------------------------------------------------------------------
-- Company: 
-- Engineer:
--
-- Create Date:    11:52:30 10/02/05
-- Design Name:    
-- Module Name:    cordic_top - 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;
use work.fixed_pkg.all;
use work.cordic_pkg.all;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity cordic_pipe_top is
Generic
(
	cordic_mode			: cordic_mode_t := cordic_mode_rotate;
	z_range				: real := pi;
	gain_corr_mode		: gain_corr_mode_t := gain_mode_unity;
	nstages				: integer := 18;
	nbits_x_in			: integer := 18;
	nbits_y_in			: integer := 18;
	nbits_z_in			: integer := 18;
	nbits_frac_x_in		: integer := 16;
	nbits_frac_y_in		: integer := 16;
	nbits_frac_z_in		: integer := 16;
	nbits_x_out			: integer := 18;
	nbits_y_out			: integer := 18;
	nbits_z_out			: integer := 18;
	nbits_frac_x_out	: integer := 17;
	nbits_frac_y_out	: integer := 17;
	nbits_frac_z_out	: integer := 17
);
Port 
( 
	rst		: in std_logic;
	clk		: in std_logic;
	vld_in	: in std_logic;
	xin		: in sfixed(shi(nbits_x_in, nbits_frac_x_in) downto slo(nbits_x_in, nbits_frac_x_in));
	yin		: in sfixed(shi(nbits_y_in, nbits_frac_y_in) downto slo(nbits_y_in, nbits_frac_y_in));
	zin		: in sfixed(shi(nbits_z_in, nbits_frac_z_in) downto slo(nbits_z_in, nbits_frac_z_in));
	xout	: out sfixed(shi(nbits_x_out, nbits_frac_x_out) downto slo(nbits_x_out, nbits_frac_x_out));
	yout	: out sfixed(shi(nbits_y_out, nbits_frac_y_out) downto slo(nbits_y_out, nbits_frac_y_out));
	zout	: out sfixed(shi(nbits_z_out, nbits_frac_z_out) downto slo(nbits_z_out, nbits_frac_z_out));
	vld_out	: out std_logic
);
end cordic_pipe_top;

architecture Behavioral of cordic_pipe_top is

-----------------------------------------------------------------------
COMPONENT cordic_pipe_pre is
GENERIC
(
	cordic_mode		: cordic_mode_t;
	z_range			: real;
	nbits_x			: integer;
	nbits_x_frac	: integer;
	nbits_y			: integer;
	nbits_y_frac	: integer;
	nbits_z			: integer;
	nbits_z_frac	: integer
);
PORT(
	rst			: IN std_logic;
	clk			: IN std_logic;
	vld_in		: IN std_logic;
	xin			: IN sfixed;
	yin			: IN sfixed;
	zin			: IN sfixed;
	xout		: OUT sfixed;
	yout		: OUT sfixed;
	zout		: OUT sfixed;
	vld_out		: out std_logic
);
END COMPONENT;

COMPONENT cordic_pipe_stage
GENERIC
(
	cordic_mode		: cordic_mode_t;
	z_range			: real;
	stage_num		: integer;
	nbits_x			: integer;
	nbits_x_frac	: integer;
	nbits_y			: integer;
	nbits_y_frac	: integer;
	nbits_z			: integer;
	nbits_z_frac	: integer
);
PORT(
	rst			: IN std_logic;
	clk			: IN std_logic;
	vld_in		: IN std_logic;
	xin			: IN sfixed;
	yin			: IN sfixed;
	zin			: IN sfixed;
	xout		: OUT sfixed;
	yout		: OUT sfixed;
	zout		: OUT sfixed;
	vld_out		: out std_logic
);
END COMPONENT;

COMPONENT cordic_pipe_post is
GENERIC
(
	cordic_mode		: cordic_mode_t;
	nstages			: integer;
	nbits_x			: integer;
	nbits_x_frac	: integer;
	nbits_y			: integer;
	nbits_y_frac	: integer;
	nbits_z			: integer;
	nbits_z_frac	: integer
);
PORT(
	rst			: IN std_logic;
	clk			: IN std_logic;
	vld_in		: IN std_logic;
	xin			: IN sfixed;
	yin			: IN sfixed;
	zin			: IN sfixed;
	xout		: OUT sfixed;
	yout		: OUT sfixed;
	zout		: OUT sfixed;
	vld_out		: out std_logic
);
END COMPONENT;

-----------------------------------------------------------------------

-- Define number of internal stage bits
constant stage_x_nbits			: integer := nbits_x_in			+ integer(log2(real(nbits_x_in))+0.5);
constant stage_x_nbits_frac		: integer := nbits_frac_x_in	+ integer(log2(real(nbits_x_in))+0.5);
constant stage_y_nbits			: integer := nbits_y_in			+ integer(log2(real(nbits_y_in))+0.5);
constant stage_y_nbits_frac		: integer := nbits_frac_y_in	+ integer(log2(real(nbits_y_in))+0.5);
constant stage_z_nbits			: integer := nbits_z_in			+ integer(log2(real(nbits_z_in))+0.5);
constant stage_z_nbits_frac		: integer := nbits_frac_z_in	+ integer(log2(real(nbits_z_in))+0.5);

-- INPUT
-- Input pre stage
signal pre_xin	: sfixed(shi(stage_x_nbits, stage_x_nbits_frac) downto slo(stage_x_nbits, stage_x_nbits_frac));
signal pre_yin	: sfixed(shi(stage_y_nbits, stage_y_nbits_frac) downto slo(stage_y_nbits, stage_y_nbits_frac));
signal pre_zin	: sfixed(shi(stage_z_nbits, stage_z_nbits_frac) downto slo(stage_z_nbits, stage_z_nbits_frac));
signal pre_xout	: sfixed(shi(stage_x_nbits, stage_x_nbits_frac) downto slo(stage_x_nbits, stage_x_nbits_frac));
signal pre_yout	: sfixed(shi(stage_y_nbits, stage_y_nbits_frac) downto slo(stage_y_nbits, stage_y_nbits_frac));
signal pre_zout	: sfixed(shi(stage_z_nbits, stage_z_nbits_frac) downto slo(stage_z_nbits, stage_z_nbits_frac));

-- Input processing stage
subtype stage_x_t is sfixed(shi(stage_x_nbits, stage_x_nbits_frac) downto slo(stage_x_nbits, stage_x_nbits_frac));
subtype stage_y_t is sfixed(shi(stage_y_nbits, stage_y_nbits_frac) downto slo(stage_y_nbits, stage_y_nbits_frac));
subtype stage_z_t is sfixed(shi(stage_z_nbits, stage_z_nbits_frac) downto slo(stage_z_nbits, stage_z_nbits_frac));
type stage_x_array_t is array(0 to nstages) of stage_x_t;
type stage_y_array_t is array(0 to nstages) of stage_y_t;
type stage_z_array_t is array(0 to nstages) of stage_z_t;

signal stage_vld: unsigned(0 to nstages);
signal stage_x 			: stage_x_array_t;
signal stage_y			: stage_y_array_t;
signal stage_z			: stage_z_array_t;
 
-- Output post stage
signal post_xin		: sfixed(shi(nbits_x_out, nbits_frac_x_out) downto slo(nbits_x_out, nbits_frac_x_out));
signal post_yin		: sfixed(shi(nbits_y_out, nbits_frac_y_out) downto slo(nbits_y_out, nbits_frac_y_out));
signal post_zin		: sfixed(shi(nbits_z_out, nbits_frac_z_out) downto slo(nbits_z_out, nbits_frac_z_out));
signal post_xout	: sfixed(shi(nbits_x_out, nbits_frac_x_out) downto slo(nbits_x_out, nbits_frac_x_out));
signal post_yout	: sfixed(shi(nbits_y_out, nbits_frac_y_out) downto slo(nbits_y_out, nbits_frac_y_out));
signal post_zout	: sfixed(shi(nbits_z_out, nbits_frac_z_out) downto slo(nbits_z_out, nbits_frac_z_out));


begin

	pre_xin			<= resize(xin, pre_xin);
	pre_yin			<= resize(yin, pre_yin);
	pre_zin			<= resize(zin, pre_zin);

	stage_x(0)		<= resize(pre_xout, stage_x(0));
	stage_y(0)		<= resize(pre_yout, stage_y(0));
	stage_z(0)		<= resize(pre_zout, stage_z(0));

	post_xin		<= resize(stage_x(nstages), post_xin, cordic_saturate_mode, cordic_round_mode);
	post_yin		<= resize(stage_y(nstages), post_yin, cordic_saturate_mode, cordic_round_mode);
	post_zin		<= resize(stage_z(nstages), post_zin, cordic_saturate_mode, cordic_round_mode);

gen_output_unity:
	if gain_corr_mode = gain_mode_unity generate
	begin
		xout			<= post_xout;
		yout			<= post_yout;
		zout			<= post_zout;
	end generate;
	
gen_output_disabled:
	if gain_corr_mode = gain_mode_disabled generate
	begin
		xout			<= post_xin;
		yout			<= post_yin;
		zout			<= post_zin;
	end generate;
	
-----------------------------------------------------------------------
Inst_cordic_pipe_pre: cordic_pipe_pre 
GENERIC MAP
(
	cordic_mode		=> cordic_mode_rotate,
	z_range			=> z_range,
	nbits_x			=> stage_x_nbits,
	nbits_x_frac	=> stage_x_nbits_frac,
	nbits_y			=> stage_y_nbits,
	nbits_y_frac	=> stage_y_nbits_frac,
	nbits_z			=> stage_z_nbits,
	nbits_z_frac	=> stage_z_nbits_frac
)
PORT MAP
(
	rst				=> rst,
	clk				=> clk,
	vld_in			=> vld_in,
	xin				=> pre_xin,
	yin				=> pre_yin,
	zin				=> pre_zin,
	xout			=> pre_xout,
	yout			=> pre_yout,
	zout			=> pre_zout,
	vld_out			=> stage_vld(0)
);

gen_pipe:
	for i in 1 to nstages generate
	
	Inst_cordic_pipe: cordic_pipe_stage 
	GENERIC MAP
	(
		cordic_mode		=> cordic_mode_rotate,
		z_range			=> z_range,
		stage_num		=> i-1,
		nbits_x			=> stage_x_nbits,
		nbits_x_frac	=> stage_x_nbits_frac,
		nbits_y			=> stage_y_nbits,
		nbits_y_frac	=> stage_y_nbits_frac,
		nbits_z			=> stage_z_nbits,
		nbits_z_frac	=> stage_z_nbits_frac
	)
	PORT MAP
	(
		rst				=> rst,
		clk				=> clk,
		vld_in			=> stage_vld(i-1),
		xin				=> stage_x(i-1),
		yin				=> stage_y(i-1),
		zin				=> stage_z(i-1),
		xout			=> stage_x(i),
		yout			=> stage_y(i),
		zout			=> stage_z(i),
		vld_out			=> stage_vld(i)
	);

	end generate;
	
Inst_cordic_pipe_post: cordic_pipe_post
GENERIC MAP
(
	cordic_mode		=> cordic_mode_rotate,
	nstages			=> nstages,
	nbits_x			=> nbits_x_out,
	nbits_x_frac	=> nbits_frac_x_out,
	nbits_y			=> nbits_y_out,
	nbits_y_frac	=> nbits_frac_y_out,
	nbits_z			=> nbits_z_out,
	nbits_z_frac	=> nbits_frac_z_out
)
PORT MAP
(
	rst				=> rst,
	clk				=> clk,
	vld_in			=> stage_vld(nstages),
	xin				=> post_xin,
	yin				=> post_yin,
	zin				=> post_zin,
	xout			=> post_xout,
	yout			=> post_yout,
	zout			=> post_zout,
	vld_out			=> vld_out
);

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