AHB AMBA Protocol - Verification Code

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 39

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

You might also like