--------------------------------------------------------------------------------
-- 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_ddc IS
	Generic 
	(
		nbits_in			: integer := 16;
		nbits_in_frac		: integer := 14;
		nbits_out			: integer := 18;
		nbits_out_frac		: integer := 16;
		lo_nbits_phase		: integer := 20;
		lo_nbits_freq		: integer := 20;
		cic_nstages			: integer := 3;
		cic_max_ratio		: integer := 4096;
		cic_max_diff_delay	: integer := 1;
		cic_scale_nbits_min	: integer := 9;
		cic_scale_nbits_max	: integer := 32;
		rfgen_nbits_phase	: integer := 20;
		rfgen_nbits_freq	: integer := 20
	);
END tb_ddc;

ARCHITECTURE behavior OF tb_ddc IS 

	-- Component Declaration for the Unit Under Test (UUT)
	COMPONENT ddc
	GENERIC 
	(
		nbits_in			: integer;
		nbits_in_frac		: integer;
		nbits_out			: integer;
		nbits_out_frac		: integer;
		lo_nbits_phase		: integer;
		lo_nbits_freq		: integer;
		cic_nstages			: integer;
		cic_max_ratio		: integer;
		cic_max_diff_delay	: integer;
		cic_scale_nbits_min	: integer;
		cic_scale_nbits_max	: integer
	);
	PORT
	(
		rst					: in std_logic;
		clk					: in std_logic;
		lo_nco_rst			: in std_logic;
		lo_nco_en			: in std_logic;
		lo_freq_in			: in unsigned(lo_nbits_freq-1 downto 0);
		lo_phase_in			: in unsigned(lo_nbits_phase-1 downto 0);
		cic_ratio			: in natural range 1 to cic_max_ratio;
		cic_diff_delay		: in natural range 1 to cic_max_diff_delay;
		cic_shift_in		: in natural range 0 to cic_scale_nbits_max;
		din_i				: in  sfixed;
		din_q				: in  sfixed;
		dout_i				: out sfixed;
		dout_q				: out sfixed;
		din_vld				: in  std_logic;
		dout_vld			: out std_logic
	);
	END COMPONENT;

	-- Rf-Generator
	COMPONENT mix
	GENERIC
	(
		nbits_din		: integer;
		nbits_din_frac	: integer;
		nbits_dout		: integer;
		nbits_dout_frac	: integer;
		nbits_phase		: integer;
		nbits_freq		: integer
	);
	PORT
	(
		rst				: in std_logic;
		clk				: in std_logic;
		nco_rst			: in std_logic;
		nco_en			: in std_logic;
		freq_in			: in unsigned(nbits_freq-1 downto 0);
		phase_in		: in unsigned(nbits_phase-1 downto 0);
		din_i			: in  sfixed;
		din_q			: in  sfixed;
		dout_i			: out sfixed;
		dout_q			: out sfixed;
		din_vld			: in std_logic;
		dout_vld		: out std_logic
	);
	END COMPONENT;

	--Constants
	constant fa : REAL := 100.0E6;
	constant frf1 : REAL := 29.9E6;
	constant frf2 : REAL := 30.0E6;
	constant frf3 : REAL := 30.1E6;
	constant flo : REAL := 30.0E6;
	constant PERIOD : time := 10 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);

	--Inputs
	SIGNAL clk				: std_logic := '0';
	SIGNAL rst				: std_logic := '1';
	SIGNAL ddc_nco_rst		: std_logic := '0';
	SIGNAL ddc_nco_en		: std_logic := '0';
	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');
	SIGNAL ddc_diff_delay	: natural := 1;
	SIGNAL ddc_ratio		: natural := 64;
	SIGNAL ddc_shift_in		: natural := 18-cic_scale_nbits_min;

	--Outputs
	SIGNAL ddc_din_i		: sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac));
	SIGNAL ddc_din_q		: sfixed(shi(nbits_in, nbits_in_frac) downto slo(nbits_in, nbits_in_frac));
	SIGNAL ddc_dout_i		: sfixed(shi(nbits_out, nbits_out_frac) downto slo(nbits_out, nbits_out_frac));
	SIGNAL ddc_dout_q		: sfixed(shi(nbits_out, nbits_out_frac) downto slo(nbits_out, nbits_out_frac));
	SIGNAL ddc_dout_vld		: std_logic;
	SIGNAL ddc_din_vld		: 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';

	-- Debug
	signal ddc_i_out_f		: real;
	signal ddc_q_out_f		: real;
	signal rfgen_i_out_f	: real;
	signal rfgen_q_out_f	: real;

BEGIN

	-- Instantiate the Unit Under Test (UUT)
	uut : 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_max_ratio		=> cic_max_ratio,
		cic_max_diff_delay	=> cic_max_diff_delay,
		cic_scale_nbits_min	=> cic_scale_nbits_min,
		cic_scale_nbits_max	=> cic_scale_nbits_max
	)
	PORT MAP
	(
		rst					=> rst,
		clk					=> clk,
		lo_nco_rst			=> ddc_nco_rst,
		lo_nco_en			=> ddc_nco_en,
		lo_freq_in			=> ddc_freq_in,
		lo_phase_in			=> ddc_phase_in,
		cic_ratio			=> ddc_ratio,
		cic_diff_delay		=> ddc_diff_delay,
		cic_shift_in		=> ddc_shift_in,
		din_i				=> ddc_din_i,
		din_q				=> ddc_din_q,
		dout_i				=> ddc_dout_i,
		dout_q				=> ddc_dout_q,
		din_vld				=> ddc_din_vld,
		dout_vld			=> ddc_dout_vld
	);
	
	rfgen1: 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					=> 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: 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					=> 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: 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					=> 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_clk : PROCESS
	BEGIN
		clk <= not clk;
		wait for PERIOD/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);

	ddc_din_i	<= rfgen_dout_i;
	ddc_din_q	<= to_sfixed(0.0, ddc_din_q);
	ddc_din_vld	<= rfgen1_dout_vld and rfgen2_dout_vld and rfgen3_dout_vld;
	
	ddc_i_out_f	<= to_real(ddc_dout_i);
	ddc_q_out_f	<= to_real(ddc_dout_q);
	
	rfgen_i_out_f	<= to_real(rfgen_dout_i);
	rfgen_q_out_f	<= to_real(rfgen_dout_q);
	
	tb : PROCESS
	file RESULT_FREQ:   text open write_mode is "freq.txt"; 
	variable L:         line;

	BEGIN

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

		fprint(RESULT_FREQ, L,"%s\n", REAL'image(flo));

		wait for 2*PERIOD;
		-------------------------------------------
		-- Program gains
		wait for 2*PERIOD;
		wait until rising_edge(clk);

		-- start DDC
		ddc_phase_in <= to_unsigned(0,lo_nbits_phase);
		ddc_freq_in <= to_unsigned(lo_freq_word,lo_nbits_freq);
		wait until rising_edge(clk);
		ddc_nco_en	<= '1';
		
		wait for 20*PERIOD;
		fileout_enable <= '1';

		wait; 
	END PROCESS;
	
	
	rfgen_ctrl : PROCESS

	BEGIN
			wait until rising_edge(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(clk);
			rfgen_nco_en <= '1';
	

		wait; 
	END PROCESS;

	tb_fo : PROCESS(clk)
	file RESULT_Ii:      text open write_mode is "i_in.txt"; 
	file RESULT_Qi:      text open write_mode is "q_in.txt"; 
	file RESULT_Io:      text open write_mode is "i_dec.txt"; 
	file RESULT_Qo:      text open write_mode is "q_dec.txt"; 
	variable L:         line;

	BEGIN
		if rising_edge(clk) and fileout_enable = '1' then
			if ddc_din_vld = '1' then
				fprint(RESULT_Ii, L,"%s\n", REAL'image(to_real(rfgen_dout_i)));
				fprint(RESULT_Qi, L,"%s\n", REAL'image(to_real(rfgen_dout_q)));
			end if;
			if ddc_dout_vld = '1' then
				fprint(RESULT_Io, L,"%s\n", REAL'image(to_real(ddc_dout_i)));
				fprint(RESULT_Qo, L,"%s\n", REAL'image(to_real(ddc_dout_q)));
			end if;
		end if;

	END PROCESS;

END;
