----------------------------------------------
-- MSS copyright 1999-2005
-- File: NCO32.VHD
-- Author: Alain Zarembowitch / MSS
-- Inheritance: NCO.VHD rev24 1-29-01
-- Last edit date: 11/16/08
-- Revision: 3 
--
-- Description: Numerically Controlled Oscillator (NCO). 32-bit precision.
-- Frequency is computed on the basis of the system clock. Phase is provided 
-- at the output for use by derotator/frequency translation modules.
-- In addition to the frequency input, the module accepts fine discrete phase 
-- corrections (to be used in conjunction with PLL for example).
--
-- Implementation: 32-bit accumulator. 
-- Very simple. The main purpose of this module is to avoid cluttering the 
-- top level code. (better abstraction). 
-- Size: FF 32, LUT4s 64, Slices 32
-- Speed:  133 MHz (Spartan-3 -4 speed grade)
--
-- Rev 2 8-27-05 AZ
-- pipelined for better timing
-- 
-- Rev 3 11-16-08 AZ
-- Added synchronous reset to reset the phase
----------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity NCO32 is
	port (
		--// CLOCK
 		CLK: in std_logic;
 			-- system clock
		SYNC_RESET: in std_logic;

		--// CONTROL
		NOMINAL_FREQUENCY: in std_logic_vector(31 downto 0);
			-- Desired frequency: Expressed as a function of the system clock fclk:
			-- frequency * 2^31 / fclk
			-- Value must be changed if the master clock frequency or desired frequency changes.
		PHASE_OFFSET: in std_logic_vector(31 downto 0);
			-- occasional phase corrections.
			-- 2's complement.
			-- read at rising edge of CLK when NCO_OFFSET_SAMPLE_CLK = '1'
		PHASE_OFFSET_SAMPLE_CLK: in std_logic;
			-- The NCO_OFFSET phase correction can occur anytime. No special timing
			-- requirement with respect to inputs or outputs sample clocks.

		--// OUTPUT
		PHASE: out std_logic_vector(31 downto 0)
			-- 32-bit NCO phase. For use by derotator/frequency translators.
	);
end entity;
    
architecture behavioral of NCO32 is
-----------------------------------------------------------------
-- COMPONENTS
-----------------------------------------------------------------

-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
signal NCO_ACCUMULATOR: std_logic_vector(31 downto 0) := (others => '0');
signal NCO_ACCUMULATOR_PARTIAL: std_logic_vector(31 downto 0) := (others => '0');
	-- NCO accumulator. 
	-- 2's complement. full scale = +/-pi

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

NCO_001: process (CLK)
begin 
	if rising_edge(CLK) then
		if(PHASE_OFFSET_SAMPLE_CLK = '0') then
			NCO_ACCUMULATOR_PARTIAL <= NOMINAL_FREQUENCY;
				-- nominal NCO increment (no phase correction)
		else
			NCO_ACCUMULATOR_PARTIAL <= NOMINAL_FREQUENCY + PHASE_OFFSET;
				-- NCO update with phase correction
		end if;
	end if;
end process;


NCO_002: process (CLK)
begin 
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') then
			NCO_ACCUMULATOR <= (others => '0');
		else
			NCO_ACCUMULATOR <= NCO_ACCUMULATOR + NCO_ACCUMULATOR_PARTIAL;
		end if;
	end if;
end process;

PHASE <= NCO_ACCUMULATOR;

end behavioral;
