100% found this document useful (1 vote)
2K views

AHB AMBA Protocol - Verification Code

The document describes a SystemVerilog module that defines an AHB bus interface with multiple masters and a single slave. It instantiates the interface modules, connects the masters and slave ports, and configures the UVM database. It also defines clock and reset signals and instantiates an arbiter module between the masters and slave ports.

Uploaded by

Monik Monaa
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
2K views

AHB AMBA Protocol - Verification Code

The document describes a SystemVerilog module that defines an AHB bus interface with multiple masters and a single slave. It instantiates the interface modules, connects the masters and slave ports, and configures the UVM database. It also defines clock and reset signals and instantiates an arbiter module between the masters and slave ports.

Uploaded by

Monik Monaa
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 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