SystemVerilog Verification – TB Architecture
Transaction-based verification
Generator/driver/monitor
Scoreboard/reference model
Mailbox communication
Environment layering
Concept and setup
Understand what you will build
Day 27 — Transaction-Based Verification (Non-UVM)
Simulation status (28 Oct 2026): run_day27.sh passes on Verilator 5.052: 24 of 24 transactions match, and the injected-error run detects exactly one mismatch. Fixed on 28 Oct 2026: the monitor now samples only cycles with valid high; it used to stop at the first clock edge, before the driver had sent anything. Details: Week 6 validation record (VALIDATION.md).
Learning goals
- Model a transaction as a class and transfer it using typed mailboxes.
- Build generator, driver, monitor, scoreboard and environment classes.
- Explain reference-model checking, synchronization and mismatch diagnostics.
- Demonstrate an intentional negative test without accepting silent errors.
Component responsibilities
| Component | Owns | Must not silently take over |
|---|---|---|
| Generator | Chooses the next transaction and its identifying fields. | It should not decide whether the DUT output is correct. |
| Driver | Converts a transaction into timed pin-level activity. | It should not rewrite the expected result to match the DUT. |
| Monitor | Samples the interface and reports what actually happened. | It should not alter the DUT signals it observes. |
| Scoreboard | Compares observed behavior with a reference model or expected transaction. | It should not depend on internal DUT state to predict public behavior. |
| Environment | Connects components and controls test setup and completion. | It should not hide a component failure behind an unconditional PASS. |
The data path is therefore: generate intent, drive the interface, observe the result, then compare it. Keep transaction IDs in the observed record so a mismatch can be traced back to the stimulus that caused it. A negative test counts only when the expected defect is detected and the run reports failure.
Files
alu_dut.sv: 8-bit ALU design.tb_alu_environment.sv: complete educational non-UVM ALU environment with 24 transactions.run_day27.sh: Verilator build, then the positive test and the injected-mismatch negative test.architecture.svg: class-to-DUT flow.LABS.md: exact XLS 16-lab inventory and coverage gaps.
Caveats
- Classes, mailboxes and virtual interfaces need Verilator 5 or a commercial simulator; Icarus Verilog 12 does not support them.
- Driver drives on the falling edge; the monitor samples on the rising edge and only records cycles where
validis high. - Transaction ID is based on fixed in-order stimulus; advanced protocols need correlation and reset handling.
- FIFO and timer environments are not included yet, despite appearing in the XLS lab inventory.
This day demonstrates the separation of verification responsibilities; it is not a substitute for the integrated FIFO project on Day 30.
Architecture
Follow the verification data flow
Worked source
Study the supplied implementation
alu_dut.sv
// Educational combinational ALU; op 0=add, 1=sub, 2=and, 3=xor
module alu_dut(input logic [7:0] a,b, input logic [1:0] op, output logic [7:0] y);
always_comb case(op)
2'd0: y=a+b;
2'd1: y=a-b;
2'd2: y=a&b;
default: y=a^b;
endcase
endmodule
tb_alu_environment.sv
`timescale 1ns/1ps
// Non-UVM class-based transaction verification example. Needs SV class/mailbox support.
interface alu_if(input logic clk);
logic [7:0] a,b,y;
logic [1:0] op;
logic valid;
modport dut(input a,b,op,output y);
endinterface
class alu_txn;
rand bit [7:0] a,b;
rand bit [1:0] op;
int id;
bit [7:0] observed;
function alu_txn clone();
alu_txn t=new(); t.a=a; t.b=b; t.op=op; t.id=id; t.observed=observed;
return t;
endfunction
endclass
class alu_generator;
mailbox #(alu_txn) to_driver;
int count;
function new(mailbox #(alu_txn) channel, int n);to_driver=channel;count=n;endfunction
task run();
alu_txn t;
for(int i=0;i<count;i++) begin
t=new(); t.id=i;
// Directed repeatable stimulus; Day 28 will add constraints.
t.a=8'(i*13); t.b=8'(i*7+3); t.op=2'(i%4);
to_driver.put(t);
end
endtask
endclass
class alu_driver;
virtual alu_if vif;
mailbox #(alu_txn) input_q;
int count;
function new(virtual alu_if vif_, mailbox #(alu_txn) q, int n);
vif=vif_;input_q=q;count=n;
endfunction
task run();
alu_txn t;
for(int i=0;i<count;i++) begin
input_q.get(t);
@(negedge vif.clk); // Drive away from monitor sampling edge
vif.a=t.a;vif.b=t.b;vif.op=t.op;vif.valid=1;
end
@(negedge vif.clk);vif.valid=0;
endtask
endclass
class alu_monitor;
virtual alu_if vif;
mailbox #(alu_txn) to_scoreboard;
int count;
function new(virtual alu_if vif_, mailbox #(alu_txn) q, int n);
vif=vif_;to_scoreboard=q;count=n;
endfunction
task run();
alu_txn t;
for(int i=0;i<count;i++) begin
// Sample only cycles that carry a transaction; the first one is driven after the first posedge.
do @(posedge vif.clk); while(!vif.valid);
t=new();t.id=i;t.a=vif.a;t.b=vif.b;t.op=vif.op;t.observed=vif.y;
to_scoreboard.put(t);
end
endtask
endclass
class alu_scoreboard;
mailbox #(alu_txn) input_q;
int count,passed=0,failed=0;
bit inject_error;
function new(mailbox #(alu_txn) q,int n,bit inject=0);
input_q=q;count=n;inject_error=inject;
endfunction
function bit [7:0] expected(alu_txn t);
case(t.op)
0:return t.a+t.b;
1:return t.a-t.b;
2:return t.a&t.b;
default:return t.a^t.b;
endcase
endfunction
task run();
alu_txn t;bit [7:0] exp;
for(int i=0;i<count;i++) begin
input_q.get(t);exp=expected(t);
// Educational negative test: corrupt expected value for exactly one transaction.
if(inject_error && i==count/2) exp=exp^8'h01;
if(t.observed===exp) passed++;
else begin failed++;$display("MISMATCH id=%0d op=%0d a=%0h b=%0h expected=%0h actual=%0h",t.id,t.op,t.a,t.b,exp,t.observed);end
end
$display("SUMMARY checked=%0d pass=%0d fail=%0d",count,passed,failed);
if(inject_error) begin
if(failed!=1) $fatal(1,"Negative test did not detect exactly one mismatch");
$display("EXPECTED_MISMATCH_DETECTED");
end else if(failed!=0) $fatal(1,"Unexpected scoreboard mismatches");
endtask
endclass
class alu_env;
alu_generator gen;
alu_driver drv;
alu_monitor mon;
alu_scoreboard sb;
mailbox #(alu_txn) gen_to_drv, mon_to_sb;
function new(virtual alu_if vif,int n,bit inject=0);
gen_to_drv=new();mon_to_sb=new();
gen=new(gen_to_drv,n);drv=new(vif,gen_to_drv,n);
mon=new(vif,mon_to_sb,n);sb=new(mon_to_sb,n,inject);
endfunction
task run();
fork gen.run();drv.run();mon.run();sb.run(); join
endtask
endclass
module tb_alu_environment;
bit clk=0;always #5 clk=~clk;
alu_if intf(clk);
alu_dut dut(.a(intf.a),.b(intf.b),.op(intf.op),.y(intf.y));
alu_env env;
bit inject;
initial begin
intf.valid=0;intf.a=0;intf.b=0;intf.op=0;
inject=$test$plusargs("INJECT_MISMATCH");
env=new(intf,24,inject);
env.run();
$display("DAY27_DONE");$finish;
end
initial begin #10000;$fatal(1,"TIMEOUT");end
endmodule
Guided and independent work
Complete the lab checklist
Day 27 — XLS Lab Inventory (16 labs)
- [ ] Lab 1: Transaction class — Code and demonstrate transaction class with simulation evidence; document observations or debug result.
- [ ] Lab 2: Generator — Code and demonstrate generator with simulation evidence; document observations or debug result.
- [ ] Lab 3: Generator→driver mailbox — Code and demonstrate generator→driver mailbox with simulation evidence; document observations or debug result.
- [ ] Lab 4: Driver — Code and demonstrate driver with simulation evidence; document observations or debug result.
- [ ] Lab 5: Monitor — Code and demonstrate monitor with simulation evidence; document observations or debug result.
- [ ] Lab 6: Monitor→scoreboard channel — Code and demonstrate monitor→scoreboard channel with simulation evidence; document observations or debug result.
- [ ] Lab 7: Reference model — Code and demonstrate reference model with simulation evidence; document observations or debug result.
- [ ] Lab 8: Scoreboard — Code and demonstrate scoreboard with simulation evidence; document observations or debug result.
- [ ] Lab 9: Actual/expected compare — Code and demonstrate actual/expected compare with simulation evidence; document observations or debug result.
- [ ] Lab 10: Environment class — Code and demonstrate environment class with simulation evidence; document observations or debug result.
- [ ] Lab 11: End-of-test statistics — Code and demonstrate end-of-test statistics with simulation evidence; document observations or debug result.
- [ ] Lab 12: Error injection — Code and demonstrate error injection with simulation evidence; document observations or debug result.
- [ ] Lab 13: ALU environment — Code and demonstrate alu environment with simulation evidence; document observations or debug result.
- [ ] Lab 14: FIFO environment — Code and demonstrate fifo environment with simulation evidence; document observations or debug result.
- [ ] Lab 15: Timer environment — Code and demonstrate timer environment with simulation evidence; document observations or debug result.
- [ ] Lab 16: Scoreboard mismatch debug — Code and demonstrate scoreboard mismatch debug with simulation evidence; document observations or debug result.
Coverage note: The included ALU example demonstrates labs 1–13 and 16 conceptually; FIFO and timer environments (labs 14–15) remain planned and unimplemented. The supplied ALU environment runs on Verilator 5.052; each lab still needs your own evidence.
Assignment and evidence
Demonstrate the required engineering outcome
Debug assignment
Debug a scoreboard mismatch
Draw and document TB architecture
Submission evidence
- Source files
- README with commands and environment
- Lab evidence log and screenshots if applicable
- Debug observations and outstanding issues
Review rubric
- Source and design
- 35
- Functional checks
- 30
- Debug and explanation
- 20
- Reproducibility
- 15
Personal evidence
This lesson is public; no account is needed to study it.
Knowledge check
Confirm the verification concepts
The scored check is being prepared.