10 Advanced SystemVerilog Projects
10 Advanced SystemVerilog Projects
10 ADVANCED
SYSTEMVERILOG
PROJECTS
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
// 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
// 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
// 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
// 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
// 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];
// 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
// 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
// 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];
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
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
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
+91- 9182280927