Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Paths
  • Quick Start: Your First Green Build
  • Part 1: How Chips Get Made6
  • Part 2: Your Workstation5
  • Part 3: Specify and Architect3
    • Writing a Testable Spec
    • From Spec to Microarchitecture
    • Golden Model and Register Contract
  • Part 4: The Design Loop6
  • Part 5: The Verification Ladder6
  • Part 6: Automation and Reproducibility5
  • Part 7: Hand-Off to the Back-End3
  • Part 8: When Things Go Wrong3
  • Part 9: Project and Next Steps3
  • Reference4
Loading lesson

‹Part 3: Specify and Architect
  1. Topics
  2. Start Here: RTL and Verification
  3. Part 3: Specify and Architect
  4. Golden Model and Register Contract

Part 3 · Specify and Architect · Foundation (F)

Golden Model and Register Contract

Check the design against an independent answer key: a golden model written from the spec, plus the register contract software would see.

On this page

    Note

    Level: Foundation (F) · Answers: How do you get an answer key for your design that does not come from the design?

    Before this: From Spec to Microarchitecture

    How do you get an answer key for your design that does not come from the design?

    A testbench that copies its expected values from the design code repeats the design mistakes and passes on both. You need an answer key with an independent source: a small program written from the spec, never from the RTL, that predicts what the design must output on every edge.

    That program is a golden model, which means a reference implementation of the spec used only for checking. RTL is register-transfer level: hardware described as registers and the logic between them. This lesson runs the course golden model for mini_controller, explains it line by line, and then states the register contract at awareness level: the agreement software would see if this counter were visible to a program.

    Two implementations of one spec catch each other

    The figure below shows the arrangement. Look at the two arrows leaving the spec first: one team builds the design while the other writes the model, and neither reads the other work. Then follow both output arrows into the comparator, which feeds both sides the same inputs each edge and reports the first mismatch.

    The spec feeds both the design and the model, and a comparator checks their outputs. Follow the two arrows out of the spec first, then both output arrows into the comparator.

    Independence is the whole point. If the model author reads the RTL, the model copies the RTL logic including its bugs, and the comparator compares the design against itself. Written from the spec table instead, the model disagrees with a buggy design on exactly the edge where the design leaves the spec.

    The model predicts from the spec table

    The listing below is the complete golden model. It uses only the Python standard library and checks its own results, so you can run it anywhere you have Python 3:

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    """Golden model of mini_controller, written from docs/spec.md (not from the RTL)."""
    import random
    
    
    class MiniController:
        WIDTH = 4
    
        def __init__(self):
            self.count = None                     # unknown until the first reset edge
    
        def step(self, rst_n, clear, valid):
            """Advance one rising clock edge. Priority: reset > clear > count > hold."""
            if not rst_n or clear:
                self.count = 0
            elif valid:
                self.count = (self.count + 1) % (1 << self.WIDTH)
            return self.count
    
    
    if __name__ == "__main__":
        m = MiniController()
        m.step(0, 0, 0)                           # reset
        seen = [m.step(1, 0, 1) for _ in range(17)]
        assert seen[14] == 15 and seen[15] == 0   # wraps 15 -> 0
        assert m.step(1, 1, 1) == 0               # clear beats valid
        rng = random.Random(1)
        for _ in range(1000):
            out = m.step(rng.random() > 0.1, rng.random() > 0.8, rng.random() > 0.3)
            assert 0 <= out <= 15
        print("PASS: model follows the spec table")

    This listing is the independent answer key: the spec behaviour table as a runnable program.

    Diagram
    # captured terminal output
    $ python3 -I model/mini_controller_model.py
    PASS: model follows the spec table

    This output came from Python 3.14.3 on macOS. The first line runs the model in isolated mode from the model folder; the second line is the verdict after the model checks itself.

    What does each line of the model do?

    Read the model against the spec behaviour table, not against the design. The class holds one value, count, starting unknown until the first reset edge, which mirrors hardware whose register holds no valid value before reset.

    The step method advances one rising edge. Its first branch answers the top two spec rows: reset asserted or clear high sets the count to 0. Its second branch answers the counting row: a valid event adds 1 modulo 16, which wraps 15 to 0. Falling through both branches answers the hold row: the count returns unchanged.

    The main block checks the model against the spec in three stages. It resets, then counts 17 events and asserts the wrap: the fifteenth value is 15 and the sixteenth is 0. It asserts that clear beats a simultaneous valid event. Then it runs 1000 seeded random steps and asserts every result stays within 0 to 15. The seed fixes the sequence, so the run repeats identically everywhere. Only after all three stages pass does the verdict line appear.

    Predict the seventeenth event before you look

    Predict first Starting from reset, you offer 17 valid events with clear held low. What does the model hold after the seventeenth edge?

    1. The first fifteen events climb 1 to 15, the sixteenth wraps to 0, and the seventeenth counts once more to 1. The wrap row is the one most hand-written tests never reach, which is why the model asserts it directly.

    What contract would software see?

    A register map is the agreement between hardware and software: which addresses software reads and writes, what each field means, and what value each field holds after reset. Access type is part of the contract: read-only fields are observed, and write-one-to-clear fields are cleared by writing a 1 while a write of 0 leaves them alone.

    The mini_controller itself has no register interface: it exposes the count as a plain output with no address bus, so no software can read or clear it through registers. The table below is illustrative: an example of what the contract would look like if this counter were software-visible, given only to teach the shape of such a table:

    Address (illustrative)

    Name

    Width

    Access

    Reset value

    0x0

    COUNT

    4 bits

    read-only

    0

    0x4

    CLEAR

    1 bit

    write-one-to-clear

    0 (no pending clear)

    Read the two rows as the two halves of the job. COUNT lets software observe the value without changing it. CLEAR lets software request a clear without touching the count path: writing 1 clears, writing 0 does nothing. The golden model and the RTL would both obey this table, and the comparator would check both against it.

    Two mistakes that quietly copy the bug

    • Writing the model by reading the RTL. A model transcribed from design code agrees with the design by construction, so the comparator stays green over real bugs. Write from the spec table with the design file closed, then let the first mismatch teach you which side misread the spec.

    • Letting the model and the RTL share code. A shared helper, constant or copy-pasted branch carries one mistake into both sides at once. Keep the two implementations separate down to the small details, so each one can surprise the other.

    Rule: the answer key earns trust only when it is written from the spec with the design closed.

    Check yourself The comparator reports a mismatch on the edge where clear and valid arrive together. Which side do you suspect first, and how do you decide?

    Neither side gets the benefit of the doubt: you open the spec behaviour table. It orders clear above counting, so the expected count is 0. Whichever side produced the other value misread the spec, and the spec row settles it without debate.

    Check yourself Why does the model start the count as unknown instead of 0?

    Because the hardware holds no valid value before the first reset edge. Starting unknown forces every user of the model to reset first, which matches the acceptance criterion that reset works from any state. Starting at 0 would hide a design that forgets its reset.

    Check yourself Extend the model with an optional saturation mode: when enabled, the count sticks at 15 instead of wrapping. Sketch the change.

    The answer below is a fragment, not a runnable program on its own:

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # snippet
    SATURATE = True
    count = 15
    valid = True
    if valid:
        if SATURATE and count == 15:
            count = 15            # stick: saturation replaces the wrap
        else:
            count = (count + 1) % 16
    assert count == 15

    This fragment shows the decision point: saturation replaces the wrap branch while reset, clear and hold stay untouched.

    Interview

    Asked: "Why is the reference model written separately from the design?"

    Weak answer: So there are two copies in case one file gets lost.

    Strong answer: So the comparator checks two independent readings of the spec. The design team reads the spec and writes hardware; the model team reads the same spec and writes a small program with the design file closed. A shared misreading is still possible, but a bug on one side shows up as a mismatch on the exact edge where it leaves the spec, instead of passing silently.

    Follow-ups: (1) What do you do when the model and the design disagree? (2) How do you keep the two sides from sharing code by accident?

    Key takeaways

    • A golden model predicts the design outputs from the spec alone, with the design file closed.

    • Independence is what makes mismatches meaningful: shared code or shared readings hide bugs on both sides.

    • The register contract states address, name, width, access type and reset value for every software-visible field.

    Keep going

    Next: Lesson 4.1, Compile, Elaborate, Simulate, Synthesize, Lint. The answer key is ready. The next lesson opens the design loop: compile, elaborate, simulate, synthesize and lint.

    Related topics

    • RTL course: Simulation and Testbenches

    • Later in this course: Tests That Can Fail

    • Earlier in this part: From Spec to Microarchitecture

    Previous

    17 / 47

    Next: Part 4: The Design Loop

    Up next

    Up nextPart 4: The Design Loop

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Writing a Testable Spec