Part 8 · Checking & Coverage · Intermediate
Algorithmic (Untimed) Reference Models
Pure computation models — CRC example, package functions, and TLM wrapper components.
Untimed transforms
Algorithmic reference models compute a pure function of input data: CRC over a byte stream, AES encryption of a payload, checksum accumulation, parity generation. They consume no simulation time, hold no protocol state beyond the computation, and run entirely inside a write() call or a standalone predict() function.
The preferred pattern is a package function for the spec algorithm (unit-testable in isolation) wrapped by a thin uvm_component that implements the analysis imp and analysis port for TLM connectivity.
[CHECK] algorithmic model data flow
byte_pkt (observed payload) ──► crc32_spec(data[]) ──► crc_result
│
▼
compare with DUT CRC field
(via scoreboard exp vs act)[UVM] package + component split
ref_model_pkg::crc32_spec() ← unit tests, spec from datasheet
▲
│ called from
│
crc_ref_model::write(pkt) ← TLM only: req_imp + apCRC reference model component
Ethernet and storage controllers often expose a hardware CRC engine. The verification plan checks that the DUT-computed CRC matches the IEEE 802.3 polynomial. The model implements the spec algorithm — bit-reversed polynomial 0xEDB88320 for CRC-32 — independent of whether the RTL uses a linear-feedback shift register, lookup table, or parallel tree.
class crc_ref_model extends uvm_component;
`uvm_component_utils(crc_ref_model)
uvm_analysis_imp #(byte_pkt, crc_ref_model) pkt_in;
uvm_analysis_port #(crc_result) ap;
function new(string name, uvm_component parent);
super.new(name, parent);
pkt_in = new("pkt_in", this);
ap = new("ap", this);
endfunction
function void write(byte_pkt pkt);
crc_result res = crc_result::type_id::create("res");
res.id = pkt.id;
res.crc = crc32_spec(pkt.data);
`uvm_info("CRC_REF", $sformatf("id=%0d crc=%08h", res.id, res.crc), UVM_HIGH)
ap.write(res);
endfunction
// Spec algorithm — lives here or in ref_model_pkg for unit tests
function bit [31:0] crc32_spec(byte data[]);
bit [31:0] crc = 32'hFFFFFFFF;
foreach (data[i]) crc = update_crc_byte(crc, data[i]);
return ~crc;
endfunction
function bit [31:0] update_crc_byte(bit [31:0] crc, byte d);
crc ^= d;
for (int b = 0; b < 8; b++)
crc = (crc[0]) ? ((crc >> 1) ^ 32'hEDB88320) : (crc >> 1);
return crc;
endfunction
endclassNo virtual interface — zero simulation time consumed in the model.
Spec algorithm from datasheet — independent of RTL implementation (LFSR vs table).
Package function variant allows directed unit tests without UVM overhead.
Component wrapper connects pkt_in to monitor, ap to scoreboard exp_imp.
Include transaction ID in output so scoreboard can pair out-of-order CRC results.
Package-level unit test pattern
Test before env integration
Run directed tests on crc32_spec() with known vectors from the spec appendix before wiring into the environment. Catches polynomial, bit-order, and init-value bugs without simulation overhead.
// ref_model_pkg — no UVM required
package ref_model_pkg;
function automatic bit [31:0] crc32_spec(byte data[]);
// ... same implementation ...
endfunction
endpackage
// Directed test (module or class)
initial begin
byte vec[] = '{8'h00, 8'h01, 8'h02};
bit [31:0] exp_crc = 32'hXXXX_XXXX; // from spec appendix
assert (ref_model_pkg::crc32_spec(vec) == exp_crc);
endOther algorithmic examples
AES encrypt/decrypt — NIST test vectors in package, component wraps for block-aligned bus transactions.
IP checksum — RFC 1071 one's complement sum over payload bytes.
ECC encode — matrix multiply over GF(2); verify syndrome on injected bit errors.
Key takeaways
Algorithmic models: lowest cost, highest independence from RTL.
Package function + thin component = testable spec + TLM connectivity.
Common pitfalls
Reimplementing RTL CRC micro-architecture instead of spec polynomial — couples to implementation.
Missing transaction ID in output — scoreboard cannot pair on out-of-order buses.
Scheduling delays in algorithmic model — unnecessary; latency is not the check target.