CPROVER Manual TOC

## Hardware and Software Equivalence and Co-Verification

### A Small Tutorial

#### Verilog vs. ANSI-C

We assume that CBMC is installed on your system. If not so, follow these instructions.

The following Verilog module implements a 4-bit counter (counter.v):

    module top(input clk);

      reg [3:0] counter;

      initial counter=0;

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

    endmodule

HW-CBMC can take Verilog modules as the one above as additional input. Similar as in co-simulation, the data in the Verilog modules is available to the C program by means of global variables. For the example above, the following C fragment shows the definition of the variable that holds the value of the `counter` register:

    struct module_top {
      unsigned int counter;
    };

    extern struct module_top top;

Using this definition, the value of the `counter` register in the Verilog fragment above can be accessed as `top.counter`. Please note that the name of the variable must match the name of the top module. The C program only has a view of one state of the Verilog model. The Verilog model makes a transition once the function `next_timeframe()` is called.

As CBMC performs Bounded Model Checking, the number of timeframes available for analysis must be bounded (SATABS has no such restriction). 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:

`extern const unsigned int bound;`

Also note that the fragment above declares a constant variable of struct type. Thus, the C program can only read the trace values and is not able to modify them. We will later on describe how to drive inputs of the Verilog module from 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 (counter.c):

    void next_timeframe();

    struct module_top {
      unsigned int counter;
    };

    extern struct module_top top;

    int main() {
      next_timeframe();
      next_timeframe();
      assert(top.counter==2);
      next_timeframe();
      assert(top.counter==3);
    }

The following CBMC command line checks these assertions with a bound of 20:

`hw-cbmc counter.c counter.v --module top --bound 20`

Note that a specific version of CBMC is used, called `hw-cbmc`. The module name given must match the name of the module in the Verilog file. Multiple Verilog files can be given on the command line.

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

#### Counterexamples

For the given example, the verification is successful. If the first assertion is changed to

`assert(top.counter==10);`

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.

`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)`

#### Using the Bound

The following program is using the bound variable to check the counter value in all cycles:

    void next_timeframe();
    extern const unsigned int bound;

    struct module_top {
      unsigned int counter;
    };

    extern struct module_top top;

    int main() {
      unsigned cycle;

      for(cycle=0; cycle<bound; cycle++) {
        assert(top.counter==(cycle & 15));
        next_timeframe();
      }
    }

CBMC performs bounds checking, and restricts the number of times that `next_timeframe()` can be called. SATABS does not require a bound, and thus, `next_timeframe()` can be called arbitrarily many times.