----------------------------------------------
-- MSS copyright 2012-2016
-- Filename: POWER_MEASUREMENT.VHD
-- Author: Alain Zarembowitch / MSS
-- Inheritance: none
-- Edit date: 2/3/16 
-- Revision: 4
-- Description: 
--		baseband signal power measurement
--		Averaged over 1K complex samples
--		Assumption: input samples have a mean of zero
--
-- Rev 2 2/24/13 AZ
-- prevent X propagation forever during simulation
--
-- Rev 3 12/19/14 AZ
-- Modified for Vivado
--
-- Rev 4 2/3/16 AZ
-- Added sync reset (previously disabled)
-- corrected double width of SAMPLE_CLK_OUT
-- accepts real and complex inputs
---------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity POWER_MEASUREMENT is
	generic (
		  REAL_COMPLEXn: std_logic := '0';
			-- input is real (I only) or complex (I/Q)?
        SIMULATION: std_logic := '0'
        -- 1 during simulation, 0 for release    
    );
   port (
	CLK: in  std_logic;   
		-- clock synchronous
	SYNC_RESET: in std_logic;
		-- synchronous reset.
	SAMPLE_CLK_IN: in std_logic;
		-- input samples
	DATA_I_IN: in std_logic_vector(17 downto 0);
	DATA_Q_IN: in std_logic_vector(17 downto 0);
		-- input samples. Signed. Assumed format 8.10 
		-- read at rising edge of CLK, when SAMPLE_CLK_IN = '1'

	SAMPLE_CLK_OUT: out std_logic;
	POWER_OUT: out std_logic_vector(23 downto 0)	
		-- power. format 16.8, unsigned
		-- latency: 4 CLK
    );
end entity;

architecture behavior of POWER_MEASUREMENT is



-----------------------------------------------------------------
-- COMPONENT
-----------------------------------------------------------------
	COMPONENT MULT18X18SIGNED
	PORT(
		A : IN std_logic_vector(17 downto 0);
		B : IN std_logic_vector(17 downto 0);          
		P : OUT std_logic_vector(35 downto 0)
		);
	END COMPONENT;

-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
-- Suffix _X is for precision extended
-- Suffix _D for delay

signal STATE: integer range 0 to 1 := 0;
signal SAMPLE_CLK_IN_D: std_logic := '0';
signal SAMPLE_CLK_IN_D2: std_logic := '0';
signal SAMPLE_CLK_IN_D3: std_logic := '0';
signal DATA_Q_IN_D: std_logic_vector(17 downto 0) := (others => '0');
signal AMPLITUDE: std_logic_vector(17 downto 0) := (others => '0');
signal POWER: std_logic_vector(35 downto 0) := (others => '0');
signal POWER_SAMPLE_CLK: std_logic := '0';
signal POWER_SAMPLE_CLK_D: std_logic := '0';
signal POWER_D: std_logic_vector(23 downto 0) := (others => '0');
signal POWER_ACC: std_logic_vector(34 downto 0) := (others => '0');


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

-- Reclock input signals
-- Share the subsequent multiplier
RECLOCK_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN = '1') and (STATE = 0) then
			-- Time share multiplier. Start with I.
			AMPLITUDE <= DATA_I_IN;
			POWER_SAMPLE_CLK <= '1';
			STATE <= 1;
			if(REAL_COMPLEXn = '0') then
				-- if complex input, save I & Q as an indivisible group. 
				DATA_Q_IN_D <= DATA_Q_IN;
			end if;
		elsif (STATE = 1) and (REAL_COMPLEXn = '0') then
			-- complex input case
			AMPLITUDE <= DATA_Q_IN_D;
			POWER_SAMPLE_CLK <= '1';
			STATE <= 0;
		else 
			POWER_SAMPLE_CLK <= '0';
	  	end if;
	end if;
end process;

IMULT18X18SIGNED_001: MULT18X18SIGNED PORT MAP(
	A => AMPLITUDE,	--
	B => AMPLITUDE,
	P => POWER
);

-- reclock multiplier output for better timing. Keep 18 MSbs.
RECLOCK_002: process(CLK)
begin
	if rising_edge(CLK) then
		POWER_SAMPLE_CLK_D <= POWER_SAMPLE_CLK;
		POWER_D <= POWER(33 downto 10);	-- drop 2 sign bits
	end if;
end process;

-- Leaky integrator
-- average over 2K (1K complex) samples
ACC_001: process (CLK)
begin
	if rising_edge(CLK) then
		SAMPLE_CLK_IN_D <= SAMPLE_CLK_IN;
		SAMPLE_CLK_IN_D2 <= SAMPLE_CLK_IN_D;
		SAMPLE_CLK_IN_D3 <= SAMPLE_CLK_IN_D2;
		if(REAL_COMPLEXn = '1') then
			SAMPLE_CLK_OUT <= SAMPLE_CLK_IN_D2;
		else
			SAMPLE_CLK_OUT <= SAMPLE_CLK_IN_D3;
		end if;
		
		if(SYNC_RESET = '1') then
			POWER_ACC <= (others => '0');
		elsif(POWER_SAMPLE_CLK_D = '1') and ((SIMULATION = '0') or (POWER_D(0) /= 'X')) then
			-- prevent 'X' propagation forever
			POWER_ACC <= POWER_ACC + ext(POWER_D,35) - POWER_ACC(34 downto 11);
		end if;
	end if;
end process;
 
POWER_OUT <= POWER_ACC(34 downto 11);
 
end behavior;

