Comportability in Pavona

A Guide for Design and Verification Engineers


What Is Comportability? (Start Here)

The word comes from Johnson’s 1808 Dictionary of the English Language:

“Comportable, a. consistent, suitable, fit”

In Pavona, comportability is a design philosophy and enforceable standard which requires every hardware IP block to follow a common set of interfaces, conventions, and behaviors. This facilitates a subsystem or an entire SoC can be assembled, verified, and maintained in a uniform, scalable way.

Think of it like a building ordinance for hardware IP. Just as a building ordinance’s ensures every contractor uses standard electrical outlets, plumbing fittings, and load bearing rules; comportability ensures every IP block exposes registers the same way, signals interrupts the same way, raises security alerts the same way, and connects to the bus the same way.

The payoff: tools, firmware, and verification infrastructure can treat all blocks uniformly. No block-specific special cases (However there can be exceptional block level outliers).


Why Does Comportability Exist?

With comportability, a new IP block that follows the spec gets:

  • Auto-generated register RTL, RAL model, and documentation from a single .hjson file
  • Auto-generated top-level connections for bus, alerts, and inter-module signals
  • Shared DV infrastructure that gives you CSR tests, interrupt tests, and alert tests for free
  • Compliance gating through a formal checklist before a block can be taped out

The result: roughly a significant portion of RTL development and DV effort is handled by shared infrastructure, leaving the block owner to focus only on the block’s unique functionality. At the top-level, interconnect is fully checked and generated by the tooling.


The Two .hjson Files Every Design and DV Engineer Must Know

Comportability in practice is anchored by two Hjson configuration files. Understanding them is the most important first step for anyone contributing to Pavona DV.

FileOwnerPurpose
hw/ip/<block>/data/<block>.hjsonDesign + DVDeclares what the block is: registers, interrupts, alerts, clocks, countermeasures
hw/ip/<block>/dv/<block>_sim_cfg.hjsonDVDeclares how the block is simulated: DUT, testbench, tool, testplan, tests, regressions

The design <block>.hjson drives reggen, tlgen, and topgen to auto-generate RTL and connectivity. <block>_sim_cfg.hjson drives dvsim.py to build and run simulations. Together they form the machine-readable specification that make Pavona’s DV automation possible.

Key Insight for New Contributors: Two files unlock the entire comportability DV framework for a block — the design .hjson (what the block is) and the sim_cfg.hjson (how to simulate it). Get these right with the correct imports, and roughly 30-40% of the DV work is done by shared infrastructure before a single block-specific test is written.


The Design <block>.hjson — The Comportability Declaration

Every comportable IP ships with a block-level Hjson configuration file (<block>.hjson) in its data/ directory. This is the single source of truth for everything the block declares about itself.

A simplified example for a UART:

{
  name: "uart",
  clocking: [
    {clock: "clk", reset: "rst_n"}
  ],
  bus_interfaces: [
    { protocol: "tlul", direction: "device", racl_support: true}
  ],
  available_input_list: [
    { name: "rx", desc: "Receive bit" }
  ],
  available_output_list: [
    { name: "tx", desc: "Transmit bit" }
  ],
  interrupt_list: [
    { name: "tx_watermark", desc: "Raised if the transmit FIFO is past high water mark", type: "status" },
    { name: "rx_overflow",  desc: "Raised if the receive FIFO has overflowed" }
  ],
  alert_list: [
    { name: "fatal_fault", desc: This fatal alert is triggered when a fatal TL-UL bus integrity fault is detected." }
  ],
  countermeasures: [
    { name: "BUS.INTEGRITY", desc: "End-to-end bus integrity scheme." }
  ],
  regwidth: "32",
  registers: [ ... ]
}

All tooling reads this file. reggen generates the register RTL, RAL model, INTR_STATE/ENABLE/TEST registers, ALERT_TEST register, software headers, and HTML documentation. topgen uses it to auto-wire the top level.

Documentation: All IP must use the standard Pavona specification template. Register documentation is auto-generated by reggen from the <block>.hjson.


Comportable Item List

The following items are declared in the design <block>.hjson. Important items are required for every peripheral; optional ones are included as needed. This is not a complete list: see util/reggen for details.

FeatureImportant/OptionalDescription
ClockingImportantDeclare primary functional clock and any other clocks needed
Bus InterfacesImportantAt least one TL-UL device interface required
RegistersImportantAll CSRs defined in reggen format
Available IOOptionalPeripheral pins available for chip-level IO
InterruptsOptionalSignals sent to the processor interrupt controller
AlertsOptionalSecurity-critical signals sent to the alert handler
Inter-module SignalsOptionalBundled signals connecting to other peripherals
Security CountermeasuresOptional (expected for security-critical IP)Named protection mechanisms against FI/SCA attacks

Feature Details

Clocking and Reset

Each peripheral specifies its clocking using the clocking field. One item is designated the primary clock — this is the clock that drives the bus interface; Additional clocks can be added as needed.

Resets in Pavona are asynchronous active-low with synchronous deassertion:

  • Reset assertion can happen at any time (asynchronous)
  • Reset release is synchronized to the associated clock edge

Security-sensitive storage elements require extra care — for example, resetting to a randomized value rather than all-zeros, to prevent an attacker inferring sensitive state from Hamming distance analysis.


Bus Interface — TL-UL

All comportable peripherals connect to the chip bus using TL-UL (TileLink-Uncached-Lite). This is currently the only supported bus protocol. Every peripheral must declare at least one device direction interface. Some peripherals (e.g., DMA) also act as a host.

The TL-UL protocol handles addressed register reads and writes, error signaling (d_error) for invalid accesses, and end-to-end bus integrity (ECC on data and address).


Available IO

Peripherals can optionally expose pins for chip-level IO using available_input_list, available_output_list, and available_inout_list. These map to module ports: For example,

  • An input named rx appears as an input port named cio_rx_i;
  • an output port named tx appears as two output ports named cio_tx_o and cio_tx_en_o; and
  • an inout port appears as all three signals above.

Pin multiplexing and pad control are handled centrally by the pinmux module at the top level — not by the peripheral itself.


Registers

All registers are defined in the design <block>.hjson file. From this single definition, reggen auto-generates register RTL, a UVM RAL model, software header files, and HTML documentation. This means you never manually write register RTL or a RAL model for a comportable block.

More details is found in documentation for util/reggen


Interrupts

Peripherals declare interrupts in interrupt_list. For each declared interrupt, reggen automatically creates a field in three registers at the top of the peripheral’s address map:

RegisterOffsetDescription
INTR_STATE0x0Current state of each interrupt; RO or W1C depending on type
INTR_ENABLE0x4Enables/masks INTR_STATE bits to produce the wired interrupt output
INTR_TEST0x8Write-only; forces interrupt assertion for testing

The output interrupt wire: intr_name_o = INTR_STATE & INTR_ENABLE. INTR_STATE always reflects raw hardware state regardless of INTR_ENABLE.

Two Interrupt Types

Event Type (default): An instantaneous event (e.g., a counter crossing a threshold) latches INTR_STATE high. Software clears it by writing 1 to the bit (W1C). If the event is still active when software clears it, the bit sets again immediately.

{signal: [
  {name: 'clk_i',      wave: 'p.............'},
  {name: 'hw_i',       wave: '0..1......0...'},
  {name: 'INTR_STATE', wave: '0...1......0..'},
  {name: 'intr_o',     wave: '0....1....0...'},
  {name: 'SW w1c',     wave: '0.......10....'},
]}

Status Type: A persistent condition (e.g., FIFO non-empty) drives INTR_STATE directly. INTR_STATE is RO — software cannot W1C it. The interrupt only deasserts when the root cause is addressed. If software needs to defer handling, it must mask INTR_ENABLE.

{signal: [
  {name: 'clk_i',                  wave: 'p.............'},
  {name: 'hw_i',                   wave: '0..1......0...'},
  {name: 'INTR_STATE',             wave: '0...1......0..'},
  {name: 'intr_o',                 wave: '0...1......0..'},
  {name: 'SW addresses the cause', wave: '0........10...'},
]}

Alerts

Alerts are security-critical signals sent from a peripheral to the central Alert Handler module (not directly to the processor). Each alert is transmitted as a differential signal pair via prim_alert_sender, to protect against single-point failures.

There are two categories of alerts:

  • Recoverable (recov_*): One-time triggered for recoverable error conditions; Alert sender fires once when the error is asserted.
  • Fatal (fatal_*) : Continuously triggered until system reset; Used for terminal conditions. Should also trigger local security countermeasures (e.g., moving an FSM into a locked terminal state).

reggen by default auto-generates an ALERT_TEST register for every peripheral with alerts — a write-only register that lets software force-trigger each alert for testing.

Common guideline: one fatal alert + one recoverable alert per peripheral to keep the system-level alert count manageable. The following table lists examples of events that cause alerts and whether they are considered recoverable or fatal. Examples drawn from multiple peripherals. A given peripheral would expose only the rows relevant to it.

Error EventRegular IRQRecoverable AlertFatal Alert
ECC correctable in NVMOptionalYes
ECC uncorrectable in FlashOptionalYes
ECC uncorrectable in OTPOptionalYes
Any ECC/Parity error in SRAMsOptionalYes
Glitch detectors (invalid FSM encoding)OptionalYes
Incorrect usage of security IPOptionalYes
Incorrect usage of regular IPYes

Inter-Module Signals

Signals connecting peripherals to each other (beyond interrupts and alerts) are declared in inter_signal_list. The topgen tool uses this to auto-wire the top level.

There are two signal types:

  • req_rsp: Request-response pair. The requester sends a request struct; the responder returns a response struct. Example: flash_ctrl sending read/write/erase requests to the flash macro.
  • uni: Unidirectional one-way signal. Used for broadcasts or signals that need no response.
AttributeDescription
namePort name; for req_rsp type generates name_req and name_rsp ports
structData structure type (e.g., a package-defined struct, or logic for simple signals)
packageSystemVerilog package containing the struct definition
typereq_rsp or uni
actRole: req or rsp (for req_rsp); req or rcv (for uni)
widthVector width if connecting to multiple peripherals

Security Countermeasures

If this IP block is considered security-critical, it will probably have design features that try to mitigate against attacks like fault injection or side channel analysis. These features can be loosely categorized and named with identifiers of the following form:

[UNIQUIFIER.]ASSET.CM_TYPE

Here, ASSET is the asset that is being protected. This might be secret information like a key, or it might be internal state like a processor’s control flow. The countermeasure that is providing the protection is named with CM_TYPE. The UNIQUIFIER label is optional and allows to add a custom prefix to make the identifier unique or more concise.

Below are a few examples for generic and more concise labels following this format:

LFSR.REDUN or MASKING_PRNG.LFSR.REDUN
FSM.SPARSE or HASHING_INTERFACE.FSM.SPARSE
INTERSIG.MUBI or ALERT.INTERSIG.MUBI

The following standardized assets are defined:

Asset nameIntended meaning
KEYA key (secret data)
ADDRAn address
DATA_REGA configuration data register that doesn’t come from software (such as Keccak state)
DATA_REG_SWA data holding register that is manipulated by software
CTRL_FLOWThe control flow of software or a module
CTRLLogic used to steer hardware behavior
CONFIGSoftware-supplied configuration, programmed through the comportable register interface
LFSRA linear feedback shift register
RNGA random number generator
CTRA counter
FSMA finite state machine
MEMA generic data memory; volatile or non-volatile
CLKA clock
RSTA reset signal
BUSData transferred on a bus
INTERSIGA non-bus signal between two IP blocks
MUXA multiplexer that controls propagation of sensitive data
CONSTANTSA netlist constant
STATEAn internal state signal (other than FSM state, which is covered by the FSM label)
TOKENA cryptographic token
LOGICAny logic. This is a very broad category: avoid if possible and give an instance or net name if not.

The following standardized countermeasures are defined:

Countermeasure nameIntended meaningCommonly associated assets
MUBIA signal is multi-bit encodedCTRL, CONFIG, CONSTANTS, INTERSIG
SPARSEA signal is sparsely encodedFSM
DIFFA signal is differentially encodedCTRL, CTR
REDUNThere are redundant versions of the assetADDR, CTRL, CONFIG, CTR
REGWENA register write enable is used to protect the asset from write accessCONFIG, MEM
REGWEN_MUBIA multi-bit encoded register write enable is used to protect the asset from write accessCONFIG, MEM
SHADOWThe asset has a shadow replica to cross-check againstCONFIG
REGRENA register write enable is used to protect the asset from read accessCONFIG, MEM
SCRAMBLEThe asset is scrambledCONFIG, MEM
INTEGRITYThe asset has integrity protection from a computed value such as a checksumCONFIG, REG, MEM
READBACKA readback check is performed to validate that the asset has been correctly modified or fetchedMEM
ADDR_INFECTIONThe asset is infected using the read addressMEM
CONSISTENCYThis asset is checked for consistency other than by associating integrity bitsCTRL, RST
DIGESTSimilar to integrity but more computationally intensive, implying a full hash functionCONFIG, REG, MEM
LC_GATEDAccess to the asset is qualified by life-cycle stateREG, MEM, CONSTANTS, CONFIG
BKGN_CHKThe asset is protected with a continuous background health check
GLITCH_DETECTThe asset is protected by an analog glitch detectorCTRL, FSM, CLK, RST
SW_UNREADABLEThe asset is not readable by softwareMEM, KEY
SW_UNWRITABLEThe asset is not writable by softwareMEM, KEY
SW_NOACCESSThe asset is not writable nor readable by software (SW_UNWRITABLE and SW_UNREADABLE at the same time)MEM, KEY
SIDELOADThe asset can be loaded without exposing it to softwareKEY
SEC_WIPEThe asset is initialized or cleared using pseudo-random dataKEY, DATA_REG, MEM
SCAA countermeasure that provides side-channel attack resistance
MASKINGA more specific version of SCA where an asset is split into shares
LOCAL_ESCA local escalation event is triggered when an attack is detected
GLOBAL_ESCA global escalation event is triggered when an attack is detected
UNPREDICTABLEBehaviour is unpredictable to frustrate repeatable FI attacks
TERMINALThe asset goes into a terminal state that no longer responds to any stimulus
COUNTThe number of operations or items processed is counted which can be checked by software to ensure the correct number have occurred
CMCatch-all for countermeasures that cannot be further specified. This is a very broad category: avoid if possible and give an instance or net name if not.

Design Verification (DV) for Comportability

Because every comportable IP follows the same spec, DV can be built generically across all blocks. This shared DV infrastructure lives in cip_lib (Comportable IP Library). The first file a DV engineer works with on any block — is the <block>_sim_cfg.hjson.


The <block>_sim_cfg.hjson — The DV Entry Point

Location: hw/ip/<block>/dv/<block>_sim_cfg.hjson For templated blocks the editable file is located at: hw/ip_templates/<block>/dv/<block>_sim_cfg.hjson.tpl. This is used to generate a top specific hjson file located at hw/<specific_top>/ip_autogen/<block>/dv/<block>_sim_cfg.hjson

This is the mandatory input to dvsim.py — Pavona’s command-line simulation and regression manager. It is the single entry point for all DV activity on a block. Without it, you cannot build or run any simulation. Just as the design .hjson declares what a block is, the sim_cfg.hjson declares how that block is simulated and regressed.

It tells dvsim.py everything needed to build a simulation executable and run tests:

  • Which RTL module is the DUT and which testbench top to elaborate
  • Which simulator to use for sign-off (VCS, Xcelium)
  • Which FuseSoC core file provides the RTL + DV file list
  • Which testplan to track DV progress against
  • Which RAL spec to use for auto-generating the RAL model at build time
  • What simulation bind-file tops (coverage, assertions) to include
  • What tests exist, their build/run options, and which regression suites they belong to

Every DV action flows through this file:

# Run a single smoke test
util/dvsim/dvsim.py hw/ip/uart/dv/uart_sim_cfg.hjson -i uart_smoke

# Run the CSR hw_reset test (auto-generated from .hjson)
util/dvsim/dvsim.py hw/ip/uart/dv/uart_sim_cfg.hjson -i uart_csr_hw_reset

# Run with waveforms for debugging
util/dvsim/dvsim.py hw/ip/uart/dv/uart_sim_cfg.hjson -i uart_smoke --waves fsdb

# Run the full V1 regression (comportability tests)
util/dvsim/dvsim.py hw/ip/uart/dv/uart_sim_cfg.hjson -i v1

# Run the full V2 regression with coverage
util/dvsim/dvsim.py hw/ip/uart/dv/uart_sim_cfg.hjson -i v2

Key Fields

The following table shows key fields of a sim config. The annotated example below puts all of these fields together.

FieldDescription
nameDUT name — typically the block name (e.g., uart)
dutTop-level RTL module name
tbTop-level testbench SV module name
toolDefault simulator for sign-off (typically vcs)
fusesoc_coreFuseSoC VLNV identifier that resolves the complete RTL + DV filelist
testplanPath to the block’s <block>_testplan.hjson — used to track DV progress
ral_specPath to the block’s design .hjson; dvsim invokes ralgen at build time to auto-generate the RAL model
sim_topsAdditional top-level SV modules to elaborate (e.g., bind files for coverage, assertions, FI)
import_cfgsShared sim cfg files to import (typically common_sim_cfg.hjson)
build_modesNamed sets of compile-time options (e.g., different parameters, tool-specific flags)
run_modesNamed sets of simulation-time options (plusargs, UVM verbosity, etc.)
testsList of test specifications — each names a UVM test class and its build/run options
regressionsNamed groups of tests: sanity, nightly, v1, v2, v3 — tied to DV stage gates

Annotated Example

// Copyright Pavona contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{
  // Name of the sim cfg - same as the block name.
  name: uart

  // Top-level RTL DUT module.
  dut: uart

  // Top-level testbench SV module.
  tb: tb

  // Default sign-off simulator.
  tool: vcs

  // FuseSoC core file that resolves the RTL + DV filelist.
  fusesoc_core: lowrisc:dv:uart_sim:0.1

  // Points to the block testplan .hjson for tracking DV progress.
  testplan: "{proj_root}/hw/ip/uart/data/uart_testplan.hjson"

  // RAL spec: dvsim invokes ralgen at build time to auto-generate the RAL model.
  ral_spec: "{proj_root}/hw/ip/uart/data/uart.hjson"

  // Additional top-level elaboration targets: bind files for coverage and
  // countermeasure fault injection.
  sim_tops: ["uart_bind", "uart_cov_bind"]

  // Import the shared sim cfg common to all comportable CIP blocks.
  // This pulls in common build options, coverage config, and tool flags.
  import_cfgs: ["{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson"]

  // Block-specific tests.
  tests: [
    {
      name: uart_smoke
      uvm_test_seq: uart_smoke_vseq
    }
    {
      name: uart_tx_rx
      uvm_test_seq: uart_tx_rx_vseq
      run_opts: ["+zero_delays=1"]
    }
  ]

  // Regression suites mapped to DV stage gates.
  regressions: [
    {
      name: sanity        // Quick CI check - smoke only
      tests: ["uart_smoke"]
    }
    {
      name: v1            // D1 gate: comportability tests
      tests: ["uart_smoke", "uart_csr_hw_reset", "uart_csr_rw", "uart_csr_bit_bash"]
    }
    {
      name: v2            // D2 gate: full functional + alert/interrupt tests
      tests: ["all"]
    }
  ]
}

How sim_cfg.hjson Connects to Comportability

The critical link is through the testplan and import_cfgs fields.

The block’s testplan (<block>_testplan.hjson) imports shared comportability testplans from the common dvsim library. These shared testplans define all the standard CSR, alert, interrupt, and TL-UL test points that every comportable block must satisfy.

// uart_testplan.hjson
{
  name: "uart"
  import_testplans: [
    "hw/dv/tools/dvsim/testplans/csr_testplan.hjson",
    "hw/dv/tools/dvsim/testplans/alert_test_testplan.hjson",
    "hw/dv/tools/dvsim/testplans/intr_test_testplan.hjson",
    "hw/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson",
    "hw/dv/tools/dvsim/testplans/stress_all_with_reset_testplan.hjson",
    "uart_sec_cm_testplan.hjson"   // countermeasure tests
  ]
  testpoints: [
    // Block-specific tests only — all comportability tests come from imports above
    { name: smoke, ... }
    { name: tx_rx, ... }
  ]
}

This means every comportability test — CSR checks, alert tests, interrupt tests, TL-UL access type tests is automatically included in the block’s regression simply by the import. The block-specific testplan only adds its own functional testpoints on top.

Similarly, import_cfgs: common_sim_cfg.hjson pulls in shared build options, simulator flags, and coverage configuration common to all comportable blocks and will not need to configure these per-block.

The result: a sim_cfg.hjson with the correct imports gives you a complete, runnable regression covering all comportability requirements from the moment you first build it.

Auto-Generation with uvmdvgen

For a brand-new block, the uvmdvgen tool auto-generates a skeleton sim_cfg.hjson along with the entire initial DV environment:

util/uvmdvgen.py <block_name> -e -c -hi -ha -eo hw/ip/<block>

Key flags: -c extends from cip_lib (for a comportable IP), -hi adds interrupt interface support, -ha adds alert interface support. The generated sim_cfg.hjson already has the correct import_cfgs, ral_spec, and testplan imports.


The cip_lib Class Hierarchy

Every comportable IP’s testbench extends from cip_lib base classes:

uvm_env
  +-- cip_base_env            <- in cip_lib; auto-instantiates TL-UL agent,
        +-- uart_env              alert agents, interrupt interfaces

uvm_scoreboard
  +-- cip_base_scoreboard     <- handles TL-UL, CSR, interrupt, alert checking
        +-- uart_scoreboard   <- adds block-specific checking

uvm_sequence
  +-- cip_base_vseq           <- CSR tests, TL-UL integrity, alert/interrupt tests
        +-- uart_base_vseq    <- block-specific sequences

By inheriting from these, every block gets standard comportability checks for free.


1. Registers : Auto-Generated RAL + CSR Tests

reggen generates a UVM RAL model from the design .hjson. dvsim invokes ralgen at build time (via the ral_spec field in sim_cfg.hjson) to produce this model. DV is then enabled to run standard CSR test suite on every comportable block:

TestWhat It Checks
csr_hw_resetAll reset values match the spec
csr_rwRead/write access works correctly for each register
csr_bit_bashBit-level access types: RO, RW, WO, W1C, RC, etc.
csr_aliasingNo two addresses alias to the same register unexpectedly
csr_mem_walkFor embedded memories: walks all addresses

These can be run on every block automatically from shared sequences in cip_base_vseq. A correct design .hjson means these tests pass with zero block-specific code.


2. TL-UL Interface : Shared TL-UL Agent

The shared TL-UL UVM agent drives and monitors every comportable block’s mandatory device interface. It provides protocol checking on every transaction, integrity error injection (ECC faults on data/address bits), and error response checking (d_error assertion on integrity violations). The shared sequence tl_intg_err_vseq handles bus integrity fault injection on every comportable block.


3. Interrupts : Shared Interrupt Verification

Because the spec mandates INTR_STATE, INTR_ENABLE, and INTR_TEST with fixed behavior, cip_lib provides scoreboard hooks that work for any comportable block:

  • Monitor when the interrupt condition occurs in the DUT
  • Predict expected INTR_STATE bit using the RAL model
  • Check intr_o = INTR_STATE & INTR_ENABLE
  • Use INTR_TEST to force-trigger interrupts and verify the path end-to-end

The scoreboard distinguishes between Event type (checks W1C clearing) and Status type (checks interrupt stays asserted until root cause resolved).


4. Alerts : Shared Alert Agent + Sequences

Every comportable IP with alerts gets a shared alert UVM agent connected in the testbench. DV verifies that alerts fire on the expected error condition, the alert handshake (ping/response between prim_alert_sender and the alert handler) completes correctly, recoverable alerts fire once while fatal alerts keep firing until reset, and ALERT_TEST can force-trigger each alert end-to-end.


5. Security Countermeasures : Standardized FI Tests

Countermeasures declared in the design .hjson directly drive what DV must test. Below table is an example:

Declared CountermeasureWhat DV Tests
BUS.INTEGRITYInject TL-UL ECC errors; expect alert + d_error
FSM.SPARSEForce FSM into invalid encoding; expect fatal alert + terminal behavior
CONFIG.SHADOWTest shadow register update errors and storage errors
MEM.SCRAMBLEVerify scrambling is applied and read-back is correct

Pavona has standardized sequences for each countermeasure type, largely reusable across blocks.


6. Shadow Register Verification

For security-critical configuration registers, Pavona uses shadow registers: a primary register and a hidden shadow copy. Any write must go through a two-phase commit. If the two copies disagree, an update error is flagged. cip_lib sequences verify write phase consistency, update errors when primary and shadow disagree, storage errors injected via fault injection, and that fatal alerts are raised for unrecoverable shadow errors.


7. Comportability Compliance Checklist

Pavona maintains a formal Hardware Design & DV Checklist. Before a block advances through design and verification stages, comportability sign-offs must be completed across both the Design (D) and Verification (V) stage gates:

Checklist ItemStage
Design spec 90% complete, all features definedD1
Design .hjson complete with CSRs defined and reviewedD1
IP top-level .sv meets comportability requirementsD1
IP instantiable in top-level (compiles, no X propagation on TL-UL, no spurious alerts/interrupts)D1
ASSERT_KNOWN added on all IP outputsD1
Security countermeasures scoped and reviewed with Security WGD1
Lint flow set up and compilingD1
All features implemented (feature complete)D2
Feature and port specifications frozenD2
Block diagram and interface documentation updatedD2
Integration guide documented for non-comportable specificsD2
Security countermeasures documented (custom + standard)D2
Lint, CDC, RDC flows passing cleanD2
Area and timing checks completed (FPGA or ASIC synthesis)D2
Countermeasure assets listed in canonical format in IP .hjsonD2S
All security countermeasures implemented per Secure HW Design GuidelinesD2S
Sparse FSM encoding, prim_count, prim_mubi_pkg usage verifiedD2S
Shadow registers implemented for critical control storageD2S
Security council review of assets and countermeasures completeD2S
All TODOs resolved; lint, CDC, RDC flows fully clean and signed offD3
Independent RTL design review completedD3
SW-visible changes and errata reviewed by SW teamD3
DV document drafted (goals, strategy, TB architecture, coverage rationale)V1
Testplan completed in Hjson (testpoints mapped to features, coverage plan)V1
sim_cfg.hjson created with correct importsV1
TB top created: DUT instantiated, TL-UL/clk/rst/interrupts/alerts connectedV1
UVM environment created (agents, UVCs, TLM ports, scoreboard shell)V1
RAL model generation automated via regtoolV1
CSR check generation automated and bound in TBV1
All CSR/memory test suites passing (hw_reset, rw, bit_bash, aliasing, mem_walk)V1
Smoke test exercising main datapath passingV1
Structural coverage model checked in; functional coverage shell createdV1
Nightly regression set up with multiple seedsV1
Alt-tool smoke regression passingV1
TB lint (VeribleLint) set up in nightly regressionV1
Pre-verified sub-modules at V1 or higherV1
Testplan reviewed by designer, DV peers, SW, chip lead, security architectV1
DV document fully completed; design deltas capturedV2
Functional coverage plan fully implemented and sampledV2
All interfaces exercised; all planned assertions enabledV2
Scoreboard end-to-end checks enabledV2
All testplan tests written and passing (≥1 seed each)V2
Interrupt tests implemented and passingV2
Alert tests implemented and passingV2
TL-UL integrity error tests passingV2
Nightly regression ≥90% passingV2
Code coverage (line, toggle, FSM, branch, assertion) ≥90%V2
Functional coverage ≥90%V2
Security countermeasures planned and documented in testplanV2
All P0/P1 bugs closed; all P2/P3 bugs root-causedV2
DV document + testplan re-reviewed (coverage exclusions scrutinised)V2
Security countermeasures testplan completed (auto-generated via reggen, imported)V2S
All countermeasure tests implemented and verified in simulationV2S
FPV security countermeasure assertions provenV2S
Coverage exclusions for sec_cm blocks removed; UNR re-generatedV2S
Sec_cm DV effort reviewed by designer, DV peers, security architectV2S
X-propagation analysis completed, no unsuitable logic reportedV3
Nightly regression 100% passing (≥1 week soak)V3
Code coverage at 100% (line, toggle, FSM, branch, assertion)V3
Functional coverage at 100%V3
All TB TODOs resolved; no tool warningsV3
TB lint flow clean and signed offV3
Pre-verified sub-modules at V3V3
All design and testbench bugs closedV3

Practical Onboarding: Adding a New Comportable IP

Here is the end-to-end workflow for a new peripheral from both design and DV perspectives:

Step 1: Write the design .hjson Declare clocks, bus interfaces, registers, interrupts, alerts, inter-signals, and countermeasures. Location: hw/ip//data/.hjson

Step 2: Run reggen Auto-generates: - Register RTL (the register file submodule) - UVM RAL model - INTR_STATE/ENABLE/TEST registers - ALERT_TEST register - Software headers and HTML documentation

Step 3: Run topgen Auto-wires inter-module signals and alert/interrupt connections at the top level.

Step 4: Bootstrap with uvmdvgen (strongly recommended) util/uvmdvgen/uvmdvgen.py -e -c -hi -ha -eo hw/ip//dv

    Auto-generates:
      - <block>_sim_cfg.hjson with correct import_cfgs and ral_spec
      - <block>_testplan.hjson importing shared comportability testplans
      - cip_lib-based UVM environment skeleton
      - Testbench, base sequences, scoreboard shell
      - FuseSoC core file for the DV filelist

Step 5: Complete sim_cfg.hjson - Verify dut, tb, fusesoc_core, ral_spec fields - Confirm testplan imports: csr_testplan.hjson, alert_test_testplan.hjson, intr_test_testplan.hjson - Add your block-specific tests to tests[] - Define regression suites: sanity, v1, v2, v3

Step 6: Create the UVM environment Extend cip_base_env, cip_base_scoreboard, cip_base_vseq. Connect DUT’s TL-UL, alert, and interrupt ports.

Step 7: Run shared comportability tests util/dvsim/dvsim.py hw/ip//dv/_sim_cfg.hjson -i v1 All CSR, TL-UL, alert, and interrupt tests run immediately.

Step 8: Write block-specific functional tests Cover the unique functionality of your IP. Add them to tests[] and regressions[] in sim_cfg.hjson.

Step 9: Complete the DV checklist util/dvsim/dvsim.py hw/ip//dv/_sim_cfg.hjson -i v2 Sign off each comportability item for D1/D2/D3 gates.