简体   繁体   中英

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM