Shankhadeep Mukerji
Shankhadeep Mukerji

Reputation: 668

displaying fractions in systemverilog

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

Upvotes: 0

Views: 4095

Answers (2)

dave_59
dave_59

Reputation: 42673

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

Upvotes: 1

Morgan
Morgan

Reputation: 20514

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

Upvotes: 1

Related Questions