This commit is contained in:
2026-06-12 07:53:32 +02:00
commit 59e71f3297
259 changed files with 29010 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_test_top.sv
DESCRIPTION top module
- connects DUT and interface
- generates clk and reset
- runs UVM test
****************************************************************************/
`ifndef APB_TEST_TOP_SV
`define APB_TEST_TOP_SV
/**
* Module: apb_test_top
*/
module apb_test_top;
import uvm_pkg::*; // import the UVM library
`include "uvm_macros.svh" // Include the UVM macros
import apb_pkg::*; // import the APB pkg
`include "apb_test_lib.sv"
`include "dut.sv"
logic clock;
logic reset;
// interface
apb_if apb_vif(clock, reset);
// DUT
dut #( .ADDR_WIDTH(32),
.RDATA_WIDTH(32),
.WDATA_WIDTH(32),
.SLV_NUM(15)
) dut_inst (
.paddr (apb_vif.paddr ),
.psel (apb_vif.psel ),
.penable (apb_vif.penable),
.pwrite (apb_vif.pwrite ),
.pwdata (apb_vif.pwdata ),
.pready (apb_vif.pready ),
.prdata (apb_vif.prdata ),
.pslverr (apb_vif.pslverr)
);
// set interface in db; run UVM test
initial begin
uvm_config_db#(virtual apb_if)::set(null,"uvm_test_top.*","apb_if", apb_vif);
run_test();
end
// initialize clock and reset
initial begin
clock <= 1'b0;
reset <= 1'b0;
#50 reset <= 1'b1;
end
// generate clock
always #5 clock = ~clock;
endmodule : apb_test_top
`endif

View File

@@ -0,0 +1,36 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE dut.sv
DESCRIPTION
****************************************************************************/
`ifndef DUT_SV
`define DUT_SV
/**
* Module: dut
*/
module dut#(
parameter ADDR_WIDTH = 32,
parameter RDATA_WIDTH = 32,
parameter WDATA_WIDTH = 32,
parameter SLV_NUM = 15
)
(
ref logic [ADDR_WIDTH - 1 : 0] paddr,
ref logic [SLV_NUM - 1 : 0] psel,
ref logic penable,
ref logic pwrite,
ref logic [WDATA_WIDTH - 1 : 0] pwdata,
ref logic pready,
ref logic [RDATA_WIDTH - 1 : 0] prdata,
ref logic pslverr
);
endmodule : dut
`endif

View File

@@ -0,0 +1,48 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_test_base.sv
DESCRIPTION base test to be extended by other tests
****************************************************************************/
`ifndef APB_TEST_BASE_SV
`define APB_TEST_BASE_SV
/**
* Class: apb_test_base
*/
class apb_test_base extends uvm_test;
// UVM factory registration
`uvm_component_utils (apb_test_base)
// main environment
apb_env env;
// new - constructor
function new(string name = "apb_test_base", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// build environment
env = apb_env::type_id::create("env", this);
endfunction : build_phase
// UVM end_of_elaboration_phase
function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
// display verification environment topology
uvm_top.print_topology();
endfunction : end_of_elaboration_phase
endclass : apb_test_base
`endif

View File

@@ -0,0 +1,18 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_test_lib.sv
DESCRIPTION test includes
****************************************************************************/
`ifndef APB_TEST_LIB_SV
`define APB_TEST_LIB_SV
`include "apb_test_base.sv"
`include "apb_test_simple.sv"
`endif

View File

@@ -0,0 +1,59 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_test_simple.sv
DESCRIPTION simple test for debug
****************************************************************************/
`ifndef APB_TEST_SIMPLE_SV
`define APB_TEST_SIMPLE_SV
/**
* Class: apb_test_simple
*/
class apb_test_simple extends apb_test_base;
// UVM factory registration
`uvm_component_utils (apb_test_simple)
// sequences
apb_master_simple_seq master_seq;
apb_slave_simple_seq slave_seq;
// new - constructor
function new(string name = "apb_test_simple", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// build all sequences
master_seq = apb_master_simple_seq::type_id::create("master_seq");
slave_seq = apb_slave_simple_seq::type_id::create("slave_seq");
endfunction : build_phase
// UVM run_phase
task run_phase(uvm_phase phase);
assert(master_seq.randomize()); // random fields in master seq.
phase.raise_objection(this); // test cannot end yet
// start all sequences
fork
master_seq.start(env.master.seqr);
slave_seq.start(env.slaves[0].seqr); // runs forever
join_any
// only way to get here is if master sequence finished
phase.drop_objection(this); // test can end
endtask : run_phase
endclass : apb_test_simple
`endif

View File

@@ -0,0 +1,29 @@
################################################################################
# +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
# |F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
# +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
#
# FILE run
#
# DESCRIPTION
#
################################################################################
# Create the library.
if [file exists work] {
vdel -all
}
vlib work
# compile testbench
vlog -sv \
+incdir+$env(UVM_HOME) \
+incdir+../sv \
+incdir+../examples \
+incdir+../examples/tests \
../sv/apb_pkg.sv \
../examples/apb_test_top.sv
# run simulation
vsim apb_test_top -novopt +UVM_TESTNAME=apb_test_simple -sv_seed random

View File

@@ -0,0 +1,117 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_config.sv
DESCRIPTION contains main and default configurations
****************************************************************************/
`ifndef APB_CONFIG_SV
`define APB_CONFIG_SV
/**
* Class: apb_config
*/
class apb_config extends uvm_object;
// number of master and slave agents
int unsigned num_of_slaves; // total number of slaves (DUT or agents)
int unsigned num_of_slave_agents; // number of UVM slave agents
bit has_master;
// configurations for every agent
apb_slave_config slave_cfg_queue[$];
apb_master_config master_cfg;
// control
bit has_pslverr = 1; // APB peripherals are not required to support the PSLVERR pin
bit has_checks = 1;
bit has_coverage = 1;
// UVM factory registration
`uvm_object_utils_begin(apb_config)
`uvm_field_int(num_of_slaves, UVM_DEFAULT)
`uvm_field_int(num_of_slave_agents, UVM_DEFAULT)
`uvm_field_int(has_master, UVM_DEFAULT)
`uvm_field_queue_object(slave_cfg_queue, UVM_DEFAULT)
`uvm_field_object(master_cfg, UVM_DEFAULT)
`uvm_field_int(has_pslverr, UVM_DEFAULT)
`uvm_field_int(has_checks, UVM_DEFAULT)
`uvm_field_int(has_coverage, UVM_DEFAULT)
`uvm_object_utils_end
// new - constructor
function new(string name = "apb_config");
super.new(name);
endfunction : new
// additional class methods
extern function void add_slave( bit [ADDR_WIDTH - 1 : 0] start_addr,
bit [ADDR_WIDTH - 1 : 0] end_addr,
int unsigned psel_indx,
bit create_agent = 1,
uvm_active_passive_enum is_active = UVM_ACTIVE);
extern function void add_master(uvm_active_passive_enum is_active = UVM_ACTIVE);
extern function int unsigned get_slave_psel_by_addr(bit [ADDR_WIDTH - 1 : 0] addr);
endclass : apb_config
// creates and configures a slave agent config and adds to a queue
function void apb_config::add_slave(bit [ADDR_WIDTH - 1 : 0] start_addr,
bit [ADDR_WIDTH - 1 : 0] end_addr,
int unsigned psel_indx,
bit create_agent = 1,
uvm_active_passive_enum is_active = UVM_ACTIVE);
apb_slave_config tmp_cfg;
++num_of_slaves;
if(create_agent == 1) ++num_of_slave_agents;
tmp_cfg = apb_slave_config::type_id::create("slave_cfg");
tmp_cfg.start_address = start_addr;
tmp_cfg.end_address = end_addr;
tmp_cfg.psel_index = psel_indx;
tmp_cfg.create_agent = create_agent;
tmp_cfg.is_active = is_active;
tmp_cfg.has_checks = has_checks;
tmp_cfg.has_coverage = has_coverage;
slave_cfg_queue.push_back(tmp_cfg);
endfunction : add_slave
// creates and configures a master agent configuration
function void apb_config::add_master(uvm_active_passive_enum is_active = UVM_ACTIVE);
has_master = 1;
master_cfg = apb_master_config::type_id::create("master_cfg");
master_cfg.is_active = is_active;
master_cfg.has_checks = has_checks;
master_cfg.has_coverage = has_coverage;
endfunction : add_master
// returns the slave psel index
function int unsigned apb_config::get_slave_psel_by_addr(bit [ADDR_WIDTH - 1 : 0] addr);
for (int i = 0; i < slave_cfg_queue.size(); i++)
if(slave_cfg_queue[i].check_address_range(addr)) begin
return slave_cfg_queue[i].psel_index;
end
return 0;
endfunction : get_slave_psel_by_addr
/**
* Class: default_apb_config
*
* Description: default configuration - one master, no slaves
*/
class default_apb_config extends apb_config;
`uvm_object_utils(default_apb_config)
function new(string name = "default_apb_config");
super.new(name);
add_master(UVM_ACTIVE);
add_slave(0, 2**ADDR_WIDTH - 1, 1, 1, UVM_ACTIVE); // TODO : remove after debug
endfunction : new
endclass : default_apb_config
`endif

View File

@@ -0,0 +1,75 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_env.sv
DESCRIPTION environment containing the master and slave agents
****************************************************************************/
`ifndef APB_ENV_SV
`define APB_ENV_SV
/**
* Class: apb_env
*/
class apb_env extends uvm_env;
apb_slave_agent slaves[]; // can have more than one slave
apb_master_agent master; // one master
apb_config cfg; // uvc configuration
// UVM factory registration
`uvm_component_utils_begin(apb_env)
`uvm_field_object(cfg, UVM_DEFAULT)
`uvm_component_utils_end
// new - constructor
function new(string name = "apb_env", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration from db or use default configuration if none is set
if(!uvm_config_db#(apb_config)::get(this, "", "apb_config", cfg)) begin
`uvm_info("NOCONFIG", "Using default_apb_config", UVM_LOW)
apb_config::type_id::set_type_override(default_apb_config::get_type(), 1);
cfg = apb_config::type_id::create("cfg");
end
// set the master configuration
if(cfg.has_master) begin
uvm_config_db#(apb_config)::set(this, "master*", "apb_config", cfg);
end
// set the slave configurations
foreach(cfg.slave_cfg_queue[i]) begin
string sname;
sname = $sformatf("slave[%0d]*", i);
uvm_config_db#(apb_slave_config)::set(this, sname, "apb_slave_config", cfg.slave_cfg_queue[i]);
end
// create agents
if(cfg.has_master) begin
master = apb_master_agent::type_id::create("master",this);
end
if(cfg.num_of_slave_agents != 0) begin
slaves = new[cfg.num_of_slave_agents];
for(int i = 0; i < cfg.slave_cfg_queue.size(); i++) begin
if(cfg.slave_cfg_queue[i].create_agent == 1) begin
slaves[i] = apb_slave_agent::type_id::create($sformatf("slave[%0d]", i), this);
end
end
end
endfunction : build_phase
endclass : apb_env
`endif

View File

@@ -0,0 +1,48 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_if.sv
DESCRIPTION apb interface
****************************************************************************/
`ifndef APB_IF_SV
`define APB_IF_SV
/**
* Interface: apb_if
*/
interface apb_if (input logic pclk, input logic presetn);
parameter ADDR_WIDTH = 32; // up to 32 bits
parameter RDATA_WIDTH = 32; // up to 32 bits
parameter WDATA_WIDTH = 32; // up to 32 bits
parameter SLV_NUM = 15;
// source is master
logic [ADDR_WIDTH - 1 : 0] paddr; // the APB address bus
logic [SLV_NUM - 1 : 0] psel; // select; the slave device is selected
// and that a data transfer is required
logic penable; // enable; the second and subsequent
// cycles of an APB transfer
logic pwrite; // direction
logic [WDATA_WIDTH - 1 : 0] pwdata; // write data
// source is slave
logic pready; // ready; the slave uses this signal to
// extend an APB transfer
logic [RDATA_WIDTH - 1 : 0] prdata; // read data
logic pslverr; // indicates a transfer failure
// control
bit has_checks = 1;
bit has_coverage = 1;
// TODO : coverage and assertions go here...
endinterface : apb_if
`endif

View File

@@ -0,0 +1,83 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_pkg.sv
DESCRIPTION package containing all parameters and includes
****************************************************************************/
`ifndef APB_PKG_SV
`define APB_PKG_SV
/**
* Package: apb_pkg
*/
package apb_pkg;
parameter ADDR_WIDTH = 32; // up to 32 bits
parameter RDATA_WIDTH = 32; // up to 32 bits
parameter WDATA_WIDTH = 32; // up to 32 bits
parameter SLV_NUM = 15; // up to 15 slaves
// ==================== OBJECTS ==============================
typedef class apb_transaction;
typedef class apb_master_config;
typedef class apb_slave_config;
typedef class apb_config;
// ==========================================================
// ==================== SLAVE ===============================
typedef class apb_slave_driver;
typedef class apb_slave_sequencer;
typedef class apb_slave_monitor;
typedef class apb_slave_agent;
// ==========================================================
// ==================== MASTER ==============================
typedef class apb_master_driver;
typedef class apb_master_sequencer;
typedef class apb_master_monitor;
typedef class apb_master_agent;
// ==========================================================
// ==================== TOP ==================================
typedef class apb_env;
// ==========================================================
import uvm_pkg::*;
`include "uvm_macros.svh"
`include "apb_types.sv"
`include "apb_config.sv"
// ==================== MASTER ==============================
`include "master/sequences/apb_master_seq_lib.sv"
`include "master/apb_master_config.sv"
`include "master/apb_master_driver.sv"
`include "master/apb_master_monitor.sv"
`include "master/apb_master_sequencer.sv"
`include "master/apb_master_agent.sv"
// ==========================================================
// ==================== SLAVE ===============================
`include "slave/sequences/apb_slave_seq_lib.sv"
`include "slave/apb_slave_config.sv"
`include "slave/apb_slave_driver.sv"
`include "slave/apb_slave_monitor.sv"
`include "slave/apb_slave_sequencer.sv"
`include "slave/apb_slave_agent.sv"
// ==========================================================
// ==================== TOP =================================
`include "apb_env.sv"
`include "apb_transaction.sv"
// ==========================================================
endpackage : apb_pkg
`include "apb_if.sv"
`endif

View File

@@ -0,0 +1,48 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_transaction.sv
DESCRIPTION sequence item
****************************************************************************/
`ifndef APB_TRANSACTION_SV
`define APB_TRANSACTION_SV
/**
* Class: apb_transaction
*/
class apb_transaction extends uvm_sequence_item;
// fields
rand bit [ADDR_WIDTH - 1 : 0] addr;
rand apb_direction_enum dir;
rand bit [RDATA_WIDTH - 1 : 0] rdata;
rand bit [WDATA_WIDTH - 1 : 0] wdata;
rand int unsigned delay = 0;
bit error;
// constraints
constraint c_delay { delay <= 10 ; }
// UVM factory registration
`uvm_object_utils_begin(apb_transaction)
`uvm_field_int(addr, UVM_DEFAULT)
`uvm_field_enum(apb_direction_enum, dir, UVM_DEFAULT)
`uvm_field_int(rdata, UVM_DEFAULT)
`uvm_field_int(wdata, UVM_DEFAULT)
`uvm_field_int(delay, UVM_DEFAULT)
`uvm_field_int(error, UVM_DEFAULT)
`uvm_object_utils_end
// new - constructor
function new(string name = "apb_transaction");
super.new(name);
endfunction : new
endclass : apb_transaction
`endif

View File

@@ -0,0 +1,22 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_types.sv
DESCRIPTION contains all typedef-s used in project
****************************************************************************/
`ifndef APB_TYPES_SV
`define APB_TYPES_SV
// APB direction - read or write
typedef enum {
APB_READ = 0,
APB_WRITE = 1
} apb_direction_enum;
`endif

View File

@@ -0,0 +1,67 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_agent.sv
DESCRIPTION master agent
****************************************************************************/
`ifndef APB_MASTER_AGENT_SV
`define APB_MASTER_AGENT_SV
/**
* Class: apb_master_agent
*/
class apb_master_agent extends uvm_agent;
// configuration object
apb_config cfg;
// components
apb_master_driver drv;
apb_master_sequencer seqr;
apb_master_monitor mon;
// UVM factory registration
`uvm_component_utils_begin(apb_master_agent)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// new - constructor
function new(string name = "apb_master_agent", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(apb_config)::get(this, "", "apb_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
// create driver and sequencer if agent is active
if(cfg.master_cfg.is_active == UVM_ACTIVE) begin
seqr = apb_master_sequencer::type_id::create("seqr", this);
drv = apb_master_driver::type_id::create("drv", this);
end
// always create monitor
mon = apb_master_monitor::type_id::create("mon", this);
endfunction : build_phase
// UVM connect_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// connect driver and sequencer if agent is active
if(cfg.master_cfg.is_active == UVM_ACTIVE) begin
drv.seq_item_port.connect(seqr.seq_item_export);
end
endfunction : connect_phase
endclass : apb_master_agent
`endif

View File

@@ -0,0 +1,41 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_config.sv
DESCRIPTION master configuration object
****************************************************************************/
`ifndef APB_MASTER_CONFIG_SV
`define APB_MASTER_CONFIG_SV
/**
* Class: apb_master_config
*/
class apb_master_config extends uvm_object;
// is agent active or passive
uvm_active_passive_enum is_active = UVM_ACTIVE;
// checks and coverage control
bit has_checks = 1;
bit has_coverage = 1;
// UVM factory registration
`uvm_object_utils_begin(apb_master_config)
`uvm_field_enum(uvm_active_passive_enum, is_active, UVM_DEFAULT)
`uvm_field_int(has_checks, UVM_DEFAULT)
`uvm_field_int(has_coverage, UVM_DEFAULT)
`uvm_object_utils_end
// new - constructor
function new(string name = "apb_master_config");
super.new(name);
endfunction : new
endclass : apb_master_config
`endif

View File

@@ -0,0 +1,132 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_driver.sv
DESCRIPTION
****************************************************************************/
`ifndef APB_MASTER_DRIVER_SV
`define APB_MASTER_DRIVER_SV
/**
* Class: apb_master_driver
*/
class apb_master_driver extends uvm_driver #(apb_transaction, apb_transaction);
// apb virtual interface
virtual apb_if vif;
// configuration
apb_config cfg;
// UVM factory registration
`uvm_component_utils_begin(apb_master_driver)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// new - constructor
function new(string name = "apb_master_driver", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(apb_config)::get(this, "*", "apb_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
endfunction: build_phase
// UVM connect_phase
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// get interface from db
if(!uvm_config_db#(virtual apb_if)::get(this, "", "apb_if", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"})
endfunction : connect_phase
// additional class methods
extern virtual task run_phase(uvm_phase phase);
extern virtual task get_and_drive();
extern virtual task reset();
extern virtual task drive_tr (apb_transaction tr);
endclass : apb_master_driver
// UVM run_phase
task apb_master_driver::run_phase(uvm_phase phase);
reset(); // init.
forever begin
fork
get_and_drive(); // thread killed at reset
@(negedge vif.presetn); // reset is active low
join_any
disable fork;
reset();
end
endtask : run_phase
// reset signals
task apb_master_driver::reset();
`uvm_info(get_type_name(), "Reset observed", UVM_MEDIUM)
vif.paddr <= {ADDR_WIDTH {1'b0}};
vif.pwdata <= {WDATA_WIDTH {1'b0}};
vif.pwrite <= 1'b0;
vif.psel <= {SLV_NUM {1'b0}};
vif.penable <= 1'b0;
@(posedge vif.presetn); // reset dropped
endtask : reset
// sequencer/driver handshake
task apb_master_driver::get_and_drive();
forever begin
seq_item_port.get_next_item(req);
drive_tr(req);
seq_item_port.item_done();
end
endtask : get_and_drive
// drive transaction
task apb_master_driver::drive_tr (apb_transaction tr);
int unsigned slave_index;
// delay
@(posedge vif.pclk);
if (tr.delay > 0) begin
repeat(tr.delay) @(posedge vif.pclk);
end
// address phase
slave_index = cfg.get_slave_psel_by_addr(tr.addr);
if(slave_index == 0) begin
`uvm_warning(get_type_name(), "No slave with choosed address")
return;
end
vif.paddr <= tr.addr;
vif.psel <= (1 << (slave_index - 1));
vif.penable <= 0;
vif.pwrite <= apb_direction_enum'(tr.dir);
if (tr.dir == APB_WRITE) begin
vif.pwdata <= tr.wdata;
end
// data phase
@(posedge vif.pclk);
vif.penable <= 1;
@(posedge vif.pclk iff vif.pready);
tr.error = vif.pslverr;
if (tr.dir == APB_READ) begin
tr.rdata = vif.prdata;
end
vif.penable <= 0;
vif.psel <= 0;
`uvm_info(get_type_name(), $sformatf("APB Finished Driving tr \n%s", tr.sprint()), UVM_HIGH)
endtask : drive_tr
`endif

View File

@@ -0,0 +1,140 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_monitor.sv
DESCRIPTION
****************************************************************************/
`ifndef APB_MASTER_MONITOR_SV
`define APB_MASTER_MONITOR_SV
/**
* Class: apb_master_monitor
*/
class apb_master_monitor extends uvm_monitor;
// apb virtual interface
virtual apb_if vif;
// configuration
apb_config cfg;
// TLM - from monitor to other components
uvm_analysis_port #(apb_transaction) item_collected_port;
// keep track of number of transactions
int unsigned num_transactions = 0;
// current transaction
apb_transaction tr_collected;
// UVM factory registration
`uvm_component_utils_begin(apb_master_monitor)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// coverage
covergroup cg_apb_master;
// cover direction - read or write
cp_direction : coverpoint tr_collected.dir {
bins write = {APB_WRITE};
bins read = {APB_READ};
}
// cover delay - zero or more
cp_delay : coverpoint tr_collected.delay {
bins zero = {0};
bins other = default;
}
// TODO : add others
endgroup : cg_apb_master;
// new - constructor
function new(string name = "apb_master_monitor", uvm_component parent = null);
super.new(name, parent);
item_collected_port = new("item_collected_port", this);
cg_apb_master = new();
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(apb_config)::get(this, "", "apb_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
endfunction: build_phase
// UVM connect_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// get interface from db
if(!uvm_config_db#(virtual apb_if)::get(this, "", "apb_if", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"})
endfunction : connect_phase
// additional class methods
extern virtual task run_phase(uvm_phase phase);
extern virtual task collect_transactions();
extern virtual function void report_phase(uvm_phase phase);
endclass : apb_master_monitor
// UVM run_phase
task apb_master_monitor::run_phase(uvm_phase phase);
forever begin
@(posedge vif.presetn); // reset dropped
`uvm_info(get_type_name(), "Reset dropped", UVM_MEDIUM)
fork
collect_transactions(); // thread killed at reset
@(negedge vif.presetn); // reset is active low
join_any
disable fork;
end
endtask : run_phase
// monitor apb interface and collect transactions
task apb_master_monitor::collect_transactions();
forever begin
tr_collected = apb_transaction::type_id::create("tr_collected");
// wait for valid transaction
@(posedge vif.pclk iff (vif.psel != 0));
tr_collected.addr = vif.paddr;
tr_collected.dir = apb_direction_enum'(vif.pwrite);
if(tr_collected.dir == APB_WRITE)
tr_collected.wdata = vif.pwdata;
@(posedge vif.pclk); // enable
@(posedge vif.pclk); // ready
while (vif.pready !== 1'b1) begin
@(posedge vif.pclk);
tr_collected.delay++;
end
if(tr_collected.dir == APB_READ) begin
tr_collected.rdata = vif.prdata;
tr_collected.error = vif.pslverr;
end
item_collected_port.write(tr_collected); // TLM
// collect coverage if enabled
if(cfg.has_coverage == 1) begin
cg_apb_master.sample();
end
`uvm_info(get_type_name(), $sformatf("Tr collected :\n%s", tr_collected.sprint()), UVM_MEDIUM)
num_transactions++;
end // forever
endtask : collect_transactions
// UVM report_phase
function void apb_master_monitor::report_phase(uvm_phase phase);
// final report
`uvm_info(get_type_name(), $sformatf("Report: APB monitor collected %0d transfers", num_transactions), UVM_LOW);
endfunction : report_phase
`endif

View File

@@ -0,0 +1,44 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_sequencer.sv
DESCRIPTION
****************************************************************************/
`ifndef APB_MASTER_SEQUENCER_SV
`define APB_MASTER_SEQUENCER_SV
/**
* Class: apb_master_sequencer
*/
class apb_master_sequencer extends uvm_sequencer #(apb_transaction, apb_transaction);
// configuration
apb_config cfg;
// UVM factory registration
`uvm_component_utils_begin(apb_master_sequencer)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// new - constructor
function new(string name = "apb_master_sequencer", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(apb_config)::get(this, "", "apb_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
endfunction: build_phase
endclass : apb_master_sequencer
`endif

View File

@@ -0,0 +1,33 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_base_seq.sv
DESCRIPTION base sequence to be extended by other sequences
****************************************************************************/
`ifndef APB_MASTER_BASE_SEQ_SV
`define APB_MASTER_BASE_SEQ_SV
/**
* Class: apb_master_base_seq
*/
class apb_master_base_seq extends uvm_sequence #(apb_transaction, apb_transaction);
// p_sequencer for APB master sequences
`uvm_declare_p_sequencer(apb_master_sequencer)
// UVM factory registration
`uvm_object_utils(apb_master_base_seq)
// new - constructor
function new(string name = "apb_master_base_seq");
super.new(name);
endfunction : new
endclass : apb_master_base_seq
`endif

View File

@@ -0,0 +1,50 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_read_after_write_seq.sv
DESCRIPTION sequence for writing and reading from one address
****************************************************************************/
`ifndef APB_MASTER_READ_AFTER_WRITE_SEQ_SV
`define APB_MASTER_READ_AFTER_WRITE_SEQ_SV
/**
* Class: apb_master_read_after_write_seq
*/
class apb_master_read_after_write_seq extends apb_master_base_seq;
rand int unsigned delay; // transaction delay
rand bit [ADDR_WIDTH - 1 : 0] addr; // address to write/read
// constraints
constraint delay_cst { delay inside {[1 : 10]};}
// UVM factory registration
`uvm_object_utils(apb_master_read_after_write_seq)
// new - constructor
function new(string name = "apb_master_read_after_write_seq");
super.new(name);
endfunction : new
// sequence generation logic in body
virtual task body();
// write
`uvm_do_with( req,
{req.addr == addr;
req.dir == APB_READ;
req.delay == delay;})
// read
`uvm_do_with( req,
{req.addr == addr;
req.dir == APB_READ;
req.delay == delay;})
endtask : body
endclass : apb_master_read_after_write_seq
`endif

View File

@@ -0,0 +1,50 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_read_all_seq.sv
DESCRIPTION sequence for reading from all valid addresses
****************************************************************************/
`ifndef APB_MASTER_READ_ALL_SEQ_SV
`define APB_MASTER_READ_ALL_SEQ_SV
/**
* Class: apb_master_read_all_seq
*/
class apb_master_read_all_seq extends apb_master_base_seq;
// UVM factory registration
`uvm_object_utils(apb_master_read_all_seq)
// new - constructor
function new(string name = "apb_master_read_all_seq");
super.new(name);
endfunction : new
// sequence generation logic in body
virtual task body();
bit [ADDR_WIDTH - 1 : 0] end_addr, curr_addr;
// read from all addresses in all slaves
foreach (p_sequencer.cfg.slave_cfg_queue[i]) begin
curr_addr = p_sequencer.cfg.slave_cfg_queue[i].start_address;
end_addr = p_sequencer.cfg.slave_cfg_queue[i].end_address;
while (curr_addr != end_addr) begin
`uvm_do_with( req, {
req.addr == curr_addr;
req.dir == APB_READ;})
curr_addr++;
end
end
endtask : body
endclass : apb_master_read_all_seq
`endif

View File

@@ -0,0 +1,44 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_read_seq.sv
DESCRIPTION sequence for reading from one address
****************************************************************************/
`ifndef APB_MASTER_READ_SEQ_SV
`define APB_MASTER_READ_SEQ_SV
/**
* Class: apb_master_read_seq
*/
class apb_master_read_seq extends apb_master_base_seq;
rand int unsigned delay; // transaction delay
rand bit [ADDR_WIDTH - 1 : 0] addr; // address to read
// constraints
constraint delay_cst { delay inside {[1 : 10]};}
// UVM factory registration
`uvm_object_utils(apb_master_read_seq)
// new - constructor
function new(string name = "apb_master_read_seq");
super.new(name);
endfunction : new
// sequence generation logic in body
virtual task body();
`uvm_do_with( req,
{req.addr == addr;
req.dir == APB_READ;
req.delay == delay;})
endtask : body
endclass : apb_master_read_seq
`endif

View File

@@ -0,0 +1,23 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_seq_lib.sv
DESCRIPTION sequence includes
****************************************************************************/
`ifndef APB_MASTER_SEQ_LIB_SV
`define APB_MASTER_SEQ_LIB_SV
`include "master/sequences/apb_master_base_seq.sv"
`include "master/sequences/apb_master_simple_seq.sv"
`include "master/sequences/apb_master_read_seq.sv"
`include "master/sequences/apb_master_write_seq.sv"
`include "master/sequences/apb_master_read_all_seq.sv"
`include "master/sequences/apb_master_write_all_seq.sv"
`include "master/sequences/apb_master_read_after_write_seq.sv"
`endif

View File

@@ -0,0 +1,42 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_simple_seq.sv
DESCRIPTION simple sequence; random transactions
****************************************************************************/
`ifndef APB_MASTER_SIMPLE_SEQ_SV
`define APB_MASTER_SIMPLE_SEQ_SV
/**
* Class: apb_master_simple_seq
*/
class apb_master_simple_seq extends apb_master_base_seq;
rand int unsigned num_of_tr;
// constraints
constraint num_of_tr_cst { num_of_tr inside {[1 : 10]};}
// UVM factory registration
`uvm_object_utils(apb_master_simple_seq)
// new - constructor
function new(string name = "apb_master_simple_seq");
super.new(name);
endfunction : new
// sequence generation logic in body
virtual task body();
repeat(num_of_tr) begin
`uvm_do(req)
end
endtask : body
endclass : apb_master_simple_seq
`endif

View File

@@ -0,0 +1,64 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_write_all_seq.sv
DESCRIPTION sequence for writing to all valid addresses
****************************************************************************/
`ifndef APB_MASTER_WRITE_ALL_SEQ_SV
`define APB_MASTER_WRITE_ALL_SEQ_SV
/**
* Class: apb_master_write_all_seq
*/
class apb_master_write_all_seq extends apb_master_base_seq;
bit data_is_rand = 1; // 1 = data will be randomly chosen for every write
// 0 = used data from "data_to_write" field
bit [WDATA_WIDTH - 1 : 0] data_to_write;
rand bit [WDATA_WIDTH - 1 : 0] data;
// UVM factory registration
`uvm_object_utils(apb_master_write_all_seq)
// new - constructor
function new(string name = "apb_master_write_all_seq");
super.new(name);
endfunction : new
// sequence generation logic in body
virtual task body();
bit [ADDR_WIDTH - 1 : 0] end_addr, curr_addr;
// write to all addresses in all slaves
foreach (p_sequencer.cfg.slave_cfg_queue[i]) begin
curr_addr = p_sequencer.cfg.slave_cfg_queue[i].start_address;
end_addr = p_sequencer.cfg.slave_cfg_queue[i].end_address;
while (curr_addr != end_addr) begin
if (data_is_rand) begin
assert(this.randomize());
end
else begin
data = data_to_write;
end
`uvm_do_with( req, {
req.addr == curr_addr;
req.wdata == data;
req.dir == APB_WRITE;})
curr_addr++;
end
end
endtask : body
endclass : apb_master_write_all_seq
`endif

View File

@@ -0,0 +1,47 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_master_write_seq.sv
DESCRIPTION sequence for writing to one address
****************************************************************************/
`ifndef APB_MASTER_WRITE_SEQ_SV
`define APB_MASTER_WRITE_SEQ_SV
/**
* Class: apb_master_write_seq
*/
class apb_master_write_seq extends apb_master_base_seq;
rand int unsigned delay; // transaction delay
rand bit [ADDR_WIDTH - 1 : 0] addr; // address to write
rand bit [WDATA_WIDTH - 1 : 0] data; // data to write
// constraints
constraint delay_cst { delay inside {[1 : 10]};}
// UVM factory registration
`uvm_object_utils(apb_master_write_seq)
// new - constructor
function new(string name = "apb_master_write_seq");
super.new(name);
endfunction : new
// sequence generation logic in body
virtual task body();
`uvm_do_with( req, {
req.addr == addr;
req.dir == APB_WRITE;
req.wdata == data;
req.delay == delay;})
endtask : body
endclass : apb_master_write_seq
`endif

View File

@@ -0,0 +1,67 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_slave_agent.sv
DESCRIPTION slave agent
****************************************************************************/
`ifndef APB_SLAVE_AGENT_SV
`define APB_SLAVE_AGENT_SV
/**
* Class: apb_slave_agent
*/
class apb_slave_agent extends uvm_agent;
// configuration object
apb_slave_config cfg;
// components
apb_slave_driver drv;
apb_slave_sequencer seqr;
apb_slave_monitor mon;
// UVM factory registration
`uvm_component_utils_begin(apb_slave_agent)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// new - constructor
function new(string name = "apb_slave_agent", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(apb_slave_config)::get(this, "", "apb_slave_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
// create driver and sequencer if agent is active
if(cfg.is_active == UVM_ACTIVE) begin
seqr = apb_slave_sequencer::type_id::create("seqr", this);
drv = apb_slave_driver::type_id::create("drv", this);
end
// always create monitor
mon = apb_slave_monitor::type_id::create("mon", this);
endfunction : build_phase
// UVM connect_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// connect driver and sequencer if agent is active
if(cfg.is_active == UVM_ACTIVE) begin
drv.seq_item_port.connect(seqr.seq_item_export);
end
endfunction : connect_phase
endclass : apb_slave_agent
`endif

View File

@@ -0,0 +1,70 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_slave_config.sv
DESCRIPTION slave configuration object
****************************************************************************/
`ifndef APB_SLAVE_CONFIG_SV
`define APB_SLAVE_CONFIG_SV
/**
* Class: apb_slave_config
*/
class apb_slave_config extends uvm_object;
// is agent active or passive
uvm_active_passive_enum is_active = UVM_ACTIVE;
// checks and coverage control
bit has_checks = 1;
bit has_coverage = 1;
// address range
rand bit [ADDR_WIDTH - 1 : 0] start_address;
rand bit [ADDR_WIDTH - 1 : 0] end_address;
// slave index
rand int unsigned psel_index;
// create agent or just use cfg for address and psel purposes
bit create_agent = 1;
// constraints
constraint addr_cst { start_address <= end_address; }
constraint psel_cst { psel_index inside {[0 : SLV_NUM]};} // max 15 slaves
// UVM factory registration
`uvm_object_utils_begin(apb_slave_config)
`uvm_field_enum(uvm_active_passive_enum, is_active, UVM_DEFAULT)
`uvm_field_int(has_checks, UVM_DEFAULT)
`uvm_field_int(has_coverage, UVM_DEFAULT)
`uvm_field_int(start_address, UVM_DEFAULT)
`uvm_field_int(end_address, UVM_DEFAULT)
`uvm_field_int(psel_index, UVM_DEFAULT)
`uvm_field_int(create_agent, UVM_DEFAULT)
`uvm_object_utils_end
// new - constructor
function new(string name = "apb_slave_config");
super.new(name);
endfunction : new
// checks to see if an address is in the configured range
function bit check_address_range(bit [ADDR_WIDTH - 1 : 0] addr);
return (!((start_address > addr) || (end_address < addr)));
endfunction : check_address_range
// checks to see if current psel index is for this slave
function bit check_psel_index(logic [SLV_NUM - 1 : 0] psel);
for (int i = 0; i < SLV_NUM; i++) begin
if((psel[i] == 1) && (psel_index == (i + 1)))
return 1;
end
return 0;
endfunction : check_psel_index
endclass : apb_slave_config
`endif

View File

@@ -0,0 +1,117 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_slave_driver.sv
DESCRIPTION drives slave response
****************************************************************************/
`ifndef APB_SLAVE_DRIVER_SV
`define APB_SLAVE_DRIVER_SV
/**
* Class: apb_slave_driver
*/
class apb_slave_driver extends uvm_driver #(apb_transaction, apb_transaction);
// apb virtual interface
virtual apb_if vif;
// configuration
apb_slave_config cfg;
// UVM factory registration
`uvm_component_utils_begin(apb_slave_driver)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// new - constructor
function new(string name = "apb_slave_driver", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(apb_slave_config)::get(this, "", "apb_slave_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
endfunction: build_phase
// UVM connect_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// get interface from db
if(!uvm_config_db#(virtual apb_if)::get(this, "", "apb_if", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"})
endfunction : connect_phase
// additional class methods
extern virtual task run_phase(uvm_phase phase);
extern virtual task get_and_drive();
extern virtual task reset();
extern virtual task drive_tr (apb_transaction tr);
endclass : apb_slave_driver
// UVM run_phase
task apb_slave_driver::run_phase(uvm_phase phase);
reset(); // init.
forever begin
fork
get_and_drive(); // thread killed at reset
@(negedge vif.presetn); // reset is active low
join_any
disable fork;
reset();
end
endtask : run_phase
// reset signals
task apb_slave_driver::reset();
`uvm_info(get_type_name(), "Reset observed", UVM_MEDIUM)
vif.prdata <= {WDATA_WIDTH {1'bZ}};
vif.pready <= 1'b0;
vif.pslverr <= 1'b0;
@(posedge vif.presetn); // reset dropped
endtask : reset
// sequencer/driver handshake
task apb_slave_driver::get_and_drive();
forever begin
seq_item_port.get_next_item(req);
drive_tr(req);
seq_item_port.item_done();
end
endtask : get_and_drive
// drive transaction
task apb_slave_driver::drive_tr (apb_transaction tr);
// wait for the master to initiate the transaction
@(posedge vif.pclk iff (vif.penable && cfg.check_psel_index(vif.psel)));
tr.dir = apb_direction_enum'(vif.pwrite);
// delay
if (tr.delay > 0) begin
repeat(tr.delay) @(posedge vif.pclk);
end
// respond
vif.pslverr <= tr.error;
vif.pready <= 1'b1;
if (tr.dir == APB_READ)
vif.prdata <= tr.rdata;
@(posedge vif.pclk);
vif.prdata <= {WDATA_WIDTH {1'bZ}};
vif.pready <= 1'b0;
`uvm_info(get_type_name(), $sformatf("APB Finished Driving tr \n%s", tr.sprint()), UVM_HIGH)
endtask : drive_tr
`endif

View File

@@ -0,0 +1,140 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_slave_monitor.sv
DESCRIPTION monitors transactions for slave
****************************************************************************/
`ifndef APB_SLAVE_MONITOR_SV
`define APB_SLAVE_MONITOR_SV
/**
* Class: apb_slave_monitor
*/
class apb_slave_monitor extends uvm_monitor;
// apb virtual interface
virtual apb_if vif;
// configuration
apb_slave_config cfg;
// TLM - from monitor to other components
uvm_analysis_port #(apb_transaction) item_collected_port;
// keep track of number of transactions
int unsigned num_transactions = 0;
// current transaction
apb_transaction tr_collected;
// UVM factory registration
`uvm_component_utils_begin(apb_slave_monitor)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// coverage
covergroup cg_apb_slave;
// cover direction - read or write
cp_direction : coverpoint tr_collected.dir {
bins write = {APB_WRITE};
bins read = {APB_READ};
}
// cover delay - zero or more
cp_delay : coverpoint tr_collected.delay {
bins zero = {0};
bins other = default;
}
// TODO : add others
endgroup : cg_apb_slave;
// new - constructor
function new(string name = "apb_slave_monitor", uvm_component parent = null);
super.new(name, parent);
item_collected_port = new("item_collected_port", this);
cg_apb_slave = new();
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(apb_slave_config)::get(this, "", "apb_slave_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
endfunction: build_phase
// UVM connect_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// get interface from db
if(!uvm_config_db#(virtual apb_if)::get(this, "", "apb_if", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"})
endfunction : connect_phase
// additional class methods
extern virtual task run_phase(uvm_phase phase);
extern virtual task collect_transactions();
extern virtual function void report_phase(uvm_phase phase);
endclass : apb_slave_monitor
// UVM run_phase
task apb_slave_monitor::run_phase(uvm_phase phase);
forever begin
@(posedge vif.presetn); // reset dropped
`uvm_info(get_type_name(), "Reset dropped", UVM_MEDIUM)
fork
collect_transactions(); // thread killed at reset
@(negedge vif.presetn); // reset is active low
join_any
disable fork;
end
endtask : run_phase
// monitor apb interface and collect transactions
task apb_slave_monitor::collect_transactions();
forever begin
tr_collected = apb_transaction::type_id::create("tr_collected");
// collect transactions only for this slave
@(posedge vif.pclk iff (cfg.check_psel_index(vif.psel)));
tr_collected.addr = vif.paddr;
tr_collected.dir = apb_direction_enum'(vif.pwrite);
if(tr_collected.dir == APB_WRITE)
tr_collected.wdata = vif.pwdata;
@(posedge vif.pclk); // enable
@(posedge vif.pclk); // ready
// wait for ready
while (vif.pready !== 1'b1) begin
@(posedge vif.pclk);
tr_collected.delay++;
end
if(tr_collected.dir == APB_READ) begin
tr_collected.rdata = vif.prdata;
tr_collected.error = vif.pslverr;
end
item_collected_port.write(tr_collected); // TLM
// collect coverage if enabled
if(cfg.has_coverage == 1) begin
cg_apb_slave.sample();
end
`uvm_info(get_type_name(), $sformatf("Tr collected :\n%s", tr_collected.sprint()), UVM_MEDIUM)
num_transactions++;
end // forever
endtask : collect_transactions
// UVM report_phase
function void apb_slave_monitor::report_phase(uvm_phase phase);
// final report
`uvm_info(get_type_name(), $sformatf("Report: APB monitor collected %0d transfers", num_transactions), UVM_LOW);
endfunction : report_phase
`endif

View File

@@ -0,0 +1,34 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_slave_sequencer.sv
DESCRIPTION
****************************************************************************/
`ifndef APB_SLAVE_SEQUENCER_SV
`define APB_SLAVE_SEQUENCER_SV
/**
* Class: apb_slave_sequencer
*/
class apb_slave_sequencer extends uvm_sequencer #(apb_transaction, apb_transaction);
// UVM factory registration
`uvm_component_utils (apb_slave_sequencer)
// new - constructor
function new(string name = "apb_slave_sequencer", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// Note: equivalent to
// typedef uvm_sequencer#(apb_transaction, apb_transaction) apb_slave_sequencer;
endclass : apb_slave_sequencer
`endif

View File

@@ -0,0 +1,31 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_slave_base_seq.sv
DESCRIPTION base sequence to be extended by other sequences
****************************************************************************/
`ifndef APB_SLAVE_BASE_SEQ_SV
`define APB_SLAVE_BASE_SEQ_SV
/**
* Class: apb_slave_base_seq
*/
class apb_slave_base_seq extends uvm_sequence #(apb_transaction, apb_transaction);
// UVM factory registration
`uvm_object_utils(apb_slave_base_seq)
// new - constructor
function new(string name = "apb_slave_base_seq");
super.new(name);
endfunction : new
endclass : apb_slave_base_seq
`endif

View File

@@ -0,0 +1,18 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_slave_seq_lib.sv
DESCRIPTION sequence includes
****************************************************************************/
`ifndef APB_SLAVE_SEQ_LIB_SV
`define APB_SLAVE_SEQ_LIB_SV
`include "slave/sequences/apb_slave_base_seq.sv"
`include "slave/sequences/apb_slave_simple_seq.sv"
`endif

View File

@@ -0,0 +1,38 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE apb_slave_simple_seq.sv
DESCRIPTION simple sequence; always respond with random data
****************************************************************************/
`ifndef APB_SLAVE_SIMPLE_SEQ_SV
`define APB_SLAVE_SIMPLE_SEQ_SV
/**
* Class: apb_slave_simple_seq
*/
class apb_slave_simple_seq extends apb_slave_base_seq;
// UVM factory registration
`uvm_object_utils(apb_slave_simple_seq)
// new - constructor
function new(string name = "apb_slave_simple_seq");
super.new(name);
endfunction : new
// sequence generation logic in body
virtual task body();
forever begin
`uvm_do(req)
end
endtask : body
endclass : apb_slave_simple_seq
`endif

View File

@@ -0,0 +1,30 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE dut.sv
DESCRIPTION
****************************************************************************/
`ifndef DUT_SV
`define DUT_SV
/**
* Module: dut
*/
module dut#(
parameter ADDR_WIDTH = 7,
parameter DATA_WIDTH = 8
)
(
input logic clk,
input logic rst,
ref logic sda,
ref logic scl
);
endmodule : dut
`endif

View File

@@ -0,0 +1,67 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_test_top.sv
DESCRIPTION top module
- connects DUT and interface
- generates clk and reset
- runs UVM test
****************************************************************************/
`ifndef I2C_TEST_TOP_SV
`define I2C_TEST_TOP_SV
/**
* Module: i2c_test_top
*/
module i2c_test_top;
import uvm_pkg::*; // import the UVM library
`include "uvm_macros.svh" // Include the UVM macros
import i2c_pkg::*; // import the i2c pkg
`include "i2c_test_lib.sv"
`include "dut.sv"
logic clock;
logic reset;
// interface
i2c_if i2c_vif(clock, reset);
// DUT
dut #( .ADDR_WIDTH(7),
.DATA_WIDTH(8)
) dut_inst (
.clk (clock),
.rst (reset),
.scl (i2c_vif.scl),
.sda (i2c_vif.sda)
);
// set interface in db; run UVM test
initial begin
uvm_config_db#(virtual i2c_if)::set(null,"uvm_test_top.*","i2c_if", i2c_vif);
run_test();
end
// initialize clock and reset
initial begin
clock <= 1'b0;
reset <= 1'b1;
#50 reset <= 1'b0;
end
// generate clock
always #5 clock = ~clock;
endmodule : i2c_test_top
`endif

View File

@@ -0,0 +1,48 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_test_base.sv
DESCRIPTION base test to be extended by other tests
****************************************************************************/
`ifndef I2C_TEST_BASE_SV
`define I2C_TEST_BASE_SV
/**
* Class: i2c_test_base
*/
class i2c_test_base extends uvm_test;
// UVM factory registration
`uvm_component_utils (i2c_test_base)
// main environment
i2c_env env;
// new - constructor
function new(string name = "i2c_test_base", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// build environment
env = i2c_env::type_id::create("env", this);
endfunction : build_phase
// UVM end_of_elaboration_phase
function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
// display verification environment topology
uvm_top.print_topology();
endfunction : end_of_elaboration_phase
endclass : i2c_test_base
`endif

View File

@@ -0,0 +1,18 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_test_lib.sv
DESCRIPTION test includes
****************************************************************************/
`ifndef I2C_TEST_LIB_SV
`define I2C_TEST_LIB_SV
`include "i2c_test_base.sv"
`include "i2c_test_simple.sv"
`endif

View File

@@ -0,0 +1,59 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_test_simple.sv
DESCRIPTION simple test for debug
****************************************************************************/
`ifndef I2C_TEST_SIMPLE_SV
`define I2C_TEST_SIMPLE_SV
/**
* Class: i2c_test_simple
*/
class i2c_test_simple extends i2c_test_base;
// UVM factory registration
`uvm_component_utils (i2c_test_simple)
// sequences
i2c_master_simple_seq master_seq;
i2c_slave_simple_seq slave_seq;
// new - constructor
function new(string name = "i2c_test_simple", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// build all sequences
master_seq = i2c_master_simple_seq::type_id::create("master_seq");
slave_seq = i2c_slave_simple_seq::type_id::create("slave_seq");
endfunction : build_phase
// UVM run_phase
task run_phase(uvm_phase phase);
assert(master_seq.randomize()); // random fields in master seq.
phase.raise_objection(this); // test cannot end yet
// start all sequences
fork
master_seq.start(env.master.seqr);
slave_seq.start(env.slave.seqr); // runs forever
join_any
// only way to get here is if master sequence finished
phase.drop_objection(this); // test can end
endtask : run_phase
endclass : i2c_test_simple
`endif

View File

@@ -0,0 +1,29 @@
################################################################################
# +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
# |F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
# +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
#
# FILE run
#
# DESCRIPTION
#
################################################################################
# Create the library.
if [file exists work] {
vdel -all
}
vlib work
# compile testbench
vlog -sv \
+incdir+$env(UVM_HOME) \
+incdir+../sv \
+incdir+../examples \
+incdir+../examples/tests \
../sv/i2c_pkg.sv \
../examples/i2c_test_top.sv
# run simulation
vsim i2c_test_top -novopt +UVM_TESTNAME=i2c_test_simple -sv_seed random

View File

@@ -0,0 +1,88 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_config.sv
DESCRIPTION contains main and default configurations
****************************************************************************/
`ifndef I2C_CONFIG_SV
`define I2C_CONFIG_SV
/**
* Class: i2c_config
*/
class i2c_config extends uvm_object;
// master/slave agents
bit has_master;
bit has_slave;
// configurations for every agent
i2c_slave_config slave_cfg;
i2c_master_config master_cfg;
// control
bit has_checks = 1;
bit has_coverage = 1;
// UVM factory registration
`uvm_object_utils_begin(i2c_config)
`uvm_field_int(has_master, UVM_DEFAULT)
`uvm_field_int(has_slave, UVM_DEFAULT)
`uvm_field_object(slave_cfg, UVM_DEFAULT)
`uvm_field_object(master_cfg, UVM_DEFAULT)
`uvm_field_int(has_checks, UVM_DEFAULT)
`uvm_field_int(has_coverage, UVM_DEFAULT)
`uvm_object_utils_end
// new - constructor
function new(string name = "i2c_config");
super.new(name);
endfunction : new
// additional class methods
extern function void add_slave(uvm_active_passive_enum is_active = UVM_ACTIVE);
extern function void add_master(uvm_active_passive_enum is_active = UVM_ACTIVE);
endclass : i2c_config
// creates and configures a slave agent config and adds to a queue
function void i2c_config::add_slave(uvm_active_passive_enum is_active = UVM_ACTIVE);
slave_cfg = i2c_slave_config::type_id::create("slave_cfg");
has_slave = 1;
slave_cfg.is_active = is_active;
slave_cfg.has_checks = has_checks;
slave_cfg.has_coverage = has_coverage;
endfunction : add_slave
// creates and configures a master agent configuration
function void i2c_config::add_master(uvm_active_passive_enum is_active = UVM_ACTIVE);
master_cfg = i2c_master_config::type_id::create("master_cfg");
has_master = 1;
master_cfg.is_active = is_active;
master_cfg.has_checks = has_checks;
master_cfg.has_coverage = has_coverage;
endfunction : add_master
/**
* Class: default_i2c_config
*
* Description: default configuration - one master, no slaves
*/
class default_i2c_config extends i2c_config;
`uvm_object_utils(default_i2c_config)
function new(string name = "default_i2c_config");
super.new(name);
add_master(UVM_ACTIVE);
add_slave(UVM_ACTIVE); // TODO : remove after debug
endfunction : new
endclass : default_i2c_config
`endif

View File

@@ -0,0 +1,70 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_env.sv
DESCRIPTION environment containing the master and slave agents
****************************************************************************/
`ifndef I2C_ENV_SV
`define I2C_ENV_SV
/**
* Class: i2c_env
*/
class i2c_env extends uvm_env;
i2c_slave_agent slave; // one slave
i2c_master_agent master; // one master
i2c_config cfg; // uvc configuration
// UVM factory registration
`uvm_component_utils_begin(i2c_env)
`uvm_field_object(cfg, UVM_DEFAULT)
`uvm_component_utils_end
// new - constructor
function new(string name = "i2c_env", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration from db or use default configuration if none is set
if(!uvm_config_db#(i2c_config)::get(this, "", "i2c_config", cfg)) begin
`uvm_info("NOCONFIG", "Using default_i2c_config", UVM_LOW)
i2c_config::type_id::set_type_override(default_i2c_config::get_type(), 1);
cfg = i2c_config::type_id::create("cfg");
end
// set the master configuration
if(cfg.has_master) begin
uvm_config_db#(i2c_master_config)::set(this, "master*", "i2c_master_config", cfg.master_cfg);
uvm_config_db#(i2c_config)::set(this, "master.mon*", "i2c_config", cfg);
end
// set the slave configuration
if(cfg.has_slave) begin
uvm_config_db#(i2c_slave_config)::set(this, "slave*", "i2c_slave_config", cfg.slave_cfg);
uvm_config_db#(i2c_config)::set(this, "slave.mon*", "i2c_config", cfg);
end
// create agents
if(cfg.has_master) begin
master = i2c_master_agent::type_id::create("master", this);
end
if(cfg.has_slave) begin
slave = i2c_slave_agent::type_id::create("slave", this);
end
endfunction : build_phase
endclass : i2c_env
`endif

View File

@@ -0,0 +1,40 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_if.sv
DESCRIPTION i2c interface
****************************************************************************/
`ifndef I2C_IF_SV
`define I2C_IF_SV
/*
* Interface: i2c_if
*/
interface i2c_if(input logic clk, input logic rst);
// connected to DUT
wire sda_wire;
wire scl_wire;
// driven by uvc
logic sda;
logic scl;
assign sda_wire = sda;
assign scl_wire = scl;
// control
bit has_checks = 1;
bit has_coverage = 1;
// TODO : coverage and assertions go here...
endinterface : i2c_if
`endif

View File

@@ -0,0 +1,208 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_monitor.sv
DESCRIPTION
****************************************************************************/
`ifndef I2C_MONITOR_SV
`define I2C_MONITOR_SV
/*
* Class: i2c_monitor
*/
class i2c_monitor extends uvm_monitor;
// i2c virtual interface
virtual i2c_if vif;
// configuration
i2c_config cfg;
// TLM - from monitor to other components
uvm_analysis_port #(i2c_transaction) item_collected_port;
// keep track of number of transactions
int unsigned num_transactions = 0;
// current transaction
i2c_transaction tr_collected;
// start and stop helper events
event start_e;
event stop_e;
// UVM factory registration
`uvm_component_utils_begin(i2c_monitor)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// coverage
covergroup cg_i2c_monitor;
// cover direction - read or write
cp_direction : coverpoint tr_collected.dir {
bins write = {I2C_WRITE};
bins read = {I2C_READ};
}
// cover address ack
cp_addr_ack : coverpoint tr_collected.addr_ack {
bins ack = {I2C_ACK};
bins nack = {I2C_NACK};
}
// cover data ack
cp_data_ack : coverpoint tr_collected.data_ack {
bins ack = {I2C_ACK};
bins nack = {I2C_NACK};
}
// TODO : add others
endgroup : cg_i2c_monitor;
// new - constructor
function new(string name = "i2c_monitor", uvm_component parent = null);
super.new(name, parent);
item_collected_port = new("item_collected_port", this);
cg_i2c_monitor = new();
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(i2c_config)::get(this, "", "i2c_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
endfunction: build_phase
// UVM connect_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// get interface from db
if(!uvm_config_db#(virtual i2c_if)::get(this, "", "i2c_if", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"})
endfunction : connect_phase
// additional class methods
extern virtual task start_condition(ref event start_e);
extern virtual task stop_condition(ref event stop_e);
extern virtual task run_phase(uvm_phase phase);
extern virtual task collect_transactions();
extern virtual function void report_phase(uvm_phase phase);
endclass : i2c_monitor
// UVM run_phase
task i2c_monitor::run_phase(uvm_phase phase);
forever begin
@(negedge vif.rst); // reset dropped
`uvm_info(get_type_name(), "Reset dropped", UVM_MEDIUM)
fork
@(posedge vif.rst); // reset is active high
start_condition(start_e);
stop_condition(stop_e);
collect_transactions();
join_any
disable fork;
// only way to get here is after reset
end
endtask : run_phase
// trigger event when start
task i2c_monitor::start_condition(ref event start_e);
forever begin
wait(vif.sda_wire !== 1'bx); // don't trigger from an X to 0 transition
@(negedge vif.sda_wire);
if(vif.scl_wire === 1'b1) begin
->start_e;
end
end
endtask : start_condition
// trigger event when stop
task i2c_monitor::stop_condition(ref event stop_e);
forever begin
wait(vif.sda_wire !== 1'bx); // don't trigger from an X to 1 transition
@(posedge vif.sda_wire);
if(vif.scl_wire === 1'b1) begin
->stop_e;
end
end
endtask : stop_condition
// monitor i2c interface and collect transactions
task i2c_monitor::collect_transactions();
forever begin
wait(start_e.triggered);
tr_collected = i2c_transaction::type_id::create("tr_collected", this);
// address
tr_collected.addr = 0;
repeat(ADDR_WIDTH) begin
@(posedge vif.scl_wire);
#1;
tr_collected.addr = {tr_collected.addr[ADDR_WIDTH - 2 : 0], vif.sda_wire};
end
// read / write bit
@(posedge vif.scl_wire);
#1;
tr_collected.dir = i2c_direction_enum'(vif.sda_wire);
// ack bit
@(posedge vif.scl_wire);
#1;
if(vif.sda_wire === 1'b0) tr_collected.addr_ack = I2C_ACK;
else tr_collected.addr_ack = I2C_NACK;
if(cfg.has_checks) begin // check for NACK
asrt_addr_nack : assert (tr_collected.addr_ack == I2C_ACK)
else
`uvm_error(get_type_name(), $sformatf("Observed address NACK during %s", tr_collected.dir.name))
end
// only if ack
if(tr_collected.addr_ack == I2C_ACK) begin
// data
repeat(DATA_WIDTH) begin
@(posedge vif.scl_wire);
#1;
tr_collected.data = {tr_collected.data[DATA_WIDTH - 2 : 0], vif.sda_wire};
end
// ack bit
@(posedge vif.scl_wire);
#1;
if(vif.sda_wire === 1'b0) tr_collected.data_ack = I2C_ACK;
else tr_collected.data_ack = I2C_NACK;
if(cfg.has_checks) begin // check for NACK
asrt_data_nack : assert (tr_collected.data_ack == I2C_ACK)
else
`uvm_error(get_type_name(), $sformatf("Observed data NACK during %s", tr_collected.dir.name))
end
end
wait(stop_e.triggered);
item_collected_port.write(tr_collected); // TLM
// collect coverage if enabled
if(cfg.has_coverage == 1) begin
cg_i2c_monitor.sample();
end
`uvm_info(get_type_name(), $sformatf("Tr collected :\n%s", tr_collected.sprint()), UVM_MEDIUM)
num_transactions++;
end
endtask : collect_transactions
// UVM report_phase
function void i2c_monitor::report_phase(uvm_phase phase);
// final report
`uvm_info( get_type_name(),
$sformatf("Report: I2C monitor collected: %0d transactions", num_transactions),
UVM_LOW);
endfunction : report_phase
`endif

View File

@@ -0,0 +1,62 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_pkg.sv
DESCRIPTION package containing all parameters and includes
****************************************************************************/
`ifndef I2C_PKG_SV
`define I2C_PKG_SV
/*
* Package: i2c_pkg
*/
package i2c_pkg;
parameter int ADDR_WIDTH = 7;
parameter int DATA_WIDTH = 8;
typedef class i2c_transaction;
typedef class i2c_master_config;
typedef class i2c_master_driver;
typedef class i2c_master_agent;
typedef class i2c_slave_config;
typedef class i2c_slave_driver;
typedef class i2c_slave_agent;
typedef class i2c_config;
typedef class i2c_monitor;
typedef class i2c_env;
import uvm_pkg::*;
`include "uvm_macros.svh"
`include "i2c_types.sv"
// master
`include "master/i2c_master_config.sv"
`include "master/i2c_master_driver.sv"
`include "master/i2c_master_agent.sv"
`include "master/sequences/i2c_master_seq_lib.sv"
// slave
`include "slave/i2c_slave_config.sv"
`include "slave/i2c_slave_driver.sv"
`include "slave/i2c_slave_agent.sv"
`include "slave/sequences/i2c_slave_seq_lib.sv"
// top
`include "i2c_transaction.sv"
`include "i2c_config.sv"
`include "i2c_monitor.sv"
`include "i2c_env.sv"
endpackage: i2c_pkg
`include "i2c_if.sv"
`endif

View File

@@ -0,0 +1,67 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_transaction.sv
DESCRIPTION sequence item
****************************************************************************/
`ifndef I2C_TRANSACTION_SV
`define I2C_TRANSACTION_SV
/*
* Class: i2c_transaction
*/
class i2c_transaction extends uvm_sequence_item;
// fields
rand i2c_direction_enum dir;
rand bit [ADDR_WIDTH - 1 : 0] addr;
rand i2c_ack_enum addr_ack;
rand bit [DATA_WIDTH - 1 : 0] data;
rand i2c_ack_enum data_ack;
// timings (#clk cycles)
rand int unsigned scl_period; // SCL period
rand int unsigned start_hold; // start hold time before SCL toggle
rand int unsigned stop_setup; // setup time from SCL posedge to SDA assert
rand int unsigned delay; // time between stop and start conditions
// constraints
constraint timing_constraint {
scl_period inside {[1 : 20]};
scl_period % 4 == 0;
start_hold inside {[1 : 10]};
stop_setup inside {[1 : 10]};
delay inside {[1 : 10]};
}
constraint ack_constraint {
addr_ack dist {I2C_ACK := 8, I2C_NACK := 2};
data_ack dist {I2C_ACK := 8, I2C_NACK := 2};
}
// UVM factory registration
`uvm_object_utils_begin (i2c_transaction)
`uvm_field_enum (i2c_direction_enum, dir, UVM_DEFAULT)
`uvm_field_enum (i2c_ack_enum, data_ack, UVM_DEFAULT)
`uvm_field_enum (i2c_ack_enum, addr_ack, UVM_DEFAULT)
`uvm_field_int (addr, UVM_DEFAULT)
`uvm_field_int (data, UVM_DEFAULT)
`uvm_field_int (scl_period, UVM_DEFAULT)
`uvm_field_int (start_hold, UVM_DEFAULT)
`uvm_field_int (stop_setup, UVM_DEFAULT)
`uvm_field_int (delay, UVM_DEFAULT)
`uvm_object_utils_end
// new - constructor
function new(string name = "i2c_transaction");
super.new(name);
endfunction : new
endclass : i2c_transaction
`endif

View File

@@ -0,0 +1,26 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_types.sv
DESCRIPTION contains all typedef-s used in project
****************************************************************************/
`ifndef I2C_TYPES_SV
`define I2C_TYPES_SV
typedef enum {
I2C_WRITE = 0,
I2C_READ = 1
} i2c_direction_enum;
typedef enum {
I2C_ACK = 0,
I2C_NACK = 1
} i2c_ack_enum;
`endif

View File

@@ -0,0 +1,69 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_master_agent.sv
DESCRIPTION master agent
****************************************************************************/
`ifndef I2C_MASTER_AGENT_SV
`define I2C_MASTER_AGENT_SV
typedef uvm_sequencer #(i2c_transaction) i2c_master_sequencer;
/*
* Class: i2c_master_agent
*/
class i2c_master_agent extends uvm_agent;
// configuration object
i2c_master_config cfg;
// components
i2c_monitor mon;
i2c_master_driver drv;
i2c_master_sequencer seqr;
// UVM factory registration
`uvm_component_utils_begin(i2c_master_agent)
`uvm_field_object(cfg, UVM_DEFAULT)
`uvm_component_utils_end
// new - constructor
function new(string name = "i2c_master_agent", uvm_component parent);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(i2c_master_config)::get(this, "", "i2c_master_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
// create driver and sequencer if agent is active
if(cfg.is_active == UVM_ACTIVE) begin
seqr = i2c_master_sequencer::type_id::create("seqr", this);
drv = i2c_master_driver::type_id::create("drv", this);
end
// always create monitor
mon = i2c_monitor::type_id::create("mon", this);
endfunction : build_phase
// UVM connect_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// connect driver and sequencer if agent is active
if(cfg.is_active == UVM_ACTIVE) begin
drv.seq_item_port.connect(seqr.seq_item_export);
end
endfunction : connect_phase
endclass : i2c_master_agent
`endif

View File

@@ -0,0 +1,41 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_master_config.sv
DESCRIPTION contains main and default configurations
****************************************************************************/
`ifndef I2C_MASTER_CONFIG_SV
`define I2C_MASTER_CONFIG_SV
/*
* Class: i2c_master_config
*/
class i2c_master_config extends uvm_object;
// is agent active or passive
uvm_active_passive_enum is_active = UVM_ACTIVE;
// checks and coverage control
bit has_checks = 1;
bit has_coverage = 1;
// UVM factory registration
`uvm_object_utils_begin(i2c_master_config)
`uvm_field_enum(uvm_active_passive_enum, is_active, UVM_DEFAULT)
`uvm_field_int(has_checks, UVM_DEFAULT)
`uvm_field_int(has_coverage, UVM_DEFAULT)
`uvm_object_utils_end
// new - constructor
function new(string name = "i2c_master_config");
super.new(name);
endfunction : new
endclass : i2c_master_config
`endif

View File

@@ -0,0 +1,195 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_master_driver.sv
DESCRIPTION
****************************************************************************/
`ifndef I2C_MASTER_DRIVER_SV
`define I2C_MASTER_DRIVER_SV
/*
* Class: i2c_master_driver
*/
class i2c_master_driver extends uvm_driver #(i2c_transaction);
// i2c virtual interface
virtual i2c_if vif;
// configuration
i2c_master_config cfg;
// UVM factory registration
`uvm_component_utils_begin(i2c_master_driver)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// new - constructor
function new(string name = "i2c_master_driver", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(i2c_master_config)::get(this, "*", "i2c_master_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
endfunction: build_phase
// UVM connect_phase
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// get interface from db
if(!uvm_config_db#(virtual i2c_if)::get(this, "", "i2c_if", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"})
endfunction : connect_phase
// additional class methods
extern virtual task run_phase(uvm_phase phase);
extern virtual task reset();
extern virtual task drive_transaction(i2c_transaction tr);
extern virtual task drive_start(i2c_transaction tr);
extern virtual task drive_stop(i2c_transaction tr);
extern virtual task drive_bit(input logic bit_to_drive, input int unsigned scl_period);
extern virtual task read_bit(output logic bit_read, input int unsigned scl_period);
endclass : i2c_master_driver
// UVM run_phase
task i2c_master_driver::run_phase(uvm_phase phase);
reset(); // init
forever begin
fork
@(posedge vif.rst); // reset is active high
forever begin
seq_item_port.get_next_item(req);
drive_start(req);
drive_transaction(req);
drive_stop(req);
seq_item_port.item_done();
end
join_any
disable fork;
reset();
end
endtask : run_phase
// reset signals
task i2c_master_driver::reset();
`uvm_info(get_type_name(), "Reset observed", UVM_MEDIUM)
vif.scl <= 1'b1;
vif.sda <= 1'b1;
@(negedge vif.rst); // reset dropped
endtask : reset
// drive start condition
task i2c_master_driver::drive_start(i2c_transaction tr);
@(posedge vif.clk); // sync
vif.scl <= 1'b1;
vif.sda <= 1'b0;
repeat(tr.start_hold) @(posedge vif.clk);
vif.scl <= 1'b1;
repeat(tr.scl_period / 2) @(posedge vif.clk);
vif.scl <= 1'b0;
repeat(tr.scl_period / 4) @(posedge vif.clk);
endtask : drive_start
// drive stop condition
task i2c_master_driver::drive_stop(i2c_transaction tr);
@(posedge vif.clk); // sync
vif.sda <= 1'b0;
repeat(tr.scl_period / 2) @(posedge vif.clk);
vif.scl <= 1'b1;
repeat(tr.stop_setup) @(posedge vif.clk);
vif.sda <= 1'b1;
repeat(tr.delay) @(posedge vif.clk);
endtask : drive_stop
// drive transaction
task i2c_master_driver::drive_transaction(i2c_transaction tr);
logic ack;
// drive address (msb first)
for(int i = ADDR_WIDTH; i > 0; --i) begin
drive_bit(tr.addr[i-1], tr.scl_period);
end
// drive direction
drive_bit(tr.dir, tr.scl_period);
// get ack from slave
read_bit(ack, tr.scl_period);
if(ack === 1'b0) tr.addr_ack = I2C_ACK;
else tr.addr_ack = I2C_NACK;
// recieved ack - continue
if(tr.addr_ack == 1'b0) begin
if(tr.dir == I2C_WRITE) begin
for(int i = DATA_WIDTH; i > 0; --i) begin
drive_bit(tr.data[i - 1], tr.scl_period);
end
// get ack from slave
read_bit(ack, tr.scl_period);
if(ack === 1'b0) tr.data_ack = I2C_ACK;
else tr.data_ack = I2C_NACK;
end
else begin // READ
// get data - msb first
for(int i = DATA_WIDTH; i > 0; --i) begin
read_bit(tr.data[i-1], tr.scl_period);
end
// ack or nack
drive_bit(tr.data_ack, tr.scl_period);
end
end
`uvm_info(get_type_name(), $sformatf("I2C Finished Driving tr \n%s", tr.sprint()), UVM_HIGH)
endtask : drive_transaction
// drive one bit
task i2c_master_driver::drive_bit(input logic bit_to_drive, input int unsigned scl_period);
vif.sda <= bit_to_drive;
repeat(scl_period / 4) @(posedge vif.clk);
vif.scl <= 1'b1;
repeat(scl_period / 2) @(posedge vif.clk);
vif.scl <= 1'b0;
repeat(scl_period / 4) @(posedge vif.clk);
endtask : drive_bit
// read one bit
task i2c_master_driver::read_bit(output logic bit_read, input int unsigned scl_period);
vif.sda <= 1'bZ;
repeat(scl_period / 4) @(posedge vif.clk);
vif.scl <= 1'b1;
repeat(scl_period / 4) @(posedge vif.clk);
bit_read = vif.sda_wire;
repeat(scl_period / 4) @(posedge vif.clk);
vif.scl <= 1'b0;
repeat(scl_period / 4) @(posedge vif.clk);
endtask : read_bit
`endif

View File

@@ -0,0 +1,31 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_master_base_seq.sv
DESCRIPTION base sequence to be extended by other sequences
****************************************************************************/
`ifndef I2C_MASTER_BASE_SEQ_SV
`define I2C_MASTER_BASE_SEQ_SV
/*
* Class: i2c_master_base_seq
*/
class i2c_master_base_seq extends uvm_sequence #(i2c_transaction);
// UVM factory registration
`uvm_object_utils(i2c_master_base_seq)
// new - constructor
function new(string name = "i2c_master_base_seq");
super.new(name);
endfunction: new
endclass: i2c_master_base_seq
`endif

View File

@@ -0,0 +1,18 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_master_seq_lib.sv
DESCRIPTION sequence includes
****************************************************************************/
`ifndef I2C_MASTER_SEQ_LIB_SV
`define I2C_MASTER_SEQ_LIB_SV
`include "master/sequences/i2c_master_base_seq.sv"
`include "master/sequences/i2c_master_simple_seq.sv"
`endif

View File

@@ -0,0 +1,42 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_master_simple_seq.sv
DESCRIPTION simple sequence; random transactions
****************************************************************************/
`ifndef I2C_MASTER_SIMPLE_SEQ_SV
`define I2C_MASTER_SIMPLE_SEQ_SV
/**
* Class: i2c_master_simple_seq
*/
class i2c_master_simple_seq extends i2c_master_base_seq;
rand int unsigned num_of_tr;
// constraints
constraint num_of_tr_cst { num_of_tr inside {[1 : 10]};}
// UVM factory registration
`uvm_object_utils(i2c_master_simple_seq)
// new - constructor
function new(string name = "i2c_master_simple_seq");
super.new(name);
endfunction : new
// sequence generation logic in body
virtual task body();
repeat(num_of_tr) begin
`uvm_do(req)
end
endtask : body
endclass : i2c_master_simple_seq
`endif

View File

@@ -0,0 +1,70 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_slave_agent.sv
DESCRIPTION slave agent
****************************************************************************/
`ifndef I2C_SLAVE_AGENT_SV
`define I2C_SLAVE_AGENT_SV
typedef uvm_sequencer #(i2c_transaction) i2c_slave_sequencer;
/**
* Class: i2c_slave_agent
*/
class i2c_slave_agent extends uvm_agent;
// configuration object
i2c_slave_config cfg;
// components
i2c_slave_driver drv;
i2c_slave_sequencer seqr;
i2c_monitor mon;
// UVM factory registration
`uvm_component_utils_begin(i2c_slave_agent)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// new - constructor
function new(string name = "i2c_slave_agent", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(i2c_slave_config)::get(this, "", "i2c_slave_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
// create driver and sequencer if agent is active
if(cfg.is_active == UVM_ACTIVE) begin
seqr = i2c_slave_sequencer::type_id::create("seqr", this);
drv = i2c_slave_driver::type_id::create("drv", this);
end
// always create monitor
mon = i2c_monitor::type_id::create("mon", this);
endfunction : build_phase
// UVM connect_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// connect driver and sequencer if agent is active
if(cfg.is_active == UVM_ACTIVE) begin
drv.seq_item_port.connect(seqr.seq_item_export);
end
endfunction : connect_phase
endclass : i2c_slave_agent
`endif

View File

@@ -0,0 +1,41 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_slave_config.sv
DESCRIPTION slave configuration object
****************************************************************************/
`ifndef I2C_SLAVE_CONFIG_SV
`define I2C_SLAVE_CONFIG_SV
/**
* Class: i2c_slave_config
*/
class i2c_slave_config extends uvm_object;
// is agent active or passive
uvm_active_passive_enum is_active = UVM_ACTIVE;
// checks and coverage control
bit has_checks = 1;
bit has_coverage = 1;
// UVM factory registration
`uvm_object_utils_begin(i2c_slave_config)
`uvm_field_enum(uvm_active_passive_enum, is_active, UVM_DEFAULT)
`uvm_field_int(has_checks, UVM_DEFAULT)
`uvm_field_int(has_coverage, UVM_DEFAULT)
`uvm_object_utils_end
// new - constructor
function new(string name = "i2c_slave_config");
super.new(name);
endfunction : new
endclass : i2c_slave_config
`endif

View File

@@ -0,0 +1,148 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_slave_driver.sv
DESCRIPTION drives slave response
****************************************************************************/
`ifndef I2C_SLAVE_DRIVER_SV
`define I2C_SLAVE_DRIVER_SV
/**
* Class: i2c_slave_driver
*/
class i2c_slave_driver extends uvm_driver #(i2c_transaction, i2c_transaction);
// i2c virtual interface
virtual i2c_if vif;
// configuration
i2c_slave_config cfg;
// UVM factory registration
`uvm_component_utils_begin(i2c_slave_driver)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// new - constructor
function new(string name = "i2c_slave_driver", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(i2c_slave_config)::get(this, "", "i2c_slave_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
endfunction: build_phase
// UVM connect_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// get interface from db
if(!uvm_config_db#(virtual i2c_if)::get(this, "", "i2c_if", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"})
endfunction : connect_phase
// additional class methods
extern virtual task run_phase(uvm_phase phase);
extern virtual task reset();
extern virtual task get_and_drive();
extern virtual task drive_tr(i2c_transaction tr);
endclass : i2c_slave_driver
// UVM run_phase
task i2c_slave_driver::run_phase(uvm_phase phase);
reset(); // init.
forever begin
fork
@(posedge vif.rst); // reset is active low
// threads killed at reset
get_and_drive();
join_any
disable fork;
reset();
end
endtask : run_phase
// reset signals
task i2c_slave_driver::reset();
`uvm_info(get_type_name(), "Reset observed", UVM_MEDIUM)
vif.scl <= 1'b1;
vif.sda <= 1'b1;
@(negedge vif.rst); // reset dropped
endtask : reset
// sequencer/driver handshake
task i2c_slave_driver::get_and_drive();
forever begin
seq_item_port.get_next_item(req);
drive_tr(req);
seq_item_port.item_done();
end
endtask : get_and_drive
// drive transaction
task i2c_slave_driver::drive_tr (i2c_transaction tr);
// wait for the master to initiate the transaction
@(negedge vif.sda_wire iff vif.scl_wire === 1'b1); // start condition
// address
tr.addr = 0;
repeat(ADDR_WIDTH) begin
@(posedge vif.scl_wire);
#1;
tr.addr = {tr.addr[ADDR_WIDTH - 2 : 0], vif.sda_wire};
end
// read / write bit
@(posedge vif.scl_wire);
#1;
tr.dir = i2c_direction_enum'(vif.sda_wire);
// drive addr ack / nack
@(posedge vif.scl_wire);
vif.sda = tr.addr_ack;
// recieved ack - continue
if(tr.addr_ack == I2C_ACK) begin
if(tr.dir == I2C_WRITE) begin
// data
repeat(DATA_WIDTH) begin
@(posedge vif.scl_wire);
#1;
tr.data = {tr.data[DATA_WIDTH - 2 : 0], vif.sda_wire};
end
// drive data ack / nack
@(posedge vif.scl_wire);
vif.sda <= tr.data_ack;
end
else begin // READ
// drive data - msb first
for(int i = DATA_WIDTH; i > 0; --i) begin
@(posedge vif.scl_wire);
vif.sda <= tr.data[i-1];
end
// read data ack / nack
@(posedge vif.scl_wire);
#1;
if(vif.sda_wire === 1'b0) tr.data_ack = I2C_ACK;
else tr.data_ack = I2C_NACK;
end
end
`uvm_info(get_type_name(), $sformatf("i2c Finished Driving tr \n%s", tr.sprint()), UVM_HIGH)
endtask : drive_tr
`endif

View File

@@ -0,0 +1,31 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_slave_base_seq.sv
DESCRIPTION base sequence to be extended by other sequences
****************************************************************************/
`ifndef I2C_SLAVE_BASE_SEQ_SV
`define I2C_SLAVE_BASE_SEQ_SV
/**
* Class: i2c_slave_base_seq
*/
class i2c_slave_base_seq extends uvm_sequence #(i2c_transaction, i2c_transaction);
// UVM factory registration
`uvm_object_utils(i2c_slave_base_seq)
// new - constructor
function new(string name = "i2c_slave_base_seq");
super.new(name);
endfunction : new
endclass : i2c_slave_base_seq
`endif

View File

@@ -0,0 +1,18 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_slave_seq_lib.sv
DESCRIPTION sequence includes
****************************************************************************/
`ifndef I2C_SLAVE_SEQ_LIB_SV
`define I2C_SLAVE_SEQ_LIB_SV
`include "slave/sequences/i2c_slave_base_seq.sv"
`include "slave/sequences/i2c_slave_simple_seq.sv"
`endif

View File

@@ -0,0 +1,38 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE i2c_slave_simple_seq.sv
DESCRIPTION simple sequence; always respond with random data
****************************************************************************/
`ifndef I2C_SLAVE_SIMPLE_SEQ_SV
`define I2C_SLAVE_SIMPLE_SEQ_SV
/**
* Class: i2c_slave_simple_seq
*/
class i2c_slave_simple_seq extends i2c_slave_base_seq;
// UVM factory registration
`uvm_object_utils(i2c_slave_simple_seq)
// new - constructor
function new(string name = "i2c_slave_simple_seq");
super.new(name);
endfunction : new
// sequence generation logic in body
virtual task body();
forever begin
`uvm_do(req)
end
endtask : body
endclass : i2c_slave_simple_seq
`endif

View File

@@ -0,0 +1,72 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE reset_agent.sv
DESCRIPTION
****************************************************************************/
`ifndef RESET_AGENT_SV
`define RESET_AGENT_SV
// reset sequencer
typedef uvm_sequencer#(reset_transaction) reset_sequencer;
/**
* Class: reset_agent
*/
class reset_agent extends uvm_agent;
// configuration object
reset_config cfg;
// components
reset_sequencer seqr;
reset_driver drv;
reset_monitor mon;
// UVM factory registration
`uvm_component_utils_begin(reset_agent)
`uvm_field_enum(uvm_active_passive_enum, is_active, UVM_DEFAULT)
`uvm_component_utils_end
// new - constructor
function new (string name = "reset_agent", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(reset_config)::get(this, "", "reset_config", cfg)) begin
`uvm_info("NOCONFIG", "Using default reset_config", UVM_LOW)
cfg = reset_config::type_id::create("cfg");
uvm_config_db#(reset_config)::set(this, "*", "reset_config", cfg);
end
// create driver and sequencer if agent is active
if(cfg.is_active == UVM_ACTIVE) begin
seqr = reset_sequencer::type_id::create("seqr", this);
drv = reset_driver::type_id::create("drv", this);
end
// always create monitor
mon = reset_monitor::type_id::create("mon", this);
endfunction : build_phase
// UVM connect_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// connect driver and sequencer if agent is active
if(cfg.is_active == UVM_ACTIVE) begin
drv.seq_item_port.connect(seqr.seq_item_export);
end
endfunction : connect_phase
endclass : reset_agent
`endif

View File

@@ -0,0 +1,46 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE reset_config.sv
DESCRIPTION configuration class for reset agent
****************************************************************************/
`ifndef RESET_CONFIG_SV
`define RESET_CONFIG_SV
/**
* Class: reset_config
*/
class reset_config extends uvm_object;
// reset value at the start of simulation
bit value_at_0 = 0;
// 1 = reset is active high; 0 = active low
bit active_high = 1;
// is agent active or passive
uvm_active_passive_enum is_active = UVM_ACTIVE;
// checks and coverage control
bit has_checks = 1;
bit has_coverage = 1;
// UVM factory registration
`uvm_object_utils_begin(reset_config)
`uvm_field_int(value_at_0, UVM_DEFAULT)
`uvm_field_int(active_high, UVM_DEFAULT)
`uvm_field_enum(uvm_active_passive_enum, is_active, UVM_DEFAULT)
`uvm_field_int(has_checks, UVM_DEFAULT)
`uvm_field_int(has_coverage, UVM_DEFAULT)
`uvm_object_utils_end
// new - constructor
function new(string name = "reset_config");
super.new(name);
endfunction : new
endclass : reset_config
`endif

View File

@@ -0,0 +1,93 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE reset_driver.sv
DESCRIPTION drives reset
****************************************************************************/
`ifndef RESET_DRIVER_SV
`define RESET_DRIVER_SV
/**
* Class: reset_driver
*/
class reset_driver extends uvm_driver #(reset_transaction);
// reset virtual interface
virtual reset_if vif;
// configuration
reset_config cfg;
// UVM factory registration
`uvm_component_utils_begin(reset_driver)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// new - constructor
function new (string name = "reset_driver", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// UVM build_phase
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(reset_config)::get(this, "*", "reset_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
endfunction: build_phase
// UVM connect_phase
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// get interface from db
if(!uvm_config_db#(virtual reset_if)::get(this, "", "reset_if", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"})
endfunction : connect_phase
// additional class methods
extern virtual task run_phase(uvm_phase phase);
extern virtual function void start_of_simulation_phase(uvm_phase phase);
extern virtual task drive_tr (reset_transaction tr);
endclass : reset_driver
// UVM start_of_simulation_phase
function void reset_driver::start_of_simulation_phase(uvm_phase phase);
super.start_of_simulation_phase(phase);
vif.reset <= cfg.value_at_0; // init reset
endfunction
// UVM run_phase
task reset_driver::run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
drive_tr(req);
seq_item_port.item_done();
end
endtask : run_phase
// Drives a transfer when an item is ready to be sent.
task reset_driver::drive_tr (reset_transaction tr);
`uvm_info( get_type_name(),
$sformatf("Driving reset: delay %0d clocks duration of %0d clocks",
tr.transmit_delay, tr.duration),
UVM_LOW)
// delay
if (tr.transmit_delay > 0) begin
repeat(tr.transmit_delay) @(posedge vif.clk);
end
// start reset
vif.reset <= cfg.active_high;
// duration
repeat(tr.duration) @(posedge vif.clk);
// drop reset
vif.reset <= ~cfg.active_high;
endtask : drive_tr
`endif

View File

@@ -0,0 +1,22 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE reset_if.sv
DESCRIPTION reset interface
****************************************************************************/
`ifndef RESET_IF_SV
`define RESET_IF_SV
/**
* Interface: reset_if
*/
interface reset_if (input clk, output logic reset);
endinterface : reset_if
`endif

View File

@@ -0,0 +1,127 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE reset_monitor.sv
DESCRIPTION monitors interface for reset; collects coverage
****************************************************************************/
`ifndef RESET_MONITOR_SV
`define RESET_MONITOR_SV
/**
* Class: reset_monitor
*/
class reset_monitor extends uvm_monitor;
// reset virtual interface
virtual reset_if vif;
// configuration
reset_config cfg;
// TLM - from monitor to other components
uvm_analysis_port #(reset_transaction) item_collected_port;
// keep track of number of transactions
int unsigned num_transactions = 0;
// current transaction
reset_transaction tr_collected;
// UVM factory registration
`uvm_component_utils_begin(reset_monitor)
`uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
`uvm_component_utils_end
// coverage
covergroup cg_reset;
// reset duration
cp_duration : coverpoint tr_collected.duration {
bins one_clk = {1};
bins other = default;
}
endgroup : cg_reset;
// new - constructor
function new(string name = "reset_monitor", uvm_component parent = null);
super.new(name, parent);
item_collected_port = new("item_collected_port", this);
cg_reset = new();
endfunction : new
// UVM build_phase
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get configuration object from db
if(!uvm_config_db#(reset_config)::get(this, "", "reset_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
endfunction: build_phase
// UVM connect_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// get interface from db
if(!uvm_config_db#(virtual reset_if)::get(this, "", "reset_if", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"})
endfunction : connect_phase
// additional class methods
extern virtual task run_phase(uvm_phase phase);
extern virtual function void report_phase(uvm_phase phase);
endclass : reset_monitor
// UVM run_phase
task reset_monitor::run_phase(uvm_phase phase);
forever begin
tr_collected = reset_transaction::type_id::create("tr_collected");
// monitor reset
if(cfg.active_high) begin
@(posedge vif.reset);
end
else begin
@(negedge vif.reset);
end
`uvm_info(get_type_name(), "Reset observed", UVM_MEDIUM)
tr_collected.duration = 1;
fork
// get duration
forever begin
@(posedge vif.clk) tr_collected.duration++;
end
// monitor reset dropped
begin
if(cfg.active_high) begin
@(negedge vif.reset);
end
else begin
@(posedge vif.reset);
end
end
join_any
disable fork;
item_collected_port.write(tr_collected); // TLM
// collect coverage if enabled
if(cfg.has_coverage == 1) begin
cg_reset.sample();
end
num_transactions++;
end // forever begin
endtask : run_phase
// UVM report_phase
function void reset_monitor::report_phase(uvm_phase phase);
// final report
`uvm_info(get_type_name(), $sformatf("Report: reset monitor collected %0d transfers", num_transactions), UVM_LOW);
endfunction : report_phase
`endif

View File

@@ -0,0 +1,34 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE reset_pkg.sv
DESCRIPTION package containing all parameters and includes
****************************************************************************/
`ifndef RESET_PKG_SV
`define RESET_PKG_SV
/**
* Package: reset_pkg
*/
package reset_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
`include "reset_config.sv"
`include "reset_transaction.sv"
`include "reset_driver.sv"
`include "reset_monitor.sv"
`include "reset_agent.sv"
`include "sequences/reset_seq_lib.sv"
endpackage : reset_pkg
`include "reset_if.sv"
`endif

View File

@@ -0,0 +1,42 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE reset_transaction.sv
DESCRIPTION reset sequence item
****************************************************************************/
`ifndef RESET_TRANSACTION_SV
`define RESET_TRANSACTION_SV
/**
* Class: reset_transaction
*/
class reset_transaction extends uvm_sequence_item;
// delay before asserting reset (#clk cycles)
rand int unsigned transmit_delay;
// duration of reset (#clk cycles)
rand int unsigned duration;
// constraints
constraint c_transmit_delay { transmit_delay <= 10; }
constraint c_duration { duration inside {[0:5]}; }
// UVM factory registration
`uvm_object_utils_begin(reset_transaction)
`uvm_field_int(transmit_delay, UVM_DEFAULT)
`uvm_field_int(duration, UVM_DEFAULT)
`uvm_object_utils_end
// new - constructor
function new (string name = "reset_transaction");
super.new(name);
endfunction : new
endclass : reset_transaction
`endif

View File

@@ -0,0 +1,31 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE reset_base_seq.sv
DESCRIPTION base sequence
****************************************************************************/
`ifndef RESET_BASE_SEQ_SV
`define RESET_BASE_SEQ_SV
/**
* Class: reset_base_seq
*/
class reset_base_seq extends uvm_sequence #(reset_transaction, reset_transaction);
// UVM factory registration
`uvm_object_utils(reset_base_seq)
// new - constructor
function new(string name = "reset_base_seq");
super.new(name);
endfunction : new
endclass : reset_base_seq
`endif

View File

@@ -0,0 +1,47 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE reset_seq.sv
DESCRIPTION sequence for assertion reset
****************************************************************************/
`ifndef RESET_SEQ_SV
`define RESET_SEQ_SV
/**
* Class: reset_seq
*/
class reset_seq extends reset_base_seq;
// delay before asserting reset (#clk cycles)
rand int unsigned transmit_del;
// duration of reset (#clk cycles)
rand int unsigned duration_time;
// UVM factory registration
`uvm_object_utils(reset_seq)
// constraints
constraint c_transmit_delay { transmit_del <= 10; }
constraint c_duration_time { duration_time inside {[1:5]}; }
// new - constructor
function new(string name = "reset_seq");
super.new(name);
endfunction : new
// sequence generation logic in body
virtual task body();
// send one transaction
`uvm_do_with(req, { req.duration == duration_time;
req.transmit_delay == transmit_del; } )
endtask : body
endclass : reset_seq
`endif

View File

@@ -0,0 +1,18 @@
/****************************************************************************
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
|F|u|n|c|t|i|o|n|a|l| |V|e|r|i|f|i|c|a|t|i|o|n| |o|f| |H|a|r|d|w|a|r|e|
+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+ +-+-+-+-+-+-+-+-+
FILE reset_seq_lib.sv
DESCRIPTION sequence includes
****************************************************************************/
`ifndef RESET_SEQ_LIB_SV
`define RESET_SEQ_LIB_SV
`include "sequences/reset_base_seq.sv"
`include "sequences/reset_seq.sv"
`endif