--------------------------------------------------------------------------------
-- 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_top is
Generic
(
	nbits			: integer := 8;
	nbits_frac		: integer := 6;
	nbits_out		: integer := 8;
	nbits_frac_out	: integer := 6
);
Port ( 
	rst : in std_logic;
	clk : in std_logic;
	ce : in std_logic;
	xin : in sfixed;
	yin : in sfixed;
	zin : in sfixed;
	xout : out sfixed;
	yout : out sfixed;
	zout : out sfixed;
	ready : out std_logic;
	valid : out std_logic;
	cordic_mode	: in cordic_mode_t
);
end cordic_top;

architecture Behavioral of cordic_top is

-----------------------------------------------------------------------
COMPONENT cordic_stage_pre is
GENERIC
(
	nbits			: integer;
	nbits_frac		: integer;
	nbits_out		: integer;
	nbits_frac_out	: integer;
	reg_mode		: reg_mode_t
);
PORT
(
	rst			: in std_logic;
	clk			: in std_logic;
	ce			: in std_logic;
	xin			: in sfixed;
	yin			: in sfixed;
	zin			: in sfixed;
	xout		: out sfixed;
	yout		: out sfixed;
	zout		: out sfixed;
	cordic_mode	: in cordic_mode_t;
	ready 		: OUT std_logic;
	valid 		: out std_logic
);
END COMPONENT;

COMPONENT cordic_stage
GENERIC
(
	nbits			: integer;
	nbits_frac		: integer;
	nbits_out		: integer;
	nbits_frac_out	: integer;
	reg_mode		: reg_mode_t
);
PORT(
	rst			: IN std_logic;
	clk			: IN std_logic;
	ce			: IN std_logic;
	xin			: IN sfixed;       
	yin			: IN sfixed;
	zin			: IN sfixed;
	xout		: OUT sfixed;
	yout		: OUT sfixed;
	zout		: OUT sfixed;
	coeff		: in sfixed;
	dir_cw		: in std_logic;
	stage_count	: IN integer;
	cordic_mode	: in cordic_mode_t;
	ready 		: OUT std_logic;
	valid 		: out std_logic
);
END COMPONENT;

COMPONENT cordic_stage_post is
GENERIC
(
	nbits			: integer;
	nbits_frac		: integer;
	nbits_out		: integer;
	nbits_frac_out	: integer;
	reg_mode		: reg_mode_t
);
PORT
(
	rst			: in std_logic;
	clk			: in std_logic;
	ce			: in std_logic;
	xin			: in sfixed;
	yin			: in sfixed;
	zin			: in sfixed;
	xout		: out sfixed;
	yout		: out sfixed;
	zout		: out sfixed;
	cordic_mode	: in cordic_mode_t;
	ready 		: OUT std_logic;
	valid 		: out std_logic
);
END COMPONENT;

COMPONENT rom_arctan is
GENERIC 
(
	nbits		: integer := 8;
	nbits_frac	: integer := 8
);
PORT 
(
	addr		: in unsigned(6 downto 0);
	dout		: out sfixed
);
END COMPONENT;

-----------------------------------------------------------------------
type state_type is (st_input, st_ready, st_pre_stage_in, st_pre_stage_out, st_proc_stage_in, st_proc_stage_out, st_post_stage_in, st_post_stage_out); 

constant zero_sfix : sfixed := to_sfixed(0.0, sproto(nbits_out, nbits_frac_out)'high, sproto(nbits_out, nbits_frac_out)'low);

-- Define number of LSB guard bits
constant guard_nbits			: integer := integer(log2(real(nbits))+0.5);

-- Define number of internal stage bits
constant stage_nbits			: integer := nbits + guard_nbits; -- add more internal precision
constant stage_nbits_frac		: integer := nbits_frac;

-- Set number of coefficient bits
constant coeff_nbits			: integer := nbits;
constant coeff_nbits_frac		: integer := nbits; -- coeffs have no integer part

-- Set number of iteration with respect to bit size
constant max_stage_count 		: integer := stage_nbits;

-- INPUT
-- Input pre stage
signal pre_stage_en : std_logic;
signal xin_pre, yin_pre, zin_pre : sfixed(sproto(nbits, nbits_frac)'high downto sproto(nbits, nbits_frac)'low);

-- Output pre stage
signal pre_stage_ready, pre_stage_valid : std_logic;
signal xout_pre, yout_pre, zout_pre : sfixed(sproto(stage_nbits, stage_nbits_frac)'high downto sproto(stage_nbits, stage_nbits_frac)'low);

-- Input processing stage
signal proc_stage_en: std_logic;
signal xin_stage, yin_stage, zin_stage : sfixed(sproto(stage_nbits, stage_nbits_frac)'high downto sproto(stage_nbits, stage_nbits_frac)'low);

-- Output processing stage
signal proc_stage_ready, proc_stage_valid : std_logic;
signal xout_stage, yout_stage, zout_stage : sfixed(sproto(stage_nbits, stage_nbits_frac)'high downto sproto(stage_nbits, stage_nbits_frac)'low);

-- Input post stage
signal post_stage_en : std_logic;
signal xin_post, yin_post, zin_post : sfixed(sproto(stage_nbits, stage_nbits_frac)'high downto sproto(stage_nbits, stage_nbits_frac)'low);

-- Output post stage
signal post_stage_ready, post_stage_valid : std_logic;
signal xout_post, yout_post, zout_post : sfixed(sproto(nbits, nbits_frac)'high downto sproto(nbits, nbits_frac)'low);

-- ROM
signal rom_addr : unsigned (6 downto 0);
signal rom_data : sfixed(sproto(coeff_nbits, coeff_nbits_frac)'high downto sproto(coeff_nbits, coeff_nbits_frac)'low);

-- Misc.
signal state, next_state : state_type; 
signal count : integer range 0 to max_stage_count-1 := 0;
signal count_en, dir_cw, valid_s : std_logic;


begin

-----------------------------------------------------------------------
cordic_proc_mode : process(rst, zin_stage, yin_stage, cordic_mode)

begin
	
	if (rst = '1') then
		dir_cw <= '0';
	else
		dir_cw <= '0';
		case cordic_mode is

			when cordic_mode_rotate =>
				if (zin_stage(zin_stage'high) = '1') then 
					dir_cw <= '1';
				end if;
				
			when cordic_mode_vector =>
				if (yin_stage(yin_stage'high) = '1') then 
					dir_cw <= '0';
				else	
					dir_cw <= '1';
				end if;
				
			when others => null;

		end case;
	end if;
end process;
	
-----------------------------------------------------------------------
counter: process (clk, rst, count, count_en)
begin
	if (rst = '1') then
		count <= 0;
		rom_addr <= (others => '0');
	else
		if (clk'event and clk = '1') then
			rom_addr <= to_unsigned(count, rom_addr'length);
			if (count_en = '1' and count < max_stage_count-1) then
				count <= count + 1 after tpd;
			else
				count <= 0;
			end if;
		end if;
	end if;
end process;

-----------------------------------------------------------------------
OUTPUT_PROC: process (clk, rst, state, xout_stage, yout_stage, zout_stage)
begin
	if (rst='1') then
		valid <= '0';
		xout <= zero_sfix after tpd;
		yout <= zero_sfix after tpd;
		zout <= zero_sfix after tpd;

	 -- assign other outputs to reset value      
	elsif (clk'event and clk = '1') then
		valid <= '0';
		if(post_stage_valid = '1') then
			xout <= xout_post;
			yout <= yout_post;
			zout <= zout_post;
			valid <= '1';
		end if;
  end if;
end process;

-----------------------------------------------------------------------
--Insert the following in the architecture after the begin keyword
   FSM_PROC: process (clk, rst, xout_stage, yout_stage, zout_stage)
   begin
      if (rst='1') then
      	state <= st_ready;
         -- assign other outputs to reset value      
      elsif (clk'event and clk = '1') then
         state <= next_state after tpd;
         -- assign other outputs to internal signals        
      end if;
   end process;
 
   --MOORE State Machine - Outputs based on state only
Control_proc: process (state, xin, yin, zin, xout_pre, yout_pre, zout_pre, xout_stage, yout_stage, zout_stage)
begin
      --insert statements to decode internal output signals
      --below is simple example
	ready <= '0';
	valid_s <= '0';
	count_en <= '0';
	pre_stage_en <= '0';
	proc_stage_en <= '0';
	post_stage_en <= '0';

	xin_pre <= xin;
	yin_pre <= yin;
	zin_pre <= zin;
	xin_stage <= xout_stage;
	yin_stage <= yout_stage;
	zin_stage <= zout_stage;
	xin_post <= xout_stage;
	yin_post <= yout_stage;
	zin_post <= zout_stage;
	
	case (state) is
	when st_ready =>
		ready <= '1';
	when st_pre_stage_in =>
		pre_stage_en <= '1';
	when st_pre_stage_out =>
		count_en <= '1';
		proc_stage_en <= '1';
		xin_stage <= xout_pre;
		yin_stage <= yout_pre;
		zin_stage <= zout_pre;
	when st_proc_stage_in =>
		count_en <= '1';
		proc_stage_en <= '1';
	when st_post_stage_in =>
		post_stage_en <= '1';
		
	when others =>
	end case;      
end process;
 
NEXT_STATE_DECODE: process (state, ce, count)
begin
	--declare default state for next_state to avoid latches
	next_state <= state;  --default is to stay in current state
	--insert statements to decode next_state
	--below is a simple example
	case (state) is
	 when st_ready =>
		if ce = '1' then
		   next_state <= st_input;
		end if;

	 when st_input =>
		if ce = '0' then
		   next_state <= st_pre_stage_in;
		end if;

	 when st_pre_stage_in =>
		next_state <= st_pre_stage_out;

	 when st_pre_stage_out =>
		next_state <= st_proc_stage_in;

	 when st_proc_stage_in =>
		if (count = max_stage_count-2) then
			next_state <= st_post_stage_in;
		end if;

	 when st_post_stage_in =>
		next_state <= st_ready;

	 when others =>
		next_state <= st_ready;
		
	end case;      
end process;

-----------------------------------------------------------------------
Inst_cordic_stage_pre: cordic_stage_pre 
GENERIC MAP
(
	nbits => nbits,
	nbits_frac => nbits_frac,
	nbits_out => stage_nbits,
	nbits_frac_out => stage_nbits_frac,
	reg_mode => reg_mode_in
)
PORT MAP
(
	rst => rst,
	clk => clk,
	ce => pre_stage_en,
	xin => xin_pre,
	yin => yin_pre,
	zin => zin_pre,
	xout => xout_pre,
	yout => yout_pre,
	zout => zout_pre,
	ready => pre_stage_ready,
	valid => pre_stage_valid,
	cordic_mode => cordic_mode
);

Inst_cordic_stage: cordic_stage 
GENERIC MAP
(
	nbits => stage_nbits,
	nbits_frac => stage_nbits_frac,
	nbits_out => stage_nbits,
	nbits_frac_out => stage_nbits_frac,
	reg_mode => reg_mode_in
)
PORT MAP
(
	rst => rst,
	clk => clk,
	ce => proc_stage_en,
	xin => xin_stage,
	yin => yin_stage,
	zin => zin_stage,
	xout => xout_stage,
	yout => yout_stage,
	zout => zout_stage,
	coeff => rom_data,
	dir_cw => dir_cw,
	stage_count => count,
	ready => proc_stage_ready,
	valid => proc_stage_valid,
	cordic_mode => cordic_mode
);

Inst_cordic_stage_post: cordic_stage_post
GENERIC MAP
(
	nbits => stage_nbits,
	nbits_frac => stage_nbits_frac,
	nbits_out => nbits_out,
	nbits_frac_out => nbits_frac_out,
	reg_mode => reg_mode_in
)
PORT MAP
(
	rst => rst,
	clk => clk,
	ce => post_stage_en,
	xin => xin_post,
	yin => yin_post,
	zin => zin_post,
	xout => xout_post,
	yout => yout_post,
	zout => zout_post,
	ready => post_stage_ready,
	valid => post_stage_valid,
	cordic_mode => cordic_mode
);

Inst_rom_arctan: rom_arctan
GENERIC MAP
(
	nbits		=> coeff_nbits,
	nbits_frac	=> coeff_nbits_frac
)
PORT MAP
(
	addr		=> rom_addr,
	dout		=> rom_data
);

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