Now we'll consider a more complex (though still trivial) implementation with multiple stages of delay. The goal is to verify the end-to-end delivery of data by considering each stage in turn, specifying a refinement map for each stage. The refinement map for each stage drives the input of the next. Suppose we replace the above implementation with the following implementation that has three time units of delay:
stage1, stage2 : struct{ valid : boolean; idx : INDEX; data : BYTE; } init(stage1.valid) := 0; next(stage1) := inp; init(stage2.valid) := 0; next(stage2) := stage1; init(out.valid) := 0; next(out) := stage2;We'll include a refinement map for each intermediate delay stage, similar to the maps for the input and output:
layer spec: { if(stage1.valid) stage1.data := bytes[stage1.idx]; if(stage2.valid) stage2.data := bytes[stage2.idx]; } }When verifying the output of one stage, we can drive the output of the previous stage from the abstract model, via the refinement map, thus decomposing the verification of each stage into a separate problem. Open this version in vw and select, for example, the property out.data[0]//spec. That is, we want to verify the final output against the refinement map. Select the Cone page, and notice that to define the data outputs of the stage2, SMV has chosen the layer spec, rather that the implementation definition. The number of state bits remaining (51) is still larger than in the previous case, however, because spec doesn't give any definition of the signals valid and idx, hence these are still driven by the implementation.
If you select ``Prop|Verify out.data[0]//spec'', you'll observe that we can still quickly verify this property, even thought the number of state variables is larger. Nonetheless, we would like to make the verification of the last stage independent of the previous stages, to be sure we can still verify it if the previous stages are made more complex. We can do this by explicitly ``freeing'' the signals stage2.valid and stage2.idx, that is, allowing these signals to range over any possible values of their types. This is the most abstract possible definition of a signal, and is provided by a built-in layer called free. To tell SMV explicitly to use the free layer for these signals, we add the following declaration:
using stage2.valid//free, stage2.idx//free prove out.data//spec;Open this new version, and select property out.data[0]//spec. Note the the number of state bits (in the Cone page) is now 39, as in our original problem. In fact, if you select ``Prop|Verify out.data[0]//spec'' you will probably get a very fast answer, since SMV will notice that the verification problem you are trying to solve is isomorphic to that of the one-stage implementation we started with. This information was saved in a file for future use when that property was verified.
To verify stage2, in the same way, we need to make similar using...prove declaration, as follows:
using stage1.valid//free, stage1.idx//free prove stage2.data//spec;Note that we don't need a corresponding declaration for stage1, since the input signals inp.valid and inp.idx have been left undefined, and are thus free in any event. With this addition, chose ``Prop|Verify all'', and observe that all the properties are verified very quickly, since they are all isomorphic.