Week 6 · Day 30 · 7 hours

SystemVerilog Verification – Mini Project

Verification plan creation
Stimulus/checker separation
Random + directed blend
Regression and debug workflow

01

Concept and setup

Understand what you will build

Day 30 — Integrated FIFO Verification Mini-Project

Simulation status (28 Oct 2026): run_regression.sh passes on Verilator 5.052: 4 scenario runs and 10 seeded runs, with no errors. Icarus Verilog 12 cannot compile the interface modports, so the script now uses Verilator. Details: Week 6 validation record (VALIDATION.md).

Files: fifo_interface.sv, fifo_dut.sv, tb_fifo_project.sv, run_regression.sh, verification_plan.md, LABS.md.

Run on Linux with Verilator 5 installed: bash run_regression.sh. A compile failure is reported as BLOCKED, never as PASS.

The source is a self-checking, non-UVM testbench with transaction stimulus, driver, scoreboard, reference model, directed/boundary/error/random scenarios and ten reproducible seeds. The XLS Day 30 lab inventory is included for later sign-off.

02

Architecture

Follow the verification data flow

Architecture diagram for SystemVerilog Verification – Mini Project
SystemVerilog Verification – Mini Project architecture and execution flow.
03

Worked source

Study the supplied implementation

fifo_dut.sv
`timescale 1ns/1ps
module fifo_dut #(parameter DEPTH=4)(fifo_if.dut bus);
  logic [7:0] mem[0:DEPTH-1];
  integer head=0,tail=0,count=0;
  assign bus.full = (count==DEPTH);
  assign bus.empty = (count==0);
  // Contract: when full, a write is rejected even if read is also requested;
  // when empty, a read is rejected even if write is also requested.
  always @(posedge bus.clk) begin : fifo_step
    bit accept_w,accept_r;
    if (!bus.rst_n) begin
      head <= 0; tail <= 0; count <= 0;
      bus.rd_data <= 0;
      bus.overflow <= 0; bus.underflow <= 0;
    end else begin
      accept_w = bus.wr_en && (count<DEPTH);
      accept_r = bus.rd_en && (count>0);
      bus.overflow <= bus.wr_en && !accept_w;
      bus.underflow <= bus.rd_en && !accept_r;
      if (accept_w) begin
        mem[tail] <= bus.wr_data;
        tail <= (tail+1)%DEPTH;
      end
      if (accept_r) begin
        bus.rd_data <= mem[head];
        head <= (head+1)%DEPTH;
      end
      case ({accept_w,accept_r})
        2'b10: count <= count+1;
        2'b01: count <= count-1;
        default: count <= count;
      endcase
    end
  end
endmodule
fifo_interface.sv
`timescale 1ns/1ps
interface fifo_if(input logic clk);
  logic rst_n=0, wr_en=0, rd_en=0;
  logic [7:0] wr_data=0, rd_data;
  logic full, empty, overflow, underflow;
  modport dut(input clk,rst_n,wr_en,rd_en,wr_data,
              output rd_data,full,empty,overflow,underflow);
  modport tb(input clk,rd_data,full,empty,overflow,underflow,
             output rst_n,wr_en,rd_en,wr_data);
endinterface
tb_fifo_project.sv
`timescale 1ns/1ps
// Self-checking, non-UVM FIFO verification mini-project.
// Generator -> driver -> DUT/interface -> monitor -> reference-model/scoreboard.
module tb_fifo_project;
  localparam DEPTH=4;
  logic clk=0;
  always #5 clk=~clk;
  fifo_if bus(clk);
  fifo_dut #(.DEPTH(DEPTH)) dut(bus);
  int seed=1,mode=0,checks=0,errors=0,cycles=0;
  int unsigned rng;
  byte unsigned model[0:DEPTH-1];
  integer model_head=0,model_tail=0,model_count=0;
  logic [7:0] expected_rd=0;
  bit expected_overflow=0,expected_underflow=0;

  // Local deterministic PRNG makes a 10-seed regression reproducible.
  function automatic int unsigned next_random();
    rng=(rng*32'd1664525)+32'd1013904223;
    return rng;
  endfunction

  // Reference model predicts behavior from pre-clock inputs and queue state.
  task automatic predict(input bit reset_n,input bit wr,input bit rd,input byte unsigned data);
    bit aw,ar;
    if (!reset_n) begin
      model_head=0;model_tail=0;model_count=0;
      expected_rd=0;expected_overflow=0;expected_underflow=0;
    end else begin
      aw=wr && (model_count<DEPTH);
      ar=rd && (model_count>0);
      expected_overflow=wr && !aw;
      expected_underflow=rd && !ar;
      if (aw) begin
        model[model_tail]=data;
        model_tail=(model_tail+1)%DEPTH;
      end
      if (ar) begin
        expected_rd=model[model_head];
        model_head=(model_head+1)%DEPTH;
      end
      if (aw && !ar) model_count++;
      if (ar && !aw) model_count--;
    end
  endtask

  // Driver controls signals before active edge; monitor checks after NBA updates.
  task automatic step(input bit reset_n,input bit wr,input bit rd,input byte unsigned data);
    @(negedge clk);
    bus.rst_n=reset_n;bus.wr_en=wr;bus.rd_en=rd;bus.wr_data=data;
    predict(reset_n,wr,rd,data);
    @(posedge clk);
    #1;
    cycles++;
    if (bus.full !== (model_count==DEPTH) ||
        bus.empty !== (model_count==0) ||
        bus.rd_data !== expected_rd ||
        bus.overflow !== expected_overflow ||
        bus.underflow !== expected_underflow) begin
      $display("FAIL seed=%0d mode=%0d cycle=%0d count=%0d wr=%0b rd=%0b data=%0h got(rd=%0h full=%0b empty=%0b ov=%0b un=%0b) expected(rd=%0h full=%0b empty=%0b ov=%0b un=%0b)",
        seed,mode,cycles,model_count,wr,rd,data,bus.rd_data,bus.full,bus.empty,bus.overflow,bus.underflow,
        expected_rd,(model_count==DEPTH),(model_count==0),expected_overflow,expected_underflow);
      errors++;
      $fatal(1,"scoreboard mismatch");
    end
    checks++;
  endtask

  task automatic reset_fifo();
    step(0,0,0,0);
    step(1,0,0,0);
  endtask

  task automatic directed();
    reset_fifo();
    step(1,1,0,8'h11);
    step(1,1,0,8'h22);
    step(1,0,1,0);
    step(1,0,1,0);
    step(1,0,0,0);
  endtask

  task automatic boundary();
    reset_fifo();
    for(int i=0;i<DEPTH;i++) step(1,1,0,byte'(i+1));
    step(1,1,0,8'h99); // full overflow
    step(1,1,1,8'h77); // full: write rejected, read accepted
    step(1,1,1,8'h66); // simultaneous accepted
    for(int i=0;i<DEPTH;i++) step(1,0,1,0);
    step(1,0,1,0); // empty underflow
    step(1,1,1,8'h33); // empty: write accepted, read rejected
    step(1,0,1,0);
  endtask

  task automatic error_tests();
    reset_fifo();
    step(1,0,1,0); // underflow
    for(int i=0;i<DEPTH;i++) step(1,1,0,byte'(i));
    step(1,1,0,8'hff); // overflow
    step(0,1,1,8'hff); // reset takes precedence
    step(1,0,1,0); // underflow after reset
  endtask

  task automatic random_tests(input int count);
    int unsigned x;
    reset_fifo();
    for(int i=0;i<count;i++) begin
      x=next_random();
      step(1,x[0],x[8],byte'(x>>16));
    end
  endtask

  initial begin
    if (!$value$plusargs("SEED=%d",seed)) seed=1;
    if (!$value$plusargs("MODE=%d",mode)) mode=0;
    rng=seed;
    case(mode)
      1: directed();
      2: boundary();
      3: error_tests();
      4: random_tests(300);
      0: begin directed();boundary();error_tests();random_tests(300);end
      default: $fatal(1,"invalid MODE (0=all 1=directed 2=boundary 3=error 4=random)");
    endcase
    if(errors!=0) $fatal(1,"errors=%0d",errors);
    $display("DAY30_PASS seed=%0d mode=%0d checks=%0d cycles=%0d errors=%0d",seed,mode,checks,cycles,errors);
    $finish;
  end
  initial begin
    #1000000;
    $fatal(1,"watchdog timeout");
  end
endmodule
04

Guided and independent work

Complete the lab checklist

Day 30 — XLS-derived lab checklist

  • [ ] Lab 1: Verification plan — Code and demonstrate verification plan with simulation evidence; document observations or debug result.
  • [ ] Lab 2: Interface — Code and demonstrate interface with simulation evidence; document observations or debug result.
  • [ ] Lab 3: Transaction — Code and demonstrate transaction with simulation evidence; document observations or debug result.
  • [ ] Lab 4: Generator — Code and demonstrate generator with simulation evidence; document observations or debug result.
  • [ ] Lab 5: Driver — Code and demonstrate driver with simulation evidence; document observations or debug result.
  • [ ] Lab 6: Monitor — Code and demonstrate monitor with simulation evidence; document observations or debug result.
  • [ ] Lab 7: Scoreboard — Code and demonstrate scoreboard with simulation evidence; document observations or debug result.
  • [ ] Lab 8: Reference model — Code and demonstrate reference model with simulation evidence; document observations or debug result.
  • [ ] Lab 9: Directed test — Code and demonstrate directed test with simulation evidence; document observations or debug result.
  • [ ] Lab 10: Random test — Code and demonstrate random test with simulation evidence; document observations or debug result.
  • [ ] Lab 11: Boundary test — Code and demonstrate boundary test with simulation evidence; document observations or debug result.
  • [ ] Lab 12: Error test — Code and demonstrate error test with simulation evidence; document observations or debug result.
  • [ ] Lab 13: 10-seed regression — Code and demonstrate 10-seed regression with simulation evidence; document observations or debug result.
  • [ ] Lab 14: Failure triage — Code and demonstrate failure triage with simulation evidence; document observations or debug result.
  • [ ] Lab 15: Architecture review — Code and demonstrate architecture review with simulation evidence; document observations or debug result.

The supplied project runs on Verilator 5.052 (run_regression.sh); each lab still needs your own evidence.

05

Assignment and evidence

Demonstrate the required engineering outcome

Debug assignment

Week-6 practical assessment
Peer review of architecture and code

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.

06

Knowledge check

Confirm the verification concepts

The scored check is being prepared.