@@ -0,0 +1,42 @@ | |||||
// `include "uvm_pkg.sv" | |||||
import uvm_pkg::*; | |||||
`include "uvm_macros.svh" | |||||
`include "axi_config_objs.svh" | |||||
`include "axi_interface.sv" | |||||
`include "axi_transaction.sv" | |||||
`include "axi_write_seq.sv" | |||||
`include "axi_read_seq.sv" | |||||
`include "axi_m_driver.sv" | |||||
`include "axi_m_monitor.sv" | |||||
`include "axi_master_agent.sv" | |||||
`include "axi_s_driver.sv" | |||||
`include "axi_s_monitor.sv" | |||||
`include "axi_slave_agent.sv" | |||||
`include "axi_scoreboard.sv" | |||||
`include "axi_env.sv" | |||||
`include "axi_test.sv" | |||||
`include "uvm_pkg.sv" | |||||
// parameter A_WIDTH = 8; // Address bus width | |||||
// parameter D_WIDTH = 128; // Data bus width | |||||
module top; | |||||
bit clk, rstn; | |||||
always #5 clk = ~clk; | |||||
initial rstn = 1; | |||||
axi_intf#(.A_WIDTH(A_WIDTH), .D_WIDTH(D_WIDTH)) intf(clk, rstn); | |||||
env_config env_cfg; | |||||
initial begin | |||||
env_cfg = new(); | |||||
env_cfg.intf = intf; | |||||
uvm_config_db#(env_config)::set(null, "uvm_test_top", "config", env_cfg); | |||||
uvm_config_db#(env_config)::set(null, "uvm_test_top.env.master", "config", env_cfg); | |||||
uvm_config_db#(env_config)::set(null, "uvm_test_top.env.slave", "config", env_cfg); | |||||
run_test("axi_base_test"); | |||||
end | |||||
endmodule |
@@ -0,0 +1,166 @@ | |||||
class axi_base_test extends uvm_test; | |||||
`uvm_component_utils(axi_base_test) | |||||
// Components | |||||
axi_env env; | |||||
axi_write_seq#(.D_WIDTH(D_WIDTH), .A_WIDTH(A_WIDTH)) wr_seq; | |||||
axi_read_seq#(.D_WIDTH(D_WIDTH), .A_WIDTH(A_WIDTH)) rd_seq; | |||||
// variables | |||||
env_config env_cfg; | |||||
test_config test_cfg; | |||||
function new(string name, uvm_component parent); | |||||
super.new(name, parent); | |||||
test_cfg = new("test_cfg"); | |||||
test_cfg.no_write_cases = 1; | |||||
test_cfg.no_read_cases = 1; | |||||
endfunction //new() | |||||
// Function: build_phase | |||||
extern function void build_phase(uvm_phase phase); | |||||
// Function: end_of_elaboration_phase | |||||
extern function void end_of_elaboration_phase(uvm_phase phase); | |||||
// Function: run_phase | |||||
extern task run_phase(uvm_phase phase); | |||||
endclass //axi_base_test extends uvm_test | |||||
function void axi_base_test::build_phase(uvm_phase phase); | |||||
test_cfg.burst_type = 2; | |||||
uvm_config_db#(test_config)::set(null, "uvm_test_top.seq", "config", test_cfg); | |||||
wr_seq = new("wr_seq"); | |||||
rd_seq = new("rd_seq"); | |||||
env = axi_env::type_id::create("env", this); | |||||
endfunction: build_phase | |||||
function void axi_base_test::end_of_elaboration_phase(uvm_phase phase); | |||||
super.end_of_elaboration_phase(phase); | |||||
uvm_top.print_topology(); | |||||
endfunction: end_of_elaboration_phase | |||||
task axi_base_test::run_phase(uvm_phase phase); | |||||
phase.raise_objection(this); | |||||
fork | |||||
wr_seq.start(env.master.w_seqr); | |||||
#200 | |||||
rd_seq.start(env.master.r_seqr); | |||||
// end | |||||
join | |||||
phase.drop_objection(this); | |||||
endtask: run_phase | |||||
// **************************************************************************************** | |||||
// Directed Test Cases | |||||
// **************************************************************************************** | |||||
class axi_write_test extends axi_base_test; | |||||
`uvm_component_utils(axi_write_test) | |||||
function new(string name, uvm_component parent); | |||||
super.new(name, parent); | |||||
endfunction //new() | |||||
function void build_phase(uvm_phase phase); | |||||
super.build_phase(phase); | |||||
endfunction: build_phase | |||||
function void end_of_elaboration_phase(uvm_phase phase); | |||||
super.end_of_elaboration_phase(phase); | |||||
endfunction: end_of_elaboration_phase | |||||
task run_phase(uvm_phase phase); | |||||
phase.raise_objection(this); | |||||
wr_seq.start(env.master.w_seqr); | |||||
phase.drop_objection(this); | |||||
endtask: run_phase | |||||
endclass //write_test extends axi_base_test | |||||
class axi_read_test extends axi_base_test; | |||||
`uvm_component_utils(axi_read_test) | |||||
function new(string name, uvm_component parent); | |||||
super.new(name, parent); | |||||
endfunction //new() | |||||
function void build_phase(uvm_phase phase); | |||||
super.build_phase(phase); | |||||
endfunction: build_phase | |||||
function void end_of_elaboration_phase(uvm_phase phase); | |||||
super.end_of_elaboration_phase(phase); | |||||
endfunction: end_of_elaboration_phase | |||||
task run_phase(uvm_phase phase); | |||||
phase.raise_objection(this); | |||||
wr_seq.start(env.master.w_seqr); | |||||
// rd_seq.start(env.master.r_seqr); | |||||
phase.drop_objection(this); | |||||
endtask: run_phase | |||||
endclass //write_test extends axi_base_test | |||||
class axi_fixed_test extends axi_base_test; | |||||
`uvm_component_utils(axi_fixed_test) | |||||
function new(string name, uvm_component parent); | |||||
super.new(name, parent); | |||||
endfunction //new() | |||||
function void build_phase(uvm_phase phase); | |||||
test_cfg.burst_type = 0; | |||||
uvm_config_db#(test_config)::set(null, "uvm_test_top.seq", "config", test_cfg); | |||||
wr_seq = new("wr_seq"); | |||||
rd_seq = new("rd_seq"); | |||||
env = axi_env::type_id::create("env", this); | |||||
endfunction: build_phase | |||||
task run_phase(uvm_phase phase); | |||||
super.run_phase(phase); | |||||
endtask: run_phase | |||||
endclass //axi_fixed_test extends axi_base_test | |||||
class axi_incr_test extends axi_base_test; | |||||
`uvm_component_utils(axi_incr_test) | |||||
function new(string name, uvm_component parent); | |||||
super.new(name, parent); | |||||
endfunction //new() | |||||
function void build_phase(uvm_phase phase); | |||||
test_cfg.burst_type = 1; | |||||
uvm_config_db#(test_config)::set(null, "uvm_test_top.seq", "config", test_cfg); | |||||
wr_seq = new("wr_seq"); | |||||
rd_seq = new("rd_seq"); | |||||
env = axi_env::type_id::create("env", this); | |||||
endfunction: build_phase | |||||
task run_phase(uvm_phase phase); | |||||
super.run_phase(phase); | |||||
endtask: run_phase | |||||
endclass //axi_fixed_test extends axi_base_test | |||||
class axi_wrap_test extends axi_base_test; | |||||
`uvm_component_utils(axi_wrap_test) | |||||
function new(string name, uvm_component parent); | |||||
super.new(name, parent); | |||||
endfunction //new() | |||||
function void build_phase(uvm_phase phase); | |||||
test_cfg.burst_type = 2; | |||||
uvm_config_db#(test_config)::set(null, "uvm_test_top.seq", "config", test_cfg); | |||||
wr_seq = new("wr_seq"); | |||||
rd_seq = new("rd_seq"); | |||||
env = axi_env::type_id::create("env", this); | |||||
endfunction: build_phase | |||||
task run_phase(uvm_phase phase); | |||||
super.run_phase(phase); | |||||
endtask: run_phase | |||||
endclass //axi_fixed_test extends axi_base_test |
@@ -1,125 +1,185 @@ | |||||
`include "uvm_macros.svh" | |||||
import uvm_pkg::*; | |||||
class axi_seq_item extends uvm_seq_item; | |||||
//'uvm_object_utils(axi_seq_item); | |||||
function new(string name="axi_seq_item") | |||||
super.new(name); | |||||
endfunction | |||||
//write adress channel signals | |||||
rand bit wr_rd; | |||||
rand bit [3:0] awid; | |||||
rand logic[31:0] awaddr; | |||||
rand logic[2:0] awsize; | |||||
rand logic[3:0] awlen; | |||||
rand logic[1:0] awburst; | |||||
rand logic[1:0] awlock; | |||||
logic awvalid; | |||||
logic awready; | |||||
//write data channel | |||||
rand bit [3:0] wid; | |||||
rand logic[31:0] wdata[][]; | |||||
logic[3:0] wstrb; | |||||
logic wlast; | |||||
logic wvalid; | |||||
logic wready; | |||||
// write response channel | |||||
rand bit []3:0]bid; | |||||
logic[1:0] bresp; | |||||
logic bvalid; | |||||
logic bready; | |||||
// read adress channel | |||||
rand bit [3:0] arid; | |||||
rand logic[31:0] araddr; | |||||
rand logic[2:0] arsize; | |||||
rand logic[3:0] arlen; | |||||
rand logic[1:0] arburst; | |||||
rand logic[1:0] arlock; | |||||
logic arvalid; | |||||
logic arready; | |||||
// read data channel | |||||
rand bit [3:0] rid; | |||||
logic[31:0] rdata; | |||||
logic[3:0]rresp; | |||||
logic rlast; | |||||
logic rvalid; | |||||
logic rready; | |||||
`uvm_object_utils_begin(axi_seq_item) | |||||
`uvm_field_int(awid,UVM_ALL_ON) | |||||
`uvm_field_int(awaddr,UVM_ALL_ON) | |||||
`uvm_field_int(awsize,UVM_ALL_ON) | |||||
`uvm_field_int(awlen,UVM_ALL_ON) | |||||
`uvm_field_int(awburst,UVM_ALL_ON) | |||||
`uvm_field_int(awlock,UVM_ALL_ON) | |||||
`uvm_field_int(awvalid,UVM_ALL_ON) | |||||
`uvm_field_int(awready,UVM_ALL_ON) | |||||
`uvm_field_int(wid,UVM_ALL_ON) | |||||
`uvm_field_int(wdata,UVM_ALL_ON) | |||||
`uvm_field_int(wlast,UVM_ALL_ON) | |||||
`uvm_field_int(wstrb,UVM_ALL_ON) | |||||
`uvm_field_int(wvalid,UVM_ALL_ON) | |||||
`uvm_field_int(wready,UVM_ALL_ON) | |||||
`uvm_field_int(bid,UVM_ALL_ON) | |||||
`uvm_field_int(bresp,UVM_ALL_ON) | |||||
`uvm_field_int(bvalid,UVM_ALL_ON) | |||||
`uvm_field_int(bready,UVM_ALL_ON) | |||||
`uvm_field_int(arid,UVM_ALL_ON) | |||||
`uvm_field_int(araddr,UVM_ALL_ON) | |||||
`uvm_field_int(arsize,UVM_ALL_ON) | |||||
`uvm_field_int(arlen,UVM_ALL_ON) | |||||
`uvm_field_int(arsize,UVM_ALL_ON) | |||||
`uvm_field_int(arburst,UVM_ALL_ON) | |||||
`uvm_field_int(arlock,UVM_ALL_ON) | |||||
`uvm_field_int(arvalid,UVM_ALL_ON) | |||||
`uvm_field_int(arready,UVM_ALL_ON) | |||||
`uvm_field_int(rid,UVM_ALL_ON) | |||||
`uvm_field_int(rdata,UVM_ALL_ON) | |||||
`uvm_field_int(rlast,UVM_ALL_ON) | |||||
`uvm_field_int(rresp,UVM_ALL_ON) | |||||
`uvm_field_int(rvalid,UVM_ALL_ON) | |||||
`uvm_field_int(rready,UVM_ALL_ON) | |||||
`uvm_object_utils_end | |||||
//constraints for axi | |||||
constraint aligned_addr{awadd%2**awsize==0;} | |||||
constraint wrap_addr{solve awburst before awlen | |||||
if(awburst==2'b 10) | |||||
awlen inside{1,3,7,15};} | |||||
constraint wid_sig{awid==wid;} | |||||
constraint rid_sig{arid==rid;} | |||||
constraint axi_4kb{awaddr%4096+(2**awsize*(awlen+1))<=4096;} | |||||
//:constrain | |||||
endclass:axi_seq_item | |||||
import uvm_pkg::*; | |||||
typedef enum bit[1:0] { FIXED, INCR, WRAP } B_TYPE; | |||||
// Class: axi_transaction | |||||
// | |||||
class axi_transaction#(d_width = 16, a_width = 16) extends uvm_sequence_item; | |||||
typedef axi_transaction#(d_width, a_width) this_type_t; | |||||
`uvm_object_param_utils(axi_transaction#(d_width, a_width)); | |||||
// Group: Variables | |||||
bit [8:0] id; | |||||
rand bit [a_width-1:0] addr; | |||||
rand bit write; | |||||
rand bit [7:0] data [][]; | |||||
rand bit [2:0] b_size; | |||||
rand bit [3:0] b_len; | |||||
rand B_TYPE b_type; | |||||
bit b_last; | |||||
bit [1:0] b_resp; | |||||
bit [1:0] r_resp []; | |||||
// Group: Constraints | |||||
constraint b_size_val { 8*(2**b_size) <= d_width; } | |||||
constraint data_size { | |||||
/* solve order constraints */ | |||||
solve b_len before data; | |||||
solve b_size before data; | |||||
/* rand variable constraints */ | |||||
data.size() == b_len+1; | |||||
foreach (data[i] ) | |||||
data[i].size() == 2**b_size; | |||||
} | |||||
constraint b_len_val { | |||||
/* solve order constraints */ | |||||
solve b_type before b_len; | |||||
/* rand variable constraints */ | |||||
if(b_type == FIXED) | |||||
b_len inside { 0, 1 }; | |||||
else if(b_type == WRAP) | |||||
b_len inside { 1, 3, 7, 15 }; | |||||
} | |||||
constraint addr_val { | |||||
/* solve order constraints */ | |||||
solve b_type before addr; | |||||
solve b_size before addr; | |||||
/* rand variable constraints */ | |||||
if(b_type == WRAP) | |||||
addr == int'(addr/2**b_size) * 2**b_size; | |||||
} | |||||
constraint addr_val_align { | |||||
/* solve order constraints */ | |||||
solve b_size before addr; | |||||
/* rand variable constraints */ | |||||
addr == int'(addr/2**b_size) * 2**b_size; | |||||
} | |||||
constraint addr_val_unalign { | |||||
/* solve order constraints */ | |||||
solve b_size before addr; | |||||
/* rand variable constraints */ | |||||
addr != int'(addr/2**b_size) * 2**b_size; | |||||
} | |||||
// Constructor: new | |||||
function new(string name = "axi_transaction"); | |||||
super.new(name); | |||||
endfunction: new | |||||
// Function: do_copy | |||||
extern function void do_copy(uvm_object rhs); | |||||
// Function: do_compare | |||||
extern function bit do_compare(uvm_object rhs, uvm_comparer comparer); | |||||
// Function: convert2string | |||||
extern function string convert2string(); | |||||
// Function: do_print | |||||
extern function void do_print(uvm_printer printer); | |||||
// Function: do_record | |||||
// extern function void do_record(uvm_recorder recorder); | |||||
// Function: do_pack | |||||
// extern function void do_pack(); | |||||
// Function: do_unpack | |||||
// extern function void do_unpack(); | |||||
endclass: axi_transaction | |||||
/*----------------------------------------------------------------------------*/ | |||||
/* Functions */ | |||||
/*----------------------------------------------------------------------------*/ | |||||
function void axi_transaction::do_print(uvm_printer printer); | |||||
/* chain the print with parent classes */ | |||||
super.do_print(printer); | |||||
/* list of local properties to be printed: */ | |||||
printer.print_field("ID", id, $bits(id), UVM_UNSIGNED); | |||||
printer.print_field("Addr", addr, $bits(addr), UVM_HEX); | |||||
printer.print_generic("Data", "dynamic array", 8*2**b_size*(b_len+1), $sformatf("%u", data)); | |||||
printer.print_field("Burst Size", b_size, $bits(b_size), UVM_UNSIGNED); | |||||
printer.print_field("Burst Length", b_len+1, $bits(b_len), UVM_UNSIGNED); | |||||
printer.print_generic("Burst Type", "B_TYPE", $bits(b_len), b_type.name()); | |||||
endfunction: do_print | |||||
function string axi_transaction::convert2string(); | |||||
string s; | |||||
/* chain the convert2string with parent classes */ | |||||
s = super.convert2string(); | |||||
/* list of local properties to be printed: */ | |||||
// guide 0---4---8--12--16--20--24--28--32--36--40--44--48-- | |||||
s = {s, $sformatf("ID : %0d\n", id)}; | |||||
s = {s, $sformatf("Addr : 0x%0h\n", addr)}; | |||||
s = {s, $sformatf("Data : 0x%0u\n", data)}; | |||||
s = {s, $sformatf("Busrt Type : %s\n", b_type.name())}; | |||||
s = {s, $sformatf("Burst Size : %0d\n", b_size)}; | |||||
s = {s, $sformatf("Busrt Length : %0d\n", b_len+1)}; | |||||
s = {s, $sformatf("Busrt resp : 0x%0h\n", b_resp)}; | |||||
s = {s, $sformatf("Read resp : %0u\n", r_resp)}; | |||||
return s; | |||||
endfunction: convert2string | |||||
function void axi_transaction::do_copy(uvm_object rhs); | |||||
this_type_t rhs_; | |||||
if (!$cast(rhs_, rhs)) begin | |||||
`uvm_error({this.get_name(), ".do_copy()"}, "Cast failed!"); | |||||
return; | |||||
end | |||||
// `uvm_info({this.get_name(), ".do_copy()"}, "Cast succeded.", UVM_HIGH); | |||||
/* chain the copy with parent classes */ | |||||
super.do_copy(rhs); | |||||
/* list of local properties to be copied */ | |||||
this.id = rhs_.id; | |||||
this.addr = rhs_.addr; | |||||
this.data = rhs_.data; | |||||
this.b_type = rhs_.b_type; | |||||
this.b_size = rhs_.b_size; | |||||
this.b_len = rhs_.b_len; | |||||
this.b_resp = rhs_.b_resp; | |||||
this.r_resp = rhs_.r_resp; | |||||
endfunction: do_copy | |||||
function bit axi_transaction::do_compare(uvm_object rhs, uvm_comparer comparer); | |||||
this_type_t rhs_; | |||||
if (!$cast(rhs_, rhs)) begin | |||||
`uvm_error({this.get_name(), ".do_compare()"}, "Cast failed!"); | |||||
return 0; | |||||
end | |||||
// `uvm_info({this.get_name(), ".do_compare()"}, "Cast succeded.", UVM_HIGH); | |||||
/* chain the compare with parent classes */ | |||||
do_compare = super.do_compare(rhs, comparer); | |||||
/* list of local properties to be compared: */ | |||||
do_compare &= ( | |||||
this.id == rhs_.id && | |||||
this.addr == rhs_.addr && | |||||
this.b_type == rhs_.b_type && | |||||
this.b_size == rhs_.b_size && | |||||
this.b_len == rhs_.b_len && | |||||
this.b_resp == rhs_.b_resp | |||||
); | |||||
foreach(data[i,j]) begin | |||||
do_compare &= this.data[i][j] == rhs_.data[i][j]; | |||||
end | |||||
foreach ( r_resp[i] ) begin | |||||
do_compare &= this.r_resp[i] == rhs_.r_resp[i]; | |||||
end | |||||
endfunction: do_compare |
@@ -0,0 +1,61 @@ | |||||
// Class: axi_write_seq | |||||
// | |||||
class axi_write_seq#(D_WIDTH = 16, int A_WIDTH = 16) extends uvm_sequence; | |||||
`uvm_object_param_utils(axi_write_seq#(D_WIDTH, A_WIDTH)); | |||||
// Group: Variables | |||||
const int no_of_trans; | |||||
bit[7:0] id; | |||||
axi_transaction#(D_WIDTH, A_WIDTH) trans; | |||||
test_config test_cfg; | |||||
// Constructor: new | |||||
function new(string name = "axi_write_seq"); | |||||
super.new(name); | |||||
test_cfg = new("test_cfg"); | |||||
if(!uvm_config_db#(test_config)::get(null, "uvm_test_top.seq", "config", test_cfg)) | |||||
`uvm_fatal(get_name(), "config cannot be found in ConfigDB!") | |||||
no_of_trans = test_cfg.no_write_cases; | |||||
endfunction: new | |||||
// Task: body | |||||
// This is the user-defined task where the main sequence code resides. | |||||
extern virtual task body(); | |||||
endclass: axi_write_seq | |||||
task axi_write_seq::body(); | |||||
repeat(no_of_trans) begin | |||||
id++; | |||||
trans = axi_transaction#(D_WIDTH, A_WIDTH)::type_id::create("trans"); | |||||
if(test_cfg.isAligned) begin | |||||
trans.addr_val_align.constraint_mode(1); | |||||
trans.addr_val_unalign.constraint_mode(0); | |||||
trans.addr_val.constraint_mode(0); | |||||
end | |||||
else if (!test_cfg.isAligned) begin | |||||
trans.addr_val_align.constraint_mode(0); | |||||
trans.addr_val_unalign.constraint_mode(1); | |||||
trans.addr_val.constraint_mode(0); | |||||
end | |||||
else begin | |||||
trans.addr_val_align.constraint_mode(0); | |||||
trans.addr_val_unalign.constraint_mode(0); | |||||
trans.addr_val.constraint_mode(1); | |||||
end | |||||
start_item(trans); | |||||
if(test_cfg.burst_type == 0) | |||||
assert(trans.randomize() with { b_type == FIXED; }); | |||||
else if(test_cfg.burst_type == 1) | |||||
assert(trans.randomize() with { b_type == INCR; }); | |||||
else if(test_cfg.burst_type == 2) | |||||
assert(trans.randomize() with { b_type == WRAP; addr==16'h80c6;write==1;}); | |||||
else | |||||
assert(trans.randomize()); | |||||
trans.id = {1'b0, id}; | |||||
finish_item(trans); | |||||
trans.print(); | |||||
#10; | |||||
end | |||||
endtask: body |