Reputation: 668
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
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
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