3
votes

We have a problem with Verilog. We have to use multiplication with two floating points(binary), but it doesn't work 100% perfectly.

We have a Req m[31:0]. The first numbers (before the comma) are m[31:16] and the numbers after comma m[15:0] so we have like:

m[31:16] = 1000000000000000; m[15:0] = 1000000000000000;

m[31:0] = 10000000000000000(.)1000000000000000;

The Problem is: we want to multiplicate numbers with decimal places, but we don't know how. For example: m = 2.5 in binary. The result of m*m is 6.25.

1
You seem to be describing 'Fixed Point' not floating point. Are the LSB's the exponent (Floating) or the fractional bits (Fixed)?Morgan

1 Answers

8
votes

The question does not fully cover what is understood about fixed-point numbers, therefore will cover a little background which might not be relevant to the OP.

The decimal weighting of unsigned binary (base 2) numbers, 4bit for the example follows this rule:

2^3  2^2  2^1  2^0 (Base 2)
  8    4    2    1

Just for reference the powers stay the same and the base is changed. For 4 hex it would be:

16^3  16^2  16^1  16^0
4096   256    16     1

Back to base 2, for twos complement signed number the MSB (Most Significant Bit) becomes negative.

-2^3  2^2  2^1  2^0 (Base 2, Twos complement)
  -8    4    2    1

When we insert a binary point or fractional bit the pattern continues. 4 Integer bits 4 fractional bits.

Base 2: Twos complement 4 integer, 4 bit frational
-2^3  2^2  2^1  2^0  .  2^-1    2^-2    2^-3    2^-4
  -8    4    2    1  .   0.5    0.25   0.125  0.0625

Unfortunately Verilog does not have a fixed-point format so the user has to keep track of the binary point and worked with scaled numbers. Decimal points . can not be used in in verilog numbers stored as reg or logic as they are essentially integer formats. However verilog does ignore _ when placed in number declarations, so it can be used as the binary point in numbers. Its use is only symbolic and has no meaning to the language.

In the above format 2.5 would be represented by 8'b0010_1000, the question has 16 fractional bits therefore you need to place 16 bits after the _ to keep the binary point in the correct place.

Fixed-point Multiplication bit widths

If we have two numbers A and B the width of the result A*B will be:

Integer bits    = A.integer_bits    + B.integer_bits.
Fractional bits = A.fractional_bits + B.fractional_bits.

Therefore [4 Int, 4 Frac] * [4 Int, 4 Frac] => [8 Int, 8 Frac]

reg [7:0] a = 0010_1000;
reg [7:0] b = 0010_1000;
reg [15:0] sum;

always @* begin
  sum = a * b ;
  $displayb(sum); //Binary
  $display(sum);  //Decimal
end

// sum == 00000110_01000000; //Decimal->6.25

Example on EDA Playground.

From this you should be able to change the depths to suit any type of fixed point number. and cast ing back to a 16 Int 16 fractional number can be done by part selecting the correct bits. Be careful if you need to saturate instead of overflowing.

There is a related Q&A that has 22 fractional bits.