Verilog has two different kinds of numbers: integer and vector types such as integer and reg [7:0], and the floating-point type real. The conversion functions move values between them: from real to integer and back, and from a real value to the raw 64 bits that store it, and back. They are mostly used in testbenches and behavioral models, for example to pass real values through ports or to compute with real numbers and then drive the result into the design.
9 min read | Beginner Level
What You'll Learn
- How
$rtoiand$itorconvert between real and integer values - How
$realtobitsand$bitstorealconvert a real value to its 64-bit pattern and back - How a real value is stored in IEEE 754 double precision format
- How to pass real values through module ports, and how text and numbers are converted in Verilog
| Function | Converts | Example |
|---|---|---|
$rtoi | real to integer, dropping the fraction | $rtoi(192.15) = 192 |
$itor | integer to real | $itor(192) = 192.0 |
$realtobits | real to its 64-bit pattern | $realtobits(1.0) = 64'h3FF0000000000000 |
$bitstoreal | 64-bit pattern to real | $bitstoreal(64'h3FF0000000000000) = 1.0 |
$rtoi
$rtoi converts a real number to an integer by truncating the fractional part, which means it always rounds toward zero.
integer $rtoi(real_val); // For example, 192.15 becomes 192
Truncation is different from what happens when a real value is simply assigned to an integer variable: such an assignment rounds to the nearest integer. For example, $rtoi(7.5) is 7, but int_value = 7.5; stores 8. For negative values, $rtoi(-7.5) is -7.
$itor
$itor converts an integer to a real number, so that the value can be used in real-number arithmetic, such as division with a fractional result.
real $itor(int_val); // For example, 192 becomes 192.0
This is useful because integer division drops the fraction: with integers a = 7 and b = 2, a / b is 3, while $itor(a) / b is 3.5.
$realtobits
$realtobits returns the 64-bit pattern that stores a real value. Real numbers in Verilog use the IEEE 754 double precision format, so the pattern is exactly the 64 bits the simulator keeps in memory. This is useful for storing or transmitting floating-point values through signals that can only carry bits.
[63:0] $realtobits(real_val);
The 64 bits are divided into three fields:
| Bits | Field | Meaning |
|---|---|---|
| 63 | Sign | 0 for positive, 1 for negative |
| 62:52 | Exponent (11 bits) | Power of two, stored with an offset of 1023 |
| 51:0 | Fraction (52 bits) | Digits after the leading 1 of the binary number |
$bitstoreal
$bitstoreal does the reverse: it interprets a 64-bit pattern as an IEEE 754 double and returns the real value it represents.
real $bitstoreal(bit_val);
Converting a real value to bits and back always gives exactly the original value, because no information is lost: the 64 bits are the real value.
Synthesis result: None. The real type and these conversion functions are not synthesizable. They are used in testbenches, behavioral models and reference models. Hardware that needs fractional numbers uses fixed-point arithmetic, or floating-point units built from ordinary logic.
Example
The example below starts from a 64-bit pattern, converts it to a real value, converts an integer to real, turns the first real value back into bits, and finally converts a real value to an integer.
module conversion_example;
reg [63:0] bit_pattern; // 64-bit IEEE 754 double precision pattern
real real_value;
real int_as_real;
integer int_value;
initial begin
// Example bit pattern
bit_pattern = 64'h4055480000000000; // Represents 85.125 in IEEE 754 double precision format
// Convert bit pattern to real
real_value = $bitstoreal(bit_pattern);
$display("Bit Pattern to Real: %f", real_value); // Outputs: Bit Pattern to Real: 85.125000
// Convert integer to real
int_value = 10;
int_as_real = $itor(int_value);
$display("Integer to Real: %f", int_as_real); // Outputs: Integer to Real: 10.000000
// Convert real to bits (real_value is still 85.125)
bit_pattern = $realtobits(real_value);
$display("Real to Bit Pattern: 0x%0h", bit_pattern); // Outputs the bit pattern of 85.125
// Convert real to integer
real_value = 7.5;
int_value = $rtoi(real_value);
$display("Real to Integer: %d", int_value); // Outputs: Real to Integer: 7
end
endmodule
xcelium> run Bit Pattern to Real: 85.125000 Integer to Real: 10.000000 Real to Bit Pattern: 0x4055480000000000 Real to Integer: 7 xmsim: *W,RNQUIE: Simulation is complete.
The pattern 64'h4055480000000000 decodes as follows:
- Sign: bit 63 is 0, so the value is positive.
- Exponent: bits 62:52 are
0x405= 1029. Subtracting the offset 1023 gives 6, a factor of 26 = 64. - Fraction:
0x5480000000000starts with the bits0101 0100 1, which make the binary number1.010101001= 1.330078125. - Value: 1.330078125 × 64 = 85.125.
Converting 85.125 back with $realtobits gives the same pattern, as the third line shows. The last line converts 7.5 with $rtoi, which truncates it to 7. It is printed with %d, which pads a 32-bit integer to 11 characters, hence the spaces before the 7.
Quick Check
What are $rtoi(3.99) and $rtoi(-3.99)? What would int_value = 3.99; store?
Show Answer
$rtoi(3.99) is 3 and $rtoi(-3.99) is -3, because $rtoi truncates toward zero. The plain assignment int_value = 3.99; rounds to the nearest integer and stores 4.
Passing Real Values Through Ports
In Verilog, ports cannot have the type real. To pass a real value from one module to another, for example from a behavioral model of an analog sensor to a testbench checker, the sender converts it to 64 bits, sends it over a 64-bit bus, and the receiver converts it back:
module sensor_model (output [63:0] temp_bits);
real temperature;
initial temperature = 36.6;
assign temp_bits = $realtobits(temperature);
endmodule
module monitor (input [63:0] temp_bits);
always @(temp_bits)
$display("Temperature = %0.1f", $bitstoreal(temp_bits));
endmodule
Because the conversion is lossless, monitor prints exactly the value set in sensor_model, 36.6. This is the standard Verilog technique for real-valued signals in mixed models; SystemVerilog allows real ports directly.
Behavioral Models of Analog Blocks
Chips often contain analog blocks, such as a temperature sensor, a voltage regulator or an ADC, which a digital simulation cannot simulate at the transistor level. Verification teams replace them with behavioral models that compute voltages and temperatures as real values. $realtobits and $bitstoreal carry those values through the module hierarchy, and $rtoi turns an analog value into the digital code that an ADC model drives into the design.
Checking Fixed-Point Hardware
A filter implemented in hardware uses fixed-point numbers, where an integer represents a fraction, for example 16 bits with 12 bits after the binary point. The testbench converts the hardware output to real with $itor(out) / 4096.0, compares it with an ideal result computed in real math, and reports an error if the difference is larger than the expected precision.
ASCII <-> Number Conversions
SystemVerilog provides functions to convert between text and numbers, such as atoi(), itoa(), atohex() and hextoa(). These are methods of the SystemVerilog string type, which does not exist in Verilog, so they cannot be used in plain Verilog code. Click here to learn about SystemVerilog Strings !
In Verilog, a string is stored in a reg vector with 8 bits per character, and the same conversions are done with system tasks and arithmetic:
reg [8*8:1] text;
integer value;
initial begin
$sformat(text, "%0d", 1234); // Number to text: text holds "1234"
if ($sscanf(text, "%d", value)) // Text to number: value is 1234
$display("value = %0d", value);
value = "7" - "0"; // One digit character to its value: 7
end
$sformat writes formatted text into a variable, and $sscanf reads values from text using a format, returning the number of values it read. Subtracting the ASCII code of "0" (48) from a digit character gives its numeric value.
Quick Check
What is $bitstoreal(64'h4000000000000000)?
Show Answer
2.0. The sign is 0, the exponent field 0x400 = 1024 gives 21024-1023 = 2, and the fraction is 0, so the value is 1.0 × 2 = 2.0.
Common Beginner Mistakes
Mistake #1: Expecting $rtoi to round
Wrong: count = $rtoi(9.99);, expecting 10
Right: count = $rtoi(9.99 + 0.5); for positive values, or a plain assignment count = 9.99;, which rounds
Why? $rtoi always truncates toward zero, so 9.99 becomes 9. Choose truncation or rounding deliberately, because the two give different results for half of all values.
Mistake #2: Storing $realtobits in less than 64 bits
Wrong: reg [31:0] bits = $realtobits(r);
Right: reg [63:0] bits = $realtobits(r);
Why? A Verilog real is a 64-bit double. Keeping only the lower 32 bits loses the sign, the exponent and half the fraction, and $bitstoreal can no longer recover the value.
Mistake #3: Confusing $realtobits with a numeric conversion
Wrong: data = $realtobits(10.0);, expecting data to be 10
Right: data = $rtoi(10.0);
Why? $realtobits returns the IEEE 754 encoding, 64'h4024000000000000 for 10.0, not the number 10. Use $rtoi when you want the integer value.
Mistake #4: Dividing integers before converting to real
Wrong: ratio = $itor(a / b); with a = 7 and b = 2, expecting 3.5
Right: ratio = $itor(a) / b;
Why? In the first version, the integer division 7 / 2 is done first and gives 3; converting 3 to real gives 3.0. Converting before dividing keeps the fraction.
Practice Exercise
Challenge: Fixed-Point Converter
A hardware signal reg signed [15:0] q holds a fixed-point number with 8 bits after the binary point, so its value is q / 256. Write two functions for a testbench: to_real, which converts q to a real value, and to_fixed, which converts a real value to the nearest fixed-point value. Then predict to_real(16'sd384) and to_fixed(-1.25).
Hint
Use $itor and divide by 256.0 for to_real. For to_fixed, multiply by 256.0 and round, adding 0.5 for positive values and subtracting 0.5 for negative ones, before $rtoi.
Solution
function real to_real (input signed [15:0] q);
to_real = $itor(q) / 256.0;
endfunction
function signed [15:0] to_fixed (input real r);
real scaled;
begin
scaled = r * 256.0;
to_fixed = (scaled >= 0) ? $rtoi(scaled + 0.5) : $rtoi(scaled - 0.5);
end
endfunction
to_real(384) is 384 / 256 = 1.5. to_fixed(-1.25) scales to -320.0, which is already a whole number, so the result is -320, or 16'hFEC0 in two's complement. Rounding away from zero on both sides makes positive and negative values behave symmetrically.
Summary
In this tutorial, you learned:
$rtoiconverts real to integer by truncating toward zero, while a plain assignment of a real to an integer rounds$itorconverts integer to real, which keeps fractions in later arithmetic$realtobitsand$bitstorealconvert between a real value and its 64-bit IEEE 754 pattern, without any loss- A double has a sign bit, an 11-bit exponent with an offset of 1023, and a 52-bit fraction
- Real values are passed through Verilog ports as 64-bit vectors using these functions
- Text and number conversions in Verilog use
$sformatand$sscanf, since the SystemVerilog string methods are not available