Hi All
Many thanks for all your suggestions... being lazy I ended utilizing the recent IEEE fixed_pkg. For those interested, below is the code I ended-up with which seems to do the job OK (the functionality is a little different from my initial posting as the designer changed it):
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
LIBRARY WORK;
USE WORK.math_utility_pkg.ALL;
USE WORK.fixed_pkg.ALL;
ENTITY phase_diff IS
PORT (
clk : IN STD_LOGIC;
i_I1 : IN STD_LOGIC_VECTOR (15 DOWNTO 0);
i_Q1 : IN STD_LOGIC_VECTOR (15 DOWNTO 0);
i_I2 : IN STD_LOGIC_VECTOR (15 DOWNTO 0);
i_Q2 : IN STD_LOGIC_VECTOR (15 DOWNTO 0);
i_A1 : IN STD_LOGIC_VECTOR (15 DOWNTO 0);
i_A2 : IN STD_LOGIC_VECTOR (15 DOWNTO 0);
i_cMode : IN STD_LOGIC;
i_kc : IN STD_LOGIC_VECTOR (31 DOWNTO 0);
o_phase_corr : OUT STD_LOGIC_VECTOR (31 DOWNTO 0);
o_lock_detect : OUT STD_LOGIC;
recipr : OUT STD_LOGIC_VECTOR (34 DOWNTO 0);
a1a2 : OUT STD_LOGIC_VECTOR (33 DOWNTO 0)
);
END ENTITY phase_diff ;
ARCHITECTURE arch OF phase_diff IS
SIGNAL s_phase_corr : SFIXED (0 DOWNTO -31);
SIGNAL s_phase_corr_prev : SFIXED (0 DOWNTO -31);
SIGNAL s_ld : STD_LOGIC;
SIGNAL s_lock_fixed_prev : SFIXED (0 DOWNTO -15);
BEGIN
PROCESS(clk)
VARIABLE v_I1 : SFIXED (0 DOWNTO -15);
VARIABLE v_Q1 : SFIXED (0 DOWNTO -15);
VARIABLE v_I2 : SFIXED (0 DOWNTO -15);
VARIABLE v_Q2 : SFIXED (0 DOWNTO -15);
VARIABLE v_A1_u : UFIXED (0 DOWNTO -15);
VARIABLE v_A2_u : UFIXED (0 DOWNTO -15);
VARIABLE v_A1 : SFIXED (0 DOWNTO -16);
VARIABLE v_A2 : SFIXED (0 DOWNTO -16);
VARIABLE v_kc : SFIXED (0 DOWNTO -31);
VARIABLE v_recip : SFIXED (33 DOWNTO -1);
VARIABLE v_pd_s1 : SFIXED (2 DOWNTO -32);
VARIABLE v_pd_fixed : SFIXED (36 DOWNTO -33);
VARIABLE v_pld_s1 : SFIXED (2 DOWNTO -32);
VARIABLE v_pld_fixed : SFIXED (0 DOWNTO -15);
VARIABLE v_lock_s1 : SFIXED (2 DOWNTO -46);
VARIABLE v_lock_s2 : SFIXED (1 DOWNTO -46);
VARIABLE v_lock_fixed : SFIXED (0 DOWNTO -15);
BEGIN
IF RISING_EDGE(clk) THEN
v_I1 := TO_SFIXED( i_I1, 0, -15 );
v_Q1 := TO_SFIXED( i_Q1, 0, -15 );
v_I2 := TO_SFIXED( i_I2, 0, -15 );
v_Q2 := TO_SFIXED( i_Q2, 0, -15 );
v_A1_u := TO_UFIXED( i_A1, 0, -15 );
v_A2_u := TO_UFIXED( i_A2, 0, -15 );
v_A1 := TO_SFIXED( v_A1_u );
v_A2 := TO_SFIXED( v_A2_u );
v_kc := TO_SFIXED( i_kc, 0, -31 );
a1a2 <= TO_SLV( RESIZE( v_A1 * v_A2, (2 * v_A1'HIGH) + 1, 2 * v_A1'LOW) ); -- 1 DOWNTO -32
v_recip := RESIZE( RECIPROCAL ( v_A1 * v_A2 ), (-2 * v_A1'LOW) + 1, -1 * ((2 * v_A1'HIGH) + 1) ); -- 33 DOWNTO -1
recipr <= TO_SLV( v_recip );
v_pd_s1 := RESIZE(( v_I1 * v_Q2 ) - ( v_I2 * v_Q1 ), (2 * v_A1'HIGH) + 2, 2 * v_A1'LOW );
v_pd_fixed := v_pd_s1 * v_recip; -- (I1Q2-I2Q1)/(A1A2)
v_pld_s1 := RESIZE(( v_I1 * v_I2 ) + ( v_Q1 * v_Q2 ), (2 * v_A1'HIGH) + 2, 2 * v_A1'LOW );
v_pld_fixed := RESIZE( v_pld_s1 * v_recip, 0, -15 ); -- (I1I2+Q1Q2)/(A1A2)
v_lock_s1 := ( 1 - v_kc ) * s_lock_fixed_prev;
v_lock_s2 := v_kc * v_pld_fixed;
v_lock_fixed := RESIZE( v_lock_s1 + v_lock_s2, 0, -15); -- (1-kc)*lock+kc*pld
s_lock_fixed_prev <= v_lock_fixed;
IF ((i_cMode = '1') AND (v_lock_fixed > TO_SFIXED(0.5, 0, -15))) THEN
s_ld <= '1';
ELSE
s_ld <= '0';
END IF;
IF (i_cMode = '0') THEN
s_phase_corr <= TO_SFIXED( 0, 0, -31 );
ELSE
s_phase_corr <= RESIZE( s_phase_corr_prev + (v_kc * v_pd_fixed), 0, - 31 );
END IF;
s_phase_corr_prev <= s_phase_corr;
END IF;
END PROCESS;
o_phase_corr <= TO_SLV( s_phase_corr );
o_lock_detect <= s_ld;
END arch;
There is some extra stuff in there just to help me with decoding, which I will remark out for the final version, but it seems to be passing testing at the moment.
Many thanks, Kurt