Q017FreeDesign Verification
APB Protocol Monitor without SVA
Question
Implement the supplied SystemVerilog APB monitor class for one selected peripheral, using 32-bit PADDR/PWDATA and four PSTRB lanes. Call sample once per rising clock with known-value snapshots; an upstream sampler handles X/Z detection and any optional APB signals absent from this interface. Call reset_state instead of sample on each sampled reset assertion. Reset discards any partial transfer and preserves lifetime counters. max_wait is the constructor argument, an unsigned 32-bit number of allowed selected ACCESS samples with PREADY=0 (zero is valid). Report one timeout on wait sample max_wait+1; a later valid completion still counts. Limit each lifetime counter to 0..2^31-1. Diagnose each malformed observed sample, abandon that transfer, and accept a fresh valid SETUP on the same sample when present. A stability violation abandons the transfer without counting completion. An unselected idle peripheral must ignore PENABLE, which may be shared with another peripheral.
Implementation scaffold
class ApbMonitor;
typedef enum { IDLE, SETUP, ACCESS } state_e;
state_e state = IDLE;
int unsigned errors, completions, slave_errors;
longint unsigned wait_cycles;
bit timeout_reported;
bit saved_write;
bit [31:0] saved_addr, saved_wdata;
bit [3:0] saved_strb;
int unsigned max_wait;
function new(int unsigned allowed_wait_samples = 16);
max_wait = allowed_wait_samples;
endfunction
function void fail(string message);
errors++;
$error("APB monitor: %s", message);
endfunction
// Reset cancels the partial transfer; lifetime diagnostic counters survive.
function void reset_state();
// Implement here.
endfunction
function void capture_setup(bit pwrite, bit [31:0] paddr,
bit [31:0] pwdata, bit [3:0] pstrb);
// Implement here.
endfunction
function bit controls_match(bit pwrite, bit [31:0] paddr,
bit [31:0] pwdata, bit [3:0] pstrb);
// Implement here.
endfunction
function void sample(bit psel, bit penable, bit pready, bit pwrite,
bit [31:0] paddr, bit [31:0] pwdata, bit [3:0] pstrb,
bit pslverr);
// Implement here.
endfunction
function int error_count(); return errors; endfunction
function int completed_count(); return completions; endfunction
function int slave_error_count(); return slave_errors; endfunction
endclassTrace one case
ApbMonitor m = new(1);
m.sample(1,0,0,1,32'h40,32'h11223344,4'b0001,1);
m.sample(1,1,0,1,32'h40,32'hAABBCC44,4'b0001,1);
m.sample(1,1,1,1,32'h40,32'hFFEEDD44,4'b0001,0);completed_count() = 1, error_count() = 0, slave_error_count() = 0.There is one allowed wait sample. Byte 0 remains 0x44; other write bytes are disabled. PSLVERR is ignored on SETUP and the waiting ACCESS.
Requirements
- A selected ACCESS must follow exactly one SETUP sample. Support wait states and back-to-back transfers, each with its own SETUP.
- Keep PADDR, PWRITE and PSTRB stable from SETUP through every ACCESS sample, including completion. PSTRB must be zero on reads. Only enabled write-data bytes must match; ignore read PWDATA and unstrobed write bytes.
- Interpret PSLVERR only when PSEL, PENABLE and PREADY are all high on a valid transfer. Ignore it otherwise. Count an asserted completing PSLVERR as a slave-error outcome and a completion, without a protocol error.
- Allow exactly max_wait low-PREADY ACCESS samples, then report a timeout once per transfer. Ignore PREADY during SETUP; reset cancels the in-flight phase without a completion or withdrawal error.
