0% found this document useful (0 votes)
19 views33 pages

10 Advanced SystemVerilog Projects

The document is a practical guide for RTL designers and VLSI enthusiasts, featuring 10 advanced SystemVerilog projects that include complete code and real-world problems. Each project focuses on different aspects of hardware design and verification, such as AXI4 protocol, USB 3.0 stack, PCIe verification, and memory controller simulations. The guide aims to provide reusable snippets optimized for FPGA and ASIC implementations, along with testbenches for each project.

Uploaded by

Ali Zeshan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views33 pages

10 Advanced SystemVerilog Projects

The document is a practical guide for RTL designers and VLSI enthusiasts, featuring 10 advanced SystemVerilog projects that include complete code and real-world problems. Each project focuses on different aspects of hardware design and verification, such as AXI4 protocol, USB 3.0 stack, PCIe verification, and memory controller simulations. The guide aims to provide reusable snippets optimized for FPGA and ASIC implementations, along with testbenches for each project.

Uploaded by

Ali Zeshan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 33

A PRACTICAL GUIDE FOR RTL DESIGNERS, VLSI

ENTHUSIASTS & INTERVIEW PREPARATION

10 ADVANCED
SYSTEMVERILOG
PROJECTS

COMPLETE CODE | REAL WORLD PROBLEMS | REUSABLE


SNIPPETS | OPTIMIZED FOR FPGA & ASIC

Prasanthi Chanda
CONTENTS
1.AXI4 Master Slave Verification Environment
2.Complete USB 3.0 Protocol Stack in
SystemVerilog
3.PCIe Gen4 Protocol Functional Verification with
Scoreboarding
4.SystemVerilog-Based DDR4 Memory Controller
Simulation
5.Multi-Core CPU Pipeline Simulation with Cache
Coherency (SystemVerilog-based)
6.AXI4-Lite Bus Protocol Verification
7.Out-of-Order Execution Engine Simulation
8.Memory Consistency Model Checker in SV
9.Branch Predictor Verification with
Scoreboarding
10.Transaction-Level Modeling with Virtual
Sequences
Project 1: UVM-Based AXI4 Master-Slave Verification
Environment
// File: axi4_master_slave_tb.sv
`timescale 1ns / 1ps
// AXI4 Interface Definition
interface axi4_if(input bit ACLK, input bit ARESETn);
logic [31:0] AWADDR, WDATA, ARADDR, RDATA;
logic [3:0] AWID, WID, ARID, RID;
logic AWVALID, AWREADY, WVALID, WREADY;
logic ARVALID, ARREADY, RVALID, RREADY;
logic [1:0] BRESP, RRESP;
logic BVALID, BREADY;
endinterface

// DUT: Dummy AXI4 Slave


module axi4_slave(axi4_if axi);
always @(posedge axi.ACLK) begin
if (!axi.ARESETn) begin
axi.AWREADY <= 0;
axi.WREADY <= 0;
axi.BVALID <= 0;
end else begin
if (axi.AWVALID) axi.AWREADY <= 1;
if (axi.WVALID) axi.WREADY <= 1;
if (axi.WVALID && axi.WREADY) begin
axi.BVALID <= 1;
axi.BRESP <= 2'b00; // OKAY
end
if (axi.BREADY) axi.BVALID <= 0;
end
end
endmodule

// Top-Level TB
module axi4_tb;
bit clk, rstn;
axi4_if axi(clk, rstn);
axi4_slave dut(axi);
initial begin
clk = 0;
forever #5 clk = ~clk;
end
initial begin
rstn = 0;
#20 rstn = 1;
end
initial begin
// Simple Write Transaction
axi.AWVALID = 1; axi.AWADDR = 32'hA000_0000;
axi.AWID = 4'b0001;
axi.WVALID = 1; axi.WDATA = 32'hDEADBEEF;
axi.WID = 4'b0001;
axi.BREADY = 1;
wait (axi.BVALID);
$display("Write Complete. BRESP = %0h",
axi.BRESP);
#10 $finish;
end
endmodule

Project 2: USB 3.0 Protocol Stack (Simplified Core


Layer)

// File: usb3_core.sv
`timescale 1ns/1ps
module usb3_core(
input logic clk,
input logic rstn,
input logic [7:0] data_in,
input logic valid_in,
output logic ready_out,
output logic [7:0] data_out,
output logic valid_out,
input logic ready_in
);
typedef enum logic [1:0] {
IDLE,
RECEIVE,
TRANSMIT
} state_t;
state_t state, next_state;
logic [7:0] buffer;
always_ff @(posedge clk or negedge rstn) begin
if (!rstn)
state <= IDLE;
else
state <= next_state;
end
always_ff @(posedge clk) begin
if (state == RECEIVE && valid_in) begin
buffer <= data_in;
end
end
always_comb begin
next_state = state;
valid_out = 0;
ready_out = 0;
data_out = 8'd0;
case (state)
IDLE: begin
if (valid_in)
next_state = RECEIVE;
end
RECEIVE: begin
ready_out = 1;
if (valid_in)
next_state = TRANSMIT;
end
TRANSMIT: begin
valid_out = 1;
data_out = buffer;
if (ready_in)
next_state = IDLE;
end
endcase
end
endmodule
// Testbench for usb3_core
module usb3_tb();
logic clk, rstn;
logic [7:0] data_in;
logic valid_in, ready_out;
logic [7:0] data_out;
logic valid_out, ready_in;
usb3_core uut (
.clk(clk), .rstn(rstn),
.data_in(data_in), .valid_in(valid_in),
.ready_out(ready_out),
.data_out(data_out), .valid_out(valid_out),
.ready_in(ready_in)
);
initial begin
clk = 0;
forever #5 clk = ~clk;
end
initial begin
rstn = 0; valid_in = 0; ready_in = 0;
#15 rstn = 1;
#10 data_in = 8'hA5; valid_in = 1;
#10 valid_in = 0;
#10 ready_in = 1;
#20 $display("Output: %0h (valid=%0b)", data_out,
valid_out);
#10 $finish;
end
endmodule

Project 3: UVM-Based PCIe Root Complex and


Endpoint Verification (Simplified)

// File: pcie_uvm_tb.sv
`timescale 1ns/1ps
// PCIe Transaction Layer Packet (TLP) Interface
interface pcie_if(input bit clk, input bit rstn);
logic [31:0] tlp_data;
logic tlp_valid, tlp_ready;
endinterface
// Dummy PCIe Endpoint
module pcie_endpoint(pcie_if intf);
always_ff @(posedge intf.clk or negedge intf.rstn)
begin
if (!intf.rstn) begin
intf.tlp_ready <= 0;
end else begin
if (intf.tlp_valid) begin
intf.tlp_ready <= 1;
end else begin
intf.tlp_ready <= 0;
end
end
end
endmodule
// Testbench Top
module pcie_tb;
bit clk, rstn;
pcie_if intf(clk, rstn);
pcie_endpoint dut(intf);
// Clock generation
initial begin
clk = 0;
forever #5 clk = ~clk;
end
// Reset generation
initial begin
rstn = 0;
#20 rstn = 1;
end
// Simple transaction
initial begin
intf.tlp_valid = 0;
intf.tlp_data = 0;
#25;
intf.tlp_data = 32'hCAFEBABE;
intf.tlp_valid = 1;
wait (intf.tlp_ready);
$display("TLP sent: %h", intf.tlp_data);
#10;
intf.tlp_valid = 0;
#10 $finish;
end
endmodule

Project 4: SystemVerilog-Based DDR4 Memory


Controller Simulation (Simplified)

// File: ddr4_controller.sv
`timescale 1ns/1ps
module ddr4_controller (
input logic clk,
input logic rstn,
input logic wr_en,
input logic rd_en,
input logic [7:0] wr_data,
output logic [7:0] rd_data,
output logic rd_valid
);
logic [7:0] mem [0:255];
logic [7:0] addr;
always_ff @(posedge clk or negedge rstn) begin
if (!rstn) begin
rd_valid <= 0;
end else begin
if (wr_en)
mem[addr] <= wr_data;
if (rd_en) begin
rd_data <= mem[addr];
rd_valid <= 1;
end else begin
rd_valid <= 0;
end
addr <= addr + 1;
end
end
endmodule
// Testbench
module ddr4_tb;
logic clk, rstn;
logic wr_en, rd_en;
logic [7:0] wr_data, rd_data;
logic rd_valid;

ddr4_controller uut(
.clk(clk), .rstn(rstn), .wr_en(wr_en), .rd_en(rd_en),
.wr_data(wr_data), .rd_data(rd_data),
.rd_valid(rd_valid)
);

initial begin
clk = 0;
forever #5 clk = ~clk;
end

initial begin
rstn = 0; wr_en = 0; rd_en = 0; wr_data = 8'h00;
#10 rstn = 1;
#10 wr_en = 1; wr_data = 8'hAA;
#10 wr_en = 0;
#10 rd_en = 1;
#10 rd_en = 0;
if (rd_valid) $display("Read Data = %h", rd_data);
#10 $finish;
end
endmodule

Project 5: Multi-Core CPU Pipeline Simulation with


Cache Coherency (Simplified)

// File: multicore_cpu.sv
`timescale 1ns/1ps
module multicore_cpu (
input logic clk,
input logic rstn
);
// 2 Core Simulation
logic [7:0] regfile_core0 [0:7];
logic [7:0] regfile_core1 [0:7];
logic [7:0] shared_memory [0:15];

// Simulated Instruction Execution


task automatic execute_core0();
begin
regfile_core0[0] = 8'h10;
shared_memory[0] = regfile_core0[0]; // write to
memory
end
endtask
task automatic execute_core1();
begin
regfile_core1[0] = shared_memory[0]; // read
from memory
end
endtask

// Coherency Check
always_ff @(posedge clk or negedge rstn) begin
if (!rstn) begin
regfile_core0[0] <= 0;
regfile_core1[0] <= 0;
shared_memory[0] <= 0;
end else begin
execute_core0();
execute_core1();
end
end
endmodule
// Testbench
module multicore_cpu_tb;
logic clk, rstn;
multicore_cpu uut (.clk(clk), .rstn(rstn));
initial begin
clk = 0;
forever #5 clk = ~clk;
end
initial begin
rstn = 0;
#10 rstn = 1;
#20;
$display("Core0 Write: %h", uut.shared_memory[0]);
$display("Core1 Read: %h", uut.regfile_core1[0]);
#10 $finish;
end
endmodule

Project 6: AXI4-Lite Bus Protocol Verification


(Simplified)
// File: axi4lite_uvm_tb.sv
`timescale 1ns/1ps
interface axi_if(input logic ACLK, input logic ARESETn);
logic [31:0] AWADDR, WDATA, ARADDR;
logic AWVALID, WVALID, BREADY;
logic ARVALID, RREADY;
logic AWREADY, WREADY, BVALID;
logic ARREADY, RVALID;
logic [31:0] RDATA;
endinterface

module axi_slave(axi_if axi);


logic [31:0] mem [0:15];
always_ff @(posedge axi.ACLK or negedge
axi.ARESETn) begin
if (!axi.ARESETn) begin
axi.AWREADY <= 0;
axi.WREADY <= 0;
axi.BVALID <= 0;
axi.ARREADY <= 0;
axi.RVALID <= 0;
end else begin
// Write Address
if (axi.AWVALID && !axi.AWREADY) begin
axi.AWREADY <= 1;
end else begin
axi.AWREADY <= 0;
end
// Write Data
if (axi.WVALID && !axi.WREADY) begin
axi.WREADY <= 1;
mem[axi.AWADDR[5:2]] <= axi.WDATA;
axi.BVALID <= 1;
end else begin
axi.WREADY <= 0;
end

// Read Address
if (axi.ARVALID && !axi.ARREADY) begin
axi.ARREADY <= 1;
axi.RDATA <= mem[axi.ARADDR[5:2]];
axi.RVALID <= 1;
end else begin
axi.ARREADY <= 0;
end
if (axi.BREADY) axi.BVALID <= 0;
if (axi.RREADY) axi.RVALID <= 0;
end
end
endmodule
module axi_tb;
logic ACLK, ARESETn;
axi_if axi(ACLK, ARESETn);
axi_slave dut(axi);

initial begin
ACLK = 0;
forever #5 ACLK = ~ACLK;
end
initial begin
ARESETn = 0;
#15 ARESETn = 1;
end
initial begin
axi.AWADDR = 0;
axi.WDATA = 32'hDEADBEEF;
axi.AWVALID = 1;
axi.WVALID = 1;
axi.BREADY = 1;
#10;
axi.AWVALID = 0;
axi.WVALID = 0;
#10;
axi.ARADDR = 0;
axi.ARVALID = 1;
axi.RREADY = 1;
#10;
axi.ARVALID = 0;
#10;
if (axi.RVALID) $display("Read Data: %h",
axi.RDATA);
#10 $finish;
end
endmodule

Project 7: Out-of-Order Execution Engine Simulation

// File: ooo_execution_engine.sv
`timescale 1ns/1ps
module ooo_engine(input logic clk, rstn);
typedef struct packed {
logic [7:0] opcode;
logic [7:0] src1;
logic [7:0] src2;
logic [7:0] dest;
logic valid;
} instr_t;
instr_t issue_q[0:3];
instr_t reorder_buffer[0:3];
logic [7:0] regfile[0:7];

task automatic issue_instruction(instr_t instr);


for (int i = 0; i < 4; i++) begin
if (!issue_q[i].valid) begin
issue_q[i] = instr;
break;
end
end
endtask

task automatic execute_instruction();


for (int i = 0; i < 4; i++) begin
if (issue_q[i].valid) begin
// Fake execution based on opcode
if (issue_q[i].opcode == 8'h01) begin
regfile[issue_q[i].dest] = regfile[issue_q[i].src1]
+ regfile[issue_q[i].src2];
end else if (issue_q[i].opcode == 8'h02) begin
regfile[issue_q[i].dest] = regfile[issue_q[i].src1]
- regfile[issue_q[i].src2];
end
// Move to reorder buffer
reorder_buffer[i] = issue_q[i];
issue_q[i].valid = 0;
end
end
endtask

task automatic commit_instruction();


for (int i = 0; i < 4; i++) begin
if (reorder_buffer[i].valid) begin
$display("Committed instruction: opcode=%h,
dest=%h, result=%h", reorder_buffer[i].opcode,
reorder_buffer[i].dest, regfile[reorder_buffer[i].dest]);
reorder_buffer[i].valid = 0;
end
end
endtask

always_ff @(posedge clk or negedge rstn) begin


if (!rstn) begin
foreach(issue_q[i]) issue_q[i].valid = 0;
foreach(reorder_buffer[i]) reorder_buffer[i].valid =
0;
foreach(regfile[i]) regfile[i] = i;
end else begin
execute_instruction();
commit_instruction();
end
end
endmodule

module ooo_engine_tb;
logic clk, rstn;
ooo_engine dut(.clk(clk), .rstn(rstn));

initial begin
clk = 0;
forever #5 clk = ~clk;
end
initial begin
rstn = 0;
#10 rstn = 1;
#10;
dut.issue_instruction('{opcode: 8'h01, src1: 0, src2:
1, dest: 2, valid: 1}); // add
dut.issue_instruction('{opcode: 8'h02, src1: 3, src2:
2, dest: 4, valid: 1}); // sub
#100 $finish;
end
endmodule

Project 8: Memory Consistency Model Checker in SV


// File: memory_consistency_checker.sv
`timescale 1ns/1ps
module memory_model_checker(input logic clk, rstn);
typedef struct packed {
logic [3:0] tid;
logic [31:0] addr;
logic [31:0] data;
logic is_write;
logic valid;
} mem_op_t;
mem_op_t ops[0:15];
int head, tail;
task automatic insert_op(mem_op_t op);
ops[tail] = op;
tail = (tail + 1) % 16;
endtask

task automatic check_consistency();


for (int i = 0; i < 16; i++) begin
if (ops[i].valid && ops[i].is_write) begin
for (int j = i + 1; j < 16; j++) begin
if (ops[j].valid && ops[j].addr == ops[i].addr &&
ops[j].tid != ops[i].tid && !ops[j].is_write) begin
$display("[WARNING] Read-after-write hazard
detected: TID %0d reads addr %h after TID %0d
writes", ops[j].tid, ops[j].addr, ops[i].tid);
end
end
end
end
endtask

always_ff @(posedge clk or negedge rstn) begin


if (!rstn) begin
foreach (ops[i]) ops[i].valid = 0;
head = 0;
tail = 0;
end else begin
check_consistency();
end
end
endmodule
module memory_model_checker_tb;
logic clk, rstn;
memory_model_checker dut(.clk(clk), .rstn(rstn));

initial begin
clk = 0;
forever #5 clk = ~clk;
end

initial begin
rstn = 0;
#10 rstn = 1;

#10;
dut.insert_op('{tid: 0, addr: 32'h1000, data:
32'hABCD, is_write: 1, valid: 1}); // Write
dut.insert_op('{tid: 1, addr: 32'h1000, data:
32'h0000, is_write: 0, valid: 1}); // Read hazard

#100 $finish;
end
endmodule
Project 9: Branch Predictor Verification with
Scoreboarding

// File: branch_predictor_scoreboard.sv
`timescale 1ns/1ps
module branch_predictor #(parameter SIZE = 8)(input
logic clk, rstn);
typedef struct packed {
logic [31:0] pc;
logic prediction;
logic valid;
} bp_entry_t;

bp_entry_t table[SIZE];
task automatic predict(input logic [31:0] pc, output
logic prediction);
prediction = 0;
for (int i = 0; i < SIZE; i++) begin
if (table[i].valid && table[i].pc == pc) begin
prediction = table[i].prediction;
break;
end
end
endtask
task automatic update(input logic [31:0] pc, input
logic actual_taken);
int idx = -1;
for (int i = 0; i < SIZE; i++) begin
if (table[i].valid && table[i].pc == pc) begin
idx = i;
break;
end
end
if (idx == -1) begin
for (int i = 0; i < SIZE; i++) begin
if (!table[i].valid) begin
idx = i;
break;
end
end
end
if (idx != -1) begin
table[idx].pc = pc;
table[idx].prediction = actual_taken;
table[idx].valid = 1;
end
endtask
endmodule
module branch_scoreboard_tb;
logic clk, rstn;
logic pred;
branch_predictor dut(.clk(clk), .rstn(rstn));
initial begin
clk = 0;
forever #5 clk = ~clk;
end
initial begin
rstn = 0;
#10 rstn = 1;
// Insert branch predictions and check scoreboard
logic [31:0] pc;
pc = 32'h00400020;
dut.update(pc, 1); // actual taken
dut.predict(pc, pred);
$display("Prediction for PC %h: %0b", pc, pred);
pc = 32'h00400024;
dut.update(pc, 0); // actual not taken
dut.predict(pc, pred);
$display("Prediction for PC %h: %0b", pc, pred);
#100 $finish;
end
endmodule
Project 10: Transaction-Level Modeling with Virtual
Sequences
// File: tlm_virtual_sequences.sv
`timescale 1ns/1ps
// Base transaction class
class transaction;
rand bit [31:0] addr;
rand bit [31:0] data;
rand bit write;
function void display();
$display("Transaction: addr=0x%0h, data=0x%0h,
write=%0b", addr, data, write);
endfunction
endclass

// Virtual sequence base class


class virtual_sequence;
virtual task execute();
endtask
endclass

// Sequence A - write transactions


class seq_a extends virtual_sequence;
transaction tr;
virtual task execute();
repeat (5) begin
tr = new();
tr.randomize() with { write == 1; };
tr.addr = $urandom_range(32'h1000, 32'h1FFF);
tr.data = $urandom();
tr.display();
#10;
end
endtask
endclass

// Sequence B - read transactions


class seq_b extends virtual_sequence;
transaction tr;
virtual task execute();
repeat (5) begin
tr = new();
tr.randomize() with { write == 0; };
tr.addr = $urandom_range(32'h2000, 32'h2FFF);
tr.display();
#10;
end
endtask
endclass
virtual task execute();
$display("Starting Sequence A (Writes)");
a_seq.execute();
$display("Starting Sequence B (Reads)");
b_seq.execute();
$display("Virtual Sequence Completed");
endtask
endclass

module tlm_virtual_seq_tb;
initial begin
top_virtual_sequence virt_seq = new();
virt_seq.execute();
#10 $finish;
end
endmodule
Excellence in World class
VLSI Training & Placements

Do follow for updates & enquires

+91- 9182280927

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy