Overview
In constrained-random verification (CRV) of microprocessors, automatic instruction generation must deal with the fact that purely random register values almost never satisfy the comparison operands of a backward branch. For example, a BNE R3, R4 instruction with random contents in R3 and R4 will almost never fall through, so program execution becomes stuck in a loop for a very large (effectively unbounded) number of iterations. The Loop Scenario (Backward Branch) technique addresses this by deliberately constructing the instructions around the branch so that the loop terminates after a small, controllable number of iterations.
Problem With Pure Random Backward Branches
A sample program trace with a backward branch (BNE) is shown in Figure 7 of the source article. Because random 32-bit values are extremely unlikely to make R3 equal R4, the test program would be trapped in the loop for a practically infinite number of cycles, preventing the rest of the program from executing and starving the testbench of meaningful coverage of the branch-not-taken path and of the code following the loop.
Loop-Scenario Construction
Backward branches are handled by treating them as loop scenarios. The construction rule, expressed as SystemVerilog constraints on the instruction sequence, has three parts:
- Pre-branch ADDI. The operation immediately preceding the backward branch must be an
ADDI(add immediate) that uses the same two operand registers as the branch and a small negative immediate value. This sets up the loop-index relationship between the two branch operands. - In-loop increment. Inside the loop body, the loop-index register is incremented by 1 in the instruction just before the branch operation. Each iteration brings the two compared registers one step closer together.
- Register isolation. The two registers used as branch operands must not be modified by any other instruction inside the loop. No other destination register in the loop body may alias with either of the branch's source registers. This ensures the comparison converges predictably.
Worked Example (Figure 10)
Consider the example program trace from the source article:
- If the immediate value at line 7 of the trace is
-1, then R3 and R4 are equal at the comparison on line 12, so theBNEfalls through and the loop exits immediately. - If the immediate value is less than
-1(e.g.,-3), the ADDI on line 11 brings the register values closer by 1 on each iteration. TheBNEon line 12 is taken for every iteration until R3 equals R4, at which point the branch falls through and the loop exits.
This single construction therefore spans the full range of behaviors the verifier cares about — from a single fall-through (zero iterations of the taken path) to loops with several taken iterations — without producing the absurdly long loops that pure randomness would create.
Operand Variation (Figure 11)
The article also illustrates a variant in which the backward branch uses different operand registers, and the preceding ADDI is structured accordingly. The same constraints (small negative immediate, no aliasing writes inside the loop, in-loop increment of the index) apply.
Boundary-Condition Considerations
The processor testbench must additionally consider boundary cases that could make a backward branch degenerate into a trivial always-taken or never-taken path. For example, a BGT R1, R2, LABEL_X must not be constructed when R2 holds the smallest representable value, because the branch would then be always taken, again turning the loop into an effectively unbounded construct. Similar care is needed for the maximum-value and equal-value edges of every supported branch condition.
Role in the Stimulus-Generation Strategy
Loop scenarios are one of three classes of scenarios typically supported by a microprocessor scenario generator, alongside:
- Constrained-random scenarios — for example, restricting an instruction stream to purely computational operations (no branches, loads, or stores) to focus on arithmetic coverage.
- Directed-random scenarios — for example, preloading data memory with walking-1s/0s patterns, near-zero values, and near-minimum/maximum values before an arithmetic stream, to surface rounding and overflow bugs.
- Directed scenarios — loading a pre-assembled program trace from a file, including leveraged tests from the processor's software team.
A common scenario base class encapsulates shared methods (such as loading a directed scenario from a file) and the constraints that relate instruction objects to one another, including the branch-scenario constraints described above. A scenario generator randomly selects and randomizes scenario objects from this pool until a user-specified stopping condition is reached.
Summary
The Loop Scenario (Backward Branch) pattern converts an otherwise dangerous source of unbounded execution into a well-behaved, controllable coverage point. By constraining the instruction immediately preceding a backward branch to be an ADDI with a small negative immediate on the same operand registers as the branch, incrementing the loop index by 1 per iteration, and prohibiting other writes to the two branch operands inside the loop, the testbench produces loops that range from immediate fall-through to several taken iterations — exercising the branch condition evaluation logic, the taken/not-taken paths, and the code after the loop exit.