Motivation¶
Why ml-hpi Exists¶
Modern SoC verification demands that the same test intent execute across a chain of increasingly complex environments: block-level RTL simulation, subsystem integration, full-chip simulation, emulation, and silicon bring-up. Today, teams handle this by duplicating effort — rewriting the same test logic in each environment, maintaining diverging copies, and rebuilding interface glue every time a new language or methodology enters the flow.
The root cause is the absence of a shared interface contract. A UVM sequence
that drives a DMA engine at block level typically reaches into the UVM
component hierarchy directly — env.dma_agent.reg_driver,
env.dma_agent.irq_monitor — so it cannot compile in any other environment.
The typical response is copy-paste: clone the sequence, patch every
environment reference, and maintain a second fork forever.
The fix is well-known in software engineering: program to an interface, not
an implementation. If the sequence interacts with the environment through a
DmaIf handle — an object that exposes do_transfer as a method — then
any environment capable of providing a DmaIf implementation can run the
sequence unchanged. Block-level, subsystem, SoC, virtual platform, and
emulation environments each supply a different implementation of the same
interface; the test logic is never touched.
The Multi-Language Challenge¶
Applying this principle to hardware verification introduces one further
complication: verification spans multiple languages. Defining DmaIf in
SystemVerilog does not make it available in C++, Python, or PSS. Without a
language-neutral specification, each new language context requires a
hand-written interface definition and a hand-written binding layer — and the
two must be kept in sync forever.
ml-hpi solves this with a semantic model: a language-neutral description of
interfaces, methods, types, hierarchy, and per-method attributes. The model
can be recorded in YAML/JSON, but it can equally be expressed in a host
language. A SystemVerilog interface class hierarchy is a complete, valid
representation of the same model; an ml-hpi extraction tool derives the
YAML/JSON form automatically. From that derived representation the toolchain
generates idiomatic bindings for all target languages in one step — the user
maintains one source artifact and gets everything else for free.
Verification-Specific Requirements¶
Two requirements specific to verification environments go beyond what a generic IDL can provide:
Hierarchical context.
Real designs contain many instances of the same IP block — four DMA channels,
eight PCIe ports. ml-hpi models interfaces as class hierarchies with named
field members (a single sub-interface) and array members (an indexed
collection). A test navigates naturally: chip.uarts_at(1).send(ch).
Each instance is a typed object; no handle bookkeeping is required. The
generated binding layer handles the mechanics of crossing flat DPI/FFI
boundaries while preserving the object model transparently.
Blocking vs. non-blocking calls.
Whether a method must consume simulated time before returning is a property of
the operation, not the language. ml-hpi captures a blocking attribute
per method. Generators emit the correct construct for each language: a
pure virtual task in SystemVerilog, an async def coroutine in Python,
a callback-based completion import in C. In PSS, the same attribute drives the
target-time / solve-time distinction. The interface author states what each
method does; the generator handles how each language expresses it.
Extending to PSS¶
The same interface spec that enables UVM sequence reuse across integration
levels also serves as the bridge to PSS (Accellera Portable Test and Stimulus
Standard). PSS actions call platform functionality through function import
declarations that must be kept in sync with DPI stubs and platform dispatch
logic — hand work spread across three languages. Because ml-hpi already
captures all attributes PSS needs (blocking, target, solve), the
toolchain generates the complete PSS component and function import
declarations in the same step that produces C++ and Python bindings.
The practical workflow is:
SV interface class --> (ml-hpi derives IDL) --> PSS component + function imports
+--> C++ / Python / C bindings
The IDL is a hidden intermediary — the SV interface class remains the
single maintained artifact, and the PSS infrastructure is never hand-written.