Skip to content
VLSI Mentor

C Part II · Module 24 · C Reference Models and Scoreboards

A CRC Reference Model, Validated Against Known Vectors

A CRC is the one thing in a testbench with a right answer published by somebody outside the project, which makes it the clearest demonstration of the habit this module is about: validate the oracle, then let it judge. Measured in that order — the model reaches the published 0xF4, its incremental form agrees with its one-shot form, a clean design matches on all nine bytes, and a design whose polynomial is one bit wrong mismatches on eight of nine and fails the published check on its own evidence.

Advanced22 min readCPart IIVerificationDPI-C

Part II · Module 24 · Chapter 24.5 · A CRC Reference Model, Validated Against Known Vectors

1. The Order Is the Lesson

Chapter 22.4 built a CRC in C and checked it against its published value, as part of learning how to import a function. This chapter uses the same file, unchanged, and is about something else: the moment it becomes an oracle.

Chapter 24.1 set out what that promotion requires. A CRC is the clearest possible demonstration, because it has the one thing most models never get — a right answer published by somebody outside the project.

So the chapter is an order of operations, and the order is the whole point:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  1. validate the model against the published value
  2. validate the form the testbench will actually call
  3. then, and only then, let it judge a design

Almost every model in practice skips the first two, because the design is available and running something feels like progress. Chapter 24.3 measured where that ends up.

2. Validating the Oracle

Measured, before the model judges anything at all:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  one-shot over the check string   : 0xF4  (published 0xF4) match

One comparison, against a number computed by whoever specified CRC-8/SMBUS, before this project existed. That is what Chapter 24.1 §3 means by the specification being the authority — here it is unusually concrete, because the specification shipped a test vector.

And the second check, which is the one people skip:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  incremental, one byte at a time  : 0xF4  equals the one-shot

A testbench does not have the whole message in one place; it has a byte per cycle. So the function the scoreboard actually calls is the incremental one, and it is a different function from the one that was just validated. Chapter 22.4 §4 listed how the two can diverge — an initial value applied per byte instead of per message, a final step applied in the wrong place — all of which leave one form correct and the other wrong.

Two checks, because there are two functions.

Then the prefix table, which is not a check but a debugging asset:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  97 72 C0 C2 CB FD 78 C7 F4

Those are the nine intermediate values a correct design passes through. §4 is what they are for.

3. Judging

Only now does the model judge anything. Measured, a clean design, compared byte by byte through the comparison path Chapter 24.4 built:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  clean DUT   : 0xf4 after 9 bytes (published check value 0xF4): match
                9 bytes checked against the model, 0 mismatch(es)

Note that this design is checked twice, independently:

  • its final value against the published 0xF4, with no model involved at all
  • its every intermediate byte against the model

That is unusual and worth having. Most blocks only get the second kind.

And a design whose polynomial is 0x06 where the specification says 0x07 — a one-bit transcription slip, the kind that gets written:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  poly-bug DUT: 0x2a after 9 bytes (published check value 0xF4): MISMATCH
                9 bytes checked, 8 mismatch(es), first at byte 1
  [SB] first mismatch at byte 1: expected 0x97, actual 0xA6

Caught twice. The model disagrees from the very first byte, and the final value 0x2A fails the published check on its own evidence — without the model, and without anything the project wrote.

The order in which a CRC oracle earns the right to judge a design, with every step measured. First the model is checked against the algorithm's published value over the string 1 to 9, giving 0xF4 and matching. Second the incremental form, which folds one byte at a time, is checked against the one-shot form and against the same published value, also 0xF4. Only then does the model judge anything. A clean design finishes at 0xF4 and matches the model on all nine bytes with no mismatches. A design whose polynomial is one bit wrong finishes at 0x2A, which fails the published check on its own, and mismatches the model on 8 of 9 bytes starting at the very first one. The prefix table of nine intermediate values is what localises a failure to a byte rather than to a message, and the bottom line is that the published value is the only step in the sequence that does not depend on anything the project wrote.The stepin the order it must happenWhat it checksand against what authorityMeasuredevery value1. Validate the modelbefore it judges anything at allagainst the published checkvaluecomputed by whoever specified thealgorithm0xF4, matchmeasured over the nine-byte checkstring2. Validate the incrementalformthe one the testbench willactually callagainst the one-shot formand the published valuetwo checks, not one0xF4, equals the one-shotmeasured, folding one byte at atime3. Judge a clean designthe baseline runevery byte, not just thefinal valuenine comparisons, not one0xF4 and 0 of 9 mismatchesmeasured: the design passes thepublished check too4. Judge a design with thewrong polynomial0x06 where the spec says 0x07the same nine comparisonsand the published check,independently0x2A and 8 of 9 mismatchesmeasured, first at byte 1 — and0x2A fails the published check onits ownThe published value is the only step that depends on nothing the project wrotemeasured — the prefix table 97 72 C0 C2 CB FD 78 C7 F4 is what turns a failing message into a failing byte12
Figure 1 — the order in which a CRC oracle earns the right to judge, every value measured. The first two rows happen before any design is involved: the model matches the algorithm's published check value, and the incremental form that the testbench will actually call matches both the one-shot form and the published value. The third and fourth rows are the judging, and the design with a one-bit polynomial error is caught twice over — by the model on eight of its nine bytes starting at the first, and independently by the published value, since 0x2A is simply not what a correct CRC-8 of that string is. The bottom bar is why a CRC is the clearest case in the module: the published value is the only link in the chain that does not depend on anything anyone on the project wrote.

4. Eight of Nine, and What a Rate Is Worth

The polynomial is wrong on every byte, and the mismatch count is 8 of 9. One byte happened to coincide anyway.

That is the third time this module has produced a rate that undersells the fault:

  • Chapter 24.2: a real specification departure visible in 2 of 70 checks.
  • Chapter 24.4: a comparison error producing 16 of 30 on a design with no bug.
  • Here: a wholly wrong algorithm producing 8 of 9.

Put together, they say something useful and slightly uncomfortable:

A mismatch rate tells you almost nothing about severity. A catastrophic algorithmic error can read as 89%, a cosmetic-looking one as 3%, and a perfectly good design as 53% when the harness is wrong.

What is informative is where the first mismatch is, which is why every report in this module carries it. Byte 1 says the very first operation disagrees — an initial value, a polynomial, a bit order. Byte 28 (Chapter 24.2) says everything was fine until some condition was reached, which points at a boundary.

That is what the prefix table is for. Measured, the nine values a correct design passes through:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  97 72 C0 C2 CB FD 78 C7 F4

A design that diverges at byte 5 has a different problem from one that diverges at byte 1, and without the intermediate values a failing message is just a failing message.

5. The Misconception: The Model Matched the DUT, So the CRC Is Right

"We ran a thousand packets through the model and the RTL and every CRC matched. The model is correct."

This is the right sentence with its two halves swapped.

Agreement with the design is what the oracle is for. It is the output of the arrangement, the thing you are trying to establish. Using it as evidence that the model is correct uses the conclusion as the premise.

The published value is what makes the model an oracle. It is the only input to the arrangement that did not come from the project, and Chapter 24.1's independence obligation is exactly the claim that such an input exists.

And a model validated only against the design is Chapter 24.3's RTL-derived model arrived at slowly: not transcribed, but adjusted until it agrees, which reaches the same place. That chapter measured the destination — 51 mismatches against 0 on the same design.

The practical form, and it is one line in a test:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
assert(crc8_smbus((const uint8_t *)"123456789", 9) == 0xF4);

That assertion runs before anything else and costs nothing. If it ever fails, every result the model has produced since the last time it passed is in question — which is a far better thing to learn from one line than from a week of disagreements.

The accurate position:

Validate the oracle against something outside the project, then let it judge. A thousand matching packets confirm that two things agree; the published value is the only part of the arrangement that says what they ought to be.

6. What You Should Be Able to Say Now

  1. The order is the lesson: validate the model · validate the form the testbench calls · then judge.
  2. A CRC is the clearest case because its right answer was published by somebody outside the project.
  3. Measured, step 1: the one-shot model gives 0xF4, matching the published value.
  4. Measured, step 2: the incremental form gives 0xF4 and equals the one-shot — two functions, two checks.
  5. The clean design is checked twice independently: its final value against the published 0xF4, and every byte against the model — measured, 0 of 9 mismatches.
  6. The polynomial-bug design is caught twice: 8 of 9 mismatches from byte 1, and 0x2A fails the published check on its own.
  7. 8 of 9, not 9 of 9 — one byte coincided even with the wrong polynomial.
  8. A mismatch rate says almost nothing about severity — 2 of 70 was a real bug, 16 of 30 was a correct design, 8 of 9 is a wholly wrong algorithm.
  9. Where the first mismatch is, is informative — byte 1 points at an initial value, a polynomial or a bit order.
  10. The prefix table 97 72 C0 C2 CB FD 78 C7 F4 turns a failing message into a failing byte.
  11. Agreement with the design is the output, not the evidence — a model validated only against the DUT is 24.3's model reached slowly.

7. Exercises

  1. Validate a CRC implementation against its published check value and then against its own incremental form. Why are these two different checks?
  2. Build the prefix table for your CRC. A design first diverges at entry 5 — what does that rule out?
  3. Change a polynomial by one bit and count the mismatches over a nine-byte message. Is the rate what you expected?
  4. List the three mismatch rates in §4 with their causes. What would you now ask before treating a rate as a severity estimate?
  5. Write the one-line assertion from §5 and put it where it runs before any judging. What does its failure invalidate?
  6. For a block in your project with no published vectors, work through §4's callout and say which source of an independent answer you can actually get.
  7. Derive one expected value by hand from a format you work with, showing the arithmetic. How long did it take?
  8. A colleague validated a model by running it against the RTL on 10,000 packets. Explain, in two sentences, what that established and what it did not.

8. Summary

  • Validate, then judge — and validate the form the testbench will actually call.
  • Measured: one-shot 0xF4 against the published value; incremental 0xF4, equal to the one-shot.
  • Clean design: 0xF4 and 0 of 9 mismatches, checked twice — by the published value and by the model.
  • Polynomial-bug design: 0x2A, 8 of 9 mismatches from byte 1, failing the published check on its own evidence.
  • 8 of 9, not 9 of 9 — even a wholly wrong algorithm leaves a coincidence.
  • Rates say little about severity — 2 of 70 real, 16 of 30 a correct design, 8 of 9 catastrophic.
  • The first mismatch's position is the informative part; the prefix table localises it.
  • When there are no published vectors: a worked example · a hand calculation · a second author — never the design.
  • Agreement with the design is the output, not the evidence.

A CRC has a published answer, which is what made this chapter short. Arithmetic rarely does — and the places where two defensible implementations disagree are exactly the ones a specification tends to describe in a single word.

Where this fits

Part of the C Programming curriculum.