AHB TOP
`include "ahb_pkg.sv"
import ahb_pkg::*;
import uvm_pkg::*;
module top;
//---------------------------CLOCK&RESET------------------------------//
bit CLOCK, RESET;
initial begin
RESET = 0;
CLOCK = 0;
#10 RESET = 1;
end
always #5 CLOCK = !CLOCK;
//------------------INTERFACES INSTANCES------------------------//
ahb_if slave(.CLOCK(CLOCK), .RESET(RESET));
ahb_if master[size](.CLOCK(CLOCK), .RESET(RESET));
//------------------DECODER------------------------//
wire [size_out-1:0] HGRANT;
bit [size-1:0] HGRANTSEL;
always_comb begin
for(int i = 0; i < size; i++) begin
if(HGRANT == i) HGRANTSEL[i] <= 1;
else HGRANTSEL[i] <= 0;
end
end
assign master[0].HGRANT = HGRANTSEL[0];
assign master[1].HGRANT = HGRANTSEL[1];
assign master[2].HGRANT = HGRANTSEL[2];
assign master[3].HGRANT = HGRANTSEL[3];
assign master[4].HGRANT = HGRANTSEL[4];
assign master[5].HGRANT = HGRANTSEL[5];
assign master[6].HGRANT = HGRANTSEL[6];
assign master[7].HGRANT = HGRANTSEL[7];
assign master[8].HGRANT = HGRANTSEL[8];
//------------------MASTER READY------------------------//
assign master[0].HREADY = 1;
assign master[1].HREADY = 1;
assign master[2].HREADY = 1;
assign master[3].HREADY = 1;
assign master[4].HREADY = 1;
assign master[5].HREADY = 1;
assign master[6].HREADY = 1;
assign master[7].HREADY = 1;
assign master[8].HREADY = 1;
//------------------MASTER READY------------------------//
assign master[0].HRESP = 1;
assign master[1].HRESP = 1;
assign master[2].HRESP = 1;
assign master[3].HRESP = 1;
assign master[4].HRESP = 1;
assign master[5].HRESP = 1;
assign master[6].HRESP = 1;
assign master[7].HRESP = 1;
assign master[8].HRESP = 1;
// assign slave.HRESP = 1;
//------------------SLAVE WRITE------------------------//
assign slave.HWRITE = 1;
//------------------CONTAINING SIGNALS------------------------//
wire [8*size-1:0] HWDATA;
wire [3*size-1:0] HBURST;
wire [2*size-1:0] HTRANS;
wire [8*size-1:0] HADDR;
wire [size-1:0] HBUSREQ;
wire [size-1:0] HLOCK;
assign HWDATA = { master[8].HWDATA, master[7].HWDATA, master[6].HWDATA,
master[5].HWDATA, master[4].HWDATA, master[3].HWDATA, master[2].HWDATA,
master[1].HWDATA, master[0].HWDATA};
assign HADDR = { master[8].HADDR, master[7].HADDR, master[6].HADDR, master[5].HADDR,
master[4].HADDR, master[3].HADDR, master[2].HADDR, master[1].HADDR, master[0].HADDR};
assign HBURST = { master[8].HBURST, master[7].HBURST, master[6].HBURST,
master[5].HBURST, master[4].HBURST, master[3].HBURST, master[2].HBURST,
master[1].HBURST, master[0].HBURST};
assign HTRANS = { master[8].HTRANS, master[7].HTRANS, master[6].HTRANS,
master[5].HTRANS, master[4].HTRANS, master[3].HTRANS, master[2].HTRANS,
master[1].HTRANS, master[0].HTRANS};
assign HBUSREQ = { master[8].HBUSREQ, master[7].HBUSREQ, master[6].HBUSREQ,
master[5].HBUSREQ, master[4].HBUSREQ, master[3].HBUSREQ, master[2].HBUSREQ,
master[1].HBUSREQ, master[0].HBUSREQ};
assign HLOCK = { master[8].HLOCK, master[7].HLOCK, master[6].HLOCK, master[5].HLOCK,
master[4].HLOCK, master[3].HLOCK, master[2].HLOCK, master[1].HLOCK, master[0].HLOCK};
//------------------INTERFACES CONFIG_DB------------------------//
initial begin
uvm_config_db #(virtual ahb_if)::set(null, "*", "0", master[0]);
uvm_config_db #(virtual ahb_if)::set(null, "*", "1", master[1]);
uvm_config_db #(virtual ahb_if)::set(null, "*", "2", master[2]);
uvm_config_db #(virtual ahb_if)::set(null, "*", "3", master[3]);
uvm_config_db #(virtual ahb_if)::set(null, "*", "4", master[4]);
uvm_config_db #(virtual ahb_if)::set(null, "*", "5", master[5]);
uvm_config_db #(virtual ahb_if)::set(null, "*", "6", master[6]);
uvm_config_db #(virtual ahb_if)::set(null, "*", "7", master[7]);
uvm_config_db #(virtual ahb_if)::set(null, "*", "8", master[8]);
uvm_config_db #(virtual ahb_if)::set(null, "*", "9", slave);
end
//---------------------DUT INSTANCE----------------------------//
generic_arbiter_full DUT (
.hclk(CLOCK),
.hreset(RESET),
.m_hwdata(HWDATA),
.m_haddr(HADDR),
.m_hburst(HBURST),
.m_htrans(HTRANS),
.s_hready(slave.HREADY),
.m_busreq(HBUSREQ),
.m_hlock(HLOCK),
.s_hburst_out(slave.HBURST),
.s_htrans_out(slave.HTRANS),
.s_hmaster_lock(slave.HMASTER_LOCK),
.m_hgrant(HGRANT),
.s_data_out(slave.HWDATA),
.s_addr_out(slave.HADDR),
.s_hmaster(slave.HMASTER)
);
//---------------------RUN()--------------------------//
initial begin
run_test();
end
//------------------------WAVES--------------------------------//
initial begin
$dumpfile("dump.vcd");
$dumpvars();
// #110 $finish;
end
endmodule: top
AHB INTERFACE
interface ahb_if(input CLOCK, input RESET);
wire [7:0] HADDR;
wire [7:0] HWDATA;
wire [7:0] HRDATA;
wire [3:0] HMASTER;
wire HGRANT;
wire [2:0] HBURST;
wire [2:0] HSIZE;
wire [1:0] HTRANS;
wire HREADY;
wire HBUSREQ;
wire HLOCK;
wire HMASTER_LOCK;
wire HWRITE;
wire HSEL;
wire HRESP;
wire HPROT;
//------------------MASTER CLOCKING BLOCK------------------------//
clocking cb_master @(posedge CLOCK);
input HREADY, HRDATA, HRESP, HGRANT, RESET;
output HADDR, HTRANS, HWRITE, HSIZE, HBURST, HPROT, HWDATA, HLOCK,
HBUSREQ;
endclocking: cb_master
//------------------SLAVE CLOCKING BLOCK------------------------//
clocking cb_slave @(posedge CLOCK);
input HADDR, HTRANS, HWRITE, HSIZE, HBURST, HWDATA, HMASTER_LOCK,
HMASTER, HSEL, RESET;
output HRDATA, HRESP, HREADY;
endclocking: cb_slave
//------------------MONITOR CLOCKING BLOCK------------------------//
clocking cb_monitor @(posedge CLOCK);
input HREADY, HRDATA, HRESP, HGRANT, HADDR, HTRANS, HWRITE, HSIZE,
HBURST, HPROT, HWDATA, HLOCK, HBUSREQ, HMASTER_LOCK, HMASTER;
endclocking: cb_monitor
//------------------ASSERTION BLOCKS------------------------//
property hdata_state;
@(posedge CLOCK) (!HBUSREQ && !HREADY && !RESET && !HGRANT) |=> ((HWDATA ==
0) && (HADDR == 0));
endproperty: hdata_state
property hcontrol_state;
@(posedge CLOCK) (!HBUSREQ && !HREADY && !RESET && !HGRANT) |=> ((HTRANS ==
0) && (HSIZE == 0) && (HBURST == 0));
endproperty: hcontrol_state
property hdata_stable;
@(posedge CLOCK) (!HREADY && !HBUSREQ && !HGRANT) |=> ($stable(HWDATA) &&
$stable(HADDR) && $stable(HTRANS) && $stable(HSIZE) && $stable(HBURST));
endproperty: hdata_stable
assert property(hdata_state);
assert property(hcontrol_state);
assert property(hdata_stable);
endinterface: ahb_if
AHB ITEM
typedef enum {IDLE=0, BUSY, NONSEQ, SEQ} trans_e;
typedef enum {SINGLE=0, INCR, WRAP4, INCR4, WRAP8, INCR8, WRAP16, INCR16=7} burst_e;
class ahb_item extends uvm_sequence_item;
rand bit [7:0] HADDR;
rand bit [7:0] HWDATA_A [];
rand burst_e HBURST;
rand bit [2:0] HSIZE;
bit [3:0] HMASTER;
bit HGRANT;
bit [7:0] HRDATA;
bit [7:0] HWDATA;
trans_e HTRANS;
rand bit HWRITE;
rand bit HBUSREQ;
rand bit HLOCK;
//control fields
rand bit [4:0] TRANSFERS_COUNT; // keep the number of transfers in case of bursts
rand bit BURST_KIND; // 1 - incrementing burst 0 - wrapping burst
rand bit [3:0] ADDR_INCR; // keep the number of bits by which the address should be
incremented in case of bursts
rand bit [2:0] delay_bursts;
rand bit [2:0] delay_transfers;
constraint hsize_c { HSIZE == 3'b000;}
constraint delay_c { delay_transfers == 0;
delay_bursts == 0;}
constraint write_c { HWRITE == 1; HADDR != 0; }
constraint data_c { foreach(HWDATA_A[i]) { HWDATA_A[i] != 0; } }
constraint hwdata_c { solve TRANSFERS_COUNT before HWDATA_A;
HWDATA_A.size() == TRANSFERS_COUNT; }
constraint transfers_count_c {solve HBURST before TRANSFERS_COUNT;
solve HBURST before BURST_KIND;
(HBURST == SINGLE || HBURST == INCR) -> (TRANSFERS_COUNT == 1 &&
BURST_KIND == 1);
(HBURST == WRAP4) -> (TRANSFERS_COUNT == 4 && BURST_KIND == 0);
(HBURST == INCR4) -> (TRANSFERS_COUNT == 4 && BURST_KIND == 1);
(HBURST == WRAP8) -> (TRANSFERS_COUNT == 8 && BURST_KIND == 0);
(HBURST == INCR8) -> (TRANSFERS_COUNT == 8 && BURST_KIND == 1);
(HBURST == WRAP16) -> (TRANSFERS_COUNT == 16 && BURST_KIND ==
0);
(HBURST == INCR16) -> (TRANSFERS_COUNT == 16 && BURST_KIND ==
1);
constraint address_incr_c {solve HSIZE before ADDR_INCR;
(HSIZE == 3'b000) -> (ADDR_INCR == 1);
(HSIZE == 3'b001) -> (ADDR_INCR == 2);
(HSIZE == 3'b010) -> (ADDR_INCR == 4);
(HSIZE == 3'b011) -> (ADDR_INCR == 8);
constraint hlock_c {solve HBURST before HLOCK;
(HBURST >= 2) -> (HLOCK == 1);
(HBURST <= 1) -> (HLOCK == 0);}
`uvm_object_utils_begin(ahb_item)
`uvm_field_int(HADDR,UVM_DEFAULT)
`uvm_field_enum(trans_e, HTRANS,UVM_DEFAULT | UVM_NOCOMPARE)
`uvm_field_int(HWDATA,UVM_DEFAULT)
`uvm_field_enum(burst_e,HBURST,UVM_DEFAULT | UVM_NOCOMPARE)
`uvm_field_int(HSIZE,UVM_DEFAULT)
`uvm_field_int(HRDATA,UVM_DEFAULT)
`uvm_field_int(HWRITE,UVM_DEFAULT)
`uvm_field_int(HMASTER,UVM_DEFAULT | UVM_NOCOMPARE)
`uvm_field_int(HBUSREQ,UVM_DEFAULT | UVM_NOCOMPARE|
UVM_NOPRINT)
`uvm_field_int(HGRANT,UVM_NOCOMPARE| UVM_DEFAULT)
`uvm_field_int(HLOCK,UVM_DEFAULT|UVM_NOCOMPARE|UVM_NOPRINT)
`uvm_field_int(TRANSFERS_COUNT,UVM_ALL_ON | UVM_NOCOMPARE |
UVM_NOPACK | UVM_NOPRINT)
`uvm_object_utils_end
function new(string name = "ahb_item");
super.new(name);
endfunction: new
endclass: ahb_item
AHB ITEM DELAY
class ahb_item_delay extends ahb_item;
`uvm_object_utils(ahb_item_delay)
constraint delay_c { delay_transfers != 0;
delay_bursts != 0;}
function new(string name = "ahb_item_delay");
super.new(name);
endfunction: new
endclass: ahb_item_delay
AHB MASTER DRIVER
class ahb_master_driver extends uvm_driver #(ahb_item);
`uvm_component_utils(ahb_master_driver)
uvm_analysis_port#(int) drv_scb_port;
virtual ahb_if vif;
static int count = 0;
bit [31:0] NEXT_ADDR;
bit first = 1;
int transfers_count = 0, id, data_count = 0, delay_bursts, delay_transfer;
mailbox#(ahb_item) mbx;
//---------------------NEW()--------------------------//
function new( string name="ahb_master_driver", uvm_component parent);
super.new(name, parent);
id = count ++;
drv_scb_port = new("drv_scb_port", this);
endfunction: new
extern virtual task run_phase(uvm_phase phase);
extern function void build_phase(uvm_phase phase);
extern task drive();
extern task reset_values();
extern task put_address(ahb_item req);
extern task put_data(ahb_item req);
endclass: ahb_master_driver
//---------------------BUILD()--------------------------//
function void ahb_master_driver::build_phase(uvm_phase phase);
super.build_phase(phase);
mbx = new();
if(!uvm_config_db #(virtual ahb_if)::get(null, "*", $sformatf("%0d", id), vif))
`uvm_fatal($sformatf("DRIVER%0d", id), "Interface Not Received Properly");
endfunction: build_phase
//---------------------RUN()--------------------------//
task ahb_master_driver:: run_phase(uvm_phase phase);
super.run_phase(phase);
reset_values();
@(vif.cb_master iff (vif.RESET));
forever begin
drive();
end
endtask: run_phase
//---------------------DRIVE()--------------------------//
task ahb_master_driver::drive();
seq_item_port.get_next_item(req);
vif.cb_master.HBUSREQ <= req.HBUSREQ;
if(req.HBUSREQ) begin // if initiating a transfer
if(first) drv_scb_port.write(id);
@(vif.cb_master iff (vif.cb_master.HGRANT)); //wait for grant
@(vif.cb_master);
if(id == size - 1) begin @(vif.cb_master iff (vif.cb_master.HGRANT)); @(vif.cb_master); end
`uvm_info($sformatf("DRIVER%0d", id), $sformatf("Transaction in DRIVER - BUSREQ
%0h",req.HBUSREQ), UVM_MEDIUM);
repeat(req.delay_bursts) @(vif.cb_master);
fork
put_address(req);
put_data(req);
join
end
@(vif.cb_master);
vif.cb_master.HBUSREQ <= 0;
seq_item_port.item_done();
transfers_count = 0;
first = 0;
endtask:drive
//---------------------PUT ADDRESS()--------------------------//
task ahb_master_driver::put_address(ahb_item req);
// req.print();
NEXT_ADDR = req.HADDR;
repeat(req.TRANSFERS_COUNT) begin // drive the signals for each transfer in the burst
if(transfers_count == 0) vif.cb_master.HTRANS <= 2'b10; // if it is the first transfer, HTRANS is
NONSEQ
else vif.cb_master.HTRANS <= 2'b11; // else HTRANS e SEQ
NEXT_ADDR = NEXT_ADDR + req.ADDR_INCR; // calculate the following address for the
transfer from the burst
if(!req.BURST_KIND) begin // if it is wrapping burst - check the address
if(NEXT_ADDR % (req.ADDR_INCR * req.TRANSFERS_COUNT) == 0)
NEXT_ADDR = NEXT_ADDR - (req.ADDR_INCR * req.TRANSFERS_COUNT); //wrapp
end
vif.cb_master.HADDR <= NEXT_ADDR;
vif.cb_master.HWRITE <= req.HWRITE;
vif.cb_master.HSIZE <= req.HSIZE;
vif.cb_master.HBURST <= req.HBURST;
vif.cb_master.HLOCK <= req.HLOCK;
if(vif.cb_master.HREADY) @(vif.cb_master);
else begin @(vif.cb_master iff (vif.cb_master.HREADY)); @(vif.cb_master); end
if(transfers_count == 0) mbx.put(req);
transfers_count += 1; // count the transfers
repeat(req.delay_transfers) begin reset_values(); @(vif.cb_master); end
end
reset_values();
endtask: put_address
//---------------------PUT DATA()--------------------------//
task ahb_master_driver::put_data(ahb_item req);
ahb_item item = ahb_item::type_id::create("ahb_item");
mbx.get(item);
repeat(req.TRANSFERS_COUNT) begin
if(req.HWRITE) begin
vif.cb_master.HWDATA <= req.HWDATA_A[data_count];
data_count += 1;
end
if(vif.cb_master.HREADY) @(vif.cb_master);
else begin @(vif.cb_master iff (vif.cb_master.HREADY)); @(vif.cb_master); end
vif.cb_master.HWDATA <= 0;
repeat(req.delay_transfers) @(vif.cb_master);
end
data_count = 0;
endtask: put_data
//---------------------RESET_VALUES()--------------------------//
task ahb_master_driver::reset_values();
vif.cb_master.HADDR <= 0;
vif.cb_master.HTRANS <= 0;
vif.cb_master.HWRITE <= 0;
vif.cb_master.HSIZE <= 0;
vif.cb_master.HBURST <= 0;
vif.cb_master.HPROT <= 0;
vif.cb_master.HLOCK <= 0;
vif.cb_master.HWDATA <= 0;
endtask: reset_values
AHB MASTER MONITOR
class ahb_monitor extends uvm_component;
uvm_analysis_port#(ahb_item) mon_scb_port;
`uvm_component_utils(ahb_monitor)
virtual ahb_if vif;
static int count = 0;
static int transfer_count = 0;
ahb_item item_m;
bit first_item;
int id;
bit [31:0] CUREENT_ADDR = 0;
bit coverage_enable = 1;
mailbox #(ahb_item) mbx;
//---------------------COVERGROUP()--------------------------//
covergroup ahb_transfers_cg with function sample(ahb_item item);
option.per_instance = 1;
option.name = "ahb_transfers_cg";
TRANS_ADDR: coverpoint item.HADDR {
option.at_least = 40;
bins small_b = {[1:85]};
bins medium_b = {[86:170]};
bins big_b = {[171:255]};
TRANS_WDATA: coverpoint item.HWDATA {
option.at_least = 40;
bins small_b = {[1:85]};
bins medium_b = {[86:170]};
bins big_b = {[171:255]};
TRANS_RDATA: coverpoint item.HRDATA {
option.at_least = 40;
bins small_b = {[1:85]};
bins medium_b = {[86:170]};
bins big_b = {[171:255]};
TRANS_BURST: coverpoint item.HBURST {
option.at_least = 2;
bins increment = {3, 5, 7};
bins wrapping = {2, 4, 6};
bins single = {0, 1};
}
TRANS_HSIZE: coverpoint item.HSIZE {
bins byte_b = {0};
bins halfword = {1};
bins word = {2};
TRANS_MASTER_REQ: coverpoint item.HMASTER {
bins master[8] = {[0:8]};
DATA_ADDR: cross TRANS_WDATA, TRANS_ADDR;
MASTER_BURST: cross TRANS_BURST, TRANS_MASTER_REQ;
BURST_DATA_ADDR: cross TRANS_WDATA, TRANS_ADDR, TRANS_BURST;
endgroup: ahb_transfers_cg
//---------------------NEW()--------------------------//
function new( string name, uvm_component parent);
super.new(name, parent);
id = count ++;
mon_scb_port = new("mon_scb_port", this);
ahb_transfers_cg = new();
endfunction: new
//---------------------EXTERN FUNCTION()--------------------------//
extern virtual task run_phase(uvm_phase phase);
extern task take_data();
extern task take_address();
extern virtual function void build_phase(uvm_phase phase);
extern virtual function void check_phase(uvm_phase phase);
extern function void perform_coverage(ahb_item item);
extern virtual function void report_phase(uvm_phase phase);
endclass: ahb_monitor
//---------------------BUILD()--------------------------//
function void ahb_monitor::build_phase(uvm_phase phase);
super.build_phase(phase);
mbx = new();
if(!uvm_config_db #(virtual ahb_if)::get(null, "*", $sformatf("%0d", id), vif))
`uvm_fatal($sformatf("DRIVER%0d", id), "Interface Not Received Properly")
endfunction: build_phase
//---------------------RUN()--------------------------//
task ahb_monitor::run_phase(uvm_phase phase);
super.run_phase(phase);
fork
take_address();
take_data();
join
endtask: run_phase
//---------------------TAKE DATA()--------------------------//
task ahb_monitor::take_data();
forever begin @(vif.cb_monitor);
if(first_item) begin @(vif.cb_monitor); first_item = 0; end
if(vif.cb_monitor.HREADY && vif.RESET && vif.cb_monitor.HWDATA) begin
ahb_item item_m = ahb_item::type_id::create("item");
mbx.get(item_m);
if(first_item) begin @(vif.cb_monitor); first_item = 0; end
if(!vif.cb_monitor.HRESP && id !=9)
`uvm_fatal($sformatf("DRIVER%0d", id), "SLAVE Response 0, drop packet!")
if(item_m.HWRITE) item_m.HWDATA = vif.cb_monitor.HWDATA;
else item_m.HRDATA = vif.cb_monitor.HRDATA;
if(coverage_enable) perform_coverage(item_m);
transfer_count += 1;
// `uvm_info($sformatf("MONITOR%0d", id), $sformatf("Item send to scoreboard from
MONITOR %0d", id), UVM_MEDIUM)
mon_scb_port.write(item_m); // send to scoreboard
end end
endtask: take_data
//---------------------TAKE ADDRESS()--------------------------//
task ahb_monitor::take_address();
forever begin @(vif.cb_monitor);
if(vif.cb_monitor.HADDR && vif.RESET) begin
if( vif.cb_monitor.HADDR != CUREENT_ADDR) begin
ahb_item item = ahb_item::type_id::create("item");
item.HADDR = vif.cb_monitor.HADDR;
CUREENT_ADDR = vif.cb_monitor.HADDR;
item.HWRITE = vif.cb_monitor.HWRITE;
item.HBURST = vif.cb_monitor.HBURST;
item.HTRANS = vif.cb_monitor.HTRANS;
if(id != size) begin
item.HLOCK = vif.cb_monitor.HLOCK;
item.HGRANT = vif.cb_monitor.HGRANT;
end else begin
item.HLOCK = vif.cb_monitor.HMASTER_LOCK;
item.HMASTER = vif.cb_monitor.HMASTER;
end
if(item.HTRANS == NONSEQ) first_item = 1;
mbx.put(item);
end
end
end
endtask: take_address
//---------------------CHECK PHASE()--------------------------//
function void ahb_monitor::check_phase(uvm_phase phase);
super.check_phase(phase);
if(vif.cb_monitor.HBUSREQ)
`uvm_fatal("FATAL MONITOR", $sformatf("Master %0d still request the bus.", id))
else begin
if(id == size) begin
if(vif.cb_monitor.HMASTER != 8) `uvm_fatal("FATAL MONITOR", "Did not receive default
master on the bus")
else `uvm_info($sformatf("MONITOR%0d", id), "NO BUSREQ - Default master on the bus",
UVM_MEDIUM)
end
end
endfunction: check_phase
//---------------------PERFORM CHECK()--------------------------//
function void ahb_monitor::perform_coverage(ahb_item item);
ahb_transfers_cg.sample(item);
endfunction: perform_coverage
//---------------------REPORT PHASE()--------------------------//
function void ahb_monitor::report_phase(uvm_phase phase);
super.report_phase(phase);
if(id == 8) begin
$display ("----------------TOTAL COVERAGE REPORT %.2f%
%------------------------",ahb_transfers_cg.get_coverage());
$display("Total number of transfers = %0d", transfer_count/2);
$display ("Coverage HADDR = %.2f%%", ahb_transfers_cg.TRANS_ADDR.get_coverage());
$display ("Coverage HWDATA = %.2f%%", ahb_transfers_cg.TRANS_WDATA.get_coverage());
$display ("Coverage HRDATA = %.2f%%", ahb_transfers_cg.TRANS_RDATA.get_coverage());
$display ("Coverage HBURST = %.2f%%", ahb_transfers_cg.TRANS_BURST.get_coverage());
$display ("Coverage HSIZE = %.2f%%", ahb_transfers_cg.TRANS_HSIZE.get_coverage());
$display ("Coverage HMASTER = %.2f%%",
ahb_transfers_cg.TRANS_MASTER_REQ.get_coverage());
$display ("Coverage DATA_ADDR = %.2f%%", ahb_transfers_cg.DATA_ADDR.get_coverage());
$display ("Coverage MASTER_BURST = %.2f%%",
ahb_transfers_cg.MASTER_BURST.get_coverage());
$display ("Coverage BURST_DATA_ADDR = %.2f%%",
ahb_transfers_cg.BURST_DATA_ADDR.get_coverage());
$display ("-------------------------------------------------------------------");
end
endfunction: report_phase
AHB SEQUENCES
//************************RANDOM SEQUENCES()****************************//
class random_ahb_transfer_seq extends uvm_sequence #(ahb_item);
rand bit [2:0] num_seq;
rand bit RHBUSREQ;
rand burst_e RHBURST;
constraint num_seq_c { num_seq != 0; }
`uvm_object_utils(random_ahb_transfer_seq)
`uvm_declare_p_sequencer(ahb_sequencer)
function new(string name = "random_ahb_transfer_seq");
super.new(name);
endfunction: new
virtual task body();
repeat(num_seq)
`uvm_do_with(req, { req.HBUSREQ == RHBUSREQ; req.HBURST == RHBURST;})
endtask: body
endclass: random_ahb_transfer_seq
//************************VIRTUAL SEQUENCES()****************************//
class virtual_sequences extends uvm_sequence #(ahb_item);
random_ahb_transfer_seq seq_m[];
`uvm_object_utils(virtual_sequences)
`uvm_declare_p_sequencer(virtual_ahb_sequencer)
function new(string name = "virtual_sequences");
super.new(name);
seq_m = new[size];
foreach(seq_m[i])
seq_m[i] = random_ahb_transfer_seq::type_id::create($sformatf("seq_m%0d",i));
endfunction: new
virtual task body();
fork
`uvm_do_on(seq_m[0], p_sequencer.sequencer[0]);
`uvm_do_on(seq_m[1], p_sequencer.sequencer[1]);
`uvm_do_on(seq_m[2], p_sequencer.sequencer[2]);
`uvm_do_on(seq_m[3], p_sequencer.sequencer[3]);
`uvm_do_on(seq_m[4], p_sequencer.sequencer[4]);
`uvm_do_on(seq_m[5], p_sequencer.sequencer[5]);
`uvm_do_on(seq_m[6], p_sequencer.sequencer[6]);
`uvm_do_on(seq_m[7], p_sequencer.sequencer[7]);
`uvm_do_on(seq_m[8], p_sequencer.sequencer[8]);
join
endtask: body
endclass: virtual_sequences
//************************INCREMENT SEQUENCES()****************************//
class incr_bursts_seq extends random_ahb_transfer_seq;
constraint incr_bursts_c { RHBURST inside {INCR4, INCR8, INCR16};
RHBUSREQ == 1;}
`uvm_object_utils(incr_bursts_seq)
`uvm_declare_p_sequencer(ahb_sequencer)
function new(string name = "incr_bursts_seq");
super.new(name);
endfunction: new
endclass: incr_bursts_seq
//************************WRAPPING SEQUENCES()****************************//
class wrap_bursts_seq extends random_ahb_transfer_seq;
constraint wrap_bursts_c { RHBURST inside {WRAP4, WRAP8, WRAP16}; }
`uvm_object_utils(wrap_bursts_seq)
`uvm_declare_p_sequencer(ahb_sequencer)
function new(string name = "wrap_bursts_seq");
super.new(name);
endfunction: new
endclass: wrap_bursts_seq
//************************SINGLE TRANSFER
SEQUENCES()****************************//
class single_transfers_seq extends random_ahb_transfer_seq;
constraint single_transfer_c { RHBURST inside {SINGLE, INCR}; }
`uvm_object_utils(single_transfers_seq)
`uvm_declare_p_sequencer(ahb_sequencer)
function new(string name = "single_transfers_seq");
super.new(name);
endfunction: new
endclass: single_transfers_seq
//************************WRAPPING SEQUENCES()****************************//
class no_busreq_seq extends random_ahb_transfer_seq;
constraint no_busreq_c { RHBUSREQ == 0; }
`uvm_object_utils(no_busreq_seq)
`uvm_declare_p_sequencer(ahb_sequencer)
function new(string name = "no_busreq_seq");
super.new(name);
endfunction: new
endclass: no_busreq_seq
//************************REQUEST ALL MASTERS
SEQUENCES()****************************//
class all_busreq_seq extends random_ahb_transfer_seq;
constraint all_busreq_c { RHBUSREQ == 1; }
`uvm_object_utils(all_busreq_seq)
`uvm_declare_p_sequencer(ahb_sequencer)
function new(string name = "all_busreq_seq");
super.new(name);
endfunction: new
endclass: all_busreq_seq
AHB SEQUENCER
//---------------------SEQUENCER CLASS--------------------------//
class ahb_sequencer extends uvm_sequencer #(ahb_item);
`uvm_sequencer_utils(ahb_sequencer)
//---------------------NEW()--------------------------//
function new(string name = "ahb_sequencer", uvm_component parent);
super.new(name, parent);
endfunction: new
endclass: ahb_sequencer
//---------------------VIRTUAL SEQUENCER CLASS--------------------------//
class virtual_ahb_sequencer extends uvm_sequencer#(ahb_item);
`uvm_sequencer_utils(virtual_ahb_sequencer)
ahb_sequencer sequencer[];
//---------------------NEW()--------------------------//
function new(string name = "virtual_ahb_sequencer", uvm_component parent);
super.new(name, parent);
sequencer = new[size];
foreach (sequencer[i])
sequencer[i] = ahb_sequencer::type_id::create($sformatf("sequencer%0d",i), null);
endfunction: new
endclass: virtual_ahb_sequencer
AHB AGENT
class ahb_agent extends uvm_agent;
uvm_active_passive_enum is_active = UVM_ACTIVE;
virtual_ahb_sequencer virtual_ahb_sequencer_h;
ahb_master_driver driver_master;
ahb_agent_config cfg;
ahb_slave_driver driver_slave;
ahb_monitor monitor;
static int count = 0;
int id;
`uvm_component_utils_begin(ahb_agent)
`uvm_field_enum(uvm_active_passive_enum, is_active, UVM_DEFAULT)
`uvm_component_utils_end
//---------------------NEW()--------------------------//
function new( string name="ahb_agent", uvm_component parent);
super.new(name, parent);
id = count ++;
endfunction: new
extern virtual function void build_phase(uvm_phase phase);
endclass: ahb_agent
//---------------------BUILD()--------------------------//
function void ahb_agent::build_phase(uvm_phase phase);
super.build_phase(phase);
if(cfg.agent_mode == UVM_ACTIVE_MASTER && is_active == UVM_ACTIVE)
driver_master = ahb_master_driver::type_id::create("driver_master", this);
else if(cfg.agent_mode == UVM_ACTIVE_SLAVE & is_active == UVM_ACTIVE)
driver_slave = ahb_slave_driver::type_id::create("driver_slave", this);
monitor = ahb_monitor::type_id::create("monitor", this);
endfunction: build_phase
AHB BASE TEST
class base_test extends uvm_test;
`uvm_component_utils(base_test)
ahb_env ahb_env_h;
//---------------------NEW()--------------------------//
function new(string name="base_test", uvm_component parent);
super.new(name, parent);
endfunction: new
//---------------------BUILD()--------------------------//
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
ahb_env_h = ahb_env::type_id::create("ahb_env_h", this);
endfunction: build_phase
endclass: base_test
AHB SCOREBOARD
`uvm_analysis_imp_decl(_mon_m)
`uvm_analysis_imp_decl(_mon_s)
`uvm_analysis_imp_decl(_drv)
class scoreboard extends uvm_scoreboard;
`uvm_component_utils(scoreboard)
uvm_analysis_imp_mon_m #(ahb_item, scoreboard) ahb_mon_m;
uvm_analysis_imp_mon_s #(ahb_item, scoreboard) ahb_mon_s;
uvm_analysis_imp_drv #(int, scoreboard) ahb_drv;
ahb_item q[$];
int q_master[$];
int start_test = 1;
ahb_item expected_item;
int HMASTER, NEXT_HMASTER;
//---------------------NEW()--------------------------//
function new (string name= "scoreboard" , uvm_component parent);
super.new(name,parent);
ahb_mon_m = new("ahb_mon_m", this);
ahb_mon_s = new("ahb_mon_s", this);
ahb_drv = new("ahb_drv", this);
endfunction: new
//---------------------WRITE FROM MONITOR()--------------------------//
virtual function void write_mon_m(ahb_item expected_item);
// `uvm_info("SCOREBOARD", "Item arrived from MASTER MONITOR in scoreboard in
write_mon_m", UVM_MEDIUM)
q.push_back(expected_item);
endfunction: write_mon_m
//---------------------CHECK ARBITRATION()--------------------------//
virtual function void check_arbitration(int ARRIVED_HMASTER);
if(start_test) begin
`uvm_info("SCOREBOARD", "The order of the masters who will receive access to the bus is:",
UVM_MEDIUM)
foreach (q_master[i] ) $write("%0h ",q_master[i]); $display();
end
HMASTER = q_master[0];
if(q_master.size() > 1) NEXT_HMASTER = q_master[1];
if(start_test && ARRIVED_HMASTER != HMASTER)
`uvm_fatal("FATAL SCOREBOARD0", $sformatf("Didn't received expected Master: received %0h
expected %0h", ARRIVED_HMASTER, HMASTER))
else if(!start_test && ARRIVED_HMASTER != HMASTER && q_master.size() == 1)
`uvm_fatal("FATAL SCOREBOARD1", $sformatf("Didn't received expected Master: received %0h
expected %0h", ARRIVED_HMASTER, HMASTER))
else if(!start_test && q_master.size() != 1 && ARRIVED_HMASTER != NEXT_HMASTER &&
ARRIVED_HMASTER != HMASTER)
`uvm_fatal("FATAL SCOREBOARD2", $sformatf("Didn't received expected Master: received %0h
expected %0h", ARRIVED_HMASTER, HMASTER))
if(ARRIVED_HMASTER == NEXT_HMASTER && q_master.size() != 1)
void'(q_master.pop_front());
start_test = 0;
endfunction: check_arbitration
//---------------------WRITE FROM SLAVE()--------------------------//
virtual function void write_mon_s(ahb_item arrived_item);
`uvm_info("SCOREBOARD", "Compare packages: first packet is from slave, second packet is from
master", UVM_MEDIUM)
if(q.size()) begin
expected_item = q.pop_front();
check_arbitration(arrived_item.HMASTER);
// arrived_item.print();
// expected_item.print();
if(arrived_item.compare(expected_item))
`uvm_info("SCOREBOARD", "Sent packet and received packet matched", UVM_MEDIUM)
else
`uvm_fatal("FATAL SCOREBOARD", "Sent packet and received packet mismatched")
end else
`uvm_fatal("FATAL SCOREBOARD", "No more packets in the expected queue to compare")
endfunction: write_mon_s
//---------------------WRITE FROM DRIVER()--------------------------//
virtual function void write_drv(int master);
q_master.push_back(master);
endfunction: write_drv
//---------------------CHECK PHASE()--------------------------//
virtual function void check_phase(uvm_phase phase);
super.check_phase(phase);
if(q.size() != 0)
`uvm_fatal("FATAL SCOREBOARD", $sformatf("Did not receive all the packages. %0h packages
in the list", q.size()))
else
`uvm_info("SCOREBOARD", "Transfers completed successfully", UVM_MEDIUM)
endfunction: check_phase
endclass: scoreboard
AHB ENVIRONMENT
class ahb_env extends uvm_env;
virtual_ahb_sequencer virtual_ahb_sequencer_h;
scoreboard scoreboard_h;
ahb_agent master[];
ahb_agent slave;
ahb_config cfg;
`uvm_component_utils_begin(ahb_env)
`uvm_field_object(cfg, UVM_DEFAULT)
`uvm_component_utils_end
//---------------------NEW()--------------------------//
function new( string name="ahb_env", uvm_component parent);
super.new(name, parent);
endfunction: new
//---------------------BUILD()--------------------------//
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(cfg == null) begin
cfg = ahb_config::type_id::create("cfg", this);
assert(cfg.randomize());
end
virtual_ahb_sequencer_h = virtual_ahb_sequencer::type_id::create("virtual_ahb_sequencer_h", this);
scoreboard_h = scoreboard::type_id::create("scoreboard", this);
master = new[NumMaster];
foreach (master[i]) begin
master[i] = ahb_agent::type_id::create($psprintf("master[%0d]",i), this);
master[i].cfg = cfg.master_config[i];
end
slave = ahb_agent::type_id::create("slave", this);
slave.cfg = cfg.slave_config;
endfunction: build_phase
//---------------------CONNECT()--------------------------//
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
foreach (master[i]) begin
if(master[i].is_active == UVM_ACTIVE) begin
master[i].driver_master.seq_item_port.connect(virtual_ahb_sequencer_h.sequencer[i].seq_item_exp
ort);
master[i].driver_master.drv_scb_port.connect(scoreboard_h.ahb_drv);
end
master[i].monitor.mon_scb_port.connect(scoreboard_h.ahb_mon_m);
end
slave.monitor.mon_scb_port.connect(scoreboard_h.ahb_mon_s);
endfunction: connect_phase
endclass: ahb_env
AHB SLAVE DRIVER
class ahb_slave_driver extends uvm_driver #(ahb_item);
`uvm_component_utils(ahb_slave_driver)
virtual ahb_if vif;
//---------------------NEW()--------------------------//
function new( string name="ahb_slave_driver", uvm_component parent);
super.new(name, parent);
endfunction: new
extern virtual task run_phase(uvm_phase phase);
extern function void build_phase(uvm_phase phase);
extern task drive();
endclass: ahb_slave_driver
//---------------------BUILD()--------------------------//
function void ahb_slave_driver::build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db #(virtual ahb_if)::get(null, "*", $sformatf("%0d",size), vif))
`uvm_fatal("DRIVER_SLAVE", "Interface Not Received Properly");
endfunction: build_phase
//---------------------RUN()--------------------------//
task ahb_slave_driver:: run_phase(uvm_phase phase);
super.run_phase(phase);
vif.cb_slave.HREADY <= 0;
vif.cb_slave.HRDATA <= 0;
vif.cb_slave.HRESP <= 0;
@(vif.cb_slave iff (vif.RESET));
forever begin
drive();
end
endtask: run_phase
//---------------------DRIVE()--------------------------//
task ahb_slave_driver::drive();
@(vif.cb_slave);
vif.cb_slave.HREADY <= 1;
if(!vif.HWRITE)
vif.cb_slave.HRDATA <= $urandom();
@(vif.cb_slave);
vif.cb_slave.HRDATA <= 32'h0;
endtask:drive
AHB CONFIG
typedef enum {UVM_ACTIVE_SLAVE, UVM_ACTIVE_MASTER} ahb_mode_enum;
//---------------------AHB_AGENT_CONFIG()--------------------------//
class ahb_agent_config extends uvm_object;
`uvm_object_utils(ahb_agent_config)
rand ahb_mode_enum agent_mode;
//---------------------NEW()--------------------------//
function new( string name="ahb_agent_config");
super.new(name);
endfunction: new
endclass: ahb_agent_config
//---------------------AHB_CONFIG()--------------------------//
class ahb_config extends uvm_object;
`uvm_object_utils(ahb_config)
rand ahb_agent_config master_config[];
rand ahb_agent_config slave_config;
rand bit has_bus_monitor = 1;
constraint c_slave { slave_config.agent_mode == UVM_ACTIVE_SLAVE;}
constraint c_master {
foreach (master_config[i])
master_config[i].agent_mode == UVM_ACTIVE_MASTER;
//---------------------NEW()--------------------------//
function new( string name="ahb_config");
super.new(name);
master_config = new[NumMaster];
foreach (master_config[i])
master_config[i] = ahb_agent_config::type_id::create($psprintf("master_config[%0d]",i));
slave_config = ahb_agent_config::type_id::create("slave_config");
endfunction: new
endclass: ahb_config
AHB TEST
class ahb_test extends base_test;
`uvm_component_utils(ahb_test)
virtual_sequences seq;
function new(string name="ahb_test", uvm_component parent);
super.new(name, parent);
endfunction: new
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
// set_type_override_by_type(ahb_item::get_type(), ahb_item_delay::get_type());
// set_type_override_by_type(random_ahb_transfer_seq::get_type(), incr_bursts_seq::get_type());
// set_type_override_by_type(random_ahb_transfer_seq::get_type(), wrap_bursts_seq::get_type());
// set_type_override_by_type(random_ahb_transfer_seq::get_type(), single_transfers_seq::get_type());
// set_type_override_by_type(random_ahb_transfer_seq::get_type(), no_busreq_seq::get_type());
// set_type_override_by_type(random_ahb_transfer_seq::get_type(), all_busreq_seq::get_type());
seq = virtual_sequences::type_id::create("seq");
endfunction: build_phase
//---------------------RUN()--------------------------//
task run_phase(uvm_phase phase);
super.run_phase(phase);
phase.raise_objection(this);
seq.start(ahb_env_h.virtual_ahb_sequencer_h);
#100
phase.drop_objection(this);
endtask: run_phase
endclass: ahb_test