--------------------------------------------------------------------------------
-- Company: 
-- Engineer:
--
-- Create Date:   17:16:42 13.05.2007
-- Design Name:   tb_nco
-- Module Name:   tb_nco.vhd
-- Project Name:  nco
-- Target Device:  
-- Tool versions:  
-- Description:   
-- 
--------------------------------------------------------------------------------
LIBRARY ieee;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.MATH_REAL.ALL;
USE ieee.numeric_std.ALL;
use std.textio.all; --  Imports the standard textio package.

library ieee_proposed;
use ieee_proposed.fixed_float_types.all;
use ieee_proposed.fixed_pkg.all;

library work;
use work.fixed_util_pkg.all;
use work.cordic_pkg.all;
--use work.PCK_FIO.all;

ENTITY tb_syn_ddc IS
	Generic 
	(
		nbits_in			: integer := 16;
		nbits_in_frac		: integer := 14;
		nbits_out			: integer := 32;
		nbits_out_frac		: integer := 30;
		lo_nbits_phase		: integer := 24;
		lo_nbits_freq		: integer := 24;
		cic_nstages			: integer := 5;
		cic_ratio			: integer := 25;
		cic_scale_nbits		: integer := 22;
		rfgen_nbits_phase	: integer := 32;
		rfgen_nbits_freq	: integer := 32
	);
END tb_syn_ddc;

ARCHITECTURE behavior OF tb_syn_ddc IS 


	--Constants
	constant fa : REAL := 2.0**27;
	constant frf1 : REAL := 33.99E6;
	constant frf2 : REAL := 2.1E6;
	constant frf3 : REAL := 19.01E6;
	constant flo : REAL := 2.00E6;
	constant PERIOD_ADCCLK	: time := 10 ns;
	constant PERIOD_USBCLK	: time := 20 ns;
	constant PERIOD_IFCLK	: time := 20 ns;


	SIGNAL rfgen1_freq_word	: integer := integer(frf1/fa*2.0**rfgen_nbits_freq);
	SIGNAL rfgen2_freq_word	: integer := integer(frf2/fa*2.0**rfgen_nbits_freq);
	SIGNAL rfgen3_freq_word	: integer := integer(frf3/fa*2.0**rfgen_nbits_freq);
	SIGNAL lo_freq_word		: integer := integer(flo/fa*2.0**lo_nbits_freq);

	SIGNAL ddc_freq_in		: unsigned(lo_nbits_freq-1 downto 0) := (others => '0');
	SIGNAL ddc_phase_in		: unsigned(lo_nbits_phase-1 downto 0) := (others => '0');

	--Inputs
	SIGNAL rst				: std_logic := '1';
	SIGNAL adc_clk			: std_logic := '0';
	SIGNAL adc_ofa			: std_logic := '0';
	SIGNAL adc_rand			: std_logic;
	SIGNAL adc_pga			: std_logic;
	SIGNAL adc_dith			: std_logic;
	SIGNAL adc_shdn			: std_logic;
	SIGNAL adc_da			: signed (15 downto 0);
	SIGNAL adc_da_vld		: std_logic;
	
	SIGNAL usb_usbclk		: std_logic := '0';
	SIGNAL usb_ifclk		: std_logic := '0';
	SIGNAL usb_fd			: signed (15 downto 0);
	SIGNAL usb_fifoadr		: unsigned (1 downto 0);
	SIGNAL usb_pktend		: std_logic;
	SIGNAL usb_slcs_n		: std_logic;
	SIGNAL usb_slwr_n		: std_logic;
	SIGNAL usb_slrd_n		: std_logic;
	SIGNAL usb_sloe			: std_logic;
	SIGNAL usb_flaga		: std_logic := '0';
	SIGNAL usb_flagb		: std_logic := '0';
	SIGNAL usb_flagc		: std_logic := '0';

	SIGNAL cl_dout			: unsigned (20 downto 0);
	SIGNAL cl_clk_out		: std_logic;
	SIGNAL cl_pd_n			: std_logic;

	SIGNAL reg_dio			: unsigned (7 downto 0) := (others => 'Z');
	SIGNAL reg_aen			: std_logic := '1';
	SIGNAL reg_oe			: std_logic := '0';
	SIGNAL reg_we			: std_logic := '0';

	SIGNAL rfgen_nco_rst	: std_logic := '0';
	SIGNAL rfgen_nco_en		: std_logic := '0';
	SIGNAL rfgen1_freq_in	: unsigned(rfgen_nbits_freq-1 downto 0) := (others => '0');
	SIGNAL rfgen1_phase_in	: unsigned(rfgen_nbits_phase-1 downto 0) := (others => '0');
	SIGNAL rfgen2_freq_in	: unsigned(rfgen_nbits_freq-1 downto 0) := (others => '0');
	SIGNAL rfgen2_phase_in	: unsigned(rfgen_nbits_phase-1 downto 0) := (others => '0');
	SIGNAL rfgen3_freq_in	: unsigned(rfgen_nbits_freq-1 downto 0) := (others => '0');
	SIGNAL rfgen3_phase_in	: unsigned(rfgen_nbits_phase-1 downto 0) := (others => '0');

	--Outputs
	signal rfgen_din_i		: sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac)) := to_sfixed(0.0, shi(nbits_in, nbits_in_frac), slo(nbits_in, nbits_in_frac));
	signal rfgen_din_q		: sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac)) := to_sfixed(1.0, shi(nbits_in, nbits_in_frac), slo(nbits_in, nbits_in_frac));
	SIGNAL rfgen_dout_i		: sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac));
	SIGNAL rfgen_dout_q		: sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac));
	SIGNAL rfgen1_dout_i	: sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac));
	SIGNAL rfgen1_dout_q	: sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac));
	SIGNAL rfgen1_dout_vld	: std_logic;
	SIGNAL rfgen2_dout_i	: sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac));
	SIGNAL rfgen2_dout_q	: sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac));
	SIGNAL rfgen2_dout_vld	: std_logic;
	SIGNAL rfgen3_dout_i	: sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac));
	SIGNAL rfgen3_dout_q	: sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac));
	SIGNAL rfgen3_dout_vld	: std_logic;

	SIGNAL fileout_enable   : std_logic := '0';


BEGIN

inst_syn_ddc : entity work.syn_ddc
	GENERIC MAP 
	(
		nbits_in		=> nbits_in,
		nbits_in_frac	=> nbits_in_frac,
		nbits_out		=> nbits_out,
		nbits_out_frac	=> nbits_out_frac,
		lo_nbits_phase	=> lo_nbits_phase,
		lo_nbits_freq	=> lo_nbits_freq,
		cic_nstages		=> cic_nstages,
		cic_ratio		=> cic_ratio,
		cic_scale_nbits	=> cic_scale_nbits
	)
	PORT MAP
	(
		rst			=> rst,

		adc_clk		=> adc_clk,
		adc_da		=> adc_da,
		adc_ofa		=> adc_ofa,
		adc_rand	=> adc_rand,
		adc_pga		=> adc_pga,
		adc_dith	=> adc_dith,
		adc_shdn	=> adc_shdn,

		usb_usbclk	=> usb_usbclk,
		usb_ifclk	=> usb_ifclk,
		usb_fd		=> usb_fd,
		usb_pktend	=> usb_pktend,
		usb_fifoadr	=> usb_fifoadr,
		usb_slcs_n	=> usb_slcs_n,
		usb_slwr_n	=> usb_slwr_n,
		usb_slrd_n	=> usb_slrd_n,
		usb_sloe	=> usb_sloe,
		usb_flaga	=> usb_flaga,
		usb_flagb	=> usb_flagb,
		usb_flagc	=> usb_flagc,
		
		cl_clk_out	=> cl_clk_out,
		cl_dout		=> cl_dout,
		cl_pd_n		=> cl_pd_n,
		
		reg_aen		=> reg_aen,
		reg_dio		=> reg_dio,
		reg_oe		=> reg_oe,
		reg_we		=> reg_we

	);

	
	rfgen1: entity work.mix 
	GENERIC MAP
	(
		nbits_din			=> nbits_in,
		nbits_din_frac		=> nbits_in_frac,
		nbits_dout			=> nbits_in,
		nbits_dout_frac		=> nbits_in_frac,
		nbits_phase			=> rfgen_nbits_phase,
		nbits_freq			=> rfgen_nbits_freq
	)
	PORT MAP
	(
		rst					=> rst,
		clk					=> adc_clk,
		nco_rst				=> rfgen_nco_rst,
		nco_en				=> rfgen_nco_en,
		freq_in				=> rfgen1_freq_in,
		phase_in			=> rfgen1_phase_in,
		din_i				=> rfgen_din_i,
		din_q				=> rfgen_din_q,
		dout_i				=> rfgen1_dout_i,
		dout_q				=> rfgen1_dout_q,
		din_vld				=> '1',
		dout_vld			=> rfgen1_dout_vld
	);

	rfgen2: entity work.mix 
	GENERIC MAP
	(
		nbits_din			=> nbits_in,
		nbits_din_frac		=> nbits_in_frac,
		nbits_dout			=> nbits_in,
		nbits_dout_frac		=> nbits_in_frac,
		nbits_phase			=> rfgen_nbits_phase,
		nbits_freq			=> rfgen_nbits_freq
	)
	PORT MAP
	(
		rst					=> rst,
		clk					=> adc_clk,
		nco_rst				=> rfgen_nco_rst,
		nco_en				=> rfgen_nco_en,
		freq_in				=> rfgen2_freq_in,
		phase_in			=> rfgen2_phase_in,
		din_i				=> rfgen_din_i,
		din_q				=> rfgen_din_q,
		dout_i				=> rfgen2_dout_i,
		dout_q				=> rfgen2_dout_q,
		din_vld				=> '1',
		dout_vld			=> rfgen2_dout_vld
	);

	rfgen3: entity work.mix 
	GENERIC MAP
	(
		nbits_din			=> nbits_in,
		nbits_din_frac		=> nbits_in_frac,
		nbits_dout			=> nbits_in,
		nbits_dout_frac		=> nbits_in_frac,
		nbits_phase			=> rfgen_nbits_phase,
		nbits_freq			=> rfgen_nbits_freq
	)
	PORT MAP
	(
		rst					=> rst,
		clk					=> adc_clk,
		nco_rst				=> rfgen_nco_rst,
		nco_en				=> rfgen_nco_en,
		freq_in				=> rfgen3_freq_in,
		phase_in			=> rfgen3_phase_in,
		din_i				=> rfgen_din_i,
		din_q				=> rfgen_din_q,
		dout_i				=> rfgen3_dout_i,
		dout_q				=> rfgen3_dout_q,
		din_vld				=> '1',
		dout_vld			=> rfgen3_dout_vld
	);

 	tb_adcclk : PROCESS
	BEGIN
		adc_clk <= not adc_clk;
		wait for PERIOD_ADCCLK/2;
	END PROCESS;

 	tb_usbclk : PROCESS
	BEGIN
		usb_usbclk <= not usb_usbclk;
		wait for PERIOD_USBCLK/2;
	END PROCESS;

 	tb_ifclk : PROCESS
	BEGIN
		usb_ifclk <= not usb_ifclk;
		wait for PERIOD_IFCLK/2;
	END PROCESS;

	rfgen_dout_i	<= resize(0.333*rfgen1_dout_i + 0.333*rfgen2_dout_i + 0.333*rfgen3_dout_i, rfgen_dout_i);
	rfgen_dout_q	<= resize(0.333*rfgen1_dout_q + 0.333*rfgen2_dout_q + 0.333*rfgen3_dout_q, rfgen_dout_q);

	adc_da		<= to_signed(rfgen_dout_i);
	adc_da_vld	<= rfgen1_dout_vld and rfgen2_dout_vld and rfgen3_dout_vld;
	
	tb : PROCESS

	BEGIN

		-- Wait 100 ns for global reset to finish
		wait for 400*PERIOD_USBCLK;
		rst <= '0';

		wait for 200*PERIOD_USBCLK;
		-------------------------------------------
		-- Program gains
		wait for 2*PERIOD_USBCLK;

		ddc_phase_in <= to_unsigned(0,lo_nbits_phase);
		ddc_freq_in <= to_unsigned(lo_freq_word,lo_nbits_freq);

		wait until rising_edge(usb_usbclk);
		reg_dio	<= X"10";
		reg_aen	<= '1';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= ddc_freq_in(7 downto 0);
		reg_aen	<= '0';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= X"11";
		reg_aen	<= '1';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= ddc_freq_in(15 downto 8);
		reg_aen	<= '0';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= X"12";
		reg_aen	<= '1';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= ddc_freq_in(23 downto 16);
		reg_aen	<= '0';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= X"13";
		reg_aen	<= '1';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= X"00";
		reg_aen	<= '0';
		reg_we	<= '1';
		
		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';


		wait until rising_edge(usb_usbclk);
		reg_dio	<= X"20";
		reg_aen	<= '1';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= ddc_phase_in(7 downto 0);
		reg_aen	<= '0';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= X"21";
		reg_aen	<= '1';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= ddc_phase_in(15 downto 8);
		reg_aen	<= '0';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= X"22";
		reg_aen	<= '1';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= ddc_phase_in(23 downto 16);
		reg_aen	<= '0';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= X"23";
		reg_aen	<= '1';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= X"00";
		reg_aen	<= '0';
		reg_we	<= '1';
		
		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait for 200*PERIOD_USBCLK;
		fileout_enable <= '1';


		wait until rising_edge(usb_usbclk);
		reg_dio	<= X"00";
		reg_aen	<= '1';
		reg_we	<= '1';

		wait until rising_edge(usb_usbclk);
		reg_aen	<= '0';
		reg_we	<= '0';

		wait until rising_edge(usb_usbclk);
		reg_dio	<= X"02";
		reg_aen	<= '0';
		reg_we	<= '1';

		wait; 
	END PROCESS;
	
	
	rfgen_ctrl : PROCESS

	BEGIN
			wait until rising_edge(adc_clk) and rst = '0';
			rfgen1_freq_in <= to_unsigned(rfgen1_freq_word,rfgen_nbits_freq);
			rfgen1_phase_in <= to_unsigned(0,rfgen_nbits_phase);
			rfgen2_freq_in <= to_unsigned(rfgen2_freq_word,rfgen_nbits_freq);
			rfgen2_phase_in <= to_unsigned(0,rfgen_nbits_phase);
			rfgen3_freq_in <= to_unsigned(rfgen3_freq_word,rfgen_nbits_freq);
			rfgen3_phase_in <= to_unsigned(0,rfgen_nbits_phase);
			wait until rising_edge(adc_clk);
			rfgen_nco_en <= '1';
	

		wait; 
	END PROCESS;


END;
