0

I want to do a fraction arithmetic and then display the results. I know that $display displays in integer. But what is the solution to display the exact amount as eg I want to display 10/3 = 3.3 but I get displayed 3.0000. This is my code. I do not want to use real data type here.

`timescale 1ns/1ps

module fp_check
(a,b,c,d);

    input logic signed [7:0] a;
    input real b;
    output real c;
    output logic [7:0] d;

    assign c = a*2;
    assign d = b+1;

endmodule

module fp_test;

    logic signed [7:0] a;
    real b;
    real c;
    logic signed [7:0] d;

    initial
    begin
        a = 3.3333;
        b = 11.7;
        $display("a =%f, b=%f,c=%f,d=%f", a,b,c,d);
    end

    fp_check s (.a(a), .b(b), .c(c), .d(d));
endmodule

The output I get is a =3.000000, b=11.700000,c=0.000000,d=0.000000

What I expect is a =3.333333, b=11.700000,c=6.666666,d=12.700000

  • Is it the only option to use my inputs as real/shortreal ? Can I not use logic or any other data type? Since I would be implementing a flip flop at both input and output ports, I am not sure if I can flop-in or flop out real data type. – Shankhadeep Mukerji Sep 20 '16 at 17:32

2 Answers2

1

I have a previous answer on this subject Verilog Fractional multiplication? which should serve well as background for this problem. Another answer that deals with how precision is required.

Following on from them with 4 bit integer 4 bit fractional numbers the bits represent:

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

It should start to become clear that here is an issue with your example expecting '3.333333' as an answer, unless your implementing a rational divider which keeps numerator and denominators held as separate numbers it is impossible for a binary system to hold the value '1/3' We can get very close but never exactly. On the other hand 1/4 is easy.

On way of performing the fixed point maths with integers is to scale by the number of fractional bits you want, for example:

integer a = 10;
integer b = 3;
localparam FRAC = 4;

initial begin
  #1;
  //Scaling to the power of 2.0 not 2. This forces a real evaluagion of the number for display.
  $display("No Scaling down  : %f", (a*2.0**FRAC / b*2.0**FRAC));
  //Scaling back down by 4 to the power because of fractional bit growth
  $display("Scaled back down : %f", (a*2.0**FRAC / b*2.0**FRAC)*4.0**-FRAC);
end
Community
  • 1
  • 1
Morgan
  • 19,934
  • 8
  • 58
  • 84
1

You need to use fixed point arithmetic. See http://amakersblog.blogspot.com/2008/07/fixed-point-arithmetic-with-verilog.html For example

`timescale 1ns/1ps
package fixed_point;

parameter M = 8;
parameter F = 12;

typedef bit signed [M-1:-F] fp_t;
function fp_t real2fp(real value);
   return value*2.0**F;
endfunction : real2fp
function real fp2real(fp_t value);
   return value/2.0**F;
endfunction : real2fp
endpackage : fixed_point

import fixed_point::*;


module fp_check (
    input  fp_t a,
    input  fp_t b,
    output fp_t c,
    output fp_t d);


    assign c = a*2;
    assign d = b+real2fp(1);

endmodule

module fp_test;

    fp_t a,b,c,d;
       initial
    begin
       a = real2fp(3.3333);
        b = real2fp(11.7);
       $strobe("a =%f, b=%f,c=%f,d=%f", fp2real(a),fp2real(b),fp2real(c),fp2real(d) );

    end

    fp_check s (.a(a), .b(b), .c(c), .d(d));
endmodule : fp_test
dave_59
  • 39,096
  • 3
  • 24
  • 63
  • I am getting the error after I followed this code: could not find the package (fixed_point). Design read will continue, but expect a cascade of errors after this failure. Furthermore if you experience a vopt-7 error immediately before this error then please check the package names or the library search paths on the command line. – Shankhadeep Mukerji Sep 20 '16 at 19:14