Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
17 years ago

fixed-point tips

Hi

I have some experience with Quartus, but in the past have only worked on projects that implement very basic boolean expressions (like generating pulses with user defined widths and delays). I have been asked to try and build a block that does some stuff rather more complicated than I am used to with real numbers... but of course the final block has to be synthesizable. Here is an example of a "phase diff block" that is needed.

Inputs:

I1, I2, Q1, Q2, A1, A2 (all 16-bit with values lying between -1 and +1)

cMode (Boolean)

kc (all 16-bit with values lying between 0 and +1)

Outputs:

Pd (16-bit with values lying between -1 and +1)

LD (Boolean)

The function to implement is something like:

Pd = (I1 * Q2 - I2 * Q1) / (A1 * A2)

ld = (1-kc) * ld + kc * (I1 * I2 + Q1 * Q2) / (A1 * A2)

If cMode = '0' THEN LD = 0

ELSIF ld > 0 THEN LD = 1 ELSE LD = 0

To be honest I don't really know where to start with how to define the data types and the equation for Pd. Any tips most welcome.

Many thanks, Kurt

18 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The quoted posted is dealing with fixed point respective fractional number rather than float, as far as I understand. It's basically the same method that you suggested.

    The said new VHDL standards have two different parts, fixed point and float. I didn't hear anyone suggesting float arithmetics in this thread.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    I've made a little progress. I've written a little function that multiplies two 16 bit unsigned integers, which results in a 32-bit unsigned integer. The function then just drops the 16 LSBs which results in the scaled answer. So this works fine for unsigned inputs whose 'real' value is =< 1. I don't know how general this is for values > 1... probably not. For signed values I suppose just a little extra logic is needed to test the sign bit and derive the appropriate sign bit for the result.

    --- Quote End ---

    I am totally bewildered as I see various ideas of computations from the use of functions to float ...etc.

    For most general applications you need to think fixed-point, this is "almost" always adequate:

    1) scale your real values to nearest integers, represent on available resolution.

    so a [-1.00000 to +1.00000] range must be scaled and rounded up until it fits well in your datawidth.

    2)then do the computation as (choose signed or unsigned)

    3)chop off result as required possibly with rounding.

    You may truncate at the very end or at an intermediate stage depending on resource/speed issues. You also may need some work to truncate any unused MSBs.

    Kurtar: you are almost there but why use unsigned functions when you can just instantiate signed hardware mutipliers directly without functions.

    Mathematically: Step 1) above of scaling is cancelled out at step 3) of output LSB truncation. for example if you scale by 2^n then truncate off n bits you get in effect the actual value as if you used fractional inputs.

    R => round(R*2^n) --scaled

    R => R/2^n --truncated(divided)

    edit:

    as an example, assume your input value e.g. a coeff is .705 then you scale it

    to .705 * 2^8 = 180

    then you used 180 as input to a mult with input A:

    result = 180 * A

    then you truncate reslut by 8 bit:

    result =180*A/256

    so in effect you multiplied by .705

    The use of float library is fairly recent and I don't know of any engineers using it. I don't advise beginners to go that way before learning fixed-point
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The new VHDL floating point packages actually have all necessary means for typical DSP problems as in your example. But I used my own functions for scaling of products similar to the one you discussed above up to now. I didn't even try, if they synthesize with Quartus without problems. Basically, the method works for arbitrary fixed point and fractional numbers, if you use a variable shift factor in product scaling and additional saturation logic.

    I show an example of a multiply with scaling and saturation for reference:

    FUNCTION MUL_ASL (X1,X2: SIGNED; N: INTEGER) RETURN SIGNED IS
     VARIABLE P:SIGNED(X1'length+X2'length-1 downto 0);
     BEGIN
       P:=X1*X2;
       IF P(P'left-1 downto P'left-N) /= 0 AND P>=0 THEN
        P:= (others => '1');
        P(P'left-N):='0';
       ELSIF P(P'left-1 downto P'left-N) /= -1 AND P<0 THEN
        P:= (others => '0');
        P(P'left-N):='1';
       END IF;	
    -- Result length equals X2
      RETURN P(P'left-N downto X1'length-N);
     END;

    For fractional signed numbers with a -1..1 range, the shift factor has to be set to 1 to remove the double sign bit.

    Fast parallel division as lpm_divide is consuming a lot of resources. It can't be avoided sometimes, but in many cases other solution can be found. For "slow" division applications, I generally use a serial divider, that needs one clock cycle per result bit. Another options is a 1/x look-up table.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Oops, apologies... VHDL.

    I've made a little progress. I've written a little function that multiplies two 16 bit unsigned integers, which results in a 32-bit unsigned integer. The function then just drops the 16 LSBs which results in the scaled answer. So this works fine for unsigned inputs whose 'real' value is =< 1. I don't know how general this is for values > 1... probably not. For signed values I suppose just a little extra logic is needed to test the sign bit and derive the appropriate sign bit for the result.

    The next element I need to figure out is the division part. Assuming (A1*A2) (the divisor) is not a tidy factor of 2 then would inverting then multiplying work. Is there a simple approximation for 1/x using a Taylor expansion or some other simple way? I don't think it has to be too accurate.

    Thanks in advance for any pointers, Kurt