-------------------------------------------------------------
-- MSS copyright 1999-2009
--	Filename:  BER_GEN.VHD
-- Author: Alain Zarembowitch / MSS
--	Version: 14
--	Date last modified: 10-21-03
-- Inheritance: 	COM1002 rev 1.23
--
-- description:  Bit Error Rate generator
--
-- Rev 14  9-2-09 AZ
-- Corrected high-Z output
-- Added flow control. added pullup in constraint file
-- prevented BIT_COUNT from counting too far beyond the set thresholds (takes too much time for 32-bit counter to go around)
---------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
library UNISIM;
use UNISIM.VComponents.all;

entity BER_GEN is
    port ( 
		--GLOBAL CLOCKS
	   CLK_IN1 : in std_logic;	-- master clock for this FPGA, internal to the module
	   CLK_IN2 : in std_logic;	-- master clock for this FPGA, external to the module

		--// Left connector J2, 40 pins. 
		-- Pin 1 is reserved for input clock CLK_IN2
		-- Pins 10,20,30,40 reserved for Ground
		-- Pins 37,38,39 reserved for JTAG
		-- Pins 31-36 reserved for ComBlock Monitoring and Control.
		J2: inout std_logic_vector(29 downto 2);

		--// Right and Bottom connectors: J3 (right) and J4 (bottom), 40 pins. 
		-- Pin 1 is reserved to forward clock to following module.
		-- Pins 10,20,30,40 reserved for Ground
		-- Pins 37,38,39 reserved for JTAG
		-- Pins 31-36 reserved for ComBlock Monitoring and Control.
		J3: inout std_logic_vector(29 downto 1);
		J4: inout std_logic_vector(29 downto 1);


		--// Controls
	   CONTROL: in std_logic_vector(7 downto 0);   
	   		-- IMPORTANT!!!! vector is flipped and logic is inverted to make DIP switch more readable!
	   		-- Description below is that of the CONTROL vector at this interface only.

		--// Monitoring & Control interface Atmel controller
		UC_AD: inout std_logic_vector(7 downto 0);
		UC_WRN_IN: in std_logic;
		UC_RDN: in std_logic;
		UC_ALE_IN: in std_logic;
		UC_FLASH_CSN: in std_logic;
			-- '0' when uC talks to the flash memory, '1' when otherwise (i.e. possibly
			-- talk to the FPGAs).


		--// Serial ports interface
		RX_L: in std_logic;
		RX_B: in std_logic;
		RX_R: in std_logic;
		TX_L: out std_logic;
		TX_B: out std_logic;
		TX_R: out std_logic;

		-- Test Points
		TP: out std_logic_vector(9 downto 0)	
			-- bit 0-9: undefined

			);
end entity;

architecture behavioral of BER_GEN is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
component BUFG
      port (I : in STD_LOGIC; O : out std_logic);
end component;

component IBUFG
      port (I : in STD_LOGIC; O : out std_logic);
end component;

component AWGN is
  port (
	ASYNC_RESET: in std_logic;
		-- asynchronous reset, active high
	CLK: in  std_logic;   
		-- clock synchronous
	SAMPLE_CLK_REQ: in std_logic;
		-- request for output bit, 
	SYNC_RESET: in std_logic;
		-- synchronous reset.
		-- 1 CLK wide pulse aligned with SAMPLE_CLK_REQ.

	SAMPLE_CLK_OUT: out std_logic;
	NOISE_SAMPLE1_OUT: out std_logic_vector(15 downto 0);	
	NOISE_SAMPLE2_OUT: out std_logic_vector(15 downto 0)	
		-- Two independent white gaussian noise sample. signed 2's complement. Read at rising edge of CLK
		-- when SAMPLE_CLK_OUT = '1'. Latency is 6 CLKs after request.
		-- Mean is 0. Std = 1.0
		-- Floating point format: 5.11
    );
end component;

component CLKDLL
      port (CLKIN, CLKFB, RST : in STD_LOGIC;
      CLK0, CLK90, CLK180, CLK270, CLK2X, CLKDV, LOCKED : out std_logic);
end component;

component POWER_MEASUREMENT is
  port (
	ASYNC_RESET: in std_logic;
		-- asynchronous reset, active high
	CLK: in  std_logic;   
		-- clock synchronous
	SAMPLE_CLK_IN: in std_logic;
		-- input samples
	DATA_I_ABS_IN: in std_logic_vector(14 downto 0);
	DATA_Q_ABS_IN: in std_logic_vector(14 downto 0);
		-- input samples absolute values. format 4.11 (no sign, always positive)
		-- read at rising edge of CLK, when SAMPLE_CLK_IN = '1'
	SYNC_RESET: in std_logic;
		-- synchronous reset.
		-- 1 CLK wide pulse aligned with SAMPLE_CLK_IN.

	SAMPLE_CLK_OUT: out std_logic;
	POWER_OUT: out std_logic_vector(23 downto 0)	
		-- power. format 8.16, unsigned
    );
end component;


--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
-- Suffix _D indicates a one CLK delayed version of the net with the same name
-- Suffix _E indicates an extended precision version of the net with the same name
-- Suffix _N indicates an inverted version of the net with the same name
--// CONSTANTS
signal ZERO: std_logic;
signal ONE: std_logic;
signal ZERO2: std_logic_vector(1 downto 0);
signal ZERO16: std_logic_vector(15 downto 0);

--// CLOCKS, RESETS
signal CLK_IN: 	std_logic;
signal CLK_IN1B: std_logic;
signal CLK_IN2B: std_logic;
signal CLK:       std_logic;
signal ASYNC_RESET: std_logic;

	-- asynchronous reset
signal RESET_COUNTER: std_logic_vector(5 downto 0) := "000000";	-- initialize for simulations

-- staggered resets as a means to generate independent random samples
signal AWGN_RESET1: std_logic;
signal AWGN_RESET2: std_logic;
signal RESET_COUNTER2: std_logic_vector(10 downto 0) := "00000000000";

--// I/Os

--// throughput NCO
signal NCO_SAMPLING_RATE: std_logic_vector(23 downto 0);
signal NCO_SAMPLING_RATE_DIV2: std_logic_vector(23 downto 0);
signal NCO_ACC: std_logic_vector(23 downto 0);	-- accumulator
signal NCO_ACC_MSB: std_logic;	-- accumulator last MSB
signal SAMPLE_CLK_IN_REQ: std_logic;	-- requests data samples upstream

--// input bit stream
signal SAMPLE1S_CLK: std_logic;
signal SAMPLE1S_CLK_D: std_logic;
signal SAMPLE1S_CLK_D2: std_logic;
signal SAMPLE1S_CLK_D3: std_logic;
signal SAMPLE1S_CLK_D4: std_logic;
signal SAMPLE1S_CLK_D5: std_logic;
signal SAMPLE1S_CLK_D6: std_logic;
signal SAMPLE1S_CLK_D7: std_logic;
signal DATA1_I: std_logic_vector(9 downto 0);
signal DATA1_I_D: std_logic_vector(9 downto 0);
signal DATA1_I_D2: std_logic_vector(9 downto 0);
signal DATA1_I_D3: std_logic_vector(9 downto 0);
signal DATA1_I_D4: std_logic_vector(9 downto 0);
signal DATA1_I_D5: std_logic_vector(9 downto 0);
signal DATA1_I_D6: std_logic_vector(15 downto 0);
signal DATA1_I_D7: std_logic;
signal DATA1_Q: std_logic_vector(9 downto 0);
signal DATA1_Q_D: std_logic_vector(9 downto 0);
signal DATA1_Q_D2: std_logic_vector(9 downto 0);
signal DATA1_Q_D3: std_logic_vector(9 downto 0);
signal DATA1_Q_D4: std_logic_vector(9 downto 0);
signal DATA1_Q_D5: std_logic_vector(9 downto 0);
signal DATA1_Q_D6: std_logic_vector(15 downto 0);

-- input signal amplitude scaling
signal SIGNAL_SCALING: std_logic_vector(7 downto 0);
signal SIGNAL_SCALING_D: std_logic_vector(7 downto 0);
signal DATA1_I_ABS: std_logic_vector(14 downto 0);
signal DATA1_I_SIGN: std_logic;
signal DATA1_Q_ABS: std_logic_vector(14 downto 0);
signal DATA1_Q_SIGN: std_logic;
signal DATA2_I_ABS: std_logic_vector(22 downto 0);
signal DATA2_Q_ABS: std_logic_vector(22 downto 0);
signal DATA3_I: std_logic_vector(15 downto 0);
signal DATA3_I_E: std_logic_vector(16 downto 0);
signal DATA3_Q: std_logic_vector(15 downto 0);
signal DATA3_Q_E: std_logic_vector(16 downto 0);
signal SAMPLE3S_CLK: std_logic;
signal POWER_SIGNAL: std_logic_vector(23 downto 0);
signal OVERFLOW3I: std_logic;
signal OVERFLOW3Q: std_logic;


--// Noise 
signal SAMPLE2_CLK: std_logic;
signal SAMPLE2_CLK_D: std_logic;
signal DATA2A: std_logic_vector(15 downto 0);
signal DATA2A_D: std_logic_vector(15 downto 0);
signal DATA2B: std_logic_vector(15 downto 0);
signal DATA2B_D: std_logic_vector(15 downto 0);
signal DATA2: std_logic_vector(11 downto 0);
signal DATA2A_ABS: std_logic_vector(14 downto 0);
signal DATA2B_ABS: std_logic_vector(14 downto 0);
signal POWER_NOISE: std_logic_vector(23 downto 0);

--// Scaled noise
signal AWGN_SCALING: std_logic_vector(7 downto 0);
signal AWGN_SCALING_D: std_logic_vector(7 downto 0);
signal DATA3A_ABS: std_logic_vector(22 downto 0);
signal DATA3B_ABS: std_logic_vector(22 downto 0);
signal DATA3A: std_logic_vector(15 downto 0);
signal DATA3A_E: std_logic_vector(16 downto 0);
signal DATA3B: std_logic_vector(15 downto 0);
signal DATA3B_E: std_logic_vector(16 downto 0);
signal SAMPLE3_CLK: std_logic;
signal DATA3_I_MSB_D: std_logic;
signal DATA3_Q_MSB_D: std_logic;
signal OVERFLOW3A: std_logic;
signal OVERFLOW3B: std_logic;


--// Signal + noise 
signal DATA4_I: std_logic_vector(16 downto 0);
signal DATA4_Q: std_logic_vector(16 downto 0);
signal SAMPLE4_CLK: std_logic;


--// output samples
signal DATA5_I: std_logic_vector(3 downto 0);
signal SAMPLE5_CLK: std_logic;
signal OVERFLOW5: std_logic;

signal DATA6_I: std_logic_vector(9 downto 0);
signal DATA6_Q: std_logic_vector(9 downto 0);
signal OVERFLOW6I: std_logic;
signal OVERFLOW6Q: std_logic;

signal J3_LOCAL: std_logic_vector(24 downto 2);

--// OUTPUT FLOW CONTROL
signal SAMPLE_CLK_OUT_REQ: std_logic := '0';

--// Bit error detection and BER computation
signal BIT_ERROR: std_logic;
signal BIT_COUNT: std_logic_vector(31 downto 0);	-- window length can be as high as 10^9
signal BIT_ERROR_COUNT: std_logic_vector(31 downto 0);	-- window length can be as high as 10^9
signal BER: std_logic_vector(31 downto 0);	-- window length can be as high as 10^9
signal NEW_COUNT: std_logic;

--// Noise sampling rate
signal NOISE_SAMPLING_RATE: std_logic_vector(23 downto 0);
signal NOISE_SAMPLING_RATE_DIV2: std_logic_vector(23 downto 0);
signal NOISE_SAMPLING_RATE_NCO_ACC: std_logic_vector(23 downto 0);
signal NOISE_SAMPLING_RATE_NCO_ACC_MSB: std_logic;
signal SAMPLE1_CLK: std_logic;
signal SAMPLE1N_CLK: std_logic;

--// Atmel uc interface
signal UC_WRN_INB: std_logic;
signal UC_ALE_INB: std_logic;
signal UC_ALE: std_logic;
signal UC_WRN: std_logic;
signal UC_ADDRESS: std_logic_vector(7 downto 0);
signal REG3: std_logic_vector(7 downto 0) := "00000000";
signal REG3_D: std_logic_vector(7 downto 0);
signal REG3_D2: std_logic_vector(7 downto 0);
	-- initialize for simulation, otherwise deadlock (internal/external clock undefined)
signal REG255: std_logic_vector(7 downto 0);

--// FPGA option and revision (ASCII format)
-- '0' = 48
-- 'A' = 65
constant OPTION: std_logic_vector(7 downto 0) := x"20";	-- ' '  
constant REVISION: std_logic_vector(7 downto 0) := x"45";	-- 14 

--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------

begin
--// CONSTANTS ---------------------
ZERO <= '0';
ONE <= '1';
ZERO2 <= "00";
ZERO16 <= (others => '0');

--// RESET ---------------------
RESET_COUNTER_GEN: process(CLK)
begin
	if rising_edge(CLK) then
		if(RESET_COUNTER(5) = '0') then
			RESET_COUNTER <= RESET_COUNTER + 1;
	  	end if;
  	end if;
end process;

ASYNC_RESET <= '1' when (RESET_COUNTER = "011111") else '0';

--// CLOCKS ---------------------
-- No internal clock (does not make any system-level sense)
--IBUFG_001: IBUFG port map (I => CLK_IN1, O => CLK_IN1B);	-- internal clock
IBUFG_002: IBUFG port map (I => CLK_IN2, O => CLK_IN2B);	-- external clock
CLK_IN <= CLK_IN2B;

-- Global buffers
CLK_GEN_001: BUFG  port map (I=> CLK_IN, O=> CLK);
IBUF_003: IBUF port map(I => UC_WRN_IN, O => UC_WRN_INB); -- force selection of IBUF
IBUF_004: IBUF port map(I => UC_ALE_IN, O => UC_ALE_INB); -- force selection of IBUF
BUFG_003: BUFG port map(I => UC_WRN_INB, O => UC_WRN);  
BUFG_004: BUFG port map(I => UC_ALE_INB, O => UC_ALE);  

--// NCO
-- Generate the clock request so as to control the clock throughput.
-- Needed when connecting FEC encoder and decoder back to back without modulator.
-- But first divide by two to make it easier to generate clock requests duty cycles > 50%
NCO_SAMPLING_RATE_DIV2(23) <= '0';
NCO_SAMPLING_RATE_DIV2(22 downto 0) <= NCO_SAMPLING_RATE(23 downto 1);
CLK_REQ_GEN_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		NCO_ACC <= (others => '0');
		NCO_ACC_MSB <= '0';
		SAMPLE_CLK_IN_REQ <= '0';
	elsif rising_edge(CLK) then
		NCO_ACC <= NCO_ACC + NCO_SAMPLING_RATE_DIV2;
		NCO_ACC_MSB <= NCO_ACC(23);	-- remember the last MSB
		if(NCO_SAMPLING_RATE_DIV2 = 0) then
			-- NCO is disabled when REG0-2 = 0
			SAMPLE_CLK_IN_REQ <= '1';
		elsif(NCO_ACC(23) /= NCO_ACC_MSB) then
			-- generate clock request when MSB changed
			SAMPLE_CLK_IN_REQ <= '1';
		else
			SAMPLE_CLK_IN_REQ <= '0';
		end if;
	end if;
end process;
-- send the sample request upstream


--// Reclock inputs
RECLOCK_001: process(ASYNC_RESET, CLK, J2)
begin
	if(ASYNC_RESET = '1') then
		SAMPLE1S_CLK <= '0';
		DATA1_I <= (others => '0');
		DATA1_Q <= (others => '0');
	elsif rising_edge(CLK) then
		SAMPLE1S_CLK <= J2(2);
		DATA1_I(9) <= J2(3);
		DATA1_I(8) <= J2(4);
		DATA1_I(7) <= J2(5);
		DATA1_I(6) <= J2(6);
		DATA1_I(5) <= J2(7);
		DATA1_I(4) <= J2(8);
		DATA1_I(3) <= J2(9);
		DATA1_I(2) <= J2(11);
		DATA1_I(1) <= J2(12);
		DATA1_I(0) <= J2(13);
		DATA1_Q(9) <= J2(14);
		DATA1_Q(8) <= J2(15);
		DATA1_Q(7) <= J2(16);
		DATA1_Q(6) <= J2(17);
		DATA1_Q(5) <= J2(18);
		DATA1_Q(4) <= J2(19);
		DATA1_Q(3) <= J2(21);
		DATA1_Q(2) <= J2(22);
		DATA1_Q(1) <= J2(23);
		DATA1_Q(0) <= J2(24);
	end if;
end process;

--// Reclock input and extend precision to 16-bit. Format is 
-- realign the input samples with the noise sample before summing (3 CLK delay)
RECLOCK_002: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA1_I_D <= (others => '0');
		DATA1_I_D2 <= (others =>'0');
		DATA1_I_D3 <= (others => '0');
		DATA1_I_D4 <= (others => '0');
		DATA1_I_D5 <= (others => '0');
		DATA1_I_D6 <= (others => '0');
		DATA1_I_D7 <= '0';
		DATA1_Q_D <= (others => '0');
		DATA1_Q_D2 <= (others =>'0');
		DATA1_Q_D3 <= (others => '0');
		DATA1_Q_D4 <= (others => '0');
		DATA1_Q_D5 <= (others => '0');
		DATA1_Q_D6 <= (others => '0');
		SAMPLE1S_CLK_D <= '0';
		SAMPLE1S_CLK_D2 <= '0';
		SAMPLE1S_CLK_D3 <= '0';
		SAMPLE1S_CLK_D4 <= '0';
		SAMPLE1S_CLK_D5 <= '0';
		SAMPLE1S_CLK_D6 <= '0';
	elsif rising_edge(CLK) then
		DATA1_I_D <= DATA1_I;
		DATA1_I_D2 <= DATA1_I_D;
		DATA1_I_D3 <= DATA1_I_D2;
		DATA1_I_D4 <= DATA1_I_D3;
		DATA1_I_D5 <= DATA1_I_D4;
		DATA1_Q_D <= DATA1_Q;
		DATA1_Q_D2 <= DATA1_Q_D;
		DATA1_Q_D3 <= DATA1_Q_D2;
		DATA1_Q_D4 <= DATA1_Q_D3;
		DATA1_Q_D5 <= DATA1_Q_D4;

		SAMPLE1S_CLK_D <= SAMPLE1S_CLK;
		SAMPLE1S_CLK_D2 <= SAMPLE1S_CLK_D;
		SAMPLE1S_CLK_D3 <= SAMPLE1S_CLK_D2;
		SAMPLE1S_CLK_D4 <= SAMPLE1S_CLK_D3;
		SAMPLE1S_CLK_D5 <= SAMPLE1S_CLK_D4;
		SAMPLE1S_CLK_D6 <= SAMPLE1S_CLK_D5;

		-- Depending on the input format, extend precision from unsigned 1 bit or 10 bits 
		-- to 16 bits 2's complement. Makes room for noise to be added.
		if(REG3_D(2 downto 1) = "00") then
			-- 1 bit serial input. Convert to floating point format 5.11
			-- Keep the range symmetrical (-2048/2048)
			DATA1_I_D6(15 downto 12) <= (others => (not DATA1_I_D5(9)));
			DATA1_I_D6(11) <= '1';
			DATA1_I_D6(10 downto 0) <= (others =>'0');
			DATA1_Q_D6 <= (others => '0');
		elsif(REG3_D(2 downto 1) = "01") then
			-- 2*10-bit parallel input. complex. unsigned.
			-- Assumes an input format 3.7 floating point to make room for noise.
			-- Convert to 2's complement, format 5.11
			DATA1_I_D6(15 downto 13) <= (others => (not DATA1_I_D5(9)));
			DATA1_I_D6(12 downto 4) <= DATA1_I_D5(8 downto 0);
			DATA1_I_D6(3 downto 0) <= (others => '0');
			DATA1_Q_D6(15 downto 13) <= (others => (not DATA1_Q_D5(9)));
			DATA1_Q_D6(12 downto 4) <= DATA1_Q_D5(8 downto 0);
			DATA1_Q_D6(3 downto 0) <= (others => '0');
		end if;

		DATA1_I_D7 <= DATA1_I_D6(15);
		-- data reference for bit error detection

	end if;
end process;

--// Scale the input signal
-- Take the absolute value before unsigned multiplication
-- Reclock for timing
ABS_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA1_I_ABS <= (others => '0');
		DATA1_I_SIGN <= '0';
		DATA1_Q_ABS <= (others => '0');
		DATA1_Q_SIGN <= '0';
		SAMPLE1S_CLK_D7 <= '0';
	elsif rising_edge(CLK) then
		SAMPLE1S_CLK_D7 <= SAMPLE1S_CLK_D6;
		
		if(DATA1_I_D6(15) = '0') then
			-- positive
			DATA1_I_ABS(14 downto 0) <= DATA1_I_D6(14 downto 0);
			DATA1_I_SIGN <= '0';
	 	elsif(DATA1_I_D6 = "1000000000000000") then
			-- special case
			DATA1_I_ABS <= "111111111111111";
			DATA1_I_SIGN <= '1';
	  	else
			-- negative
			DATA1_I_ABS <= not(DATA1_I_D6(14 downto 0)) + 1;
			DATA1_I_SIGN <= '1';
	  	end if;

		if(DATA1_Q_D6(15) = '0') then
			-- positive
			DATA1_Q_ABS(14 downto 0) <= DATA1_Q_D6(14 downto 0);
			DATA1_Q_SIGN <= '0';
	 	elsif(DATA1_Q_D6 = "1000000000000000") then
			-- special case
			DATA1_Q_ABS <= "111111111111111";
			DATA1_Q_SIGN <= '1';
	  	else
			-- negative
			DATA1_Q_ABS <= not(DATA1_Q_D6(14 downto 0)) + 1;
			DATA1_Q_SIGN <= '1';
	  	end if;

  	end if;
end process;

RECLOCK_003: process(ASYNC_RESET, CLK, SIGNAL_SCALING, AWGN_SCALING)
begin
	if(ASYNC_RESET = '1') then
		SIGNAL_SCALING_D <= (others => '0');
		AWGN_SCALING_D <= (others => '0');
	elsif rising_edge(CLK) then
		SIGNAL_SCALING_D <= SIGNAL_SCALING;
		AWGN_SCALING_D <= AWGN_SCALING;
	end if;
end process;



-- Scale noise (reclock immediately after the multiplication to 
-- maximize speed)
-- Precision = 4.11 * 3.5 = 7.16
DATA2_I_ABS <= DATA1_I_ABS * SIGNAL_SCALING_D;
DATA2_Q_ABS <= DATA1_Q_ABS * SIGNAL_SCALING_D;

-- restore sign after unsigned multiplication
-- Keep format 5.11
-- Detect overflow
ABS_002: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA3_I <= (others => '0');
		OVERFLOW3I <= '0';
		SAMPLE3S_CLK <= '0';
	elsif rising_edge(CLK) then
		SAMPLE3S_CLK <= SAMPLE1S_CLK_D7;	-- latency 8 CLKs after input data1
		
		if(DATA1_I_SIGN = '0') then
			-- positive
			if (DATA2_I_ABS(22 downto 20) = "000") then
				-- positive, no overflow
				DATA3_I(15) <= '0';
				DATA3_I(14 downto 0) <= DATA2_I_ABS(19 downto 5);
				OVERFLOW3I <= '0';
		  	else
				-- positive overflow
				DATA3_I <= x"7FFF";
				OVERFLOW3I <= '1';
		  	end if;
		elsif (DATA2_I_ABS(22 downto 20) = "000") then
			-- negative, no overflow
			DATA3_I <= ("1" & (not DATA2_I_ABS(19 downto 5))) + 1;
			OVERFLOW3I <= '0';
	  	else
			-- negative overflow
			DATA3_I <= x"8001";
			OVERFLOW3I <= '1';
	  	end if;
  	end if;
end process;

ABS_003: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA3_Q <= (others => '0');
		OVERFLOW3Q <= '0';
	elsif rising_edge(CLK) then
		if(DATA1_Q_SIGN = '0') then
			-- positive
			if (DATA2_Q_ABS(22 downto 20) = "000") then
				-- positive, no overflow
				DATA3_Q(15) <= '0';
				DATA3_Q(14 downto 0) <= DATA2_Q_ABS(19 downto 5);
				OVERFLOW3Q <= '0';
		  	else
				-- positive overflow
				DATA3_Q <= x"7FFF";
				OVERFLOW3Q <= '1';
		  	end if;
		elsif (DATA2_Q_ABS(22 downto 20) = "000") then
			-- negative, no overflow
			DATA3_Q <= ("1" & (not DATA2_Q_ABS(19 downto 5))) + 1;
			OVERFLOW3Q <= '0';
	  	else
			-- negative overflow
			DATA3_Q <= x"8001";
			OVERFLOW3Q <= '1';
	  	end if;
  	end if;
end process;


--// AWGN noise generation
-- Noise sampling rate generation
-- First divide by two to make it easier to generate clock requests duty cycles > 50%
NOISE_SAMPLING_RATE_DIV2(23) <= '0';
NOISE_SAMPLING_RATE_DIV2(22 downto 0) <= NOISE_SAMPLING_RATE(23 downto 1);
NOISE_SAMPLE_GEN_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		NOISE_SAMPLING_RATE_NCO_ACC <= (others => '0');
		NOISE_SAMPLING_RATE_NCO_ACC_MSB <= '0';
		SAMPLE1N_CLK <= '0';
	elsif rising_edge(CLK) then
		NOISE_SAMPLING_RATE_NCO_ACC <= NOISE_SAMPLING_RATE_NCO_ACC + NOISE_SAMPLING_RATE_DIV2;
		NOISE_SAMPLING_RATE_NCO_ACC_MSB <= NOISE_SAMPLING_RATE_NCO_ACC(23);	-- remember the last MSB
		if(NOISE_SAMPLING_RATE_NCO_ACC(23) /= NOISE_SAMPLING_RATE_NCO_ACC_MSB) then
			-- generate clock sample when MSB changed
			SAMPLE1N_CLK <= '1';
		else
			SAMPLE1N_CLK <= '0';
		end if;
	end if;
end process;

-- special case if NOISE_SAMPLING_RATE = 0, sampling is set by SAMPLE_CLK_IN
SAMPLE1_CLK <= SAMPLE1S_CLK when (NOISE_SAMPLING_RATE = 0) else SAMPLE1N_CLK;

-- Latency is 2 CLKs
RESET_COUNTER_GEN_002: process(CLK)
begin
	if rising_edge(CLK) then
		if(RESET_COUNTER2(10) = '0') then
			RESET_COUNTER2 <= RESET_COUNTER2 + 1;
	  	end if;
  	end if;
end process;

-- Start the generators at different times to generate independent samples
AWGN_RESET1 <= '1' when (RESET_COUNTER2 = "00001000000") else '0';

-- 2 AWGN samples.
-- Latency between request and sample is 6 CLK.
-- Normalized samples. floating point format 5.11
-- Std dev = 1.0
AWGN_GEN_001: AWGN port map(
	ASYNC_RESET => ASYNC_RESET, 
	CLK => CLK,
	SAMPLE_CLK_REQ => SAMPLE1_CLK,
	SYNC_RESET => AWGN_RESET1,
	SAMPLE_CLK_OUT => SAMPLE2_CLK,
	NOISE_SAMPLE1_OUT => DATA2A,
	NOISE_SAMPLE2_OUT => DATA2B
	);

--// Scale the AWGN
-- Take the absolute value before unsigned multiplication
-- Reclock for timing
ABS_004: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA2A_ABS <= (others => '0');
		DATA2A_D <= (others => '0');
		DATA2B_ABS <= (others => '0');
		DATA2B_D <= (others => '0');
		SAMPLE2_CLK_D <= '0';
	elsif rising_edge(CLK) then
		SAMPLE2_CLK_D <= SAMPLE2_CLK;
		DATA2A_D <= DATA2A;
		DATA2B_D <= DATA2B;

		if(DATA2A(15) = '0') then
			-- positive
			DATA2A_ABS(14 downto 0) <= DATA2A(14 downto 0);
	 	elsif(DATA2A = "1000000000000000") then
			-- special case
			DATA2A_ABS <= "111111111111111";
	  	else
			-- negative
			DATA2A_ABS <= not(DATA2A(14 downto 0)) + 1;
	  	end if;

		if(DATA2B(15) = '0') then
			-- positive
			DATA2B_ABS(14 downto 0) <= DATA2B(14 downto 0);
	 	elsif(DATA2B = "1000000000000000") then
			-- special case
			DATA2B_ABS <= "111111111111111";
	  	else
			-- negative
			DATA2B_ABS <= not(DATA2B(14 downto 0)) + 1;
	  	end if;

  	end if;
end process;

-- Scale noise (reclock immediately after the multiplication to 
-- maximize speed)
-- Precision = 4.11 * 3.5 = 7.16
DATA3A_ABS <= DATA2A_ABS * AWGN_SCALING_D;
DATA3B_ABS <= DATA2B_ABS * AWGN_SCALING_D;

-- restore sign after unsigned multiplication
-- Keep format 5.11
ABS_005: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA3A <= (others => '0');
		SAMPLE3_CLK <= '0';
		OVERFLOW3A <= '0';
	elsif rising_edge(CLK) then
		SAMPLE3_CLK <= SAMPLE2_CLK_D;

		if(DATA2A_D(15) = '0') then
			-- positive
			if (DATA3A_ABS(22 downto 20) = "000") then
				-- positive, no overflow
				DATA3A(15) <= '0';
				DATA3A(14 downto 0) <= DATA3A_ABS(19 downto 5);
				OVERFLOW3A <= '0';
		  	else
				-- positive, overflow
				DATA3A <= x"7FFF";
				OVERFLOW3A <= '1';
		  	end if;
		elsif (DATA3A_ABS(22 downto 20) = "000") then
			-- negative, no overflow
			DATA3A(15 downto 0) <= ("1" & (not DATA3A_ABS(19 downto 5))) + 1;
			OVERFLOW3A <= '0';
	 	else
			-- negative, overflow
			DATA3A <= x"8001";
			OVERFLOW3A <= '1';
	  	end if;
  	end if;
end process;

ABS_006: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA3B <= (others => '0');
		OVERFLOW3B <= '0';
	elsif rising_edge(CLK) then
		if(DATA2B_D(15) = '0') then
			-- positive
			if (DATA3B_ABS(22 downto 20) = "000") then
					-- positive, no overflow
				DATA3B(15) <= '0';
				DATA3B(14 downto 0) <= DATA3B_ABS(19 downto 5);
				OVERFLOW3B <= '0';
		  	else
				-- positive, overflow
				DATA3B <= x"7FFF";
				OVERFLOW3B <= '1';
		  	end if;
		elsif (DATA3B_ABS(22 downto 20) = "000") then
			-- negative, no overflow
			DATA3B <= ("1" & (not DATA3B_ABS(19 downto 5))) + 1;
			OVERFLOW3B <= '0';
		else
			-- negative, overflow
			DATA3B <= x"8001";
			OVERFLOW3B <= '1';
	  	end if;
  	end if;
end process;


--// Add signal + noise
-- Extend precision to avoid overflow
DATA3_I_E(15 downto 0) <= DATA3_I;
DATA3_I_E(16) <= DATA3_I(15);
DATA3_Q_E(15 downto 0) <= DATA3_Q;
DATA3_Q_E(16) <= DATA3_Q(15);
DATA3A_E(15 downto 0) <= DATA3A;
DATA3A_E(16) <= DATA3A(15);
DATA3B_E(15 downto 0) <= DATA3B;
DATA3B_E(16) <= DATA3B(15);

-- Sample the S+N at the same rate as input sampling clock,
-- irrespective of the noise sampling clock. If REG6/7/8 = 0, 
-- noise and signal sampling clocks are equal.
S_PLUS_N_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA4_I <= (others => '0');
		DATA4_Q <= (others => '0');
		DATA3_I_MSB_D <= '0';
		DATA3_Q_MSB_D <= '0';
		SAMPLE4_CLK <= '0';
	elsif rising_edge(CLK) then
		SAMPLE4_CLK <= SAMPLE3S_CLK;
		DATA4_I <= DATA3_I_E + DATA3A_E;
		DATA4_Q <= DATA3_Q_E + DATA3B_E;
		DATA3_I_MSB_D <= DATA3_I_E(16);
		DATA3_Q_MSB_D <= DATA3_Q_E(16);
	end if;
end process;

--// Clamp the I-channel output from a 6.11 representation to a 2.2
-- Truncation to 4 bits for soft quantization
-- Convert to unsigned representation
CLAMP_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA5_I <= (others => '0');
		SAMPLE5_CLK <= '0';
		OVERFLOW5 <= '0';
	elsif rising_edge(CLK) then
		SAMPLE5_CLK <= SAMPLE4_CLK;

		if(DATA4_I(16) = '0') and (DATA4_I(15 downto 12) /= "0000") then
			-- clamp at most positive 4 output bits
			DATA5_I <= "1111";
			OVERFLOW5 <= '1';
		elsif(DATA4_I(16) = '1') and (DATA4_I(15 downto 12) /= "1111") then
			-- clamp at most negative 4 output bits
			DATA5_I <= "0000";
			OVERFLOW5 <= '1';
	 	else
			-- unsigned representation
			DATA5_I(3) <= not DATA4_I(12);
			DATA5_I(2 downto 0) <= DATA4_I(11 downto 9);
			OVERFLOW5 <= '0';
		end if;
  	end if;
end process;

--// Clamp the I & Q channels outputs from a 6.11 representation to a 3.7 UNSIGNED
-- clock is SAMPLE5_CLK
CLAMP_002: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA6_I <= (others => '0');
		DATA6_Q <= (others => '0');
		OVERFLOW6I <= '0';
		OVERFLOW6Q <= '0';
	elsif rising_edge(CLK) then
		if(DATA4_I(16) = '0') and (DATA4_I(15 downto 13) /= "000") then
			-- clamp at most positive 10 output bits
			DATA6_I <= "1111111111";
			OVERFLOW6I <= '1';
		elsif(DATA4_I(16) = '1') and (DATA4_I(15 downto 13) /= "111") then
			-- clamp at most negative 10 output bits
			DATA6_I <= "0000000000";
			OVERFLOW6I <= '1';
	 	else
			-- unsigned representation
			DATA6_I(9) <= not DATA4_I(13);
			DATA6_I(8 downto 0) <= DATA4_I(12 downto 4);
			OVERFLOW6I <= '0';
		end if;

		if(DATA4_Q(16) = '0') and (DATA4_Q(15 downto 13) /= "000") then
			-- clamp at most positive 10 output bits
			DATA6_Q <= "1111111111";
			OVERFLOW6Q <= '1';
		elsif(DATA4_Q(16) = '1') and (DATA4_Q(15 downto 13) /= "111") then
			-- clamp at most negative 10 output bits
			DATA6_Q <= "0000000000";
			OVERFLOW6Q <= '1';
	 	else
			-- unsigned representation
			DATA6_Q(9) <= not DATA4_Q(13);
			DATA6_Q(8 downto 0) <= DATA4_Q(12 downto 4);
			OVERFLOW6Q <= '0';
		end if;
  	end if;
end process;

--// Output mux
-- Reclock a final time to minimize output timing delay
OUTPUT_MUX_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		J3_LOCAL <= (others => 'Z');
	elsif rising_edge(CLK) then
		J3_LOCAL(2) <= SAMPLE5_CLK;

		if(REG3_D(4 downto 3) = "00") then
			-- 4-bit serial output. Convert to floating point format 5.11
			J3_LOCAL(3) <= DATA5_I(3);
			J3_LOCAL(5) <= DATA5_I(2);
			J3_LOCAL(7) <= DATA5_I(1);
			J3_LOCAL(9) <= DATA5_I(0);
		elsif(REG3_D(4 downto 3) = "01") then
			-- 2*10-bit complex output. unsigned representation.
			J3_LOCAL(3) <= DATA6_I(9);
			J3_LOCAL(4) <= DATA6_I(8);
			J3_LOCAL(5) <= DATA6_I(7);
			J3_LOCAL(6) <= DATA6_I(6);
			J3_LOCAL(7) <= DATA6_I(5);
			J3_LOCAL(8) <= DATA6_I(4);
			J3_LOCAL(9) <= DATA6_I(3);
			J3_LOCAL(11) <= DATA6_I(2);
			J3_LOCAL(12) <= DATA6_I(1);
			J3_LOCAL(13) <= DATA6_I(0);
			J3_LOCAL(14) <= DATA6_Q(9);
			J3_LOCAL(15) <= DATA6_Q(8);
			J3_LOCAL(16) <= DATA6_Q(7);
			J3_LOCAL(17) <= DATA6_Q(6);
			J3_LOCAL(18) <= DATA6_Q(5);
			J3_LOCAL(19) <= DATA6_Q(4);
			J3_LOCAL(21) <= DATA6_Q(3);
			J3_LOCAL(22) <= DATA6_Q(2);
			J3_LOCAL(23) <= DATA6_Q(1);
			J3_LOCAL(24) <= DATA6_Q(0);
		end if;
  	end if;
end process;


--// detect bit errors. Aligned with SAMPLE4_CLK
BIT_ERROR <= '1' when (DATA4_I(15) /= DATA3_I_MSB_D) else '0';

-- BER window
BER_WINDOW_001: process(ASYNC_RESET, CLK, REG3)
begin
	if(ASYNC_RESET = '1') then
		BIT_COUNT <= (others => '0');
		REG3_D <= (others => '0');
		REG3_D2 <= (others => '0');
		NEW_COUNT <= '0';
	elsif rising_edge(CLK) then
		REG3_D <= REG3;
		REG3_D2 <= REG3_D;

		-- reset bit counter when window size is modified by user (so that we do not
		-- wait forever if the user selects a very large window by mistake)
		if(REG3_D(7 downto 5) /= REG3_D2(7 downto 5)) then
				BIT_COUNT <= (others => '0');
				NEW_COUNT <= '1';
		elsif(SAMPLE4_CLK = '1') then
			-- check for window size
			if(REG3_D(7 downto 5) = "000") and ((BIT_COUNT = 999) or (BIT_COUNT(10) = '1')) then  -- trick to avoid counting beyond threshold (32 bit counter!)
				BIT_COUNT <= (others => '0');
				NEW_COUNT <= '1';
			elsif(REG3_D(7 downto 5) = "001") and ((BIT_COUNT = 9999) or (BIT_COUNT(14) = '1')) then
				BIT_COUNT <= (others => '0');
				NEW_COUNT <= '1';
			elsif(REG3_D(7 downto 5) = "010") and ((BIT_COUNT = 99999) or (BIT_COUNT(17) = '1')) then
				BIT_COUNT <= (others => '0');
				NEW_COUNT <= '1';
			elsif(REG3_D(7 downto 5) = "011") and ((BIT_COUNT = 999999) or (BIT_COUNT(20) = '1')) then
				BIT_COUNT <= (others => '0');
				NEW_COUNT <= '1';
			elsif(REG3_D(7 downto 5) = "100") and ((BIT_COUNT = 9999999) or (BIT_COUNT(24) = '1')) then
				BIT_COUNT <= (others => '0');
				NEW_COUNT <= '1';
			elsif(REG3_D(7 downto 5) = "101") and ((BIT_COUNT = 99999999) or (BIT_COUNT(27) = '1')) then
				BIT_COUNT <= (others => '0');
				NEW_COUNT <= '1';
			elsif(REG3_D(7 downto 5) = "110") and ((BIT_COUNT = 999999999) or (BIT_COUNT(30) = '1')) then
				BIT_COUNT <= (others => '0');
				NEW_COUNT <= '1';
			else
				BIT_COUNT <= BIT_COUNT + 1;
				NEW_COUNT <= '0';
		  	end if;
	  	else
			NEW_COUNT <= '0';
	  	end if;
	end if;
end process;


--// count errors
BER_WINDOW_002: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		BIT_ERROR_COUNT <= (others => '0');
		BER <= (others => '0');
	elsif rising_edge(CLK) then
		if(NEW_COUNT = '1') then
			BIT_ERROR_COUNT <= (others => '0');
			BER <= BIT_ERROR_COUNT;
		elsif(SAMPLE4_CLK = '1') and (BIT_ERROR = '1') then
			BIT_ERROR_COUNT <= BIT_ERROR_COUNT + 1;
	  	end if;
  	end if;
end process;

--// POWER MEASUREMENT
PM_001: POWER_MEASUREMENT port map(
	ASYNC_RESET => ASYNC_RESET,
	CLK => CLK,
	SAMPLE_CLK_IN => ONE,
	DATA_I_ABS_IN => DATA1_I_ABS,
	DATA_Q_ABS_IN => DATA1_Q_ABS,
	SYNC_RESET => ZERO,
--	SAMPLE_CLK_OUT =>
	POWER_OUT => POWER_SIGNAL
	);		

PM_002: POWER_MEASUREMENT port map(
	ASYNC_RESET => ASYNC_RESET,
	CLK => CLK,
	SAMPLE_CLK_IN => ONE,
	DATA_I_ABS_IN => DATA2A_ABS,
	DATA_Q_ABS_IN => DATA2B_ABS,
	SYNC_RESET => ZERO,
--	SAMPLE_CLK_OUT =>
	POWER_OUT => POWER_NOISE
	);		


-- Forward clocks to right and bottom connectors
-- Invert output clocks for better timing
J3(1) <= not CLK;
J4(1) <= not CLK;

--J3(10) <= 'Z';
--J3(20) <= 'Z';
--J4(10) <= 'Z';
--J4(20) <= 'Z';

--// J2 CONNECTOR OUTPUTS
-- no point in requesting samples when output flow control SAMPLE_CLK_OUT_REQ does not show a clear to send
J2(27) <= (SAMPLE_CLK_IN_REQ and SAMPLE_CLK_OUT_REQ) when (REG3(2 downto 1) = "01") else 'Z';  -- 10-bit unsigned complex input
J2(12 downto 2) <= (others => 'Z');
J2(13) <= (SAMPLE_CLK_IN_REQ and SAMPLE_CLK_OUT_REQ) when (REG3(2 downto 1) = "00") else 'Z';  -- 1 bit serial input
J2(26 downto 14) <= (others => 'Z');
J2(29 downto 28) <= (others => 'Z');

--// J3 CONNECTOR OUTPUTS
-- set unused output pins to high-impedance
J3_GEN: process(J3_LOCAL, REG3_D)
begin
	if(REG3_D(4 downto 3) = "00") then
		-- 4-bit serial output. Convert to floating point format 5.11
		J3(2) <= J3_LOCAL(2);
		J3(3) <= J3_LOCAL(3);
		J3(4) <= 'Z';
		J3(5) <= J3_LOCAL(5);
		J3(6) <= 'Z';
		J3(7) <= J3_LOCAL(7);
		J3(8) <= 'Z';
		J3(9) <= J3_LOCAL(9);
		J3(19 downto 11) <= (others => 'Z');
		J3(25 downto 21) <= (others => 'Z');
		J3(27) <= 'Z';
--	elsif(REG3_D(4 downto 3) = "01") then
	else
		-- 2*10-bit complex output. unsigned representation.
		J3(9 downto 2) <= J3_LOCAL(9 downto 2);
		J3(19 downto 11) <= J3_LOCAL(19 downto 11) ;
		J3(24 downto 21) <= J3_LOCAL(24 downto 21);
		J3(25) <= not(CLK);	-- DAC_CLK_OUT
		J3(27) <= 'Z';
	end if;
end process;

--// J4 CONNECTOR OUTPUTS
-- set unused output pins to high-impedance
J4_GEN: process(J3_LOCAL, REG3_D)
begin
	if(REG3_D(4 downto 3) = "00") then
		J4(2) <= J3_LOCAL(2);
		J4(3) <= J3_LOCAL(3);
		J4(4) <= 'Z';
		J4(5) <= J3_LOCAL(5);
		J4(6) <= 'Z';
		J4(7) <= J3_LOCAL(7);
		J4(8) <= 'Z';
		J4(9) <= J3_LOCAL(9);
		J4(19 downto 11) <= (others => 'Z');
		J4(25 downto 21) <= (others => 'Z');
		J4(27) <= 'Z';
--	elsif(REG3_D(4 downto 3) = "01") then
	else
		-- 2*10-bit complex output. unsigned representation.
		J4(9 downto 2) <= J3_LOCAL(9 downto 2);
		J4(19 downto 11) <= J3_LOCAL(19 downto 11) ;
		J4(24 downto 21) <= J3_LOCAL(24 downto 21);
		J4(25) <= not(CLK);	-- DAC_CLK_OUT
		J4(27) <= 'Z';
	end if;
end process;

--// OUTPUT FLOW CONTROL
-- note: J3(13) and J4(13) must be pulled high in the constraint file
-- note: J3(27) and J4(27) must be pulled high in the constraint file
FC_GEN: process(CLK)
begin
	if rising_edge(CLK) then
		if(REG3_D(4 downto 3) = "00") then
			-- 4-bit serial output. Convert to floating point format 5.11
			SAMPLE_CLK_OUT_REQ <= J3(13) and J4(13);
		elsif(REG3_D(4 downto 3) = "01") then
			-- 2*10-bit complex output. unsigned representation.
			SAMPLE_CLK_OUT_REQ <= J3(27) and J4(27);
		else
			SAMPLE_CLK_OUT_REQ <= '1';  -- ignore flow control
		end if;
	end if;
end process;


--// J4 CONNECTOR OUTPUTS (TEST POINTS unsigned)
--RECLOCK_OUTPUT_001: process(ASYNC_RESET, CLK)
--begin
--	if(ASYNC_RESET = '1') then
--		J4(2) <= '0';
--		J4(4) <= '0';
--		J4(6) <= '0';
--		J4(8) <= '0';
--		J4(12) <= '0';
--		J4(14) <= '0';
--		J4(16) <= '0';
--		J4(18) <= '0';
--		J4(22) <= '0';
--		J4(24) <= '0';
--		J4(26) <= '0';
--	elsif rising_edge(CLK) then
--		J4(2) <= SAMPLE5_CLK;
--		J4(4) <= DATA6_Q(9);
--		J4(6) <= DATA6_Q(8);
--		J4(8) <= DATA6_Q(7);
--		J4(12) <= DATA6_Q(6);
--		J4(14) <= DATA6_Q(5);
--		J4(16) <= DATA6_Q(4);
--		J4(18) <= DATA6_Q(3);
--		J4(22) <= DATA6_Q(2);
--		J4(24) <= DATA6_Q(1);
--		J4(26) <= DATA6_Q(0);
--		J4(27) <= 
 --	end if;
--end process;


--J4(2) <= SAMPLE5_CLK;
--J4(3) <= DATA5(3);
--J4(5) <= DATA5(2);
--J4(7) <= DATA5(1);
--J4(9) <= DATA5(0);

--// Serial interfaces
-- REG255 reserved for reading 3 serial port inputs
-- These signals are pulled high (to mimic stop bit).
REG255(0) <= RX_L	;	-- port 1 left
REG255(1) <= RX_B	;	-- port 2 bottom
REG255(2) <= RX_R	;	-- port 3 right
REG255(7 downto 3) <= "00000";


--// MONITORING REGISTERS (TBD) --------------------------
--// Atmel microcontroller interface
-- Used for monitoring and control.

-- address latch
UC_ADDR_001: process(ASYNC_RESET, UC_ALE, UC_FLASH_CSN, UC_AD)
begin
	if(ASYNC_RESET = '1') then
		UC_ADDRESS <= (others => '0');
	elsif falling_edge(UC_ALE) then
		if(UC_FLASH_CSN = '1') then
			UC_ADDRESS <= UC_AD;
	  	end if;
  	end if;
end process;

-- read
UC_READ_001: process(UC_FLASH_CSN, UC_RDN, UC_ADDRESS, REG255, 
		BER, POWER_SIGNAL, POWER_NOISE)
begin
	if(UC_FLASH_CSN = '1') and (UC_RDN = '0') then
		if(UC_ADDRESS(7 downto 2) = "111111") then
			if(UC_ADDRESS(1 downto 0) = "11") then
				UC_AD <= REG255;
			elsif(UC_ADDRESS(1 downto 0) = "01") then
				UC_AD <= REVISION;	-- reg 253 = fpga revision
			elsif(UC_ADDRESS(1 downto 0) = "00") then
				UC_AD <= OPTION;		-- reg 252 = fpga option
			else
				UC_AD <= "ZZZZZZZZ";
		  	end if;
		elsif(UC_ADDRESS = 10) then
			UC_AD <= BER(7 downto 0);
		elsif(UC_ADDRESS = 11) then
			UC_AD <= BER(15 downto 8);
		elsif(UC_ADDRESS = 12) then
			UC_AD <= BER(23 downto 16);
		elsif(UC_ADDRESS = 13) then
			UC_AD <= BER(31 downto 24);		
		elsif(UC_ADDRESS = 14) then
			UC_AD <= POWER_SIGNAL(7 downto 0);		
		elsif(UC_ADDRESS = 15) then
			UC_AD <= POWER_SIGNAL(15 downto 8);		
		elsif(UC_ADDRESS = 16) then
			UC_AD <= POWER_SIGNAL(23 downto 16);		
		elsif(UC_ADDRESS = 17) then
			UC_AD <= POWER_NOISE(7 downto 0);		
		elsif(UC_ADDRESS = 18) then
			UC_AD <= POWER_NOISE(15 downto 8);		
		elsif(UC_ADDRESS = 19) then
			UC_AD <= POWER_NOISE(23 downto 16);		
		else
			UC_AD <= "ZZZZZZZZ";
		end if;
	else
		UC_AD <= "ZZZZZZZZ";
 	end if;
end process;


-- write
UC_WRITE_001: process(ASYNC_RESET, UC_FLASH_CSN, UC_WRN, UC_ADDRESS, UC_AD)
begin
	if(ASYNC_RESET = '1') then
		-- default values
		-- CAREFUL!!!!!! 
		-- when the external clock comes from a bigger FPGA, the ASYNC_RESET
		-- may arrive here AFTER the Atmel uC has configured the registers.
		-- We should avoid resetting the registers.
		TX_L <= '1';	-- stop bit
		TX_B <= '1';
		TX_R <= '1';
	elsif falling_edge(UC_WRN) then
		if(UC_FLASH_CSN = '1') then
			if (UC_ADDRESS(7 downto 4) = "0000") then
				if (UC_ADDRESS(3 downto 0) = "0000") then
					NCO_SAMPLING_RATE(7 downto 0) <= UC_AD;
				end if;
				if (UC_ADDRESS(3 downto 0) = "0001") then
					NCO_SAMPLING_RATE(15 downto 8) <= UC_AD;
				end if;
				if (UC_ADDRESS(3 downto 0) = "0010") then
					NCO_SAMPLING_RATE(23 downto 16) <= UC_AD;
				end if;
				if (UC_ADDRESS(3 downto 0) = "0011") then
					REG3 <= UC_AD;
				end if;
				if (UC_ADDRESS(3 downto 0) = "0100") then
					-- input signal amplitude scaling factor. format 3.5
					SIGNAL_SCALING <= UC_AD;
				end if;
				if (UC_ADDRESS(3 downto 0) = "0101") then
					-- AWGN amplitude scaling factor. format 3.5
					AWGN_SCALING <= UC_AD;
				end if;
				if (UC_ADDRESS(3 downto 0) = "0110") then
					-- Noise bandwidth
					NOISE_SAMPLING_RATE(7 downto 0) <= UC_AD;
				end if;
				if (UC_ADDRESS(3 downto 0) = "0111") then
					-- Noise bandwidth
					NOISE_SAMPLING_RATE(15 downto 8) <= UC_AD;
				end if;
				if (UC_ADDRESS(3 downto 0) = "1000") then
					-- Noise bandwidth
					NOISE_SAMPLING_RATE(23 downto 16) <= UC_AD;
				end if;

		  	end if;
			if (UC_ADDRESS = "11111110") then
				-- REG254 reserved for output serial
				TX_L <= UC_AD(0);
				TX_B <= UC_AD(1);
				TX_R <= UC_AD(2);
			end if;
		end if;

	end if;
end process;


--// TEST POINTS -----------------------
-- defined in demod.vhd
TP(0) <= J2(3);	-- input data stream
TP(1) <= J2(2);	-- input bit clock
TP(2) <= SAMPLE_CLK_IN_REQ and SAMPLE_CLK_OUT_REQ;	-- input sample clk req
TP(3) <= BIT_ERROR;	-- bit errors
TP(4) <= DATA5_I(3);	-- output data stream
TP(5) <= SAMPLE5_CLK;	-- output bit clock
TP(6) <= OVERFLOW3I or OVERFLOW3Q;
TP(7) <= OVERFLOW3A or OVERFLOW3B;
TP(8) <= OVERFLOW6I or OVERFLOW6Q;
TP(9) <= NEW_COUNT;

end behavioral;

