----------------------------------------------
-- MSS copyright 1999-2001
-- Filename: SIGNED_SIN_COS_TBL.VHD
-- Author: Alain Zarembowitch / MSS
-- Inheritance: new
-- Edit date: 1-29-01
-- Revision: 0.004
--
-- VHDL code for sine/cos ROM table
-- The ROM represents only one quarter period of the 
-- sinewave. The complete sinewave is obtained by 
-- pre-processing the address and post processing the 
-- ROM output. 
-- The ROM size is 64 x 8 (address x data widths).
-- The table size is thus 256 x 9 (address x data widths).    
--	Latency between input and output is 2 CLKs.
--
-- Two versions of the function exist: 
--	one with unsigned output (symmetrical, no zero representation)
--  the other with signed output(2's complement)
--
-- Changes in Rev 0.003 az
--	Added pipelining (latency is now 4 CLKs) operation at 30 MHz on Spartan XL
--
-- Rev 0.004 az
-- Switched from active low to active high reset
-- Removed references to inc_slv functions
----------------------------------------------
---------------------------------------
-- SIN/COS TABLE WITH SIGNED OUTPUT		
---------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


entity SIGNED_SIN_COS_TBL is
	port (
		ADDR: in std_logic_vector(7 downto 0);
			-- angle. 0 to 360 degree. No 0 representation.
			-- 0x00 -> 0.703 deg, 0xff -> 359.296 deg.
		DATA_OUT: out std_logic_vector(8 downto 0);
			-- sine or cosine value. range -1 to +1. 
			-- 9-bit signed (2's complement)
			-- Note: the output is asymmetrical due to 2's complement 
			-- representation(+255 positive, -256 negative)
		CLK: in std_logic;
		ASYNC_RESET: in std_logic;

		SIN_COSN: in std_logic
			-- sine or cosine# selection flag
			-- reason: the same table is used for both cosine and sine
			-- generation
	);
end SIGNED_SIN_COS_TBL;

architecture BEHAVIOR of SIGNED_SIN_COS_TBL is

-----------------------------------------------------------------
-- COMPONENTS
-----------------------------------------------------------------
-- sine table (0-90 deg input, 8-bit unsigned output)
component ROM64X8
  port( A: in std_logic_vector(5 downto 0);
		CLK: in std_logic;
		ASYNC_RESET: in std_logic;
 		Q: out std_logic_vector(7 downto 0)
			-- positive range only (0-1). MSB/sign bit dropped.
			-- Latency is 2 CLKs
	);
end component;     

-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
signal zero: std_logic;
signal one: std_logic;
signal PP_ADDR: std_logic_vector(5 downto 0) := (others => '0');	
	-- pre-processed address. Depends on whether the calling function
	-- wants to exercise the sine table or the cosine table, and 
	-- depends on the quadrant.
signal TBL_DATA: std_logic_vector(7 downto 0) := (others => '0');
signal TBL_DATA_N: std_logic_vector(7 downto 0) := (others => '0');
	-- raw data from the quadrant sine table. need to be
	-- post-processed to get the 4-quadrant cosine or sine value.  
signal NEG_TBL_DATA: std_logic_vector(7 downto 0) := (others => '0');
	-- 2's complement of the table data
signal SIGN: std_logic := '0';
signal SIGN_D: std_logic := '0';
signal SIGN_D2: std_logic := '0';

-----------------------------------------------------------------
-- IMPLEMENTATION
-----------------------------------------------------------------
begin   

zero <= '0';
one <= '1';


-- pre-processing(see detailed design document)
PREPROCESSING_001: process (ADDR, SIN_COSN, CLK, ASYNC_RESET)
begin
	if(ASYNC_RESET = '1') then
		PP_ADDR <= "000000";
	elsif rising_edge(CLK) then
		if (((SIN_COSN = '1') and (ADDR(6) = '0'))
		 or ((SIN_COSN = '0') and (ADDR(6) = '1'))) then
			PP_ADDR <= ADDR (5 downto 0);
		else
			PP_ADDR <= NOT ADDR(5 downto 0);
		end if;
  	end if;
end process;    

-- Keep track of whether the output should be negated or not
SIGN_GEN_001: process(ADDR, SIN_COSN,TBL_DATA, NEG_TBL_DATA, CLK, ASYNC_RESET, SIGN, SIGN_D)
begin
	if(ASYNC_RESET = '1') then
		SIGN <= '0';
		SIGN_D <= '0';
		SIGN_D2 <= '0';
	elsif rising_edge(CLK) then
		SIGN_D <= SIGN;
		SIGN_D2 <= SIGN_D;

		if (((SIN_COSN = '1') and (ADDR(7) = '0'))
		 or ((SIN_COSN = '0') and (ADDR(7 downto 6) = "00"))
		 or ((SIN_COSN = '0') and (ADDR(7 downto 6) = "11"))
		 ) then
		 	-- output data is positive
			SIGN <= '1';
		else
			-- output data is negative
			SIGN <= '0';
		end if;
 	end if;
end process;


-- instantiate the ROM table (one quadrant of sinewave)
--	Latency is 2 CLKs
ROM0: ROM64X8 port map(A => PP_ADDR, CLK => CLK, ASYNC_RESET => ASYNC_RESET, Q => TBL_DATA);   


-- compute 2's complement of the output data
TBL_DATA_N <= not TBL_DATA;
NEG_TBL_DATA <= TBL_DATA_N + 1;

-- post-processing
POSTPROCESSING_001: process(SIGN_D2,TBL_DATA, NEG_TBL_DATA, CLK, ASYNC_RESET)
begin
	if(ASYNC_RESET = '1') then
		DATA_OUT <= "000000000";
	elsif rising_edge(CLK) then
		if (SIGN_D2 = '1') then
		 	-- output data is positive
			DATA_OUT(7 downto 0) <= TBL_DATA;
			DATA_OUT(8) <= '0';	
		else
			-- output data is negative
			DATA_OUT(7 downto 0) <= NEG_TBL_DATA; 
			DATA_OUT(8) <= '1';
		end if;
 	end if;
end process;
				
end BEHAVIOR;

		

