----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    11:30:30 08/27/2006 
-- Design Name: 
-- Module Name:    ac97_test - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.fixed_pkg.all;
use work.mix_pkg.all;
use work.cpu_pkg.all;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
library UNISIM;
use UNISIM.VComponents.all;

entity ac97_test is
	Port (
			sys_rst_n_in	: in std_logic;
			sys_clk_in		: in std_logic;
			sys_btn			: in std_logic_vector(4 downto 0);
			sys_dip			: in std_logic_vector(7 downto 0);
			sys_led			: out std_logic_vector(8 downto 0);
			sys_rx			: in std_logic;
			sys_tx			: out std_logic;
			sys_lcd_d		: inout std_logic_vector(3 downto 0);
			sys_lcd_e		: out std_logic;
			sys_lcd_rs		: out std_logic;
			sys_lcd_rw		: out std_logic;
			ac97_bit_clk	: in  STD_LOGIC;
			ac97_sdata_in	: in  STD_LOGIC;
			ac97_reset_n	: out STD_LOGIC;
			ac97_sdata_out	: out STD_LOGIC;
			ac97_sync		: out STD_LOGIC
		);
end ac97_test;

architecture Behavioral of ac97_test is

	constant mix_nbits : integer := 18;
	constant nco_nbits_wave : integer := 18;
	constant nco_nbits_phase : integer := 16;
	constant fir_bp_nbits : integer := 18;
	constant fir_lp_nbits : integer := 18;
	constant f : REAL := 1.0E3;
	constant df : REAL := 100.0;
	constant fa : REAL := 48.0E3;
	
	constant nco_freq_word : integer := integer(f/fa*2.0**nco_nbits_phase);
	constant nco_freq_inc : integer := integer(df/fa*2.0**nco_nbits_phase);

	type stereo_t is (left, right);
	type pcm_data_t is array (stereo_t) of signed(17 downto 0);
	type stereo_bits_t is array (stereo_t) of std_logic;

------------------------------------------------------------------
	COMPONENT singleshot
	GENERIC (mode : integer);
	PORT(
		rst : IN std_logic;
		clk : IN std_logic;
		input : IN std_logic;          
		output : OUT std_logic
		);
	END COMPONENT;

	COMPONENT ac_io
    Port (
			rst				: in  std_logic;
			clk				: in  std_logic;
			ready			: out std_logic;
			sync_strobe		: out unsigned(0 to 2);
			slot_valid		: out unsigned(0 to 12);
			stat_addr		: out unsigned (19 downto 0);
			stat_data		: out unsigned (19 downto 0);
			rx_pcm_addr		: in  unsigned (3 downto 0);
			rx_pcm_data		: out unsigned (19 downto 0);
			cmd_addr 		: in  unsigned(19 downto 0);
			cmd_data		: in  unsigned(19 downto 0);
			cmd_we			: in  std_logic;
			tx_pcm_addr		: in  unsigned(3 downto 0);
			tx_pcm_data		: in  unsigned(19 downto 0);
			tx_pcm_we		: in  std_logic;
			ac_sdata_in		: in  std_logic;
			ac_bit_clk		: in  std_logic;          
			ac_reset_n		: out std_logic;
			ac_sdata_out	: out std_logic;
			ac_ssync		: out std_logic
			);
	END COMPONENT;

	SIGNAL sync_strobe		: unsigned(0 to 2);
	SIGNAL slot_valid		: unsigned(0 to 12);
	SIGNAL cmd_we			: std_logic;
	SIGNAL cmd_addr			: unsigned(19 downto 0);
	SIGNAL cmd_data			: unsigned(19 downto 0);
	SIGNAL stat_addr		: unsigned(19 downto 0);
	SIGNAL stat_data		: unsigned(19 downto 0);
	SIGNAL tx_pcm_addr		: unsigned(3 downto 0);
	SIGNAL tx_pcm_data		: unsigned(19 downto 0);
	SIGNAL rx_pcm_addr		: unsigned(3 downto 0);
	SIGNAL tx_pcm_we		: std_logic;
	SIGNAL rx_pcm_data		: unsigned(19 downto 0);

	COMPONENT syn_nco
	PORT(
		rst			: in std_logic;
		clk			: in std_logic;
		pacc_clr	: in std_logic;
		pacc_inc	: in std_logic;
		freq_in		: in unsigned(nco_nbits_phase-1 downto 0);
		freq_load	: in std_logic;
		phase_in	: in unsigned(nco_nbits_phase-1 downto 0);
		phase_load	: in std_logic;
		phase_out	: out unsigned(nco_nbits_phase-1 downto 0);
		wave_out_i	: out signed(nco_nbits_wave-1 downto 0);
		wave_out_q	: out signed(nco_nbits_wave-1 downto 0);
		out_valid	: out std_logic
	);
	END COMPONENT;

	SIGNAL nco_pacc_clr		: std_logic;
	SIGNAL nco_pacc_inc		: std_logic;
	SIGNAL nco_freq_in		: unsigned(nco_nbits_phase-1 downto 0);
	SIGNAL nco_freq_load	: std_logic;
	SIGNAL nco_phase_in		: unsigned(nco_nbits_phase-1 downto 0);
	SIGNAL nco_phase_load	: std_logic;
	SIGNAL nco_phase_out	: unsigned(nco_nbits_phase-1 downto 0);
	signal pcm_nco_data 	: pcm_data_t;
	SIGNAL nco_out_valid	: std_logic;

	COMPONENT cpu_embedded
	Port (
		rst			: in  STD_LOGIC;
		clk			: in  STD_LOGIC;
		ce			: in  STD_LOGIC;
		int_in		: in  STD_LOGIC;
		int_ack		: out  STD_LOGIC;
		xmem_we		: out STD_LOGIC;
		xmem_re		: out STD_LOGIC;
		xmem_din	: in  unsigned (DMEM_DATA_WIDTH-1 downto 0);
		xmem_dout	: out unsigned (DMEM_DATA_WIDTH-1 downto 0);
		xmem_addr	: out unsigned (DMEM_ADDR_WIDTH-1 downto 0);
		io_sel		: out STD_LOGIC
	);
	END COMPONENT;

	signal cpu_ce  : std_logic;
	signal cpu_int_in : std_logic;
	signal cpu_int_ack : std_logic;
	signal cpu_din : dmem_data_t;
	signal cpu_dout : dmem_data_t;
	signal cpu_addr : dmem_addr_t;
	signal cpu_we : std_logic;
	signal cpu_re : std_logic;
	signal cpu_io_sel : std_logic;

	COMPONENT xrom
	Port (
		clk			: in  STD_LOGIC;
		ce			: in  STD_LOGIC;
		addr		: in  dmem_addr_t;
		dout		: out dmem_data_t
	);
	END COMPONENT;
	signal xrom_data : dmem_data_t;

	COMPONENT syn_fir_bandpass
	PORT(
		rst			: in  std_logic;
		clk			: in  std_logic;
		ready_i		: out std_logic;
		x_valid_i	: in  std_logic;
		x_din_i		: in  signed(fir_bp_nbits-1 downto 0);
		y_valid_i	: out std_logic;
		y_dout_i	: out signed(fir_bp_nbits-1 downto 0);
		ready_q		: out std_logic;
		x_valid_q	: in  std_logic;
		x_din_q		: in  signed(fir_bp_nbits-1 downto 0);
		y_valid_q	: out std_logic;
		y_dout_q	: out signed(fir_bp_nbits-1 downto 0)
	);
	END COMPONENT;

	signal fir_bp_ready : stereo_bits_t;
	signal fir_bp_din_we : stereo_bits_t;
	signal fir_bp_dout_valid : stereo_bits_t;
	signal fir_bp_din : pcm_data_t;
	signal fir_bp_dout : pcm_data_t;

	COMPONENT syn_fir_lowpass
	PORT(
		rst			: in  std_logic;
		clk			: in  std_logic;
		ready_i		: out std_logic;
		x_valid_i	: in  std_logic;
		x_din_i		: in  signed(fir_lp_nbits-1 downto 0);
		y_valid_i	: out std_logic;
		y_dout_i	: out signed(fir_lp_nbits-1 downto 0);
		ready_q		: out std_logic;
		x_valid_q	: in  std_logic;
		x_din_q		: in  signed(fir_lp_nbits-1 downto 0);
		y_valid_q	: out std_logic;
		y_dout_q	: out signed(fir_lp_nbits-1 downto 0)
	);
	END COMPONENT;

	signal fir_lp_ready : stereo_bits_t;
	signal fir_lp_din_we : stereo_bits_t;
	signal fir_lp_dout_valid : stereo_bits_t;
	signal fir_lp_din : pcm_data_t;
	signal fir_lp_dout : pcm_data_t;

	COMPONENT mix_cpx
	GENERIC
	(
		nbits_in		: integer;
		nbits_in_frac	: integer;
		nbits_out		: integer;
		nbits_out_frac	: integer;
		nbits_scale_z	: integer;
		has_in_reg		: boolean;
		has_pipe_reg	: boolean;
		has_out_reg		: boolean;
		rounding		: boolean;
		saturating		: boolean
	);
	PORT
	(
		srst		: in std_logic;
		clk			: in std_logic;
		in_valid	: in std_logic;
		x_re_in		: in sfixed(sproto(mix_nbits, mix_nbits)'high downto sproto(mix_nbits, mix_nbits)'low);
		x_im_in		: in sfixed(sproto(mix_nbits, mix_nbits)'high downto sproto(mix_nbits, mix_nbits)'low);
		y_re_in		: in sfixed(sproto(mix_nbits, mix_nbits)'high downto sproto(mix_nbits, mix_nbits)'low);
		y_im_in		: in sfixed(sproto(mix_nbits, mix_nbits)'high downto sproto(mix_nbits, mix_nbits)'low);
		out_valid	: out std_logic;
		z_re_out	: out sfixed(sproto(mix_nbits, mix_nbits)'high downto sproto(mix_nbits, mix_nbits)'low);
		z_im_out	: out sfixed(sproto(mix_nbits, mix_nbits)'high downto sproto(mix_nbits, mix_nbits)'low)
	);
	END COMPONENT;

	constant mix_nbits_scale_z : integer := 1;
	signal mix_x_re			: sfixed(sproto(mix_nbits, mix_nbits)'high downto sproto(mix_nbits, mix_nbits)'low);
	signal mix_x_im			: sfixed(sproto(mix_nbits, mix_nbits)'high downto sproto(mix_nbits, mix_nbits)'low);
	signal mix_y_re			: sfixed(sproto(mix_nbits, mix_nbits)'high downto sproto(mix_nbits, mix_nbits)'low);
	signal mix_y_im			: sfixed(sproto(mix_nbits, mix_nbits)'high downto sproto(mix_nbits, mix_nbits)'low);
	signal mix_z_re			: sfixed(sproto(mix_nbits, mix_nbits)'high downto sproto(mix_nbits, mix_nbits)'low);
	signal mix_z_im			: sfixed(sproto(mix_nbits, mix_nbits)'high downto sproto(mix_nbits, mix_nbits)'low);
	signal mix_in_valid		: std_logic;
	signal mix_out_valid	: std_logic;

	COMPONENT lcd_port
	PORT (
			rst			: in std_logic;
			clk			: in std_logic;
			we			: in std_logic;
			din			: in unsigned(7 downto 0);
			dout		: out unsigned(7 downto 0);
			lcd_d		: inout std_logic_vector(3 downto 0);
			lcd_e		: out std_logic;
			lcd_rs		: out std_logic;
			lcd_rw		: out std_logic
		);
	END COMPONENT;

	signal cpu_lcd_in_reg, cpu_lcd_out_reg : unsigned(DMEM_DATA_WIDTH-1 downto 0);
	signal cpu_lcd_we : std_logic;
	
	------------------------------------------------------------------
--		X"1F400", -- W: DAC rate 8000Hz
--		X"AC440", -- W: DAC rate 44100Hz
	------------------------------------------------------------------

	type state_t is (st_reset, st_pcm_in, st_pcm_in3, st_pcm_in4, st_pcm_out, st_pcm_out3, st_pcm_out4);

	signal rst, clk : std_logic;
	signal acio_ready : std_logic;
	signal nco_freq_set		: unsigned(nco_nbits_phase-1 downto 0);
	signal pcm_rom_data : signed(19 downto 0);
	signal pcm_rom_addr : unsigned(9 downto 0);
	signal pcm_active, cmd_active : std_logic;
	signal state, nextstate : state_t;
	signal ac_reset_n : std_logic;
	signal ac_rst : std_logic;
	signal ac_ssync : std_logic;
	signal pcm_request, pcm_request_set, pcm_request_ack : std_logic;
	signal started_up : std_logic := '1';
	signal cpu_freq, cpu_cmd_addr, cpu_cmd_data, cpu_stat_addr, cpu_stat_data : unsigned(15 downto 0);
	signal cpu_mix_dc_adj_left, cpu_mix_dc_adj_right, cpu_pcmin_dc_adj_left, cpu_pcmin_dc_adj_right : unsigned(15 downto 0);

	
	subtype low is unsigned(7 downto 0);
	subtype high is unsigned(15 downto 8);
	
	signal pcm_in_data : pcm_data_t;
	signal pcm_out_data : pcm_data_t;
	
	signal pcm_in_data_we, pcm_in_valid : stereo_bits_t;
	
	type pcmout_mode_t is (PCMOUT_TONE, PCMOUT_LOOPTHROUGH, PCMOUT_FILTERED, PCMOUT_MIXER, PCMOUT_FM, PCMOUT_BASEBAND);
	signal pcmout_mode : pcmout_mode_t;
	signal pcm_table_data : unsigned(19 downto 0);
	signal cpu_cmd_access, cpu_freq_access, cpu_cmd_ready, cpu_stat_ready : std_logic;
	signal cpu_led_reg, cpu_btn_reg, cpu_dip_reg, cpu_pcmmode_reg : unsigned(DMEM_DATA_WIDTH-1 downto 0);
	signal cpu_cmd_we, cmd_access_is_fsm : std_logic;
	
	------------------------------------------------------------------
	function GetRequest(slot1 : unsigned) return unsigned is
	variable res : unsigned(3 to 12);
	begin
		res := (others => '0');
		for i in res'range loop
			res(i) := not slot1(14-i);
		end loop;
		return res;	

	end GetRequest;
	
begin

	------------------------------------------------------------------
	cmd_data <= (cpu_cmd_data & "0000");
	cmd_addr <= (cpu_cmd_addr & "0000");

	ac_rst <= not ac_reset_n;
	ac97_reset_n <= ac_reset_n;
	ac97_sync <= ac_ssync;
	
	sys_tx <= sys_rx;

	cpu_ce <= '1';
	clk <= sys_clk_in;
	rst <= not (started_up and sys_rst_n_in);
--	rst <= not (sys_rst_n_in);

	cpu_int_in <= sync_strobe(0);
	
	fir_bp_din_we(left) <= pcm_in_valid(left) and fir_bp_ready(left);
	fir_bp_din_we(right) <= pcm_in_valid(right) and fir_bp_ready(right);
	fir_bp_din(left to right) <= pcm_in_data(left to right);

	fir_lp_din_we(left) <= mix_out_valid and fir_lp_ready(left);
	fir_lp_din_we(right) <= mix_out_valid and fir_lp_ready(right);
	fir_lp_din(left) <= to_signed(mix_z_re);
	fir_lp_din(right) <= to_signed(mix_z_im);

	------------------------------------------------------------------
	proc_led_btn:
	process (rst, clk)
	begin
		if rising_edge(clk) then
			cpu_btn_reg <= "000" & unsigned(sys_btn);
			cpu_dip_reg <= unsigned(sys_dip);
			if rst = '1' then
				sys_led <= (others => '0');
			else	
				sys_led(7 downto 0) <= STD_LOGIC_VECTOR(cpu_led_reg);
			end if;
		end if;
	end process;	

	------------------------------------------------------------------
	host_din : process (acio_ready, sync_strobe, slot_valid, stat_addr, state, pcm_request, pcm_out_data)
	variable request : unsigned(3 to 12);
	variable rx_frame_valid : std_logic;
	variable sync_frame, sync_status, sync_tx : std_logic;
	
	begin
		request := GetRequest(stat_addr);
		rx_frame_valid := slot_valid(0);
		sync_frame := sync_strobe(0);
		sync_status := sync_strobe(1);
		sync_tx := sync_strobe(2);
		
		tx_pcm_we <= '0';
		tx_pcm_addr <= to_unsigned(3, tx_pcm_addr'length);
		tx_pcm_data <= to_unsigned(0, tx_pcm_data'length);

		rx_pcm_addr <= to_unsigned(3, rx_pcm_addr'length);
		
		nextstate <= state;
		pcm_active <= '0';
		cmd_active <= '0';
		pcm_request_set <= '0';
		pcm_request_ack <= '0';
		pcm_in_data_we <= (others => '0');
		
		nco_pacc_inc <= '0';
		nco_pacc_clr <= '0';
		nco_phase_in <= (others => '0');
		nco_phase_load <= '0';

		case state is
			
		when st_reset =>
		if rx_frame_valid = '1' and sync_status = '1' and acio_ready = '1' then
			nextstate <= st_pcm_in;
		end if;	
					
		when st_pcm_in =>
		if rx_frame_valid = '1' and sync_frame = '1' then 
			nextstate <= st_pcm_in3;
		end if;
			
		when st_pcm_in3 => 
		nextstate <= st_pcm_in4;
		rx_pcm_addr <= to_unsigned(3, rx_pcm_addr'length);
		if slot_valid(3) = '1' then
			pcm_in_data_we(left) <= '1';
		end if;	

		when st_pcm_in4 =>
		nextstate <= st_pcm_out;
		rx_pcm_addr <= to_unsigned(4, rx_pcm_addr'length);
		if slot_valid(4) = '1' then
			pcm_in_data_we(right) <= '1';
		end if;	
		
		when st_pcm_out =>
		pcm_active <= '1';
		if rx_frame_valid = '1' and sync_status = '1' then
			if request(3) = '1' and request(4) = '1' then
				pcm_request_set <= '1';
				nco_pacc_inc <= '1';				
			end if;	
		end if;	
		if pcm_request = '1' and sync_tx = '1' then
			nextstate <= st_pcm_out3;
		end if;	
		
		when st_pcm_out3 =>
		tx_pcm_data <= unsigned(pcm_out_data(left)) & "00";
		pcm_active <= '1';
		tx_pcm_addr <= to_unsigned(3, tx_pcm_addr'length);
		tx_pcm_we <= '1';
		pcm_request_ack <= '1';
		nextstate <= st_pcm_out4;

		when st_pcm_out4 =>
		tx_pcm_data <= unsigned(pcm_out_data(right)) & "00";
		pcm_active <= '1';
		tx_pcm_addr <= to_unsigned(4, tx_pcm_addr'length);
		tx_pcm_we <= '1';
		nextstate <= st_pcm_in;
		
		when others => 
			nextstate <= st_reset;
	
		end case;					

	end process;

	proc_fsm_next:
	process (rst, clk, nextstate)
	begin
		if rst = '1' then
			state <= st_reset;
		elsif rising_edge(clk) then
			state <= nextstate;
		end if;
	end process;	

	-------------------------------------------------------------
	-- proc_pcm_in
	-------------------------------------------------------------
	proc_pcm_in:
	process (rst, clk, pcm_in_data_we, rx_pcm_data)
	variable dc_adj : pcm_data_t;
	begin
		dc_adj(left) := resize(signed(cpu_pcmin_dc_adj_left), dc_adj(left)'length);
		dc_adj(right) := resize(signed(cpu_pcmin_dc_adj_right), dc_adj(right)'length);
		
		if rst = '1' then
			for i in pcm_in_data'range loop
				dc_adj(i) := (others => '0');
				pcm_in_data(i) <= (others => '0');
				pcm_in_valid(i) <= '0';
			end loop;	
		elsif rising_edge(clk) then
			for i in pcm_in_data'range loop
				pcm_in_valid(i) <= '0';
			end loop;	
			for i in pcm_in_data'range loop
				if pcm_in_data_we(i) = '1' then 
					pcm_in_valid(i) <= '1';
					pcm_in_data(i) <= dc_adj(i) + signed(rx_pcm_data(19 downto 2));
				end if;
			end loop;	
		end if;
	end process;	

	-------------------------------------------------------------
	-- proc_mix_input
	-------------------------------------------------------------
	proc_mix_input:
	process (rst, clk)
	begin

		if rst = '1' then
			mix_in_valid <= '0';
			mix_x_re <= to_sfixed(0.0, mix_x_re);
			mix_x_im <= to_sfixed(0.0, mix_x_im);
		elsif rising_edge(clk) then
			mix_in_valid <= '0';
			if fir_bp_dout_valid(right) = '1' then
				mix_in_valid <= '1';
				mix_x_re <= sfixed(signed(cpu_mix_dc_adj_left) + fir_bp_dout(left));
				mix_x_im <= sfixed(signed(cpu_mix_dc_adj_right) + fir_bp_dout(right));
			end if;	
			mix_y_re <= sfixed(pcm_nco_data(left));
			mix_y_im <= sfixed(pcm_nco_data(right));
		end if;
	end process;	

	-------------------------------------------------------------
	-- proc_pcmout_mode_mapper
	-------------------------------------------------------------
	proc_pcmout_mode_mapper:
	process (cpu_pcmmode_reg)
	begin
		case cpu_pcmmode_reg is
		when X"00" =>
			pcmout_mode <= PCMOUT_LOOPTHROUGH;
		when X"01" =>
			pcmout_mode <= PCMOUT_FILTERED;
		when X"02" =>
			pcmout_mode <= PCMOUT_TONE;
		when X"03" =>
			pcmout_mode <= PCMOUT_MIXER;
		when X"04" =>
			pcmout_mode <= PCMOUT_FM;
		when X"05" =>
			pcmout_mode <= PCMOUT_BASEBAND;
		when others =>
			pcmout_mode <= PCMOUT_LOOPTHROUGH;
		end case;
	end process;	

	-------------------------------------------------------------
	-- proc_pcm_out_mux
	-------------------------------------------------------------
	proc_pcm_out_mux:
	process (clk)
	begin
		if rising_edge(clk) then
			case pcmout_mode is
				when PCMOUT_TONE | PCMOUT_FM =>
					pcm_out_data(left to right) <= pcm_nco_data(left to right);
				when PCMOUT_LOOPTHROUGH =>
					pcm_out_data(left to right) <= pcm_in_data(left to right);
				when PCMOUT_FILTERED =>
					pcm_out_data(left to right)	<= fir_bp_dout(left to right);
				when PCMOUT_MIXER =>
					pcm_out_data(left) <= to_signed(mix_z_re);
					pcm_out_data(right) <= to_signed(mix_z_im);
				when PCMOUT_BASEBAND =>
					pcm_out_data(left to right)	<= fir_lp_dout(left to right);
				when others => 
					pcm_out_data(left to right) <= pcm_nco_data(left to right);
			end case;
		end if;
	end process;	

	-------------------------------------------------------------
	-- proc_freq_mod
	-------------------------------------------------------------
	proc_freq_mod:
	process (clk)
	begin
		if rising_edge(clk) then
			if rst = '1' then
				nco_freq_set <= to_unsigned(nco_freq_word, nco_nbits_phase);
			elsif cpu_freq_access = '1' then
				nco_freq_set <= cpu_freq;
			end if;
			if pcmout_mode = PCMOUT_FM then
				nco_freq_in <= unsigned(fir_bp_dout(left)(nco_freq_in'left downto 2) + signed(nco_freq_set));
			else	
				nco_freq_in <= nco_freq_set;
			end if;	
			nco_freq_load <= fir_bp_dout_valid(left);
		end if;	
	end process;	

	-------------------------------------------------------------
	-- proc_cpu_flags
	-------------------------------------------------------------
	proc_cpu_stat_reg_control:
	process (clk, sync_strobe, slot_valid)
	variable rx_frame_valid : std_logic;
	variable sync_frame, sync_status, sync_tx : std_logic;
	begin
		rx_frame_valid := slot_valid(0);
		sync_frame := sync_strobe(0);
		sync_status := sync_strobe(1);
		sync_tx := sync_strobe(2);

		if rising_edge(clk) then
			if rst = '1' then
				cpu_cmd_ready <= '0';
				cpu_stat_ready <= '0';
				cpu_stat_addr <= (others => '0');
				cpu_stat_data <= (others => '0');
			else
				cpu_cmd_we <= '0';
				if cpu_cmd_access = '1' then
					cpu_cmd_ready <= '0';
					cpu_stat_ready <= '0';
				end if;
			
				if cpu_cmd_ready = '0' then
					if sync_tx = '1' and rx_frame_valid = '1' then
						cpu_cmd_we <= '1';
						cpu_cmd_ready <= '1';
					end if;	
				end if;
				
				if sync_status = '1' and slot_valid(0 to 2) = "111" then
					cpu_stat_ready <= '1';
					cpu_stat_addr <= stat_addr(19 downto 4);
					cpu_stat_data <= stat_data(19 downto 4);
				end if;
			end if;
		end if;	

	end process;	

	-------------------------------------------------------------
	-- proc_cpu_dout_reg
	-------------------------------------------------------------
	proc_cpu_dout_reg:
	process (clk)
	variable addr : dmem_addr_t;
	begin
		if rising_edge(clk) then
			if rst = '1' then
				cpu_led_reg <= (others => '0');
				cpu_pcmmode_reg <= (others => '0');
				cpu_freq <= (others => '0');
				cpu_cmd_addr <= (others => '0');
				cpu_cmd_data <= (others => '0');
				cpu_lcd_out_reg <= (others => '0');
				cpu_mix_dc_adj_left <= (others => '0');
				cpu_mix_dc_adj_right <= (others => '0');
				cpu_pcmin_dc_adj_left <= (others => '0');
				cpu_pcmin_dc_adj_right <= (others => '0');
			else 	
				addr := cpu_addr;
				cpu_cmd_access <= '0';
				cpu_freq_access <= '0';
				cpu_lcd_we <= '0';
				if cpu_we = '1' and cpu_io_sel = '1' then
					case addr is
					when X"00" =>
						cpu_led_reg <= cpu_dout;
					when X"01" =>
						cpu_pcmmode_reg <= cpu_dout;
					when X"02" =>
						cpu_freq_access <= '1';
						cpu_freq(low'range) <= cpu_dout;
					when X"03" =>
						cpu_freq(high'range) <= cpu_dout;
					when X"04" => 
						cpu_cmd_addr(low'range) <= cpu_dout;
					when X"05" => 
						cpu_cmd_addr(high'range) <= cpu_dout;
					when X"06" => 
						cpu_cmd_access <= '1';
						cpu_cmd_data(low'range) <= cpu_dout;
					when X"07" => 
						cpu_cmd_data(high'range) <= cpu_dout;
					when X"08" => 
						cpu_lcd_we <= '1';
						cpu_lcd_out_reg <= cpu_dout;
					when X"09" => 
						cpu_mix_dc_adj_left(low'range) <= cpu_dout;
					when X"0A" => 
						cpu_mix_dc_adj_left(high'range) <= cpu_dout;
					when X"0B" => 
						cpu_mix_dc_adj_right(low'range) <= cpu_dout;
					when X"0C" => 
						cpu_mix_dc_adj_right(high'range) <= cpu_dout;
					when X"0D" => 
						cpu_pcmin_dc_adj_left(low'range) <= cpu_dout;
					when X"0E" => 
						cpu_pcmin_dc_adj_left(high'range) <= cpu_dout;
					when X"0F" => 
						cpu_pcmin_dc_adj_right(low'range) <= cpu_dout;
					when X"10" => 
						cpu_pcmin_dc_adj_right(high'range) <= cpu_dout;
					when others => null;
					end case;	
				end if;	
			end if;
		end if;
	end process;	

	-------------------------------------------------------------
	-- proc_cpu_din_reg
	-------------------------------------------------------------
	proc_cpu_din_reg:
	process (clk, cpu_io_sel, xrom_data)
	variable mix_xre, mix_xim : signed (mix_nbits-1 downto 0);
	variable mix_yre, mix_yim : signed (mix_nbits-1 downto 0);
	variable addr : dmem_addr_t;
	begin
	
		mix_xre := to_signed(mix_x_re);
		mix_xim := to_signed(mix_x_im);
		mix_yre := to_signed(mix_y_re);
		mix_yim := to_signed(mix_y_im);

		if rising_edge(clk) then
			addr := cpu_addr;
		end if;

		if cpu_io_sel = '0' then
			cpu_din <= xrom_data;
		else
			case addr is
			when X"00" =>
				cpu_din <= cpu_led_reg;
			when X"01" =>
				cpu_din <= cpu_pcmmode_reg;
			when X"02" =>
				cpu_din <= cpu_freq(low'range);
			when X"03" =>
				cpu_din <= cpu_freq(high'range);
			when X"04" =>
				cpu_din <= cpu_stat_addr(low'range);
			when X"05" =>
				cpu_din <= cpu_stat_addr(high'range);
			when X"06" =>
				cpu_din <= cpu_stat_data(low'range);
			when X"07" =>
				cpu_din <= cpu_stat_data(high'range);
			when X"08" =>
				cpu_din <= cpu_lcd_in_reg;
			when X"09" =>
				cpu_din <= cpu_mix_dc_adj_left(low'range);
			when X"0A" =>
				cpu_din <= cpu_mix_dc_adj_left(high'range);
			when X"0B" =>
				cpu_din <= cpu_mix_dc_adj_right(low'range);
			when X"0C" =>
				cpu_din <= cpu_mix_dc_adj_right(high'range);
			when X"0D" =>
				cpu_din <= cpu_pcmin_dc_adj_left(low'range);
			when X"0E" =>
				cpu_din <= cpu_pcmin_dc_adj_left(high'range);
			when X"0F" =>
				cpu_din <= cpu_pcmin_dc_adj_right(low'range);
			when X"10" =>
				cpu_din <= cpu_pcmin_dc_adj_right(high'range);
			when X"80" =>
				cpu_din <= cpu_btn_reg;
			when X"81" =>
				cpu_din <= cpu_dip_reg;
			when X"82" =>
				cpu_din <= dmem_data_t(pcm_in_data(left)(low'range));
			when X"83" =>
				cpu_din <= dmem_data_t(pcm_in_data(left)(high'range));
			when X"84" =>
				cpu_din <= dmem_data_t(pcm_in_data(right)(low'range));
			when X"85" =>
				cpu_din <= dmem_data_t(pcm_in_data(right)(high'range));
			when X"86" =>
				cpu_din <= dmem_data_t(mix_xre(low'range));
			when X"87" =>
				cpu_din <= dmem_data_t(mix_xre(high'range));
			when X"88" =>
				cpu_din <= dmem_data_t(mix_xim(low'range));
			when X"89" =>
				cpu_din <= dmem_data_t(mix_xim(high'range));
			when X"8A" =>
				cpu_din <= dmem_data_t(mix_yre(low'range));
			when X"8B" =>
				cpu_din <= dmem_data_t(mix_yre(high'range));
			when X"8C" =>
				cpu_din <= dmem_data_t(mix_yim(low'range));
			when X"8D" =>
				cpu_din <= dmem_data_t(mix_yim(high'range));
			when X"A0" =>
				cpu_din <= "0000" & (fir_bp_ready(left) and fir_bp_ready(right)) & cpu_stat_ready & cpu_cmd_ready & (pcm_active and acio_ready and slot_valid(0));
			when others =>
				if addr(0) = '0' then
					cpu_din <= X"EF";
				else
					cpu_din <= X"BE";
				end if;
			end case;	
		end if;	

	end process;	
	-------------------------------------------------------------
	proc_pcm_request:
	process (clk, pcm_request_set, pcm_request_ack)
	begin
		if rising_edge(clk) then
			if pcm_request_ack = '1' or rst = '1' then
				pcm_request <= '0';
			elsif pcm_request_set = '1' then
				pcm_request <= '1';
			end if;
		end if;
	end process;	

	------------------------------------------------------------------
	-- Instantiate the Unit Under Test (UUT)
	inst_ac_io: ac_io PORT MAP(
		rst				=> rst,				
		clk				=> clk,				
		ready			=> acio_ready,				
		sync_strobe		=> sync_strobe,	
		slot_valid		=> slot_valid,	
		stat_addr		=> stat_addr,			
		stat_data		=> stat_data,			
		rx_pcm_addr		=> rx_pcm_addr,		
		rx_pcm_data		=> rx_pcm_data,		
		cmd_addr 		=> cmd_addr, 	
		cmd_data		=> cmd_data,		
		cmd_we			=> cpu_cmd_we,	
		tx_pcm_addr		=> tx_pcm_addr,		
		tx_pcm_data		=> tx_pcm_data,		
		tx_pcm_we		=> tx_pcm_we,	
		ac_sdata_in		=> ac97_sdata_in,		
		ac_bit_clk		=> ac97_bit_clk,		
		ac_reset_n		=> ac_reset_n,		
		ac_sdata_out	=> ac97_sdata_out,	
		ac_ssync		=> ac_ssync		
	);
	
	inst_syn_nco: syn_nco 
	PORT MAP(
		rst			=> rst,
		clk			=> clk,
		pacc_clr	=> nco_pacc_clr,
		pacc_inc	=> nco_pacc_inc,
		freq_in		=> nco_freq_in,
		freq_load	=> nco_freq_load,
		phase_in	=> nco_phase_in,
		phase_load	=> nco_phase_load,
		phase_out	=> nco_phase_out,
		wave_out_i	=> pcm_nco_data(left),
		wave_out_q	=> pcm_nco_data(right),
		out_valid	=> nco_out_valid
	);

	inst_cpu_embedded: cpu_embedded
	PORT MAP(
		rst => rst,
		clk => clk,
		ce => cpu_ce,
		int_in => cpu_int_in,
		int_ack => cpu_int_ack,
		xmem_we => cpu_we,
		xmem_re => cpu_re,
		xmem_din => cpu_din,
		xmem_dout => cpu_dout,
		xmem_addr => cpu_addr,
		io_sel => cpu_io_sel
	);

	inst_xrom: xrom
	PORT MAP(
		clk			=> clk,
		ce			=> cpu_ce,
		addr		=> cpu_addr,
		dout 		=> xrom_data
	);

	inst_syn_fir_bandpass: syn_fir_bandpass
	PORT MAP(
		rst			=> rst,
		clk			=> clk,
		ready_i		=> fir_bp_ready(left),
		x_valid_i	=> fir_bp_din_we(left),
		x_din_i		=> fir_bp_din(left),
		y_valid_i	=> fir_bp_dout_valid(left),
		y_dout_i	=> fir_bp_dout(left),
		ready_q		=> fir_bp_ready(right),
		x_valid_q	=> fir_bp_din_we(right),
		x_din_q		=> fir_bp_din(right),
		y_valid_q	=> fir_bp_dout_valid(right),
		y_dout_q	=> fir_bp_dout(right)
	);

	inst_syn_fir_lowpass: syn_fir_lowpass
	PORT MAP(
		rst			=> rst,
		clk			=> clk,
		ready_i		=> fir_lp_ready(left),
		x_valid_i	=> fir_lp_din_we(left),
		x_din_i		=> fir_lp_din(left),
		y_valid_i	=> fir_lp_dout_valid(left),
		y_dout_i	=> fir_lp_dout(left),
		ready_q		=> fir_lp_ready(right),
		x_valid_q	=> fir_lp_din_we(right),
		x_din_q		=> fir_lp_din(right),
		y_valid_q	=> fir_lp_dout_valid(right),
		y_dout_q	=> fir_lp_dout(right)
	);
	
	inst_mix_cpx: mix_cpx 
	GENERIC MAP
	(
		nbits_in		=> mix_nbits,
		nbits_in_frac	=> mix_nbits,
		nbits_out		=> mix_nbits,
		nbits_out_frac	=> mix_nbits,
		nbits_scale_z	=> mix_nbits_scale_z,
		has_in_reg		=> true,
		has_pipe_reg	=> true,
		has_out_reg		=> true,
		rounding		=> false,
		saturating		=> false
	)
	PORT MAP
	(
		srst		=> rst,
		clk			=> clk,
		in_valid	=> mix_in_valid,
		x_re_in		=> mix_x_re,
		x_im_in		=> mix_x_im,
		y_re_in		=> mix_y_re,
		y_im_in		=> mix_y_im,
		out_valid	=> mix_out_valid,
		z_re_out	=> mix_z_re,
		z_im_out	=> mix_z_im
	);

	inst_lcd_port: lcd_port
	PORT MAP(
		rst => rst,
		clk => clk,
		we => cpu_lcd_we,
		din => cpu_lcd_out_reg,
		dout => cpu_lcd_in_reg,
		lcd_d => sys_lcd_d,
		lcd_e => sys_lcd_e,
		lcd_rs => sys_lcd_rs,
		lcd_rw => sys_lcd_rw
	);

	------------------------------------------------------------------
	STARTUP_VIRTEX4_inst : STARTUP_VIRTEX4
	port map (
		EOS => started_up,      -- End of Startup 1-bit output
		CLK => open,      -- Clock input for start-up sequence
		GSR => '0', -- Global Set/Reset input (GSR cannot be used for the port name)
		GTS => '0', -- Global 3-state input (GTS cannot be used for the port name)
		USRCCLKO => '0',   -- USRCCLKO 1-bit input
		USRCCLKTS => '0', -- USRCCLKTS 1-bit input
		USRDONEO => '0',   -- USRDONEO 1-bit input
		USRDONETS => '0'  -- USRDONETS 1-bit input
	);
   
	------------------------------------------------------------------
   
end Behavioral;

