John R. Hauser
2019 July 29
1. Introduction 2. Limitations 3. Acknowledgments and License 4. HardFloat Package Directory Structure 5. Specializing the HardFloat Modules to Test 6. Dependence on Berkeley TestFloat 7. Makefile
Test Targets7.1. Testing Conversions Between Standard and Recoded Floating-Point ( fNToRecFN
andrecFNToFN
)7.2. Testing Conversions from Integer ( iNToRecFN
)7.3. Testing Conversions to Integer ( recFNToIN
)7.4. Testing Conversions Between Formats ( recFNToRecFN
)7.5. Testing Addition and Subtraction ( addRecFN
)7.6. Testing Multiplication ( mulRecFN
)7.7. Testing Fused Multiply-Add ( mulAddRecFN
)7.8. Testing Division and Square Root ( divSqrtRecFN_small
)7.9. Testing Comparisons ( compareRecFN
)7.10. Testing Multiple Functions 8. Interpreting the Test Output 9. Contact Information
This document provides instructions for testing Berkeley HardFloat using
Verilator and the test infrastructure supplied in the HardFloat package.
Berkeley HardFloat is a hardware implementation of binary floating-point
conforming to the IEEE Standard for Floating-Point Arithmetic.
For basic documentation about HardFloat, see
HardFloat-Verilog.html
Verilator is a free tool for converting a subset of synthesizable Verilog or
SystemVerilog into C++ code.
It is also possible to test HardFloat using a Verilog simulator, as documented
in
HardFloat-test-Verilog.html
The supplied tests for HardFloat depend on Berkeley TestFloat, which is not included in the HardFloat package. TestFloat in turn depends on Berkeley SoftFloat. The TestFloat and SoftFloat packages can be obtained from these Web pages:
http://www.jhauser.us/arithmetic/TestFloat.html
http://www.jhauser.us/arithmetic/SoftFloat.html
The supplied testbench can test only the common IEEE-defined formats supported
by TestFloat, which are
The Makefile
provided for running tests requires GNU
make
or a very close relative.
Adapting the testbench to overcome either of these limitations is possible but far from trivial.
The HardFloat package was written by me,
Par Lab: Microsoft (Award #024263), Intel (Award #024894), and U.C. Discovery (Award #DIG07-10227), with additional support from Par Lab affiliates Nokia, NVIDIA, Oracle, and Samsung. ASPIRE Lab: DARPA PERFECT program (Award #HR0011-12-2-0016), with additional support from ASPIRE industrial sponsor Intel and ASPIRE affiliates Google, Nokia, NVIDIA, Oracle, and Samsung. ADEPT Lab: ADEPT industrial sponsor Intel and ADEPT affiliates Google, Futurewei, Seagate, Siemens, and SK Hynix.
The following applies to the whole of HardFloat
Copyright 2019 The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS”, AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The directory structure for the Verilog version of HardFloat is as follows:
doc source 8086-SSE ARM-VFPv2 RISCV test source Verilator build Verilator-GCC IcarusVerilog
The source files that define HardFloat’s modules are in the main
source
directory.
The test
directory has additional files used solely for testing.
The test sources are of course all in test/source
, while the
test/build
subdirectory contains a couple of example build
targets.
For testing using Verilator, the relevant build target subdirectory is
Verilator-GCC
IcarusVerilog
, provides an example of
using a Verilog simulator instead of Verilator.)
As the name Verilator-GCC
test/source/Verilator
.
It is possible to use a different C++ compiler by copying and modifying the
Verilator-GCC
As supplied, subdirectory Verilator-GCC
Makefile config.make config.h
used to build and execute all tests.
The Makefile
is written solely for GNU make
.
Another make
variant is unlikely to work unless it is highly
GNU-compatible.
To determine the particular HardFloat variant to test, the testbench requires
that a Makefile
macro, SPECIALIZE_TYPE
, be defined
with the name of a selected specialization subdirectory within
HardFloat’s main source
directory.
As explained in
HardFloat-Verilog.html
8086-SSE ARM-VFPv2 RISCV
Macro SPECIALIZE_TYPE
can be defined either by editing the file
config.make
found in the Verilator-GCC
Makefile
, or by providing a definition for
SPECIALIZE_TYPE
among the arguments to the make
command.
The HardFloat testbench depends on Berkeley TestFloat, which must be obtained
and built separately.
The latest version of TestFloat is available at Web page
http://www.jhauser.us/arithmetic/TestFloat.html
The testbench expects the reference floating-point used by TestFloat to
exactly match the options chosen for building HardFloat.
TestFloat’s reference floating-point is provided by the Berkeley
SoftFloat library, which again must be obtained and built separately.
The Web page for SoftFloat is
http://www.jhauser.us/arithmetic/SoftFloat.html
The testbench Makefile
requires that program
testfloat_gen
be directly executable by the make
program.
Usually this is achieved by modifying your PATH
environment
variable to include the directory containing testfloat_gen
.
Makefile
Test Targets
The Makefile
in test/build/
is the driver for building and executing tests.
This Makefile
supports a number of possible targets, each testing
one or more HardFloat functions for all relevant rounding modes and other
control parameters.
In all cases, tests ultimately involve executing one or more commands of the
form
testfloat_gen ... <function> | <module-test-program> <control-args>
The vertical bar (|
) represents a pipe from the
testfloat_gen
program, which provides a sequence of test operands
and expected results, to a second program that both simulates the specific
module being tested and confirms that its output matches what
testfloat_gen
expected.
The code for simulating a HardFloat module is of course provided by Verilator,
translating from the original Verilog.
The <control-args>
control
and roundingMode
,
depending on the module being tested.
Many Makefile
targets are supported for running various sets of
tests.
The basic ones for testing individual HardFloat modules are these:
test-<level>-fNToRecFN test-<level>-recFNToFN test-<level>-iNToRecFN test-<level>-recFNToIN test-<level>-recFNToRecFN test-<level>-addRecFN_add test-<level>-addRecFN_sub test-<level>-addRecFN test-<level>-mulRecFN test-<level>-mulAddRecFN_add test-<level>-mulAddRecFN_mul test-<level>-mulAddRecFN test-<level>-divSqrtRecFN_small_div test-<level>-divSqrtRecFN_small_sqrt test-<level>-compareRecFN
where <level>
is always either
‘level1
’ or ‘level2
’.
The <level>
component directly controls the
-level
option given to testfloat_gen
, which
determines the number and depth of tests performed.
For example, the command to execute the complete set of
“addRecFN
is
make test-level2-addRecFN
Each test is performed for all formats supported by TestFloat (and for only
those formats), which for floating-point is IEEE
The Makefile
targets listed above are further dissected in
subsections below.
Other targets are supported that automatically test more than one module in sequence:
test-<level>-all1 test-<level>-all2 test-<level>
For more about these, see subsection 7.10 below, Testing Multiple Functions.
The supplied tests all report status and error information in a common way. As it executes, each test writes status information to the standard error output, which should be the terminal screen by default. In order for this status to be displayed properly, the standard error stream should not be redirected to a file. Any discrepancies that are found are written to the standard output stream, which is easily redirected to a file if desired. Unless redirected, reported errors will appear intermixed with the ongoing status information in the output.
fNToRecFN
and recFNToFN
)
HardFloat modules fNToRecFN
and recFNToFN
are tested
by Makefile
targets
test-<level>-fNToRecFN test-<level>-recFNToFN
Testing can be restricted to a single TestFloat-supported format with one of
these Makefile
targets:
test-<level>-f16ToRecF16 test-<level>-f32ToRecF32 test-<level>-f64ToRecF64 test-<level>-f128ToRecF128 test-<level>-recF16ToF16 test-<level>-recF32ToF32 test-<level>-recF64ToF64 test-<level>-recF128ToF128
iNToRecFN
)
Module iNToRecFN
is tested by Makefile
targets
test-<level>-iNToRecFN
Conversions from all source integer formats supported by TestFloat are tested, encompassing integers of sizes 32 bits and 64 bits, both unsigned and signed.
Testing can be restricted to a single integer size and a single floating-point
destination format with one of these Makefile
targets:
test-<level>-i32ToRecF16 test-<level>-i32ToRecF32 test-<level>-i32ToRecF64 test-<level>-i32ToRecF128 test-<level>-i64ToRecF16 test-<level>-i64ToRecF32 test-<level>-i64ToRecF64 test-<level>-i64ToRecF128
Each target tests conversions from both unsigned and signed integers of the specified size.
recFNToIN
)
Module recFNToIN
is tested by Makefile
targets
test-<level>-recFNToIN
Conversions to all destination integer formats supported by TestFloat are tested, encompassing integers of sizes 32 bits and 64 bits, both unsigned and signed.
Testing can be restricted to a single floating-point source format and a single
integer destination size with one of these Makefile
targets:
test-<level>-recF16ToI32 test-<level>-recF16ToI64 test-<level>-recF32ToI32 test-<level>-recF32ToI64 test-<level>-recF64ToI32 test-<level>-recF64ToI64 test-<level>-recF128ToI32 test-<level>-recF128ToI64
Each target tests conversions to both unsigned and signed integers of the specified size.
recFNToRecFN
)
Makefile
targets
test-<level>-recFNToRecFN
test module recFNToRecFN
.
Testing can be restricted to a single source format and single destination format using one of these targets:
test-<level>-recF16ToRecF32 test-<level>-recF16ToRecF64 test-<level>-recF16ToRecF128 test-<level>-recF32ToRecF16 test-<level>-recF32ToRecF64 test-<level>-recF32ToRecF128 test-<level>-recF64ToRecF16 test-<level>-recF64ToRecF32 test-<level>-recF64ToRecF128 test-<level>-recF128ToRecF16 test-<level>-recF128ToRecF32 test-<level>-recF128ToRecF64
addRecFN
)
Makefile
targets
test-<level>-addRecFN_add test-<level>-addRecFN_sub
test module addRecFN
, for input
subOp
= 0subOp
= 1
test-<level>-addRecFN
combine both sets of tests (both addition and subtraction).
Testing can be restricted to a single TestFloat-supported format with one of
these Makefile
targets:
test-<level>-addRecF16_add test-<level>-addRecF32_add test-<level>-addRecF64_add test-<level>-addRecF128_add test-<level>-addRecF16_sub test-<level>-addRecF32_sub test-<level>-addRecF64_sub test-<level>-addRecF128_sub test-<level>-addRecF16 test-<level>-addRecF32 test-<level>-addRecF64 test-<level>-addRecF128
mulRecFN
)
Module mulRecFN
is tested by Makefile
targets
test-<level>-mulRecFN
Testing can be restricted to a single TestFloat-supported format with one of these targets:
test-<level>-mulRecF16 test-<level>-mulRecF32 test-<level>-mulRecF64 test-<level>-mulRecF128
mulAddRecFN
)
Module mulAddRecFN
is tested by Makefile
targets
test-<level>-mulAddRecFN
However, testing is currently done only for input
op
= 0testfloat_gen
can supply test inputs.
Additional special targets,
test-<level>-mulAddRecFN_add test-<level>-mulAddRecFN_mul
exist for testing mulAddRecFN
in the roles of just addition
(a
× 1 + c
a
× b
+ 0mulAddRecFN
is expected to behave the same
as addRecFN
and mulRecFN
respectively (except
possibly for specific NaN payload propagation in the case of addition).
Testing can be restricted to a single TestFloat-supported format with one of these targets:
test-<level>-mulAddRecF16 test-<level>-mulAddRecF32 test-<level>-mulAddRecF64 test-<level>-mulAddRecF128 test-<level>-mulAddRecF16_add test-<level>-mulAddRecF32_add test-<level>-mulAddRecF64_add test-<level>-mulAddRecF128_add test-<level>-mulAddRecF16_mul test-<level>-mulAddRecF32_mul test-<level>-mulAddRecF64_mul test-<level>-mulAddRecF128_mul
divSqrtRecFN_small
)
Makefile
targets
test-<level>-divSqrtRecFN_small_div test-<level>-divSqrtRecFN_small_sqrt
test module divSqrtRecFN_small
, for input
sqrtOp
= 0sqrtOp
= 1
Testing can be restricted to a single TestFloat-supported format with one of these targets:
test-<level>-divSqrtRecF16_small_div test-<level>-divSqrtRecF32_small_div test-<level>-divSqrtRecF64_small_div test-<level>-divSqrtRecF128_small_div test-<level>-divSqrtRecF16_small_sqrt test-<level>-divSqrtRecF32_small_sqrt test-<level>-divSqrtRecF64_small_sqrt test-<level>-divSqrtRecF128_small_sqrt
compareRecFN
)
Module compareRecFN
is tested by Makefile
targets
test-<level>-compareRecFN
These targets test the module’s outputs against TestFloat’s
comparison functions, lt
, le
, and eq
.
Like all the others, testing can be restricted to a single format with one of these targets:
test-<level>-compareRecF16 test-<level>-compareRecF32 test-<level>-compareRecF64 test-<level>-compareRecF128
A few Makefile
targets combine larger collections of HardFloat
functions.
Targets named
test-<level>-all1
test all of the “one-operand” functions, the same as covered by these targets:
test-<level>-fNToRecFN test-<level>-recFNToFN test-<level>-iNToRecFN test-<level>-recFNToIN test-<level>-recFNToRecFN test-<level>-divSqrtRecFN_small_sqrt
Likewise, the “two-operand” functions can all be tested using
Makefile
targets
test-<level>-all2
which combine these targets:
test-<level>-addRecFN test-<level>-mulRecFN test-<level>-mulAddRecFN_add test-<level>-mulAddRecFN_mul test-<level>-divSqrtRecFN_small_div test-<level>-compareRecFN
Lastly, the simplest of Makefile
targets,
test-<level>
encompass all defined tests at a given level, being a combination of:
test-<level>-all1 test-<level>-all2 test-<level>-mulAddRecFN
The “errors” reported by the HardFloat tests may or may not really represent errors in HardFloat. For each test case tried, the results from HardFloat could differ from the expected results for several reasons:
It is the responsibility of the user to determine the causes for the discrepancies that are reported. Making this determination can require detailed knowledge about both the IEEE Standard and HardFloat’s recoded floating-point format. Assuming both TestFloat and the Verilator testbench are working properly, any differences found will be due to either the first or last of the reasons above.
For each reported error (or apparent error), a line of text is written to the default output. If a line would be longer than 79 characters, it is divided. The first part of each error line begins in the leftmost column, and any subsequent “continuation” lines are indented with a tab.
Each error reported is of the form:
<inputs> => <observed-output> expected <expected-output>
The <inputs>
are the inputs to the operation.
Each output (observed or expected) is shown as a pair: the result value first,
followed by the exception flags.
For example, two typical error lines could be
140FFFE00 180000100 => 041000000 03 expected 041000000 01 081000004 03FFFFFF8 => 041000000 03 expected 041000000 01
In the first line, the inputs are 140FFFE00
and
180000100
, and the observed result is 041000000
with
flags 03
.
TestFloat’s result is the same but with different flags, 01
.
The two instances above were reported as errors because the exception flag
results differ.
Each input and output value, including exception flags, is represented in raw
hexadecimal.
Floating-point inputs and outputs to HardFloat modules are usually encoded in
HardFloat’s recoded form, so they appear in this form, not in a standard
IEEE format.
The only exceptions to this rule are the fNToRecFN
tests, for
which the input is in a standard IEEE format, and the recFNToFN
tests, for which the output is in a standard format.
At the time of this writing, the most up-to-date information about HardFloat
and the latest release can be found at the Web page
http://www.jhauser.us/arithmetic/HardFloat.html