- Daniel Kroening
- SMT Lists/Sets/Maps
- Google groups:
VerifOx -- A Tool for Path-wise Symbolic Execution
One application of equivalence checking is to establish correspondence between a high-level, abstract design and a low-level implementation. We propose a new partitioning technique for the case in which the two designs are substantially different and traditional equivalence-point insertion fails. The partitioning is performed in tandem in both models, exploiting the structure present in the high-level model. The approach generates many but tractable SAT/SMT queries. We embody this technique in our tool, VerifOx. VerifOx is a path-based symbolic execution tool for equivalence checking of C programs. VerifOx supports the C89 and C99 standards. The key feature of VerifOx is symbolic reasoning on the equivalence between floating-point operations. To this end, VerifOx implements a model of the IEEE 754 arithmetic operations such as single- and double-precision addition and subtraction operations, which can be used as reference models. Note that the floating-point reference models in VerifOx are equivalent to the Berkeley SoftFloat library.
VerifOx is implemented in C++. VerifOx is built on top of CPROVER framework. The tool has been successfully used to verify Floating-point unit in ARM GPU against its built-in reference models. VerifOx has also been used for property verification of embedded softwares such as Universal Asynchronous Receiver Transmitter (UART), Ethernet MAC controller, USB PHY IP core and other data and control intensive designs. Some of these benchmarks are available here.
System Requirements
We assume that you have a Debian/Ubuntu or Red Hat-like distribution.
You need a C/C++ compiler, Flex and Bison, and GNU make.
The GNU Make needs to be version 3.81 or higher. On Debian-like
distributions, do
apt-get install g++ gcc flex bison make git libz-dev libwww-perl patch
libzip-dev
On Red Hat/Fedora or derivates, do
yum install gcc gcc-c++ flex bison perl-libwww-perl patch
Compiling VerifOx
Step 1: Download VerifOx from http://www.cprover.org/verifox/
Step 2: Check out CBMC source via
git clone https://github.com/diffblue/cbmc cbmc-git
Step 3: Navigate to VerifOx directory -- cd VerifOx
Step 4: cd src
Step 5: mv config.inc.template config.inc
Step 6: Point the CBMC variable in config.inc file to point to cbmc
that you downloaded in Step 2. Example: CBMC = /users/rajdeep/cbmc/
Step 7: make
Step 8: cd hasco
Step 9: The executables are :
-- verifox-pi (partial incremental)
-- verifox-fi (full incremental)
Using VerifOx
The following command is used to run VerifOx in partial incremental mode with SAT backend.
verifox-pi main.c --unwind N
The following command is used to run VerifOx in partial incremental mode with SMT backend.
verifox-pi main.c --unwind N --smt2 --z3
The following command is used to run VerifOx in full incremental mode with SAT backend.
verifox-fi main.c --unwind N
Equivalence Checking using HW-CBMC
Description
HW-CBMC is used for C versus Verilog RTL combinational and sequential equivalence checking. HW-CBMC supports IEEE 1364-2005 System Verilog standards and the C89, C99 standards. HW-CBMC maintains two separate flows for hardware and software. The hardware flow uses synthesis to obtain either a bit-level or a word-level netlist from Verilog RTL. The software flow illustrates the translation of the C program into static single assignment (SSA) form. These two flows meet only at the solver. Thus, HW-CBMC generates a monolithic formula from the C and RTL description, which is then checked with SAT/SMT solvers. HW-CBMC provides specific handshake primitives such as next_timeframe() and set_inputs() that direct the tool to set the inputs to the hardware signals and advance the hardware clock, respectively.
Tool Flow

The following command is used to automatically generate the top-level interface from the Verilog files.
hw-cbmc VERILOG-FILE-NAME --module TOP-MODULE --gen-interface
The following command is used to run HW-CBMC in bit-level mode.
hw-cbmc VERILOG-FILE-NAME MITER-FILE-NAME --module TOP-MODULE
--bound N --unwind M --aig --vcd VCD-FILE-NAME
The following command is used to run HW-CBMC in word-level mode.
hw-cbmc VERILOG-FILE-NAME MITER-FILE-NAME --module TOP-MODULE
--bound N --unwind M --vcd VCD-FILE-NAME
Authors: Saurabh Joshi Daniel Kroening Rajdeep Mukherjee
Contact Rajdeep Mukherjee, Saurabh Joshi with questions or feedback.
We are releasing VerifOx and HW-CBMC binaries for x86 Linux and a collection of equivalence checking benchmarks.
|
The source code of VerifOx is available online. For compilation of VerifOx, please follow the README inside the VerifOX directory.
|
Equivalence of Verilog and ANSI-C
The following example shows a very simple Verilog design for D-flipflop and the equivalent cycle-accurate design in ANSI-C. The D-flipflop design contains sequential and combinational elements as well as blocking and non-blocking statements. HW-CBMC can be used to prove the equivalence of cycle-accurate behavior of the Verilog RTL and ANSI-C implementations.
Verilog ANSI-C ------------------------------ ------------------------------ module top(Din,En,CLK,Dout); struct s_ff { wire cs; reg ns; _Bool q; input CLK, Din, En; } sff; output Dout; struct s_en { // Combinational Block _Bool ns; assign Dout = cs; struct s_ff sff; always @(Din or cs or En) } sen; begin // Combinational Logic if (En) void top(_Bool CLK,_Bool Din, ns = Din; _Bool en, _Bool *Dout) { else _Bool cs; ns = cs; if(En) sen.ns = Din; end else sen.ns = cs; ff ff1(ns,CLK,cs); ff(CLK,sen.ns,&cs); endmodule *Dout = cs; } // Sequential Block // Sequential Block module ff(Din, CLK, Dout); _Bool ff(_Bool CLK, _Bool Din, input Din, CLK; _Bool *Dout) { output Dout; _Bool tmp0; reg q; tmp0 = Din; assign Dout = q; sff.q = tmp0; always @(posedge CLK) *Dout = sff.q; q <= Din; return; endmodule }
Example of Trace Partitioning
The following example illustrates input-based trace partitioning for equivalence checking of combinational logic. The partition constraints can be encoded as assumptions in the tool. Note that trace partitioning is a common technique to scale up equivalence checking.
Miter Logic Input-based Partitioning ----------------------- ---------------------------------- void miter(float f, float g){ //setting up the inputs to hardware FPU //Partition1: fp_add_sub.f=*(unsigned *)&f; (fp_add_sub.roundingMode==RNE) fp_add_sub.g=*(unsigned *)&g; && (fp_add_sub.uf_nan) fp_add_sub.isAdd=1; && (fp_add_sub.ug_nan); //propagates inputs of the hardware circuit //Partition2: set_inputs(); (fp_add_sub.roundingMode==RNE) //get result from && (fp_add_sub.uf_inf) hardware circuit && (fp_add_sub.ug_nan); float Verilog_result= *(float *)&fp_add_sub.result; //compute fp-add in Software with rounding mode RNE float C_result=add(RNE, f, g); //compare the outputs assert(compareFloat (C_result, Verilog_result)); }
The following example illustrates transaction-based trace partitioning for sequential logic. Note that transaction based trace partitioning is different from input based case-splitting in that the former can specify conditions on internal program variables along with input/output variables while the later is only based on input/output variables or signals.
Design Transaction-based Partitioning ----------------------- ---------------------------------- #define threshold 15 if(reset) { mode=0,turn=0; feedback=0; // Power gated logic partition } Transaction1: (reset==0) && (env==1) else { && (mode == STAND_BY) && // code fragment for IP (voltage_level == 10); // Trigger IP if env is set if(env) { // Normal logic partition mode = 1; Transaction2: (reset==0) && (env==1) turn = 0; && (mode == HIBERNATE) && // check the voltage level (voltage_level == 20); if(voltage_level < threshold) power_gated = 1; else power_gated = 0; // check the low-power modes if(mode == STAND_BY || mode == TURN_OFF) { // power gated logic. if(power_gated) { trans(reset,mode,power_gated, ser_in,&buf_out); feedback = LOW; // no transmission } else { // normal logic trans(reset,mode,power_gated, ser_in,&buf_out); feedback = buf_out;} } } }