Search code examples
verilogvlsi

how can I apply fixed fraction to the integer


I'd like to multiply to integer with modified fraction as following

(Multiplication by power series summation with negative terms)

I have done what to find the method the fraction convert to CSD form. But I want to know how can I apply to multiply to integer.

For example, I got this

0.46194 = 2^-1 - 2^-5 - 2^-7 + 2^-10.

then I can get like this as verilog rtl expression :

y= (x>>1) - (x>>5) - (x>>7) + (x>>10);

But the problem is that what if I got the input value is 3, then how can I calculate above code?

y= (3>>1) - (3>>5) - (3>>7) + (3>>10);

But As i know, It does impossible calculate. because 3>>1 is 1, (3>>5) is 0, (3>>7) is 0, (3>>10) is 0;

So I can't get the normal result. Also the reason of finding the modified fraction expression has gone away. Then this posting's question point is "how can I apply the modified fraction to the integer".

UPDATE : This should be like this. y= ((3<<1024)>>1) - ((3<<1024)>>5) - ((3<<1024)>>7) + ((3<<1024)>>10);


Solution

  • If we have reg [3:0] we can consider that it can hold integer values 0 to 15.

    Now we want to have fractional information, we have to perceptually add fractional bits, but to verilog the number is still an integer.

    We still have 4 bits, but we change the binary weighting, instead of 8 4 2 1 to 2 1 0.5 0.25. but verilog does not know this it is all about how we interpret the bit pattern.

    In the question the right hand side of >> just represents the fractional bit. Also using T to represent a -1 in the CSD term

            2^-1 - 2^-5    - 2^-7      + 2^-10.
    Decimal 0.5  - 0.03125 - 0.0078125 + 0.0009765625
    Binary  0.1000T0T001
    

    As you have noted shifting a number will result in truncating to an integer. The trick is to add fractional bits to the number before doing this.

    For instance to add 10 fractional bits to an incoming integer:

    input [9:0] a,
    
    wire [19:0] a_frac = { a, 10'b0};
    

    Remember Verilog thinks this is an integer but we have have to interpret the number differently.

    wire [19:0] y = (a_frac>>1) - (a_frac>>5) - (a_frac>>7) + (a_frac>>10);
    

    y Should now contain something, as you left room for those shifted values. The output will have 10 Integer bits and 10 fractional bits.

    To display the number you could scale a real:

    $display("%d * 0.46194 = %f", a, y * 2.0**-10);
    

    NB: I would avoid x as a variable in verilog as x has a special meaning in verilog, either do not care or an unknown value on a wire.

    A quick example on EDA Playground.