shortint | 2-state SystemVerilog data type, 16 bit signed integer |
int | 2-state SystemVerilog data type, 32 bit signed integer |
longint | 2-state SystemVerilog data type, 64 bit signed integer |
byte | 2-state SystemVerilog data type, 8 bit signed integer or ASCII character |
bit | 2-state SystemVerilog data type, user-defined vector size |
logic | 4-state SystemVerilog data type, user-defined vector size |
reg | 4-state Verilog-2001 data type, user-defined vector size |
integer | 4-state Verilog-2001 data type, 32 bit signed integer |
time | 4-state Verilog-2001 data type, 64-bit unsigned integer |
2) Default values
Type | Default Initial value |
4 state | integral ’X |
2 state | integral ’0 |
real, shortreal | 0.0 |
Enumeration | First value in the enumeration |
string | "" (empty string) |
event | New event |
class | null |
chandle | (Opaque handle) null |
10) class
/////////////////////////////////////////////
//cpu_transaction.sv
/////////////////////////////////////////////
class cpu_transaction;logic [7:0 ] addr ;
logic [31:0] data ;
logic rw ;
endclass: cpu_transaction
11) program
/////////////////////////////////////////////
//cpu_interface.svi
/////////////////////////////////////////////
`ifndef __CPU_INTERFACE_SVI__
`define __CPU_INTERFACE_SVI__
interface cpu_interface (input logic clk);
logic rst_n ;
logic [7:0 ] addr ;
logic [31:0] data ;
logic rw ;
clocking cb @(posedge clk);
default input #1 output #1;
output addr ;
output data ;
output rw ;
endclocking
modport master(clocking cb, output rst_n);
endinterface
`endif
/////////////////////////////////////////////
//test.sv
/////////////////////////////////////////////
`ifndef __TEST_SV__
`define __TEST_SV__
`include "cpu_interface.svi"
program test(cpu_interface.master cpu_intf);
initial begin
end
endprogram
`endif
/////////////////////////////////////////////
//top.sv
/////////////////////////////////////////////
`include "cpu_interface.svi"
`include "test.sv"
module top;
logic clk;
cpu_interface cpu_intf(clk);
test u_test(cpu_intf);
endmodule
#############################################
#Makefile
#############################################
RTL_DIR = /mnt/program
#RTL = $(RTL_DIR)/rtl/router.v
TB_DIR = /mnt/program
SVTB = $(TB_DIR)/test.sv
SVTB += $(TB_DIR)/top.sv
INCDIR = +incdir+/mnt/program
COMPILE_LOG_ARG = -l vcs.log
COMPILE_ARG = -sverilog -debug_all
COMPILE_ARG += $(INCDIR) $(COMPILE_LOG_ARG)
RUN_LOG_ARG = -l simv.log
RUN_ARG =
RUN_ARG += $(RUN_LOG_ARG)
SEED = 1
default: test
test: compile run
run:
./simv $(RUN_ARG) +ntb_random_seed=$(SEED)
compile:
vcs $(COMPILE_ARG) $(SVTB) $(RTL)
clean:
rm -rf simv simv.* *log
12) interface
/////////////////////////////////////////////
//cpu_interface.svi
/////////////////////////////////////////////
`ifndef __CPU_INTERFACE_SVI__
`define __CPU_INTERFACE_SVI__
interface cpu_interface (input logic clk);
logic rst_n ;
logic [7:0 ] addr ;
logic [31:0] data ;
logic rw ;
clocking cb @(posedge clk);
default input #1 output #1;
output addr ;
output data ;
output rw ;
endclocking
modport master(clocking cb, output rst_n);
endinterface
`endif
/////////////////////////////////////////////
//test.sv
/////////////////////////////////////////////
`ifndef __TEST_SV__
`define __TEST_SV__
`include "cpu_interface.svi"
program test(cpu_interface.master cpu_intf);
event done;
initial begin
cpu_intf.rst_n <= 1'b0;
cpu_intf.cb.addr <= 8'h0;
cpu_intf.cb.data <= 32'h0;
cpu_intf.cb.rw <= 1'b0;
@(cpu_intf.cb);
cpu_intf.rst_n <= 1'b1;
@(cpu_intf.cb);
cpu_intf.cb.addr <= 8'h1;
cpu_intf.cb.data <= 32'h1;
cpu_intf.cb.rw <= 1'b0;
@(cpu_intf.cb);
cpu_intf.cb.addr <= 8'h2;
cpu_intf.cb.data <= 32'h2;
cpu_intf.cb.rw <= 1'b1;
->done;
end
initial begin
@done;
#10 $finish();
end
endprogram
`endif
/////////////////////////////////////////////
//top.sv
/////////////////////////////////////////////
`include "cpu_interface.svi"
`include "test.sv"
module top;
parameter cpu_clock_cycle = 10;
logic clk;
cpu_interface cpu_intf(clk);
test u_test(cpu_intf);
initial begin
$timeformat(-9, 1, "ns", 10);
clk = 0;
forever begin
#(cpu_clock_cycle/2)
clk = ~clk;
end
end
`ifdef WAVE_ON
initial begin
$vcdpluson();
end
`endif
endmodule
#############################################
#Makefile
#############################################
RTL_DIR = /mnt/interface
#RTL = $(RTL_DIR)/rtl/router.v
TB_DIR = /mnt/interface
SVTB = $(TB_DIR)/test.sv
SVTB += $(TB_DIR)/top.sv
INCDIR = +incdir+$(TB_DIR)
COMPILE_LOG_ARG = -l vcs.log
WAVE_ARG = +define+WAVE_ON=1
COMPILE_ARG = -sverilog -debug_all
COMPILE_ARG += $(INCDIR) $(COMPILE_LOG_ARG) $(WAVE_ARG)
RUN_LOG_ARG = -l simv.log
RUN_ARG =
RUN_ARG += $(RUN_LOG_ARG)
SEED = 1
default: test
test: compile run
run:
./simv $(RUN_ARG) +ntb_random_seed=$(SEED)
compile:
vcs $(COMPILE_ARG) $(SVTB) $(RTL)
clean:
rm -rf simv simv.* *log
100) transaction
/////////////////////////////////////////////
//cpu_transaction
/////////////////////////////////////////////
`ifndef __CPU_TRANSACTION_SV__
`define __CPU_TRANSACTION_SV__
class cpu_transaction;
rand logic [7:0] addr;
rand logic [31:0] data;
string name;
extern function new(string name = "CPU Transaction");
extern function void display(string prefix = "Note");
endclass
function cpu_transaction::new(string name);
this.name = name;
endfunction
function void cpu_transaction::display(string prefix);
$display("[%s]%t %s addr = %0h, data = %0h", prefix, $realtime, name, addr, data);
endfunction
`endif
/////////////////////////////////////////////
//test.sv
/////////////////////////////////////////////
`ifndef __TEST_SV__
`define __TEST_SV__
`include "cpu_transaction.sv"
program test();
event done;
initial begin
cpu_transaction cpu_tran;
cpu_tran = new();
repeat(10) begin
if(!cpu_tran.randomize()) begin
$display("Error to randomize cpu_tran");
end
cpu_tran.display();
#1;
end
->done;
end
initial begin
@done;
#10 $finish();
end
endprogram
`endif
#############################################
#Makefile
#############################################
RTL_DIR = /mnt/transaction
#RTL = $(RTL_DIR)/rtl/router.v
TB_DIR = /mnt/transaction
SVTB = $(TB_DIR)/test.sv
INCDIR = +incdir+$(TB_DIR)
COMPILE_LOG_ARG = -l vcs.log
WAVE_ARG = +define+WAVE_ON=1
COMPILE_ARG = -sverilog -debug_all
COMPILE_ARG += $(INCDIR) $(COMPILE_LOG_ARG) $(WAVE_ARG)
RUN_LOG_ARG = -l simv.log
RUN_ARG =
RUN_ARG += $(RUN_LOG_ARG)
SEED = 1
default: test
test: compile run
run:
./simv $(RUN_ARG) +ntb_random_seed=$(SEED)
compile:
vcs $(COMPILE_ARG) $(SVTB) $(RTL)
clean:
rm -rf simv simv.* *log
101) generator
/////////////////////////////////////////////
//cpu_define.sv
/////////////////////////////////////////////
`ifndef __CPU_DEFINE_SV__
`define __CPU_DEFINE_SV__
typedef class cpu_transaction;
typedef mailbox #(cpu_transaction) cpu_tran_mbox;
`endif
/////////////////////////////////////////////
//cpu_transaction.sv
/////////////////////////////////////////////
`ifndef __CPU_TRANSACTION_SV__
`define __CPU_TRANSACTION_SV__
class cpu_transaction;
rand logic [7:0] addr;
rand logic [31:0] data;
string name;
extern function new(string name = "CPU Transaction");
extern function void display(string prefix = "Note");
endclass
function cpu_transaction::new(string name);
this.name = name;
endfunction
function void cpu_transaction::display(string prefix);
$display("[%s]%t %s addr = %0h, data = %0h", prefix, $realtime, name, addr, data);
endfunction
`endif
/////////////////////////////////////////////
//cpu_generator.sv
/////////////////////////////////////////////
`ifndef __CPU_GENERATOR_SV__
`define __CPU_GENERATOR_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
class cpu_generator;
string name;
cpu_tran_mbox out_box;
int run_for_n_trans = 0;
event done;
extern function new(string name = "CPU Generator", cpu_tran_mbox out_box);
extern task start();
endclass
function cpu_generator::new(string name, cpu_tran_mbox out_box);
this.name = name;
this.out_box = out_box;
endfunction
task cpu_generator::start();
for(int i=0; i<run_for_n_trans; i++) begin
cpu_transaction cpu_tran = new();
if(!cpu_tran.randomize()) begin
$display("Error to randomize cpu_tran");
end
out_box.put(cpu_tran);
end
->done;
endtask
`endif
/////////////////////////////////////////////
//test.sv
/////////////////////////////////////////////
`ifndef __TEST_SV__
`define __TEST_SV__
`include "cpu_generator.sv"
`include "cpu_define.sv"
program test();
event done;
cpu_tran_mbox mbox = new();
cpu_generator cpu_gen;
initial begin
cpu_gen = new("CPU Generator", mbox);
cpu_gen.run_for_n_trans = 10;
cpu_gen.start();
end
initial begin
cpu_transaction cpu_tran;
forever begin
mbox.get(cpu_tran);
cpu_tran.display();
end
end
initial begin
@cpu_gen.done;
#10 $finish();
end
endprogram
`endif
#############################################
#Makefile
#############################################
RTL_DIR = /mnt/generator
#RTL = $(RTL_DIR)/rtl/router.v
TB_DIR = /mnt/generator
SVTB = $(TB_DIR)/test.sv
INCDIR = +incdir+$(TB_DIR)
COMPILE_LOG_ARG = -l vcs.log
WAVE_ARG = +define+WAVE_ON=1
COMPILE_ARG = -sverilog -debug_all
COMPILE_ARG += $(INCDIR) $(COMPILE_LOG_ARG) $(WAVE_ARG)
RUN_LOG_ARG = -l simv.log
RUN_ARG =
RUN_ARG += $(RUN_LOG_ARG)
SEED = 1
default: test
test: compile run
run:
./simv $(RUN_ARG) +ntb_random_seed=$(SEED)
compile:
vcs $(COMPILE_ARG) $(SVTB) $(RTL)
clean:
rm -rf simv simv.* *log
102) driver
/////////////////////////////////////////////
/////////////////////////////////////////////
//driver and monitor in the same bfm/////////////////////////////////////////////
/////////////////////////////////////////////
//cpu_transaction.sv
/////////////////////////////////////////////
`ifndef __CPU_TRANSACTION_SV__
`define __CPU_TRANSACTION_SV__
class cpu_transaction;
rand logic [7:0] addr;
rand logic [31:0] data;
rand logic rw;
string name;
extern function new(string name = "CPU Transaction");
extern function void display(string prefix = "Note");
endclass
function cpu_transaction::new(string name);
this.name = name;
endfunction
function void cpu_transaction::display(string prefix);
$display("[%s]%t %s addr = %0h, data = %0h, rw = %d", prefix, $realtime, name, addr, data, rw);
endfunction
`endif
/////////////////////////////////////////////
//cpu_define.sv
/////////////////////////////////////////////
`ifndef __CPU_DEFINE_SV__
`define __CPU_DEFINE_SV__
typedef class cpu_transaction;
typedef mailbox #(cpu_transaction) cpu_tran_mbox;
`endif
/////////////////////////////////////////////
//cpu_interface.svi
/////////////////////////////////////////////
`ifndef __CPU_INTERFACE_SVI__
`define __CPU_INTERFACE_SVI__
interface cpu_interface (input logic clk);
logic rst_n ;
logic [7:0 ] addr ;
logic [31:0] data ;
logic rw ;
clocking cb @(posedge clk);
default input #1 output #1;
output addr ;
output data ;
output rw ;
endclocking
modport master(clocking cb, output rst_n);
endinterface
`endif
/////////////////////////////////////////////
//cpu_generator.sv
/////////////////////////////////////////////
`ifndef __CPU_GENERATOR_SV__
`define __CPU_GENERATOR_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
class cpu_generator;
string name;
cpu_tran_mbox out_box;
int run_for_n_trans = 0;
event done;
extern function new(string name = "CPU Generator", cpu_tran_mbox out_box);
extern task start();
endclass
function cpu_generator::new(string name, cpu_tran_mbox out_box);
this.name = name;
this.out_box = out_box;
endfunction
task cpu_generator::start();
fork
for(int i=0; i<run_for_n_trans; i++) begin
cpu_transaction cpu_tran = new();
if(!cpu_tran.randomize()) begin
$display("Error to randomize cpu_tran");
end
out_box.put(cpu_tran);
end
->done;
join_none
endtask
`endif
/////////////////////////////////////////////
//cpu_driver.sv
/////////////////////////////////////////////
`ifndef __CPU_DRIVER_SV__
`define __CPU_DRIVER_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
`include "cpu_interface.svi"
class cpu_driver;
string name;
cpu_tran_mbox in_box;
virtual cpu_interface.master cpu_intf;
extern function new(string name = "CPU Driver", cpu_tran_mbox in_box, virtual cpu_interface.master cpu_intf);
extern task start();
endclass
function cpu_driver::new(string name, cpu_tran_mbox in_box, virtual cpu_interface.master cpu_intf);
this.name = name;
this.in_box = in_box;
this.cpu_intf = cpu_intf;
endfunction
task cpu_driver::start();
fork
forever begin
cpu_transaction cpu_tran;
in_box.get(cpu_tran);
cpu_tran.display();
@(cpu_intf.cb);
cpu_intf.cb.addr <= cpu_tran.addr;
cpu_intf.cb.data <= cpu_tran.data;
cpu_intf.cb.rw <= cpu_tran.rw;
@(cpu_intf.cb);
cpu_intf.cb.addr <= 8'h0 ;
cpu_intf.cb.data <= 32'h0 ;
cpu_intf.cb.rw <= 1'b1 ;
end
join_none
endtask
`endif
/////////////////////////////////////////////
//test.sv
/////////////////////////////////////////////
`ifndef __TEST_SV__
`define __TEST_SV__
`include "cpu_interface.svi"
`include "cpu_generator.sv"
`include "cpu_define.sv"
`include "cpu_driver.sv"
program test(cpu_interface.master cpu_intf);
event done;
cpu_tran_mbox mbox = new();
cpu_generator cpu_gen;
cpu_driver cpu_drv;
initial begin
cpu_gen = new("CPU Generator", mbox);
cpu_drv = new("CPU Driver", mbox, cpu_intf);
cpu_gen.run_for_n_trans = 10;
cpu_gen.start();
cpu_drv.start();
@cpu_gen.done;
repeat(100) @(cpu_intf.cb);
$finish();
end
endprogram
`endif
/////////////////////////////////////////////
//top.sv
/////////////////////////////////////////////
`timescale 1ns/1ps
`include "cpu_interface.svi"
`include "test.sv"
module top;
parameter cpu_clock_cycle = 10;
logic clk;
cpu_interface cpu_intf(clk);
test u_test(cpu_intf);
initial begin
$timeformat(-9, 1, "ns", 10);
clk = 0;
forever begin
#(cpu_clock_cycle/2) clk = ~clk;
end
end
`ifdef WAVE_ON
initial begin
$vcdpluson();
end
`endif
endmodule
#############################################
#Makefile
#############################################
ifeq ($(GUI), 1)
GUI_ARG = -gui
endif
RTL_DIR = /mnt/driver
#RTL = $(RTL_DIR)/rtl/router.v
TB_DIR = /mnt/driver
SVTB = $(TB_DIR)/top.sv
INCDIR = +incdir+$(TB_DIR)
COMPILE_LOG_ARG = -l vcs.log
WAVE_ARG = +define+WAVE_ON=1
COMPILE_ARG = -sverilog -debug_all
COMPILE_ARG += $(INCDIR) $(COMPILE_LOG_ARG) $(WAVE_ARG)
RUN_LOG_ARG = -l simv.log
RUN_ARG =
RUN_ARG += $(RUN_LOG_ARG) $(GUI_ARG)
SEED = 1
default: test
test: compile run
run:
./simv $(RUN_ARG) +ntb_random_seed=$(SEED)
compile:
vcs $(COMPILE_ARG) $(SVTB) $(RTL)
clean:
rm -rf simv simv.* *log
103) monitor
/////////////////////////////////////////////
//dut.v
/////////////////////////////////////////////
`timescale 1ns/1ps
module dut(
clk ,
rst_n ,
addr ,
din ,
rw ,
dout
);
input clk ;
input rst_n ;
input [7:0 ] addr ;
input [31:0] din ;
input rw ;
output [31:0] dout ;
wire clk ;
wire rst_n ;
wire [7:0 ] addr ;
wire [31:0] din ;
wire rw ;
reg [31:0] dout ;
wire write ;
wire read ;
reg [31:0] config_reg ;
reg [31:0] max_pkt_size ;
assign write = (rw == 1'b0);
assign read = (rw == 1'b1);
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
config_reg <= 32'h0;
end
else begin
if((addr == 8'h0) && (write == 1'b1)) begin
config_reg <= din;
end
end
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
max_pkt_size <= 32'h0;
end
else begin
if((addr == 8'h4) && (write == 1'b1)) begin
max_pkt_size <= din;
end
end
end
always @(addr) begin
case(addr)
8'h0 : dout = config_reg;
8'h1 : dout = max_pkt_size;
default : dout = 32'h0;
endcase
end
endmodule
/////////////////////////////////////////////
//cpu_interface.svi
/////////////////////////////////////////////
`ifndef __CPU_INTERFACE_SVI__
`define __CPU_INTERFACE_SVI__
interface cpu_interface (input logic clk);
logic rst_n ;
logic [7:0 ] addr ;
logic [31:0] din ;
logic rw ;
logic [31:0] dout ;
clocking cb @(posedge clk);
default input #1 output #1;
output addr ;
output din ;
output rw ;
input dout ;
endclocking
modport master(clocking cb, output rst_n);
endinterface
`endif
/////////////////////////////////////////////
//cpu_transaction.sv
/////////////////////////////////////////////
`ifndef __CPU_TRANSACTION_SV__
`define __CPU_TRANSACTION_SV__
class cpu_transaction;
string name;
rand logic [7:0] addr;
rand logic rw;
rand logic [31:0] din;
logic [31:0] dout = 32'h0;
extern function new(string name = "CPU Transaction");
extern function void display(string prefix = "Note");
endclass
function cpu_transaction::new(string name);
this.name = name;
endfunction
function void cpu_transaction::display(string prefix);
$display("[%s]%t %s addr = %0h, din = %0h, rw = %d, dout = %0h", prefix, $realtime, name, addr, din, rw, dout);
endfunction
`endif
/////////////////////////////////////////////
//cpu_define.sv
/////////////////////////////////////////////
`ifndef __CPU_DEFINE_SV__
`define __CPU_DEFINE_SV__
typedef class cpu_transaction;
typedef mailbox #(cpu_transaction) cpu_tran_mbox;
`endif
/////////////////////////////////////////////
//cpu_generator.sv
/////////////////////////////////////////////
`ifndef __CPU_GENERATOR_SV__
`define __CPU_GENERATOR_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
class cpu_generator;
string name;
cpu_tran_mbox out_box;
int run_for_n_trans = 0;
cpu_transaction cpu_tran;
event done;
extern function new(string name = "CPU Generator", cpu_tran_mbox out_box);
extern task start();
endclass
function cpu_generator::new(string name, cpu_tran_mbox out_box);
this.name = name;
this.out_box = out_box;
endfunction
task cpu_generator::start();
fork
for(int i=0; i<run_for_n_trans; i++) begin
cpu_transaction cpu_tran_cpy = new cpu_tran;
if(!cpu_tran_cpy.randomize()) begin
$display("Error to randomize cpu_tran_cpy");
end
out_box.put(cpu_tran_cpy);
end
->done;
join_none
endtask
`endif
/////////////////////////////////////////////
//cpu_driver.sv
//driver and monitor in the same bfm
/////////////////////////////////////////////
`ifndef __CPU_DRIVER_SV__
`define __CPU_DRIVER_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
`include "cpu_interface.svi"
class cpu_driver;
string name;
cpu_tran_mbox in_box;
cpu_tran_mbox out_box;
virtual cpu_interface.master cpu_intf;
extern function new(string name = "CPU Driver", cpu_tran_mbox in_box, cpu_tran_mbox out_box, virtual cpu_interface.master cpu_intf);
extern task start();
endclass
function cpu_driver::new(string name, cpu_tran_mbox in_box, cpu_tran_mbox out_box, virtual cpu_interface.master cpu_intf);
this.name = name;
this.in_box = in_box;
this.out_box = out_box;
this.cpu_intf = cpu_intf;
endfunction
task cpu_driver::start();
fork
forever begin
cpu_transaction cpu_tran;
in_box.get(cpu_tran);
cpu_tran.display();
@(cpu_intf.cb);
cpu_intf.cb.addr <= cpu_tran.addr;
cpu_intf.cb.din <= cpu_tran.din;
cpu_intf.cb.rw <= cpu_tran.rw;
@(cpu_intf.cb);
cpu_tran.dout = cpu_intf.cb.dout;
cpu_intf.cb.addr <= 8'h0 ;
cpu_intf.cb.din <= 32'h0 ;
cpu_intf.cb.rw <= 1'b1 ;
out_box.put(cpu_tran);
end
join_none
endtask
`endif
/////////////////////////////////////////////
//test.sv
/////////////////////////////////////////////
`ifndef __TEST_SV__
`define __TEST_SV__
`include "cpu_interface.svi"
`include "cpu_transaction.sv"
`include "cpu_generator.sv"
`include "cpu_define.sv"
`include "cpu_driver.sv"
program test(cpu_interface.master cpu_intf);
class cpu_transaction_ext extends cpu_transaction;
constraint addr_range {addr[7:2] inside {[8'h0:8'h1]}; addr[1:0] == 2'h0;}
//constraint write {rw == 1'b0;}
endclass
event done;
cpu_tran_mbox drv_mbox = new();
cpu_tran_mbox mon_mbox = new();
cpu_generator cpu_gen;
cpu_driver cpu_drv;
cpu_transaction_ext cpu_tran_ext = new();
initial begin
cpu_gen = new("CPU Generator", drv_mbox);
cpu_drv = new("CPU Driver", drv_mbox, mon_mbox, cpu_intf);
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b0;
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b1;
@(cpu_intf.cb);
cpu_gen.cpu_tran = cpu_tran_ext;
cpu_gen.run_for_n_trans = 100;
cpu_gen.start();
cpu_drv.start();
@cpu_gen.done;
repeat(100) @(cpu_intf.cb);
$finish();
end
initial begin
cpu_transaction cpu_tran = new();
forever begin
mon_mbox.get(cpu_tran);
cpu_tran.display("Monitor Mbox");
end
end
endprogram
`endif
/////////////////////////////////////////////
//top.sv
/////////////////////////////////////////////
`timescale 1ns/1ps
`include "cpu_interface.svi"
`include "test.sv"
module top;
parameter cpu_clock_cycle = 10;
logic clk;
cpu_interface cpu_intf(clk);
test u_test(cpu_intf);
dut u_dut (
.clk (cpu_intf.clk ) ,
.rst_n (cpu_intf.rst_n ) ,
.addr (cpu_intf.addr ) ,
.din (cpu_intf.din ) ,
.rw (cpu_intf.rw ) ,
.dout (cpu_intf.dout )
);
initial begin
$timeformat(-9, 1, "ns", 10);
clk = 0;
forever begin
#(cpu_clock_cycle/2) clk = ~clk;
end
end
`ifdef WAVE_ON
initial begin
$vcdpluson();
end
`endif
endmodule
#############################################
#Makefile
#############################################
ifeq ($(GUI), 1)
GUI_ARG = -gui
endif
RTL_DIR = /mnt/monitor
RTL = $(RTL_DIR)/dut.v
TB_DIR = /mnt/monitor
SVTB = $(TB_DIR)/top.sv
INCDIR = +incdir+$(TB_DIR)
COMPILE_LOG_ARG = -l vcs.log
WAVE_ARG = +define+WAVE_ON=1
COMPILE_ARG = -sverilog -debug_all
COMPILE_ARG += $(INCDIR) $(COMPILE_LOG_ARG) $(WAVE_ARG)
RUN_LOG_ARG = -l simv.log
RUN_ARG =
RUN_ARG += $(RUN_LOG_ARG) $(GUI_ARG)
SEED = 1
default: test
test: compile run
run:
./simv $(RUN_ARG) +ntb_random_seed=$(SEED)
compile:
vcs $(COMPILE_ARG) $(SVTB) $(RTL)
clean:
rm -rf simv simv.* *log
103) scoreboard
/////////////////////////////////////////////
//dut.v
/////////////////////////////////////////////
`timescale 1ns/1ps
module dut(
clk ,
rst_n ,
addr ,
din ,
rw ,
dout
);
input clk ;
input rst_n ;
input [7:0 ] addr ;
input [31:0] din ;
input rw ;
output [31:0] dout ;
wire clk ;
wire rst_n ;
wire [7:0 ] addr ;
wire [31:0] din ;
wire rw ;
reg [31:0] dout ;
wire write ;
wire read ;
reg [31:0] config_reg ;
reg [31:0] max_pkt_size ;
assign write = (rw == 1'b0);
assign read = (rw == 1'b1);
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
config_reg <= 32'h0;
end
else begin
if((addr == 8'h0) && (write == 1'b1)) begin
config_reg <= din;
end
end
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
max_pkt_size <= 32'h0;
end
else begin
if((addr == 8'h4) && (write == 1'b1)) begin
max_pkt_size <= din;
end
end
end
always @(*) begin
case(addr)
8'h0 : dout = config_reg;
8'h4 : dout = max_pkt_size;
default : dout = 32'h0;
endcase
end
endmodule
/////////////////////////////////////////////
//cpu_interface.svi
/////////////////////////////////////////////
`ifndef __CPU_INTERFACE_SVI__
`define __CPU_INTERFACE_SVI__
interface cpu_interface (input logic clk);
logic rst_n ;
logic [7:0 ] addr ;
logic [31:0] din ;
logic rw ;
logic [31:0] dout ;
clocking cb @(posedge clk);
default input #1 output #1;
output addr ;
output din ;
output rw ;
input dout ;
endclocking
modport master(clocking cb, output rst_n);
endinterface
`endif
/////////////////////////////////////////////
//cpu_transaction.sv
/////////////////////////////////////////////
`ifndef __CPU_TRANSACTION_SV__
`define __CPU_TRANSACTION_SV__
class cpu_transaction;
string name;
rand logic [7:0] addr;
rand logic rw;
rand logic [31:0] din;
logic [31:0] dout = 32'h0;
extern function new(string name = "CPU Transaction");
extern function void display(string prefix = "Note");
endclass
function cpu_transaction::new(string name);
this.name = name;
endfunction
function void cpu_transaction::display(string prefix);
$display("[%s]%t %s addr = %0h, din = %0h, rw = %d, dout = %0h", prefix, $realtime, name, addr, din, rw, dout);
endfunction
`endif
/////////////////////////////////////////////
//cpu_define.sv
/////////////////////////////////////////////
`ifndef __CPU_DEFINE_SV__
`define __CPU_DEFINE_SV__
typedef class cpu_transaction;
typedef mailbox #(cpu_transaction) cpu_tran_mbox;
`endif
/////////////////////////////////////////////
//cpu_generator.sv
/////////////////////////////////////////////
`ifndef __CPU_GENERATOR_SV__
`define __CPU_GENERATOR_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
class cpu_generator;
string name;
cpu_tran_mbox out_box;
int run_for_n_trans = 0;
cpu_transaction cpu_tran;
event done;
extern function new(string name = "CPU Generator", cpu_tran_mbox out_box);
extern task start();
endclass
function cpu_generator::new(string name, cpu_tran_mbox out_box);
this.name = name;
this.out_box = out_box;
endfunction
task cpu_generator::start();
fork
for(int i=0; i<run_for_n_trans; i++) begin
cpu_transaction cpu_tran_cpy = new cpu_tran;
if(!cpu_tran_cpy.randomize()) begin
$display("Error to randomize cpu_tran_cpy");
end
out_box.put(cpu_tran_cpy);
end
->done;
join_none
endtask
`endif
/////////////////////////////////////////////
//cpu_driver.sv
/////////////////////////////////////////////
`ifndef __CPU_DRIVER_SV__
`define __CPU_DRIVER_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
`include "cpu_interface.svi"
class cpu_driver;
string name;
cpu_tran_mbox in_box;
cpu_tran_mbox out_box;
virtual cpu_interface.master cpu_intf;
extern function new(string name = "CPU Driver", cpu_tran_mbox in_box, cpu_tran_mbox out_box, virtual cpu_interface.master cpu_intf);
extern task start();
endclass
function cpu_driver::new(string name, cpu_tran_mbox in_box, cpu_tran_mbox out_box, virtual cpu_interface.master cpu_intf);
this.name = name;
this.in_box = in_box;
this.out_box = out_box;
this.cpu_intf = cpu_intf;
endfunction
task cpu_driver::start();
fork
forever begin
cpu_transaction cpu_tran;
in_box.get(cpu_tran);
cpu_tran.display();
@(cpu_intf.cb);
cpu_intf.cb.addr <= cpu_tran.addr;
cpu_intf.cb.din <= cpu_tran.din;
cpu_intf.cb.rw <= cpu_tran.rw;
if(cpu_tran.rw == 1'b1) begin
@(cpu_intf.cb);
cpu_tran.dout = cpu_intf.cb.dout;
end
out_box.put(cpu_tran);
end
join_none
endtask
`endif
/////////////////////////////////////////////
//cpu_scoreboard.sv
/////////////////////////////////////////////
`ifndef __CPU_SCOREBOARD_SV__
`define __CPU_SCOREBOARD_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
class cpu_scoreboard;
string name;
cpu_tran_mbox in_box;
cpu_transaction cpu_tran;
logic [31:0] cpu_reg [7:0];
integer error_no = 0;
integer total_no = 0;
extern function new(string name = "CPU Scoreboard", cpu_tran_mbox in_box);
extern task start();
extern task check();
extern function display(string prefix = "CPU Scoreboard Result");
endclass
function cpu_scoreboard::new(string name, cpu_tran_mbox in_box);
this.name = name;
this.in_box = in_box;
for(int i=0; i<128; i++) begin
cpu_reg[i] = 32'h0;
end
endfunction
task cpu_scoreboard::start();
fork
forever begin
in_box.get(cpu_tran);
total_no++;
check();
end
join_none
endtask
task cpu_scoreboard::check();
string message;
if(cpu_tran.rw == 1'b0) begin
cpu_reg[cpu_tran.addr] = cpu_tran.din;
end
else if(cpu_tran.rw == 1'b1) begin
if(cpu_reg[cpu_tran.addr] != cpu_tran.dout) begin
message = $psprintf("[Error] %t Comparision result is not correct\n", $realtime);
message = { message, $psprintf("cpu_reg[%d] = %0h, cpu_tran.dout = %0h\n", cpu_tran.addr, cpu_reg[cpu_tran.addr], cpu_tran.dout) };
$display(message);
error_no++;
end
else begin
$display("[Note] %t comparison correct", $realtime);
end
end
else begin
$display("[Error] cpu_tran.rw can only be 0 or 1");
error_no++;
end
endtask
function cpu_scoreboard::display(string prefix);
$display("Total: %d, Error: %d", total_no, error_no);
endfunction
`endif
/////////////////////////////////////////////
//test.sv
/////////////////////////////////////////////
`ifndef __TEST_SV__
`define __TEST_SV__
`include "cpu_interface.svi"
`include "cpu_transaction.sv"
`include "cpu_generator.sv"
`include "cpu_define.sv"
`include "cpu_driver.sv"
`include "cpu_scoreboard.sv"
program test(cpu_interface.master cpu_intf);
class cpu_transaction_ext extends cpu_transaction;
constraint addr_range {addr[7:2] inside {[8'h0:8'h1]}; addr[1:0] == 2'h0;}
//constraint write {rw == 1'b0;}
endclass
event done;
cpu_tran_mbox drv_mbox = new();
cpu_tran_mbox mon_mbox = new();
cpu_generator cpu_gen;
cpu_driver cpu_drv;
cpu_transaction_ext cpu_tran_ext = new();
cpu_scoreboard cpu_sb;
initial begin
cpu_gen = new("CPU Generator", drv_mbox);
cpu_drv = new("CPU Driver", drv_mbox, mon_mbox, cpu_intf);
cpu_sb = new("CPU Scoreboard", mon_mbox);
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b0;
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b1;
@(cpu_intf.cb);
cpu_gen.cpu_tran = cpu_tran_ext;
cpu_gen.run_for_n_trans = 100;
cpu_gen.start();
cpu_drv.start();
cpu_sb.start();
@cpu_gen.done;
repeat(1000) begin
@(cpu_intf.cb);
if(cpu_sb.total_no == cpu_gen.run_for_n_trans) begin
break;
end
end
cpu_sb.display();
$finish();
end
endprogram
`endif
/////////////////////////////////////////////
//top.sv
/////////////////////////////////////////////
`timescale 1ns/1ps
`include "cpu_interface.svi"
`include "test.sv"
module top;
parameter cpu_clock_cycle = 10;
logic clk;
cpu_interface cpu_intf(clk);
test u_test(cpu_intf);
dut u_dut (
.clk (cpu_intf.clk ) ,
.rst_n (cpu_intf.rst_n ) ,
.addr (cpu_intf.addr ) ,
.din (cpu_intf.din ) ,
.rw (cpu_intf.rw ) ,
.dout (cpu_intf.dout )
);
initial begin
$timeformat(-9, 1, "ns", 10);
clk = 0;
forever begin
#(cpu_clock_cycle/2) clk = ~clk;
end
end
`ifdef WAVE_ON
initial begin
$vcdpluson();
end
`endif
endmodule
#############################################
#Makefile
#############################################
ifeq ($(GUI), 1)
GUI_ARG = -gui
endif
RTL_DIR = /mnt/scoreboard
RTL = $(RTL_DIR)/dut.v
TB_DIR = /mnt/scoreboard
SVTB = $(TB_DIR)/top.sv
INCDIR = +incdir+$(TB_DIR)
COMPILE_LOG_ARG = -l vcs.log
WAVE_ARG = +define+WAVE_ON=1
COMPILE_ARG = -sverilog -debug_all
COMPILE_ARG += $(INCDIR) $(COMPILE_LOG_ARG) $(WAVE_ARG)
RUN_LOG_ARG = -l simv.log
RUN_ARG =
RUN_ARG += $(RUN_LOG_ARG) $(GUI_ARG)
SEED = 1
default: test
test: compile run
run:
./simv $(RUN_ARG) +ntb_random_seed=$(SEED)
compile:
vcs $(COMPILE_ARG) $(SVTB) $(RTL)
clean:
rm -rf simv simv.* *log
104) env
/////////////////////////////////////////////
//dut.v
/////////////////////////////////////////////
`timescale 1ns/1ps
module dut(
clk ,
rst_n ,
addr ,
din ,
rw ,
dout
);
input clk ;
input rst_n ;
input [7:0 ] addr ;
input [31:0] din ;
input rw ;
output [31:0] dout ;
wire clk ;
wire rst_n ;
wire [7:0 ] addr ;
wire [31:0] din ;
wire rw ;
reg [31:0] dout ;
wire write ;
wire read ;
reg [31:0] config_reg ;
reg [31:0] max_pkt_size ;
assign write = (rw == 1'b0);
assign read = (rw == 1'b1);
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
config_reg <= 32'h0;
end
else begin
if((addr == 8'h0) && (write == 1'b1)) begin
config_reg <= din;
end
end
end
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
max_pkt_size <= 32'h0;
end
else begin
if((addr == 8'h4) && (write == 1'b1)) begin
max_pkt_size <= din;
end
end
end
always @(*) begin
case(addr)
8'h0 : dout = config_reg;
8'h4 : dout = max_pkt_size;
default : dout = 32'h0;
endcase
end
endmodule
/////////////////////////////////////////////
//cpu_interface.svi
/////////////////////////////////////////////
`ifndef __CPU_INTERFACE_SVI__
`define __CPU_INTERFACE_SVI__
interface cpu_interface (input logic clk);
logic rst_n ;
logic [7:0 ] addr ;
logic [31:0] din ;
logic rw ;
logic [31:0] dout ;
clocking cb @(posedge clk);
default input #1 output #1;
output addr ;
output din ;
output rw ;
input dout ;
endclocking
modport master(clocking cb, output rst_n);
endinterface
`endif
/////////////////////////////////////////////
//cpu_transaction.sv
/////////////////////////////////////////////
`ifndef __CPU_TRANSACTION_SV__
`define __CPU_TRANSACTION_SV__
class cpu_transaction;
string name;
rand logic [7:0] addr;
rand logic rw;
rand logic [31:0] din;
logic [31:0] dout = 32'h0;
extern function new(string name = "CPU Transaction");
extern function void display(string prefix = "Note");
endclass
function cpu_transaction::new(string name);
this.name = name;
endfunction
function void cpu_transaction::display(string prefix);
$display("[%s]%t %s addr = %0h, din = %0h, rw = %d, dout = %0h", prefix, $realtime, name, addr, din, rw, dout);
endfunction
`endif
/////////////////////////////////////////////
//cpu_define.sv
/////////////////////////////////////////////
`ifndef __CPU_DEFINE_SV__
`define __CPU_DEFINE_SV__
typedef class cpu_transaction;
typedef mailbox #(cpu_transaction) cpu_tran_mbox;
`endif
/////////////////////////////////////////////
//cpu_generator.sv
/////////////////////////////////////////////
`ifndef __CPU_GENERATOR_SV__
`define __CPU_GENERATOR_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
class cpu_generator;
string name;
cpu_tran_mbox out_box;
int run_for_n_trans = 0;
cpu_transaction cpu_tran;
event done;
extern function new(string name = "CPU Generator", cpu_tran_mbox out_box);
extern task start();
endclass
function cpu_generator::new(string name, cpu_tran_mbox out_box);
this.name = name;
this.out_box = out_box;
endfunction
task cpu_generator::start();
fork
begin
for(int i=0; i<run_for_n_trans; i++) begin
cpu_transaction cpu_tran_cpy = new cpu_tran;
if(!cpu_tran_cpy.randomize()) begin
$display("Error to randomize cpu_tran_cpy");
end
out_box.put(cpu_tran_cpy);
end
->done;
end
join_none
endtask
`endif
/////////////////////////////////////////////
//cpu_driver.sv
/////////////////////////////////////////////
`ifndef __CPU_DRIVER_SV__
`define __CPU_DRIVER_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
`include "cpu_interface.svi"
class cpu_driver;
string name;
cpu_tran_mbox in_box;
cpu_tran_mbox out_box;
virtual cpu_interface.master cpu_intf;
extern function new(string name = "CPU Driver", cpu_tran_mbox in_box, cpu_tran_mbox out_box, virtual cpu_interface.master cpu_intf);
extern task start();
endclass
function cpu_driver::new(string name, cpu_tran_mbox in_box, cpu_tran_mbox out_box, virtual cpu_interface.master cpu_intf);
this.name = name;
this.in_box = in_box;
this.out_box = out_box;
this.cpu_intf = cpu_intf;
endfunction
task cpu_driver::start();
fork
forever begin
cpu_transaction cpu_tran;
in_box.get(cpu_tran);
cpu_tran.display();
@(cpu_intf.cb);
cpu_intf.cb.addr <= cpu_tran.addr;
cpu_intf.cb.din <= cpu_tran.din;
cpu_intf.cb.rw <= cpu_tran.rw;
if(cpu_tran.rw == 1'b1) begin
@(cpu_intf.cb);
cpu_tran.dout = cpu_intf.cb.dout;
end
out_box.put(cpu_tran);
end
join_none
endtask
`endif
/////////////////////////////////////////////
//cpu_scoreboard.sv
/////////////////////////////////////////////
`ifndef __CPU_SCOREBOARD_SV__
`define __CPU_SCOREBOARD_SV__
`include "cpu_transaction.sv"
`include "cpu_define.sv"
class cpu_scoreboard;
string name;
cpu_tran_mbox in_box;
cpu_transaction cpu_tran;
logic [31:0] cpu_reg [7:0];
integer error_no = 0;
integer total_no = 0;
extern function new(string name = "CPU Scoreboard", cpu_tran_mbox in_box);
extern task start();
extern task check();
extern function display(string prefix = "CPU Scoreboard Result");
endclass
function cpu_scoreboard::new(string name, cpu_tran_mbox in_box);
this.name = name;
this.in_box = in_box;
for(int i=0; i<128; i++) begin
cpu_reg[i] = 32'h0;
end
endfunction
task cpu_scoreboard::start();
fork
forever begin
in_box.get(cpu_tran);
total_no++;
check();
end
join_none
endtask
task cpu_scoreboard::check();
string message;
if(cpu_tran.rw == 1'b0) begin
cpu_reg[cpu_tran.addr] = cpu_tran.din;
end
else if(cpu_tran.rw == 1'b1) begin
if(cpu_reg[cpu_tran.addr] != cpu_tran.dout) begin
message = $psprintf("[Error] %t Comparision result is not correct\n", $realtime);
message = { message, $psprintf("cpu_reg[%d] = %0h, cpu_tran.dout = %0h\n", cpu_tran.addr, cpu_reg[cpu_tran.addr], cpu_tran.dout) };
$display(message);
error_no++;
end
else begin
$display("[Note] %t comparison correct", $realtime);
end
end
else begin
$display("[Error] cpu_tran.rw can only be 0 or 1");
error_no++;
end
endtask
function cpu_scoreboard::display(string prefix);
$display("Total: %d, Error: %d", total_no, error_no);
endfunction
`endif
/////////////////////////////////////////////
//cpu_env.sv
/////////////////////////////////////////////
`ifndef __CPU_ENV_SV__
`define __CPU_ENV_SV__
`include "cpu_interface.svi"
`include "cpu_transaction.sv"
`include "cpu_generator.sv"
`include "cpu_define.sv"
`include "cpu_driver.sv"
`include "cpu_scoreboard.sv"
class cpu_env;
cpu_tran_mbox drv_mbox = new();
cpu_tran_mbox mon_mbox = new();
cpu_generator cpu_gen;
cpu_driver cpu_drv;
cpu_scoreboard cpu_sb;
virtual cpu_interface.master cpu_intf;
extern function new(virtual cpu_interface.master cpu_intf);
extern function configure();
extern task reset();
extern task start();
endclass
function cpu_env::new(virtual cpu_interface.master cpu_intf);
this.cpu_intf = cpu_intf;
cpu_gen = new("CPU Generator", drv_mbox);
cpu_drv = new("CPU Driver", drv_mbox, mon_mbox, cpu_intf);
cpu_sb = new("CPU Scoreboard", mon_mbox);
endfunction
function cpu_env::configure();
endfunction
task cpu_env::reset();
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b0;
@(cpu_intf.cb);
cpu_intf.rst_n = 1'b1;
@(cpu_intf.cb);
endtask
task cpu_env::start();
cpu_gen.start();
cpu_drv.start();
cpu_sb.start();
endtask
`endif
/////////////////////////////////////////////
//test.sv
/////////////////////////////////////////////
`ifndef __TEST_SV__
`define __TEST_SV__
`include "cpu_interface.svi"
`include "cpu_transaction.sv"
`include "cpu_env.sv"
program test(cpu_interface.master cpu_intf);
class cpu_transaction_ext extends cpu_transaction;
constraint addr_range {addr[7:2] inside {[8'h0:8'h1]}; addr[1:0] == 2'h0;}
//constraint write {rw == 1'b0;}
endclass
cpu_transaction_ext cpu_tran_ext = new();
cpu_env cpu_e;
initial begin
cpu_e = new(cpu_intf);
cpu_e.configure();
cpu_e.cpu_gen.cpu_tran = cpu_tran_ext;
cpu_e.cpu_gen.run_for_n_trans = 100;
cpu_e.reset();
cpu_e.start();
@cpu_e.cpu_gen.done;
repeat(1000) begin
@(cpu_intf.cb);
if(cpu_e.cpu_sb.total_no == cpu_e.cpu_gen.run_for_n_trans) begin
break;
end
end
cpu_e.cpu_sb.display();
$finish();
end
endprogram
`endif
/////////////////////////////////////////////
//top.sv
/////////////////////////////////////////////
`timescale 1ns/1ps
`include "cpu_interface.svi"
`include "test.sv"
module top;
parameter cpu_clock_cycle = 10;
logic clk;
cpu_interface cpu_intf(clk);
test u_test(cpu_intf);
dut u_dut (
.clk (cpu_intf.clk ) ,
.rst_n (cpu_intf.rst_n ) ,
.addr (cpu_intf.addr ) ,
.din (cpu_intf.din ) ,
.rw (cpu_intf.rw ) ,
.dout (cpu_intf.dout )
);
initial begin
$timeformat(-9, 1, "ns", 10);
clk = 0;
forever begin
#(cpu_clock_cycle/2) clk = ~clk;
end
end
`ifdef WAVE_ON
initial begin
$vcdpluson();
end
`endif
endmodule
#############################################
#Makefile
#############################################
ifeq ($(GUI), 1)
GUI_ARG = -gui
endif
RTL_DIR = /mnt/env
RTL = $(RTL_DIR)/dut.v
TB_DIR = /mnt/env
SVTB = $(TB_DIR)/top.sv
INCDIR = +incdir+$(TB_DIR)
COMPILE_LOG_ARG = -l vcs.log
WAVE_ARG = +define+WAVE_ON=1
COMPILE_ARG = -sverilog -debug_all
COMPILE_ARG += $(INCDIR) $(COMPILE_LOG_ARG) $(WAVE_ARG)
RUN_LOG_ARG = -l simv.log
RUN_ARG =
RUN_ARG += $(RUN_LOG_ARG) $(GUI_ARG)
SEED = 1
default: test
test: compile run
run:
./simv $(RUN_ARG) +ntb_random_seed=$(SEED)
compile:
vcs $(COMPILE_ARG) $(SVTB) $(RTL)
clean:
rm -rf simv simv.* *log
110) driver and monitor are in 2 different class (bfm)
link: http://scott2595.blogspot.com/2014/08/an-example-of-systemverilog-tb.html
111) TB env with 2 TB envs
linke: http://scott2595.blogspot.com/2014/10/an-example-of-sv-tb-with-callback.html
No comments:
Post a Comment