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

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • The NanoSoC Tour
  • Reading Path
  • SoC Glossary10
  • SoC Metrics Reference
  • SoC Cheatsheet
  • What SoC Integration Is12
  • Architecture and Budgets21
  • Memory Maps and Address Decode26
    • Designing the Address Map
    • Implementing Address Decode
    • Decode Errors and Default Slaves
    • Register Maps and Banks
      • Designing a Register Block
      • Checking the Register Specification
      • A Working Register Block and Its Bugs
    • Security and Privilege Regions
    • The Software View and the Hardware-Software Contract
    • IP-XACT and Automated Assembly
    • Memory-Map Verification
  • Interconnect and Bus Fabrics26
  • Clock and Reset Architecture24
  • Power Architecture21
  • Interrupts, DMA and Peripherals15
  • Memories, Boot and Security21
  • IP Integration and Handoff21
  • Top-Level Verification and Bring-up21
  • Package, Pads and I/O18
  • Chip Signoff and Tapeout18
  • SoC Interview Prep16
  • Capstone: Integrate NanoSoC14
Loading lesson

←Register Maps and Banks
  1. Topics
  2. SoC Design
  3. Memory Maps and Address Decode
  4. Register Maps and Banks
  5. Checking the Register Specification
On this page

    Part 3 of 14, lesson 13 of 26Part 3 of 14/Memory Maps and Address Decode/Lesson 13 of 26All levels

    Checking the Register Specification

    A script that validates offsets, widths, access types and reset values across the NanoSoC register tables.

    Why it matters

    Register tables are usually reviewed in a document, where a duplicated offset or a reset value that does not fit its field hides in plain sight until a driver trips over it. The same table as data can be checked exhaustively in milliseconds: alignment, uniqueness, width, reset fit and access-type sanity for every row. This is the register-level twin of the map checker from the design topic, and it runs before any RTL or header is generated from the table.

    The core idea

    Five rules cover almost every specification bug. Offsets are word aligned and unique within their block. Every field fits inside its declared register width and no two fields in one register overlap. The reset value fits inside the implemented width. The access type is one of the five the checker knows: read-write, read-only, write-1-to-clear, write-only, or mixed, where a register's fields carry different types and are checked field by field. And a write-only register still declares a width and a reset behaviour, usually acts-and-forgets, so the documentation never promises a readback. The checker below encodes the DMA and SBR tables from the design specification, validates all five rules, then proves it is awake by catching a row whose reset value is wider than its field.

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    # (block, register, offset, fields, access, width_bits, reset)
    SPEC = [
        ("DMA", "CTRL", 0x00, [(0, 0, "GO"), (1, 1, "IRQ_EN")], "RW", 2, 0x0),
        ("DMA", "STATUS", 0x04, [(0, 0, "BUSY"), (1, 1, "DONE"), (2, 2, "ERR")], "MIX", 3, 0x0),
        ("DMA", "LEN", 0x08, [(15, 0, "WORDS")], "RW", 16, 0x0),
        ("DMA", "KEY", 0x0C, [(31, 0, "KEY")], "RW", 32, 0x0),
        ("DMA", "COUNT", 0x10, [(15, 0, "WORDS")], "RO", 16, 0x0),
        ("SBR", "SRC_ADDR", 0x00, [(31, 0, "ADDR")], "RW", 32, 0x2000_0000),
        ("SBR", "DST_ADDR", 0x04, [(31, 0, "ADDR")], "RW", 32, 0x2001_0000),
        ("SBR", "LEN", 0x08, [(15, 0, "WORDS")], "RW", 16, 0x0),
        ("SBR", "CTRL", 0x0C, [(0, 0, "START"), (1, 1, "IRQ_EN"), (2, 2, "NS")], "RW", 3, 0x4),
        ("SBR", "STATUS", 0x10, [(0, 0, "BUSY"), (1, 1, "DONE"), (2, 2, "ERR")], "MIX", 3, 0x0),
    ]
    ACCESSES = {"RW", "RO", "W1C", "WO", "MIX"}
    
    def check(spec):
        problems = []
        seen = set()
        for block, name, off, fields, acc, width, reset in spec:
            if off % 4 != 0:
                problems.append(f"{block}.{name}: offset {off:#x} not word aligned")
            if (block, off) in seen:
                problems.append(f"{block}.{name}: duplicate offset {off:#x}")
            seen.add((block, off))
            if acc not in ACCESSES:
                problems.append(f"{block}.{name}: unknown access {acc}")
            if width > 32 or reset >= (1 << width):
                problems.append(f"{block}.{name}: reset {reset:#x} exceeds width {width}")
            used = 0
            for hi, lo, _fname in fields:
                if hi < lo or hi > 31:
                    problems.append(f"{block}.{name}: bad field [{hi}:{lo}]")
                if hi >= width:
                    problems.append(f"{block}.{name}: field [{hi}:{lo}] exceeds width {width}")
                bits = ((1 << (hi - lo + 1)) - 1) << lo
                if used & bits:
                    problems.append(f"{block}.{name}: overlapping fields")
                used |= bits
        return problems
    
    assert check(SPEC) == []
    bad = SPEC + [("SBR", "BROKEN", 0x14, [(7, 0, "X")], "RW", 8, 0x1FF)]
    hits = check(bad)
    assert len(hits) == 1 and "exceeds width" in hits[0]
    print("PASS: DMA + SBR tables valid; oversized reset value caught")

    What the review looks for

    • The checker output for the current specification version is attached to the integration review, like the map checker output.

    • Every block in every slot appears in the table; a block with no rows is a finding, not an omission.

    • Fields named in prose documentation exist in the table with the same widths, because both are generated from it.

    Verify and debug

    Run the checker whenever the table changes, and treat a clean run as the entry ticket for generating RTL, headers and documentation. When it reports a problem, fix the table, never the generated file. The failure it cannot see is semantic: a correct-width field with the wrong meaning, which is why the next lesson builds the behaviour and the verification topic exercises every access type from software.

    A register model whose reset values diverged from the RTL: the document says one thing, the silicon powers up as another, and every driver written against the model misbehaves until the table is fixed. The reset readback sweep exists precisely to arbitrate; the checker keeps the table itself honest in the meantime.

    If asked how you would review a register specification, answer: as data, with a checker, before RTL. Alignment, uniqueness, field overlap, reset fit and access-type sanity, all mechanical, all in the build.

    Check yourself A proposed register has width 16 and reset value 0x0001_0000. Which rule fires and why?

    The reset-fit rule: 0x0001_0000 needs 17 bits and does not fit in a 16-bit field, so the stored value would silently truncate at reset. Either widen the field or correct the reset value in the table.

    Related topics

    • Designing a Register Block

    • Next: A Working Register Block and Its Bugs

    • UVM: Why a Register Model

    Previous

    51 / 289

    Next: A Working Register Block and Its Bugs

    Up next

    Up nextA Working Register Block and Its Bugs

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error