This lesson has one job: decide which bits the chip can never change its mind about. Every field fused is a field no firmware bug can corrupt and no attacker can rewrite, but also a field no erratum can fix. The allocation below spends 256 illustrative fuse bits across six owners and leaves spares, because the only thing worse than a wasted fuse is a missing one discovered after tapeout.
Six classes share the array. Analog trim carries the oscillator and regulator settings the PHY and PLL need before anything runs. Boot configuration selects options the ROM reads in its first steps, such as whether secure boot enforces or merely reports. Repair holds the row and column addresses for both SRAM banks, written by the tester after MBIST. Secrets hold the device key material the secure-boot topic authenticates against. Version holds the minimum image version, a thermometer-coded counter that only ever advances, which the secure-boot topic compares against. Lifecycle holds the device state, covered in the third lesson. All field sizes are NanoSoC teaching values: the classes and the ordering rules are the portable part, the bit counts illustrate one plausible packing.
Field | Bits | Written by | Read by | Rule |
|---|---|---|---|---|
Oscillator and regulator trim | 64 | Tester at sort | Analog via shadow registers | Loaded before PLL lock; safe defaults until then |
Boot configuration | 16 | Tester or OEM | ROM in its first steps | Read-only after sampling; no silent default change |
SRAM repair, both banks | 64 | Tester after MBIST | Wrapper repair pins at reset | ECC of the repair field itself where provided |
Device secrets (64 bits is illustrative, not a recommended key size) | 64 | Secure facility | Secure-boot engine only | Never mapped to any bus; no software read path |
Minimum image version, thermometer-coded | 16 | OEM at provisioning, then authorised updates | ROM during image authentication | Bits only go from 0 to 1, so the minimum can rise and never fall |
Lifecycle state | 16 | Each life stage | Security controller | Monotonic: states advance, never retreat |
Spare | 16 | Reserved | None yet | Spent only by engineering order with a map revision |
fields = [("trim", 64), ("bootcfg", 16), ("repair", 64), ("secrets", 64), ("minver", 16), ("lifecycle", 16), ("spare", 16)]
total = sum(bits for _, bits in fields)
assert total == 256, total
ranges = {}
offset = 0
for name, bits in fields:
ranges[name] = (offset, offset + bits - 1)
print(f"{name}: bits [{offset}:{offset + bits - 1}]")
offset += bits
assert offset == 256
used = total - dict(fields)["spare"]
assert used == 240
spans = sorted(ranges.values())
for (lo1, hi1), (lo2, hi2) in zip(spans, spans[1:]):
assert hi1 < lo2, "fields overlap"
assert "minver" in ranges, "anti-rollback needs a fuse field"
def min_version(field):
return bin(field).count("1")
def accept(manifest_version, field):
return manifest_version >= min_version(field)
field = 0b0000_0000_0111_1111
assert min_version(field) == 7
assert accept(7, field) and accept(8, field) and not accept(6, field)
assert min_version(field | 1 << 7) == 8 and min_version(field & ~1) == 6, "a cleared bit would lower the minimum, which fuses cannot do"
print("PASS: 256-bit array, 240 used, 16 spare, no overlaps, version field present")Every fuse bit has exactly one owner, one writer and one reader; the table above is the review exhibit.
Secrets have no bus read path by construction, confirmed by a connectivity check, not by policy text.
Spare bits are reserved in the map with a spend procedure, not silently absorbed by neighbouring fields.
Pack and unpack the allocation in the build: the script above is the seed of that check, extended with field-level read-back after the reset sequence. Blow one spare bit in a scratch model and confirm nothing changes; blow one trim bit and confirm only the trimmed block moves. A field that affects two blocks is misallocated.
They share the tester-time programming flow and the at-reset read-out engine, not a security level. Sharing the array saves a second macro; the security comes from access control on the shadow registers, which keeps secrets off any bus while repair values route to the wrappers.