@@ -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 |