display a real in verilog but bitstoreal returning only 0.000000 - verilog

I am trying to display a real number during the simulation of my verilog code in modelsim. But I only get 0 as output. I am trying to use the bitstoreal system function. I'm not so good at verilog so it could be a stupid beginner's mistake.
Following is my code:
reg [31:0] y[1:0];
integer file;
localparam [31:0] test = 32'h3fb0d05d;
task read_data_from_fifo();
begin
file = $fopen("/tmp/data.fifo", "r");
$fread(y, file);
$display("y0 = %d, %f, %h", $bitstoreal(y[0]), $bitstoreal(test), $bitstoreal(y[0]));
$display("y1 = %f, %f, %h", y[1], $bitstoreal(32'h5dd0_b03f), y[1]);
end
endtask
(the task is called from an initial begin block)
Outputs:
# y0 = 0, 0.000000, 00000000
# y1 = 3742779199.000000, 0.000000, df16473f
All help appreciated.
Update
Looks like bitstoreal only supports double precision floats (64-bit). Because
localparam [63:0] test = 64'h_3FF61A0BE5109071;
$display("%f", $bitstoreal(test));
results in
1.381359

use $bitstoshortreal:
...
$shortrealtobits converts values from a shortreal type to the 32-bit vector representation of the real
number.
$bitstoshortreal converts a bit pattern created by $shortrealtobits to a value of the shortreal
type.
...

$bitstoreal takes a 64bit input double precision float.
Solution: Do a bit conversion from single to double precision float. Like this:
reg [31:0] z; // single precision float
reg [63:0] double; // double precision float
double = {z[31], z[30], {3{~z[30]}}, z[29:23], z[22:0], {29{1'b0}}};
$display("%f", $bitstoreal(double));
Disclaimer: I'm not sure if this single to double conversion is safe/correct.
Update
This is to be read in the IEEE document mentioned by toolic:
$realtobits converts values from a real type to a 64-bit vector representation of the real number.
$bitstoreal converts a bit pattern created by $realtobits to a value of the real type.

Related

Floating point to ieee convertor in verilog

I'm trying create a module that will convert 3.817 floating number or any number to its binary representation in IEEE 754 single precision format and writing a test bench to display the output.
I wrote the following code:
module float_to_ieee754_single_precision (
input wire [31:0] float, // input floating point number
output wire [31:0] ieee754_single_precision // output binary representation in IEEE 754 single precision format
);
// Declare variables to store the sign, exponent, and mantissa of the input floating point number
wire signed [31:31] sign;
wire signed [30:23] exponent;
wire [22:0] mantissa;
// Split the input floating point number into its sign, exponent, and mantissa parts
assign sign = float[31];
assign exponent = float[30:23];
assign mantissa = {float[22:0], 23'b0};
// Convert the exponent from excess-127 to 2's complement representation
wire signed [7:0] exponent_2s_complement = exponent - 127;
// Shift the mantissa to the right by the exponent value, adding an implicit leading 1 to the mantissa
wire [22:0] mantissa_normalized = mantissa >> exponent_2s_complement;
// Concatenate the sign, exponent, and mantissa to obtain the binary representation in IEEE 754 single precision format
assign ieee754_single_precision = {sign, exponent_2s_complement, mantissa_normalized};
endmodule
`timescale 1ns / 1ps
module float_to_ieee754_single_precision_tb;
// Declare input and output wires
wire [31:0] float;
wire [31:0] ieee754_single_precision;
// Instantiate the module under test
float_to_ieee754_single_precision dut (
.float(float),
.ieee754_single_precision(ieee754_single_precision)
);
// Declare a test vector with a floating point number and its expected binary representation in IEEE 754 single precision format
localparam test_vector [][2] = {
{32'h3F800000, 32'h3F800000}, // 1.0
{32'h3F8CCCCD, 32'h3F8CCCCD}, // 1.1
{32'hC3F8CCCD, 32'hBF8CCCCD}, // -1.1
{32'h40A00000, 32'h40A00000}, // 10.0
{32'hC2D60000, 32'hBE280000} // -0.1
};
// Iterate through the test vector and check the module output against the expected value
integer i;
initial begin
for (i = 0; i < 5; i = i + 1) begin
float = test_vector[i][0];
#1;
if (ieee754_single_precision != test_vector[i][1]) begin
$display("Test case %d failed:", i);
$display(" Expected output: %h", test_vector[i][1]);
$display(" Actual output: %h", ieee754_single_precision);
end
end
end
endmodule
I'm stuck on the same error and I don't know what to do.
The error are:
Error (10170): Verilog HDL syntax error at float_to_ieee754_single_precision.v(42) near text "]"; expecting an operand.
Error (10137): Verilog HDL Procedural Assignment error at floating_point_to_ieee754.v(53): object "float" on left-hand side of assignment must have a variable data type
Error (10560): Verilog HDL Expression error at floating_point_to_ieee754.v(53): indexed name specifies too many indices for array "test_vector"
Error (10560): Verilog HDL Expression error at floating_point_to_ieee754.v(55): indexed name specifies too many indices for array "test_vector"
Error (10560): Verilog HDL Expression error at floating_point_to_ieee754.v(57): indexed name specifies too many indices for array "test_vector"
Error: Quartus II 64-Bit Analysis & Synthesis was unsuccessful. 4 errors, 1 warning
Error: Peak virtual memory: 4655 megabytes
Error: Processing ended: Wed Dec 28 23:05:10 2022
Error: Elapsed time: 00:00:00
Error: Total CPU time (on all processors): 00:00:00
create a module that will convert 3.817 floating number or any number to its binary representation in IEEE 754 single precision format and writing a test bench to display the output and fix the errors!
The 1st error points to this line:
localparam test_vector [][2] = {
Change it to:
localparam bit [31:0] test_vector [5][2] = '{
Refer to IEEE Std 1800-2017, section 10.9.1 Array assignment patterns.
The 2nd error means that you need to declare float as a reg, not a wire since you assign to it in a procedural block (initial).
This code compiles without errors on 2 simulators:
module float_to_ieee754_single_precision_tb;
// Declare input and output wires
reg [31:0] float;
wire [31:0] ieee754_single_precision;
// Instantiate the module under test
float_to_ieee754_single_precision dut (
.float(float),
.ieee754_single_precision(ieee754_single_precision)
);
// Declare a test vector with a floating point number and its expected binary representation in IEEE 754 single precision format
localparam bit [31:0] test_vector [5][2] = '{
{32'h3F800000, 32'h3F800000}, // 1.0
{32'h3F8CCCCD, 32'h3F8CCCCD}, // 1.1
{32'hC3F8CCCD, 32'hBF8CCCCD}, // -1.1
{32'h40A00000, 32'h40A00000}, // 10.0
{32'hC2D60000, 32'hBE280000} // -0.1
};
// Iterate through the test vector and check the module output against the expected value
integer i;
initial begin
for (i = 0; i < 5; i = i + 1) begin
float = test_vector[i][0];
#1;
if (ieee754_single_precision != test_vector[i][1]) begin
$display("Test case %d failed:", i);
$display(" Expected output: %h", test_vector[i][1]);
$display(" Actual output: %h", ieee754_single_precision);
end
end
end
endmodule

How to get the square and cube of a fractional number (say 0.78) in verilog?

I am new to Verilog/System Verilog and I wanted to implement the square and cube a fractional number. Consider the following example
module test(
input wire [31:0] input,
output reg [63:0] output
);
reg [63:0] temp;
always # (*) begin
temp = input*input;
output <= temp*input;
end
endmodule
So, when my input is 32'h0_C7AE147 (0.78 in the hexadecimal number system using the 32 bits representation and assuming _ is the equivalent of . in Verilog) I expect an output of 32'h0_797C3D6 (0.4745 in decimal number system)
But I am getting an output of 64'hD546_4A9C_ED94_2917
Also, how to handle the increasing bit sizes in a multiplication?
When we multiply two N-bit wide operands, we get an output of width 2N-bits. When we multiply this 2N-bit wide number with a k bit wide number, we get a number of widths 2N+k-bit wide and this process goes on.
You mean you want to represent fractional number in 32-bit fixed point notation with 4-bit integer part + 28-bit fractional part? And why do you need 64 bits for output?
Anyway I think you need to shift the product to the right by 28 bits for each multiplication.
Try:
temp = input * input >> 28;
output <= temp * input >> 28;
If you need proper rounding, do it before each shifting.

Is there a mandate for the variable to be of data type "integer" for arithmetic operations "+" and "-"?

Following is the code for finding factorial of a number. If I declare "i" as "register", the output (z) remains 1, irrespective of the input. If it is declared as "integer", I get the proper result. Why is it so? Please explain.
module Factorial_calc(n, z);
input [5:0] n;
output reg [64:0] z;
reg i;
// integer i;
always #(n)
begin
i=0;
z=1;
while(i<n)
begin
i=i+1;
z=i*z;
end
end
endmodule
Because your integer is 32 bits wide and your reg is only one bit wide. Your simulation should not finish for most values of n, let alone produce a result.
HDL is not like any other programming language. Beware that even if your code simulates it does not mean it will work in hardware. In your case it will not synthesize. You value of n is undefined at compile time.
Last be not least do NOT use x or z for variables, They are too easily confused with 'x or 'z.

How does Verilog behave with negative numbers?

For instance, say I have a reg [7:0] myReg
I assign it the value -8'D69
I know Verilog stores it as 2's complement so it should be stored as
10111011
The question I have now is if I were to perform an operation on it, say myReg/2
Would it evaluate to -34? Or would it take 10111011 and turn it into 187 then perform the division, returning 93?
You need to remember that -8d69 is just a bit pattern. reg is a type which holds bit patterns. It is the type of variable that instructs / to perform signed or unsigned arithmetic.
If this is for synthesis bare in mind that you want to try and avoid dividers, you really want to try and avoid signed dividers. It will likely synthesis smaller with >>> 1
reg [7:0] a;
reg signed [7:0] b;
reg [7:0] c;
reg signed [7:0] d;
initial begin
a = -8'd69 ;
b = -8'd69 ;
c = -8'd69 ;
d = -8'd69 ;
#10ns;
a = a/2 ;
b = b/2 ;
#10ns;
$display("a : %8b, %d", a, a);
$display("b : %8b, %d", b, b);
$display("c >>>1 : %8b, %d", c>>>1, c>>>1);
$display("d >>>1 : %8b, %d", d>>>1, d>>>1);
end
Gives:
a : 01011101, 93
b : 11011110, -34
c >>>1 : 01011101, 93
d >>>1 : 11011101, -35
>> x Shifts right by x places, >>> x Shifts right x places but sign extends for signed types.
NB: the /2 is also rounding up in my examples, >>> will round down/truncate.
For instance, say I have a reg [7:0] myReg I assign it the value
-8'D69
This actually isn't a signed number but instead an expression consisting of a unary negation applied to a positive constant. If the expression was -8'd130 the result would overflow. Signed constants are declared as 8'sd69 or just 69.
The question I have now is if I were to perform an operation on it,
say myReg/2
myReg is unsigned so the expression result will also be unsigned*. If you need the result to be signed than all operands must be signed. There are a couple ways to achieve this:
//Declare the reg as signed and divide by a signed value
reg signed [7:0] myReg;
assign result = myReg/2;
//Use system functions
assign result = $signed(myReg)/2;
*The complete rules regarding expression evaluation are much more complex but basically the result of any expression is unsigned, unless all operands are signed.
reg signed [7:0] a;
reg [7:0] b;
initial
begin
result = a; //Signed
result = a * a; //Signed
result = a * 10; //Signed
result = $unsigned(a); //Unsigned
result = a[0]; //Unsigned
result = a[7:0]; //Unsigned
result = {a,a}; //Unsigned
result = 10{a}; //Unsigned
result = a + b; //Unsigned
result = a * b; //Unsigned
end
I'll add that
1. Data types bit and reg are unsigned, by default.
2. Data types int, integer, longint, shortint, and byte are signed, by default.
3. All these data types can take a signed or unsigned qualifier to change the default.
So, assigning -8'D69 to myReg does an implicit conversion to 187. Then, myReg/2 = 187/2 = 93, unsigned. It's important to understand when and how SystemVerilog does implicit type conversions in expressions and assignments.
The best place to check is the Language Reference Manual. Predictably, given Verilog's "eh" attitude to proper typing, it's a bit of a mess.
Basically signed doesn't affect the actual data stored in the variable/net, but it does affect what the arithmetic operators do in some case. The obvious case is comparison, but also multiplication and division would behave differently. Addition and subtraction should be the same for both signed and unsigned.
Note especially that when one or more of the operands is unsigned it is treated as an unsigned comparison, which is different to what you would expect from C. So if we have
byte a = -10; // byte is signed
logic [7:0] b = 10; // this is unsigned
Then a > b is true.
Again if at least one operator is unsigned then it treats them both as unsigned so if we have:
byte a = -1;
logic [7:0] b = 255;
Then a == b is true.

Converting a wire value in Verilog for further processing

I'm new to Verilog.
I have written code to convert a wire value to an integer:
wire [31:0] w1;
integer k;
always # (w1) k = w1;
Source: converting a wire value to an integer in verilog
Now, for the next part I get an ERROR!
wire [63:0] w2; // Suppose it contains some value
wire [63:0] w3;
assign w3[k-1:0] = w2[k-1:0]; // ERROR in this line
ERROR : k is not a constant.
How do I solve this issue?
Verilog requires that part selects (code like [msb:lsb] to select part of a vector) be constant. To access a variable-sized group of bits requires something more complicated. Here is one way to do it:
wire [63:0] src;
wire [6:0] k;
wire [127:0] mask = { { 64 { 1'b0 } }, { 64 { 1'b1 } } } << k;
wire [63:0] dest;
assign dest = mask[127:64] & src;
The technique here is to construct a vector of 64 zeros followed by 64 ones, shift that vector by a variable amount, and then use a portion of the vector as a qualifying mask to control which bits are transferred from src to dest.
A related concept which does not help in your example but which is worth being aware of: Verilog-2001 introduced the "indexed part-select". An indexed part select specifies a base index and a width. The width is required to be constant but the base index does not need to be constant. The syntax for an indexed part select is vec[base+:width] or vec[base-:width].
The part select operators in Verilog 2001 could be useful for what you want to achieve.
Basically verilog allows for the starting index to be variable but needs the width of the assignment to be constant. The "+:" operator indicates counting upwards from the index value and vice-versa for "-:".
You can do something like,
assign w3[k-1 -: 8 ] = w2[k-1 -: 8]; // Where 8 bits is copied downwards
Search for "+:" in the below document.
http://www.sutherland-hdl.com/papers/2001-Wescon-tutorial_using_Verilog-2001_part1.pdf
Word of caution, generally variable part selects is considered as bad verilog.

Resources