\chapter{Hardware Verification using ANSI-C as a Reference}

\label{hardware_verification_sec}

\section{Introduction}

A common hardware design approach employed by many companies is to first
write a quick prototype that behaves like the planned circuit in a language
like ANSI-C. This program is then used for extensive testing and debugging,
in particular of any embedded software that will later on be shipped with
the circuit. An example is the hardware of a cell phone and its software.
After testing and debugging of the program, the actual hardware design is
written using hardware description languages like VHDL or Verilog.

Thus, there are two implementations of the same design: one written in
ANSI-C, which is written for simulation, and one written in register
transfer level HDL, which is the actual product. The ANSI-C implementation
is usually thoroughly tested and debugged.

Due to market constraints, companies aim to sell the chip as soon as
possible, i.e., shortly after the HDL implementation is designed. There is
usually little time for additional debugging and testing of the HDL
implementation. Thus, an automated, or nearly automated way of establishing
the consistency of the HDL implementation is highly desirable.

This motivates the verification problem: we want to verify the consistency
of the HDL implementation, i.e., the product, using the ANSI-C
implementation as a reference \cite{pixley01}. Establishing the consistency
does not require a formal specification. However, formal methods to verify
either the hardware or software design are still desirable.

\paragraph{Related Work}

There have been several attempts in the past to tackle the problem. In
\cite{SSMNEP02}, a tool for verifying the combinational equivalence of RTL-C
and an HDL is described. They translate the C code into HDL and use standard
equivalence checkers to establish the equivalence. The C code has to be very
close to a hardware description (RTL level), which implies that the source
and target have to be implemented in a very similar way. There are also
variants of C specifically for this purpose. The System C standard defines a
subset of C++ that can be used for synthesis \cite{system-c}. Other variants
of ANSI-C for specifying hardware are Spec C and Handel C, among others.

The concept of verifying the equivalence of a software implementation and a
synchronous transition system was introduced by Pnueli, Siegel, and
Shtrichman \cite{CVT98a}. The C program is required to be in a very
specific form, since a mechanical translation is assumed.

In \cite{CHR2000}, Currie, Hu, and Rajan transform DSP assembly language into
an equation for the Stanford Validity Checker. However, problems involving
bit vector overflow are not detected and while loops are not supported. The
symbolic execution of programs for comparison with RTL is common practice
\cite{KH01,BELR01}.

The previous work focuses on a small subset of ANSI-C that is particularly
close to register transfer language. Thus, the designer is often required to
rewrite the C program manually in order to comply with these constraints. We
extend the methodology to handle the full set of ANSI-C language features.
This is a challenge in the presence of complex, dynamic data structures and
pointers that may dynamically point to multiple objects. Furthermore, our
methodology allows arbitrary loop constructs.

\section{A small Tutorial}

The following Verilog module implements a 4-bit counter:
%
\begin{alltt}\scriptsize
module main(clk);

input clk;
reg [3:0] counter;

initial counter=0;

always @(posedge clk)
  counter=counter+1;

endmodule
\end{alltt}

\cbmc{} can take Verilog modules as the one above as additional input. The
trace produced by the Verilog module is provided to the C program by means
of arrays. For the example above, the following C fragment is the
declaration of the array that corresponds to the trace values of the {\tt
counter} register:
%
\begin{alltt}
extern const unsigned int counter[];
\end{alltt}

Note that the array has no size specification. However, as \cbmc{} performs
Bounded Model Checking, the size of the array must be bounded. As it is
desirable to change the bound to adjust it to the available computing
capacity, the bound is given on the command line and not as part of the C
program. This makes it easy to use only one C program for arbitrary bounds.
The actual bound is available in the C program using the following
declaration:
%
\begin{alltt}
extern const unsigned int bound;
\end{alltt}

Also note that the array declaration above declares an array with constant
members. Thus, the C program can only read the trace values and not modify
them. We will later on describe how to drive inputs of the Verilog module
within the C program.

As described in previous chapters, assertions can be used to verify
properties of the Verilog trace. As an example, the following program checks
two values of the trace of the counter module:
%
\begin{alltt}\scriptsize
extern const unsigned int bound;
extern const unsigned int counter[];

int main() \{
  assert(counter[5]==5);
  assert(counter[16]==0);
\}
\end{alltt}

The following \cbmc{} command line checks these assertions with a bound of
20:
%
\begin{alltt}
cbmc counter.c counter.v --module main --bound 20 --decide
\end{alltt}

The module name given must match the name of the top module in the Verilog
file. Multiple Verilog files can be given on the command line.

The {\tt --bound} parameter is not to be confused with the {\tt --unwind}
parameter. While the {\tt --unwind} parameter specifies the maximum
unwinding depth for loops within the C program, the {\tt --bound} parameter
specifies the number of times the transition relation of the Verilog module
is to be unwound.

\paragraph{Counterexamples}

For the given example, the verification is successful. If the first
assertion is changed to
%
\begin{alltt}
  assert(counter[5]==0);
\end{alltt}
%
and the bound on the command line is changed to 6, \cbmc{} will produce a
counterexample. \cbmc{} produces two traces: One for the C program, which
matches the traces described earlier, and a separate trace for the Verilog
module. The values of the registers in the Verilog module are also shown in
the C trace as part of the initial state.
%
\begin{alltt}\scriptsize
Initial State
----------------------------------------------------
  bound=6 (00000000000000000000000000000110)
  counter={ 0, 1, 2, 3, 4, 5, 6 }

Failed assertion: assertion line 6 function main

Transition system state 0
----------------------------------------------------
  counter=0 (0000)

Transition system state 1
----------------------------------------------------
  counter=1 (0001)

Transition system state 2
----------------------------------------------------
  counter=2 (0010)

Transition system state 3
----------------------------------------------------
  counter=3 (0011)

Transition system state 4
----------------------------------------------------
  counter=4 (0100)

Transition system state 5
----------------------------------------------------
  counter=5 (0101)

Transition system state 6
----------------------------------------------------
  counter=6 (0110)
\end{alltt}

\paragraph{Using the Bound}

The following program is using the bound variable to check the counter value
in all cycles:
%
\begin{alltt}\scriptsize
extern const unsigned int bound;
extern const unsigned int counter[];

int main() \{
  unsigned cycle;

  for(cycle=0; cycle<=bound; cycle++)
    assert(counter[cycle]==(cycle & 15));
\}
\end{alltt}

\cbmc{} performs array bounds checking on the trace arrays. Thus, care must
be taken to prevent access to the trace arrays beyond the bound.

\paragraph{Synchronizing Inputs}

The example above is trivial as there is only one possible trace. The
initial state is deterministic, and there is only one possible transition,
so the verification problem can be solved by mere testing. Consider the
following Verilog module:
%
\begin{alltt}\scriptsize
module main(clk, i);

input clk;
input i;
reg [3:0] counter;

initial counter=0;

always @(posedge clk)
  if(i)
    counter=counter+1;

endmodule
\end{alltt}

Using the C program above will fail, as the Verilog module is free to use
zero as value for the input {\tt i}. This implies that the counter is not
incremented. The C program has to read the value of the input {\tt i} in
order to be able to get the correct counter value:
%
\begin{alltt}\scriptsize
extern const unsigned int bound;
extern const unsigned int counter[];
extern const unsigned _Bool i[];

int main() \{
  unsigned cycle;
  unsigned C_counter=0;

  for(cycle=0; cycle<=bound; cycle++) \{
    assert(counter[cycle]==(C_counter & 15));
    if(i[cycle]) C_counter++;
  \}
\}
\end{alltt}

Similarly, the C model has to synchronize on the choice of the initial
value of registers if the Verilog module does not perform initialization.

\paragraph{Restricting the Choice of Inputs}

The C program can also restrict the choice of inputs of the Verilog module.
This is useful for adding environment constraints. As an example, consider a
Verilog module that has a signal {\tt reset} as an input, which is
active-low. The following C fragment drives this input to be active in the
first cycle, and not active in any subsequent cycle:
%
\begin{alltt}\scriptsize
  assume(resetn[0]==0);

  for(i=1; i<=bound; i++)
    assume(resetn[i]);
\end{alltt}

\paragraph{Mapping Variables within the Module Hierarchy}

Verilog modules are hierarchical. The {\tt extern} declarations shown above
only allow reading the values of signals and registers that are in the top
module. In order to read values from sub-modules, \cbmc{} uses structures.

As an example, consider the following Verilog file:
%
\begin{alltt}\scriptsize
module counter(clk, increment);

  input clk;
  input [7:0] increment;
  reg [7:0] counter;

  initial counter=0;

  always @(posedge clk)
    counter=counter+increment;

endmodule

module main(clk);

  input clk;

  counter c1(clk, 1);
  counter c2(clk, 2);

endmodule
\end{alltt}

The file has two modules: a main module and a counter module. The counter
module is instantiated twice within the main module. A reference to the
register {\tt counter} within the C program would be ambiguous, as the two
module instances have separate instances of the register. \cbmc{} uses the
following data structures for this example:
%
\begin{alltt}\scriptsize
/* unwinding bound */

extern const unsigned int bound;

/*
  Module verilog::main
*/

extern const _Bool          clk[];

/*
  Module verilog::counter
*/

struct counter \{
  _Bool          clk;
  unsigned char  increment;
  unsigned char  counter;
\};

extern const struct counter c1[];
extern const struct counter c2[];

int main() \{
  assert(c1[5].counter==5);
  assert(c2[5].counter==10);
\}
\end{alltt}

The {\tt main} function reads both counter values for cycle 5. A deeper
hierarchy (modules in modules) is realized by using structure members.
Writing these data structures for large Verilog designs is error prone, and
thus, \cbmc{} can automatically generate them. The declarations above are
generated using the command line
%
\begin{alltt}
  cbmc --gen-interface --module main hierarchy.v
\end{alltt}

\paragraph{Mapping Verilog Vectors to Arrays or Scalars}

In Verilog, a definition such as
%
\begin{alltt}
  wire [31:0] x;
\end{alltt}
%
can be used for arithmetic (e.g., {\tt x+10}) and as array of Booleans
(e.g., {\tt x[2]}). ANSI-C does not allow both, so when mapping variables
from Verilog to C, the user has to choose one option for each such variable.
As an example, the C declaration
%
\begin{alltt}
  extern const unsigned int x[];
\end{alltt}
%
will allow using {\tt x} in arithmetic expressions, while the C declaration
%
\begin{alltt}
  extern const _Bool x[][32];
\end{alltt}
%
will allow accessing the individual bits of {\tt x} using the syntax {\tt
x[cycle][bit]}. The {\tt --gen-interface} option of \cbmc{} will generate
the first variant if the vector has the same size as one of the standard
integer types, and the second option if not so. This choice can be changed
by adjusting the declaration accordingly.
