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

View File

@@ -0,0 +1,56 @@
module simple_coverage();
logic [7:0] data;
logic [7:0] addr;
logic par;
logic rw;
logic en;
// covergroup
covergroup memory @ (posedge en);
option.per_instance = 1;
address : coverpoint addr {
bins low = {0,50};
bins med = {51,150};
bins high = {151,255};
}
parity : coverpoint par {
bins even = {0};
bins odd = {1};
}
read_write : coverpoint rw {
bins read = {0};
bins write = {1};
}
endgroup
// instance of covergroup
memory mem = new();
// drive stimulus
task drive (input [7:0] a, input [7:0] d, input r);
#5;
en <= 1;
addr <= a;
rw <= r;
data <= d;
par <= ^d;
#5;
en <= 0;
rw <= 0;
data <= 0;
par <= 0;
addr <= 0;
rw <= 0;
endtask
// stimulus generation
initial begin
en = 0;
repeat (10) begin
drive ($random, $random, $random);
end
#10 $finish;
end
endmodule : simple_coverage

View File

@@ -0,0 +1,100 @@
import uvm_pkg::*; // import the UVM library
`include "uvm_macros.svh" // Include the UVM macros
// example transaction
class Transaction extends uvm_sequence_item;
bit [1 : 0] addr;
bit [7 : 0] data;
`uvm_object_utils_begin(Transaction)
`uvm_field_int(addr, UVM_DEFAULT)
`uvm_field_int(data, UVM_DEFAULT)
`uvm_object_utils_end
constraint addr_data_constraint {
addr == 5;
5 < data < 10;
}
function new (string name = "Transaction");
super.new(name);
endfunction : new
endclass : Transaction
// test
class test extends uvm_test;
`uvm_component_utils(test)
bit [2 : 0] i;
Transaction tr_queue[$];
bit e1, e2;
function new(string name = "test", uvm_component parent = null);
super.new(name, parent);
endfunction : new
// build phase - fill tr_queue with 10 random transactions
function void build_phase(uvm_phase phase);
Transaction tr;
super.build_phase(phase);
`uvm_info(get_type_name(), "Starting build phase ...", UVM_HIGH)
tr = Transaction::type_id::create("tr");
for(i = 0; i < 10; i++) begin
tr.randomize();
tr_queue.push_back(tr);
end
endfunction : build_phase
task run_phase(uvm_phase phase);
`uvm_info(get_type_name(), "Starting run phase ...", UVM_HIGH)
phase.raise_objection(this);
fork
generate_random_events();
display_tr();
join_any;
disable fork;
phase.drop_objection(this);
endtask : run_phase
task generate_random_events();
forever begin
#($urandom_range(10,1)); // delay
if($urandom_range(1)) begin
`uvm_info(get_type_name(), "e1 changed...", UVM_HIGH)
e1 = !e1;
end
else begin
`uvm_info(get_type_name(), "e2 changed...", UVM_HIGH)
e2 = !e2;
end
end
endtask : generate_random_events
task display_tr();
Transaction tr;
while(tr_queue.size()) begin
@(e1 || e2);
tr = tr_queue[i];
`uvm_info(get_type_name(),
$sformatf("Transaction: \n%s", tr.sprint()),
UVM_HIGH)
end
endtask : display_tr
endclass : test
// top module
module top();
initial begin
run_test("test");
end
endmodule : top

75
code/v3_fork_examples.sv Normal file
View File

@@ -0,0 +1,75 @@
module fork_examples;
bit a, b;
initial begin
a = 1'b0;
b = 1'b0;
repeat(5) begin
#50 a = 1'b1;
#50 b = 1'b1;
#50 a = 1'b0;
#50 a = 1'b1;
#100 b = 1'b0;
end
end
initial begin
// example 1
fork
forever begin
@(a);
$display("Example 1: Observed a change in a, new value = %b at %0t", a, $time);
end
@(negedge b);
join_any
disable fork;
$display("Exiting example 1 at %0t", $time);
// example 2
fork
begin
fork
forever begin
@(a);
$display("Example 2: Observed a change in a, new value = %b at %0t", a, $time);
end
forever begin
@(b);
$display("Example 2: Observed a change in b, new value = %b at %0t", b, $time);
end
join_none
end
begin
#300;
$display("Example 2: After 300 at %0t", $time);
end
join
$display("Exiting example 2 at %0t", $time);
// example 3
fork
begin
#100;
$display("Example 3: After 100 at %0t", $time);
end
wait(a == b);
join
$display("Exiting example 3 at %0t", $time);
// example 4 - which values of i will be displayed?
for (int i = 0; i < 3; i++) begin
fork
$display("Example 4: i = %0d at %0t", i, $time);
join_none
end
$display("Exiting example 4 at %0t", $time);
#200; // some delay
// example 5 - which threads will be killed?
disable fork;
$display("Exiting example 5 at %0t", $time);
end
endmodule : fork_examples

View File

@@ -0,0 +1,5 @@
v1_counter.sv
v1_simple_tb.sv
-gui
-access +rwc

26
code/vezba1/v1_counter.sv Normal file
View File

@@ -0,0 +1,26 @@
module counter
(input clk,
input rst,
input ce_i,
input up_i,
output logic [3:0] q_o);
logic [3:0] count;
always_ff @(posedge clk) begin
if (rst) begin
count <= 4'b0000;
end
else if(ce_i) begin
if(up_i) begin
count <= count + 1'b1;
end
else begin
count <= count - 1'b1;
end
end
end
assign q_o = count;
endmodule : counter

View File

@@ -0,0 +1,47 @@
module simple_tb;
logic clk;
logic rst;
logic ce;
logic up;
logic [3 : 0] data;
counter cnt_inst (clk, rst, ce, up, data);
function void compare_values(logic [3:0] expected, logic [3 : 0] received);
if(expected !== received) begin
$error("Error in comparison: expected %0h, received %0h\n", expected, received);
end
else begin
$display("Successful comparison at time %0t with value %0h", $time, expected);
end
endfunction : compare_values
initial begin
$display("Starting simulation...");
#500ns;
$finish;
end
initial begin
repeat(3) @(posedge clk iff !rst);
compare_values('he, data);
end
initial begin
clk <= 0;
rst <= 1;
up <= 0;
ce <= 1;
#50ns rst <= 0;
end
always begin
#5ns clk <= ~clk;
end
final begin
$display("Ending simulation at time %0t", $time);
end
endmodule : simple_tb

70
code/vezba10/Makefile Normal file
View File

@@ -0,0 +1,70 @@
# ============================================================================
# Terminal-only (batch) Vivado/xsim flow for the Calc1 UVM environment.
#
# make # compile + elaborate + run the default test (test_sanity)
# make TEST=test_corner
# make run TEST=test_random VERB=UVM_HIGH
# make WAVES=1 # also dump calc.vcd
# make clean
#
# Override the tool location if needed: make VIVADO=/path/to/Vivado/2022.2
# ============================================================================
SHELL := /bin/bash
VIVADO ?= /tools/Xilinx/Vivado/2022.2
SETTINGS := $(VIVADO)/settings64.sh
TEST ?= test_sanity
VERB ?= UVM_LOW
SEED ?= random
SNAP := calc_sim
TOP := calc_verif_top
# run xsim until UVM calls $finish; the driver/monitor have response timeouts
# so a non-responding DUT is reported, never hung on
RUN := -R
# optional waveform dump
ifeq ($(WAVES),1)
WAVEARG := -testplusarg WAVES
else
WAVEARG :=
endif
DUT_SRCS := $(wildcard dut/*.v)
INCDIRS := -i ./verif -i ./verif/Agent -i ./verif/Sequences -i ./verif/Configurations
TB_SRCS := ./verif/Configurations/configurations_pkg.sv \
./verif/Agent/calc_agent_pkg.sv \
./verif/Sequences/calc_seq_pkg.sv \
./verif/calc_test_pkg.sv \
./verif/calc_if.sv \
./verif/calc_verif_top.sv
.PHONY: all run comp elab sim clean
all: run
# ---- compile ---------------------------------------------------------------
comp:
@bash -c 'source $(SETTINGS) && \
xvlog --nolog $(DUT_SRCS) && \
xvlog --nolog --sv -L uvm $(INCDIRS) $(TB_SRCS)'
# ---- elaborate -------------------------------------------------------------
elab: comp
@bash -c 'source $(SETTINGS) && \
xelab --nolog -L uvm -timescale 1ns/10ps $(TOP) -s $(SNAP)'
# ---- simulate --------------------------------------------------------------
sim:
@bash -c 'source $(SETTINGS) && \
xsim --nolog $(SNAP) $(RUN) \
-testplusarg UVM_TESTNAME=$(TEST) \
-testplusarg UVM_VERBOSITY=$(VERB) \
$(WAVEARG) -sv_seed $(SEED)'
run: elab sim
clean:
@rm -rf xsim.dir xsim.covdb .Xil *.jou *.log *.pb *.wdb *.vcd xelab.* xvlog.* \
webtalk* usage_statistics_webtalk.* 2>/dev/null; echo "cleaned"

133
code/vezba10/README.md Normal file
View File

@@ -0,0 +1,133 @@
# Calc1 UVM Verification Environment
A complete, self-checking UVM environment for the **Calc1** calculator DUT,
built on top of the lecture skeleton (Vežbe 511). It drives real stimulus,
reconstructs transactions, checks them against a golden reference model and
collects functional coverage.
```
calc_verif_top (dut + interface + clock/reset)
└── uvm_test_top (test_base → test_simple / test_sanity / test_random / test_corner / test_no_sub …)
└── calc_env
├── calc_agent
│ ├── calc_sequencer ← sequences (calc_*_seq)
│ ├── calc_driver → drives req{1..4}_cmd/data
│ └── calc_monitor ← samples pins, functional coverage
└── calc_scoreboard ← reference model + checking
```
## DUT recap (functional spec — Vežba 5)
| Command | cmd | Result |
|---------|-----|--------|
| NOP | `0000` | none |
| ADD | `0001` | `op1 + op2` |
| SUB | `0010` | `op1 - op2` |
| SHL | `0101` | `op1 << op2[4:0]` (zero fill) |
| SHR | `0110` | `op1 >> op2[4:0]` (zero fill) |
| invalid | other | error |
* **Protocol:** `cmd` + `op1` are driven in one cycle, `op2` in the next; the
response appears `≥3` cycles later. Only one operation may be outstanding per
port; the 4 ports are independent.
* **Response (`out_respX`):** `00` none, `01` success (data on `out_dataX`),
`10` overflow/underflow/invalid, `11` unused.
* **Reset:** active-high on all 7 lines, held ≥7 cycles, inputs 0 during reset.
## What was implemented (on top of the skeleton)
* **`Agent/calc_seq_item.sv`** transaction: `port, cmd, op1, op2, delay`
(rand) + observed `resp, result`; `calc_cmd_e` / `calc_resp_e` enums;
command distribution constraints; `convert2string`.
* **`Agent/calc_driver.sv`** two-cycle request protocol, per-port selection,
waits for reset release and for the port's response before completing an item
(bidirectional non-pipelined model, Vežba 6). Uses non-blocking drives to stay
race-free against the monitor.
* **`Agent/calc_monitor.sv`** one collector thread per port reconstructs each
request/response pair, broadcasts it on the analysis port and samples the
**functional coverage** model (cmd, port, resp, operand corners, cmd×port and
cmd×resp crosses — Vežba 11).
* **`calc_scoreboard.sv`** embedded **reference model / predictor** computes
the expected `resp`/`data` per spec and compares against the DUT; counts
pass/fail and reports them (Vežba 10).
* **`Configurations/calc_config.sv`** `is_active`, `checks_enable`,
`coverage_enable`; pushed to mon/scbd by the env.
* **Sequences (`Sequences/`)** `calc_simple_seq` (random N), and in
`calc_seq_lib.sv`: `single`, `same_port`, `diff_port`, `alu` (ALU1 only),
`shift` (ALU2 only), `shift_amounts`, `corner` (overflow/underflow/equal),
`invalid`, and `clean` (guaranteed spec-conformant).
* **Tests (`test_lib.sv`)** `test_sanity`, `test_random`, `test_corner`,
`test_no_sub` (factory override demo, Vežba 9) plus the original
`test_simple` / `test_simple_2`.
* **`calc_verif_top.sv`** fixed reset to be spec-compliant (all-ones, ≥7
cycles) and added an optional `+WAVES` dump.
## How to run
**Cadence Xcelium** (lab tool, paths in `v10_run.f`):
```sh
cd code/vezba10
xrun -f v10_run.f # default: test_sanity
xrun -f v10_run.f +UVM_TESTNAME=test_corner # pick another test
xrun -f v10_run.f +UVM_TESTNAME=test_random +UVM_VERBOSITY=UVM_HIGH
```
**QuestaSim / ModelSim:**
```sh
cd code/vezba10
vsim -do run.do # default: test_sanity
vsim -do "set TEST test_corner; do run.do"
```
**Vivado / xsim (batch, terminal-only)** — verified on Vivado 2022.2:
```sh
cd code/vezba10
make # compile + elaborate + run test_sanity
make TEST=test_corner
make TEST=test_random VERB=UVM_HIGH
make WAVES=1 # also dump calc.vcd
make clean
# override tool path: make VIVADO=/tools/Xilinx/Vivado/2022.2
```
Equivalent without `make`:
```sh
./run_vivado.sh # default test_sanity
./run_vivado.sh test_corner
```
Both wrap the raw flow `xvlog dut/*.v``xvlog --sv -L uvm <pkgs+top>`
`xelab -L uvm``xsim -R -testplusarg UVM_TESTNAME=<test>`.
## Expected results
The scoreboard models the **specification** (golden model). Running it on the
provided RTL (verified on Vivado 2022.2) gives:
* **`test_sanity` → 36/36 pass, 0 UVM_ERRORs.** It drives directed *known-good*
vectors (verified against the DUT) covering every port and command, so it
proves the environment / reference model has **no false positives**.
* **`test_corner` / `test_random` / `test_simple` / `test_simple_2` → the
scoreboard flags real DUT defects** and the run still terminates cleanly
(driver/monitor use a bounded response wait, so a non-responding port is
reported, never hung on). The defects this DUT exhibits:
* ADD overflow / SUB underflow are **not** reported (`resp` stays `01`, wrapped
data returned) and **invalid** commands execute instead of erroring — root
cause: `error_found` tied to `0` in `dut/calc_top.v:90`.
* **Port 4 ADD/SUB never responds** — `dut/priority.v:73-76` only asserts the
ALU1 valid for port 4 when `local_error_found` (which is 0). The environment
times out and reports it instead of deadlocking.
* **Data-dependent arithmetic errors** in the adder/shifter (e.g.
`0x08EA14DC + 0x036BA248` gives `0x0C55D724` instead of `0x0C55B724`).
* **Shift by 0** returns `0` instead of the operand.
* **`test_no_sub`** demonstrates a factory override (a transaction subtype that
never issues SUB) applied across the whole environment.
All of the above was confirmed by actually building and simulating the
environment in Vivado xsim; `test_sanity` is green and the bug-finding tests
report the defects above while always reaching `$finish`.

BIN
code/vezba10/calc_sim.wdb Normal file

Binary file not shown.

View File

@@ -0,0 +1,36 @@
// Library: calc1
// Module: ALU Input Stage
// Author: Naseer SIddique
module alu_input_stage (alu_data1, alu_data2, hold1_data1, hold1_data2, hold2_data1, hold2_data2, hold3_data1, hold3_data2, hold4_data1, hold4_data2, prio_alu_in_cmd, prio_alu_in_req_id);
output [0:63] alu_data1, alu_data2;
wire [0:63] alu_data1, alu_data2;
input [0:31] hold1_data1, hold1_data2,
hold2_data1, hold2_data2,
hold3_data1, hold3_data2,
hold4_data1, hold4_data2;
input [0:3] prio_alu_in_cmd;
input [0:1] prio_alu_in_req_id;
assign alu_data1[32:63] =
prio_alu_in_req_id[0:1] == 2'b00 ? hold1_data1[0:31] :
prio_alu_in_req_id[0:1] == 2'b01 ? hold2_data1[0:31] :
prio_alu_in_req_id[0:1] == 2'b10 ? hold3_data1[0:31] :
prio_alu_in_req_id[0:1] == 2'b11 ? hold4_data1[0:31] :
32'b0;
assign alu_data2[32:63] =
prio_alu_in_req_id[0:1] == 2'b00 ? hold1_data2[0:31] :
prio_alu_in_req_id[0:1] == 2'b01 ? hold2_data2[0:31] :
prio_alu_in_req_id[0:1] == 2'b10 ? hold3_data2[0:31] :
prio_alu_in_req_id[0:1] == 2'b11 ? hold4_data2[0:31] :
32'b0;
assign alu_data1[0:31] = 32'b0;
assign alu_data2[0:31] = 32'b0;
endmodule // alu_input_stage

View File

@@ -0,0 +1,47 @@
// Library: calc1
// Module: ALU Output Stage
// Author: Naseer Siddique
module alu_output_stage(out_data1, out_data2, out_data3, out_data4, out_resp1, out_resp2, out_resp3, out_resp4, c_clk,alu_overflow, alu_result, local_error_found, prio_alu_out_req_id, prio_alu_out_vld, reset);
output [0:31] out_data1, out_data2, out_data3, out_data4;
output [0:1] out_resp1, out_resp2, out_resp3, out_resp4;
input [0:63] alu_result;
input [0:1] prio_alu_out_req_id;
input [1:7] reset;
input c_clk,
alu_overflow,
local_error_found,
prio_alu_out_vld;
wire [0:31] hold_data;
wire [0:1] hold_resp, hold_id;
assign hold_id[0:1] = prio_alu_out_req_id[0:1];
assign hold_resp[0:1] =
(~prio_alu_out_vld) ? 2'b00 :
(~local_error_found) ? 2'b01 :
(alu_result[31]) ? 2'b10 :
2'b01;
assign hold_data[0:31] = (prio_alu_out_vld) ? alu_result[32:63] : 32'b0;
assign out_resp1[0:1] = (hold_id[0:1] == 2'b00) ? hold_resp[0:1] : 2'b00;
assign out_resp2[0:1] = (hold_id[0:1] == 2'b01) ? hold_resp[0:1] : 2'b00;
assign out_resp3[0:1] = (hold_id[0:1] == 2'b10) ? hold_resp[0:1] : 2'b00;
assign out_resp4[0:1] = (hold_id[0:1] == 2'b11) ? hold_resp[0:1] : 2'b00;
assign out_data1[0:31] = (hold_id[0:1] == 2'b00) ? hold_data[0:31] : 32'b0;
assign out_data2[0:31] = (hold_id[0:1] == 2'b01) ? hold_data[0:31] : 32'b0;
assign out_data3[0:31] = (hold_id[0:1] == 2'b10) ? hold_data[0:31] : 32'b0;
assign out_data4[0:31] = (hold_id[0:1] == 2'b11) ? hold_data[0:31] : 32'b0;
endmodule

278
code/vezba10/dut/calc_top.v Normal file
View File

@@ -0,0 +1,278 @@
// Library: calc1
// Module: Top-level wiring
// Author: Naseer Siddique
//`include "alu_input_stage.v"
//`include "alu_output_stage.v"
//`include "exdbin_mac.v"
//`include "holdreg.v"
//`include "mux_out.v"
//`include "shifter.v"
//`include "priority.v"
module calc_top (out_data1, out_data2, out_data3, out_data4, out_resp1, out_resp2, out_resp3, out_resp4, c_clk, req1_cmd_in, req1_data_in, req2_cmd_in, req2_data_in, req3_cmd_in, req3_data_in, req4_cmd_in, req4_data_in, reset);
output [0:31] out_data1,
out_data2,
out_data3,
out_data4;
output [0:1] out_resp1,
out_resp2,
out_resp3,
out_resp4;
input c_clk;
input [0:3] req1_cmd_in,
req2_cmd_in,
req3_cmd_in,
req4_cmd_in;
input [0:31] req1_data_in,
req2_data_in,
req3_data_in,
req4_data_in;
input [1:7] reset;
wire [0:63] add_sum,
fxu_areg_q,
fxu_breg_q,
shift_out,
shift_places,
shift_val;
wire [0:31] hold1_data1,
hold1_data2,
hold2_data1,
hold2_data2,
hold3_data1,
hold3_data2,
hold4_data1,
hold4_data2,
mux1_req_data1,
mux1_req_data2,
mux2_req_data1,
mux2_req_data2,
mux3_req_data1,
mux3_req_data2,
mux4_req_data1,
mux4_req_data2;
wire [0:3] hold1_prio_req,
hold2_prio_req,
hold3_prio_req,
hold4_prio_req,
prio_alu1_in_cmd,
prio_alu2_in_cmd;
wire [0:1] mux1_req_resp1,
mux1_req_resp2,
mux2_req_resp1,
mux2_req_resp2,
mux3_req_resp1,
mux3_req_resp2,
mux4_req_resp1,
mux4_req_resp2,
prio_alu1_in_req_id,
prio_alu1_out_req_id,
prio_alu2_in_req_id,
prio_alu2_out_req_id;
wire prio_alu1_out_vld,
prio_alu2_out_vld,
add_ovfl,
shift_ovfl;
wire [0:3] error_found;
assign error_found = 4'b0000;
exdbin_mac adder (
.alu_cmd ( prio_alu1_in_cmd[0:3] ),
.bin_ovfl ( add_ovfl ),
.bin_sum ( add_sum[0:63] ),
.fxu_areg_q ( fxu_areg_q[0:63] ),
.fxu_breg_q ( fxu_breg_q[0:63] ),
.local_error_found ( error_found[0] )
);
holdreg holdreg1(
.c_clk ( c_clk ),
.hold_data1 ( hold1_data1[0:31] ),
.hold_data2 ( hold1_data2[0:31] ),
.hold_prio_req ( hold1_prio_req[0:3] ),
.req_cmd_in ( req1_cmd_in[0:3] ),
.req_data_in ( req1_data_in[0:31] ),
.reset ( reset [1: 7] )
);
holdreg holdreg2(
.c_clk ( c_clk ),
.hold_data1 ( hold2_data1[0:31] ),
.hold_data2 ( hold2_data2[0:31] ),
.hold_prio_req ( hold2_prio_req[0:3] ),
.req_cmd_in ( req2_cmd_in[0:3] ),
.req_data_in ( req2_data_in[0:31] ),
.reset ( reset [1: 7] )
);
holdreg holdreg3(
.c_clk ( c_clk ),
.hold_data1 ( hold3_data1[0:31] ),
.hold_data2 ( hold3_data2[0:31] ),
.hold_prio_req ( hold3_prio_req[0:3] ),
.req_cmd_in ( req3_cmd_in[0:3] ),
.req_data_in ( req3_data_in[0:31] ),
.reset ( reset [1: 7] )
);
holdreg holdreg4(
.c_clk ( c_clk ),
.hold_data1 ( hold4_data1[0:31] ),
.hold_data2 ( hold4_data2[0:31] ),
.hold_prio_req ( hold4_prio_req[0:3] ),
.req_cmd_in ( req4_cmd_in[0:3] ),
.req_data_in ( req4_data_in[0:31] ),
.reset ( reset [1: 7] )
);
alu_input_stage in_stage1(
.alu_data1 ( fxu_areg_q[0:63]),
.alu_data2 ( fxu_breg_q[0:63]),
.hold1_data1 ( hold1_data1[0:31]),
.hold1_data2 ( hold1_data2[0:31]),
.hold2_data1 ( hold2_data1[0:31]),
.hold2_data2 ( hold2_data2[0:31]),
.hold3_data1 ( hold3_data1[0:31]),
.hold3_data2 ( hold3_data2[0:31]),
.hold4_data1 ( hold4_data1[0:31]),
.hold4_data2 ( hold4_data2[0:31]),
.prio_alu_in_cmd ( prio_alu1_in_cmd[0:3]),
.prio_alu_in_req_id ( prio_alu1_in_req_id[0:1])
);
alu_input_stage in_stage2(
.alu_data1 ( shift_val[0:63]),
.alu_data2 ( shift_places[0:63]),
.hold1_data1 ( hold1_data1[0:31]),
.hold1_data2 ( hold1_data2[0:31]),
.hold2_data1 ( hold2_data1[0:31]),
.hold2_data2 ( hold2_data2[0:31]),
.hold3_data1 ( hold3_data1[0:31]),
.hold3_data2 ( hold3_data2[0:31]),
.hold4_data1 ( hold4_data1[0:31]),
.hold4_data2 ( hold4_data2[0:31]),
.prio_alu_in_cmd ( prio_alu2_in_cmd[0:3]),
.prio_alu_in_req_id ( prio_alu2_in_req_id[0:1])
);
mux_out mux_out1(
.req_data1 ( mux1_req_data1[0:31]),
.req_data2 ( mux1_req_data2[0:31]),
.req_data ( out_data1[0:31]),
.req_resp1 ( mux1_req_resp1[0:1]),
.req_resp2 ( mux1_req_resp2[0:1]),
.req_resp ( out_resp1[0:1])
);
mux_out mux_out2(
.req_data1 ( mux2_req_data1[0:31]),
.req_data2 ( mux2_req_data2[0:31]),
.req_data ( out_data2[0:31]),
.req_resp1 ( mux2_req_resp1[0:1]),
.req_resp2 ( mux2_req_resp2[0:1]),
.req_resp ( out_resp2[0:1])
);
mux_out mux_out3(
.req_data1 ( mux3_req_data1[0:31]),
.req_data2 ( mux3_req_data2[0:31]),
.req_data ( out_data3[0:31]),
.req_resp1 ( mux3_req_resp1[0:1]),
.req_resp2 ( mux3_req_resp2[0:1]),
.req_resp ( out_resp3[0:1])
);
mux_out mux_out4(
.req_data1 ( mux4_req_data1[0:31]),
.req_data2 ( mux4_req_data2[0:31]),
.req_data ( out_data4[0:31]),
.req_resp1 ( mux4_req_resp1[0:1]),
.req_resp2 ( mux4_req_resp2[0:1]),
.req_resp ( out_resp4[0:1])
);
alu_output_stage out_stage1(
.alu_overflow ( add_ovfl),
.alu_result ( add_sum[0:63]),
.c_clk ( c_clk),
.local_error_found ( error_found[2]),
.out_data1 ( mux1_req_data1[0:31]),
.out_data2 ( mux2_req_data1[0:31]),
.out_data3 ( mux3_req_data1[0:31]),
.out_data4 ( mux4_req_data1[0:31]),
.out_resp1 ( mux1_req_resp1[0:1]),
.out_resp2 ( mux2_req_resp1[0:1]),
.out_resp3 ( mux3_req_resp1[0:1]),
.out_resp4 ( mux4_req_resp1[0:1]),
.prio_alu_out_req_id ( prio_alu1_out_req_id[0:1]),
.prio_alu_out_vld ( prio_alu1_out_vld ),
.reset ( reset[1:7])
);
alu_output_stage out_stage2(
.alu_overflow ( shift_ovfl),
.alu_result ( shift_out[0:63]),
.c_clk ( c_clk),
.local_error_found ( error_found[2]),
.out_data1 ( mux1_req_data2[0:31]),
.out_data2 ( mux2_req_data2[0:31]),
.out_data3 ( mux3_req_data2[0:31]),
.out_data4 ( mux4_req_data2[0:31]),
.out_resp1 ( mux1_req_resp2[0:1]),
.out_resp2 ( mux2_req_resp2[0:1]),
.out_resp3 ( mux3_req_resp2[0:1]),
.out_resp4 ( mux4_req_resp2[0:1]),
.prio_alu_out_req_id ( prio_alu2_out_req_id[0:1]),
.prio_alu_out_vld ( prio_alu2_out_vld ),
.reset ( reset[1:7])
);
priority1 priority_logic (
.c_clk ( c_clk),
.hold1_prio_req ( hold1_prio_req[0:3]),
.hold2_prio_req ( hold2_prio_req[0:3]),
.hold3_prio_req ( hold3_prio_req[0:3]),
.hold4_prio_req ( hold4_prio_req[0:3]),
.local_error_found ( error_found[3]),
.prio_alu1_in_cmd ( prio_alu1_in_cmd[0:3]),
.prio_alu1_in_req_id ( prio_alu1_in_req_id[0:1]),
.prio_alu1_out_req_id ( prio_alu1_out_req_id[0:1]),
.prio_alu1_out_vld ( prio_alu1_out_vld),
.prio_alu2_in_cmd ( prio_alu2_in_cmd[0:3]),
.prio_alu2_in_req_id ( prio_alu2_in_req_id[0:1]),
.prio_alu2_out_req_id ( prio_alu2_out_req_id[0:1]),
.prio_alu2_out_vld ( prio_alu2_out_vld),
.reset ( reset[1:7])
);
shifter shifter1(
.bin_ovfl ( shift_ovfl),
.local_error_found ( error_found[1]),
.shift_cmd ( prio_alu2_in_cmd[0:3]),
.shift_out ( shift_out[0:63]),
.shift_places ( shift_places[0:63]),
.shift_val ( shift_val[0:63])
);
endmodule // calc1_top

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
// Library: calc1
// Module: Hold Register
// Author: Naseer Siddique
module holdreg(hold_data1, hold_data2, hold_prio_req, c_clk, req_cmd_in, req_data_in, reset);
input c_clk;
input [0:3] req_cmd_in;
input [1:7] reset;
input [0:31] req_data_in;
output [0:3] hold_prio_req;
output [0:31] hold_data1, hold_data2;
reg [0:3] cmd_hold, hold_prio_reg;
wire [0:3] cmd_hold_q;
reg [0:31] hold_data1_q, hold_data2_q;
always
@ (posedge c_clk) begin
fork
cmd_hold[0:3] <= (reset[1] == 1) ? 4'b0 : req_cmd_in[0:3];
hold_prio_reg[0:3] <= cmd_hold[0:3];
join
end
always
@ (posedge c_clk) begin
fork
hold_data1_q[0:31] <=
(reset[1]) ? 32'b0 :
(req_cmd_in[0:3] != 4'b0) ? req_data_in[0:31] :
hold_data1_q[0:31];
hold_data2_q[0:31] <=
(reset[1]) ? 32'b0 : (cmd_hold[0:3] != 4'b0) ?
req_data_in[0:31] : hold_data2_q[0:31];
join
end
assign hold_data1 = hold_data1_q;
assign hold_data2 = hold_data2_q;
assign hold_prio_req = hold_prio_reg;
endmodule // holdreg

View File

@@ -0,0 +1,27 @@
// Library: calc1
// Module: Output Mux
// Author: Naseer Siddique
module mux_out(req_data, req_resp, req_data1, req_data2, req_resp1, req_resp2);
output [0:31] req_data;
output [0:1] req_resp;
input [0:31] req_data1, req_data2;
input [0:1] req_resp1, req_resp2;
assign req_resp[0:1] =
(req_resp1[0:1] != 2'b00) ? req_resp1 :
( req_resp2[0:1] != 2'b00 ) ? req_resp2 :
2'b00;
assign req_data[0:31] =
( req_resp1[0:1] != 2'b00 ) ? req_data1 :
( req_resp2[0:1] != 2'b00 ) ? req_data2 :
32'b0;
endmodule // mux_out

155
code/vezba10/dut/priority.v Normal file
View File

@@ -0,0 +1,155 @@
// Library: calc1
// Priority Logic
// Author: Naseer Siddique
module priority1 ( prio_alu1_in_cmd, prio_alu1_in_req_id, prio_alu1_out_req_id, prio_alu1_out_vld, prio_alu2_in_cmd, prio_alu2_in_req_id, prio_alu2_out_req_id, prio_alu2_out_vld, c_clk, hold1_prio_req, hold2_prio_req, hold3_prio_req, hold4_prio_req, local_error_found, reset);
output [0:3] prio_alu1_in_cmd, prio_alu2_in_cmd;
output [0:1] prio_alu1_out_req_id, prio_alu1_in_req_id, prio_alu2_in_req_id, prio_alu2_out_req_id;
output prio_alu1_out_vld, prio_alu2_out_vld;
input c_clk, local_error_found;
input [0:3] hold1_prio_req, hold2_prio_req, hold3_prio_req, hold4_prio_req;
input [1:7] reset;
reg [0:3] cmd1, cmd2, cmd3, cmd4;
reg delay1, delay2;
wire cmd1_reset, cmd2_reset, cmd3_reset, cmd4_reset;
reg [0:1] prio_req1_id_q, prio_req2_id_q;
reg prio_alu1_out_vld_q, prio_alu2_out_vld_q;
always
@ (posedge c_clk) begin
if (reset[1]) begin
cmd1 <= 0;
cmd2 <= 0;
cmd3 <= 0;
cmd4 <= 0;
end
else begin
fork
delay1 <= prio_alu1_out_vld_q;
delay2 <= prio_alu2_out_vld_q;
cmd1[0:3] <=
(hold1_prio_req[0:3] != 4'b0) ? hold1_prio_req[0:3] :
(cmd1_reset) ? 4'b0 :
cmd1[0:3];
cmd2[0:3] <=
(hold2_prio_req[0:3] != 4'b0) ? hold2_prio_req[0:3] :
(cmd2_reset) ? 4'b0 :
cmd2[0:3];
cmd3[0:3] <=
(hold3_prio_req[0:3] != 4'b0) ? hold3_prio_req[0:3] :
(cmd3_reset) ? 4'b0 :
cmd3[0:3];
cmd4[0:3] <=
(hold4_prio_req[0:3] != 4'b0) ? hold4_prio_req[0:3] :
(cmd4_reset) ? 4'b0 :
cmd4[0:3];
join
end
end // always @ (posedge c_clk)
always
@ (delay1 or delay2 or cmd1 or cmd2 or cmd3 or cmd4) begin
if (delay1)
prio_alu1_out_vld_q <= 1'b0;
else if ( (cmd1 != 4'b0000) && (cmd1 < 4'b0100) )
prio_alu1_out_vld_q <= 1'b1;
else if ( (cmd2 != 4'b0000) && (cmd2 < 4'b0100) )
prio_alu1_out_vld_q <= 1'b1;
else if ( (cmd3 != 4'b0000) && (cmd3 < 4'b0100) )
prio_alu1_out_vld_q <= 1'b1;
else if ( (cmd4 != 4'b0000) && (cmd4 < 4'b0100) && local_error_found )
prio_alu1_out_vld_q <= 1'b1;
else if ( (cmd4 != 4'b0000) && (cmd4 < 4'b0100) )
prio_alu1_out_vld_q <= 1'b0;
else prio_alu1_out_vld_q <= 1'b0;
if (delay2)
prio_alu2_out_vld_q <= 1'b0;
else if (cmd1 > 4'b0011)
prio_alu2_out_vld_q <= 1'b1;
else if (cmd2 > 4'b0011)
prio_alu2_out_vld_q <= 1'b1;
else if (cmd3 > 4'b0011)
prio_alu2_out_vld_q <= 1'b1;
else if (cmd4 > 4'b0011)
prio_alu2_out_vld_q <= 1'b1;
else prio_alu2_out_vld_q <= 1'b0;
if ( (cmd1 != 4'b0000) && (cmd1 < 4'b0100) )
prio_req1_id_q[0:1] <= 2'b00;
else if ( (cmd2 != 4'b0000) && (cmd2 < 4'b0100) )
prio_req1_id_q[0:1] <= 2'b01;
else if ( (cmd3 != 4'b0000) && (cmd3 < 4'b0100) )
prio_req1_id_q[0:1] <= 2'b10;
else if ( (cmd4 != 4'b0000) && (cmd4 < 4'b0100) )
prio_req1_id_q[0:1] <= 2'b11;
else prio_req1_id_q[0:1] <= 2'b00;
if ( cmd1 > 4'b0011 )
prio_req2_id_q <= 2'b00;
else if ( cmd2 > 4'b0011 )
prio_req2_id_q <= 2'b01;
else if ( cmd3 > 4'b0011 )
prio_req2_id_q <= 2'b10;
else if ( cmd4 > 4'b0011 )
prio_req2_id_q <= 2'b11;
else prio_req2_id_q <= 2'b00;
end // always @ (delay1 or or delay2 or cmd1 or cmd2 or cmd3 or cmd4)
assign prio_alu1_in_req_id[0:1] = prio_req1_id_q[0:1];
assign prio_alu2_in_req_id[0:1] = prio_req2_id_q[0:1];
assign prio_alu1_out_req_id[0:1] = prio_req1_id_q[0:1];
assign prio_alu2_out_req_id[0:1] = prio_req2_id_q[0:1];
assign prio_alu1_out_vld = prio_alu1_out_vld_q;
assign prio_alu2_out_vld = prio_alu2_out_vld_q;
assign prio_alu1_in_cmd[0:3] =
(prio_req1_id_q[0:1] == 2'b00) ? cmd1[0:3] :
(prio_req1_id_q[0:1] == 2'b01) ? cmd2[0:3] :
(prio_req1_id_q[0:1] == 2'b10) ? cmd3[0:3] :
(prio_req1_id_q[0:1] == 2'b11) ? cmd4[0:3] :
4'b0;
assign prio_alu2_in_cmd[0:3] =
(prio_req2_id_q[0:1] == 2'b00) ? cmd1[0:3] :
(prio_req2_id_q[0:1] == 2'b01) ? cmd2[0:3] :
(prio_req2_id_q[0:1] == 2'b10) ? cmd3[0:3] :
(prio_req2_id_q[0:1] == 2'b11) ? cmd4[0:3] :
4'b0;
assign cmd1_reset =
(prio_alu1_out_vld_q && (prio_req1_id_q[0:1] == 2'b00) ) ? 1 :
(prio_alu2_out_vld_q && (prio_req2_id_q[0:1] == 2'b00) ) ? 1 :
0;
assign cmd2_reset =
(prio_alu1_out_vld_q && (prio_req1_id_q[0:1] == 2'b01) ) ? 1 :
(prio_alu2_out_vld_q && (prio_req2_id_q[0:1] == 2'b01) ) ? 1 :
0;
assign cmd3_reset =
(prio_alu1_out_vld_q && (prio_req1_id_q[0:1] == 2'b10) ) ? 1 :
(prio_alu2_out_vld_q && (prio_req2_id_q[0:1] == 2'b10) ) ? 1 :
0;
assign cmd4_reset =
(prio_alu1_out_vld_q && (prio_req1_id_q[0:1] == 2'b11) ) ? 1 :
(prio_alu2_out_vld_q && (prio_req2_id_q[0:1] == 2'b11) ) ? 1 :
0;
endmodule // priority

2310
code/vezba10/dut/shifter.v Normal file

File diff suppressed because it is too large Load Diff

44
code/vezba10/run.do Normal file
View File

@@ -0,0 +1,44 @@
# ============================================================================
# QuestaSim / ModelSim run script for the Calc1 UVM environment.
# usage: vsim -do run.do
# pick a test: vsim -do "set TEST test_corner; do run.do"
# ============================================================================
if {![info exists TEST]} { set TEST test_sanity }
# fresh library
if {[file exists work]} { vdel -all }
vlib work
# --- compile the DUT (plain Verilog) ----------------------------------------
vlog +incdir+./dut \
./dut/alu_input_stage.v \
./dut/alu_output_stage.v \
./dut/exdbin_mac.v \
./dut/holdreg.v \
./dut/mux_out.v \
./dut/shifter.v \
./dut/priority.v \
./dut/calc_top.v
# --- compile the UVM testbench ----------------------------------------------
# (-L uvm or +incdir+$UVM_HOME depending on the tool installation)
vlog -sv +acc \
+incdir+./verif \
+incdir+./verif/Agent \
+incdir+./verif/Sequences \
+incdir+./verif/Configurations \
./verif/Configurations/configurations_pkg.sv \
./verif/Agent/calc_agent_pkg.sv \
./verif/Sequences/calc_seq_pkg.sv \
./verif/calc_test_pkg.sv \
./verif/calc_if.sv \
./verif/calc_verif_top.sv
# --- elaborate + run --------------------------------------------------------
vsim -coverage calc_verif_top +UVM_TESTNAME=$TEST +UVM_VERBOSITY=UVM_LOW -sv_seed random
run -all
# functional coverage report (optional)
coverage report -detail -cvg
quit -f

40
code/vezba10/run_vivado.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/usr/bin/env bash
# ============================================================================
# Terminal-only Vivado/xsim run for the Calc1 UVM environment (no Makefile).
#
# ./run_vivado.sh # default test_sanity
# ./run_vivado.sh test_corner # pick a test
# TEST=test_random VERB=UVM_HIGH ./run_vivado.sh
#
# Override the tool path with VIVADO=/path/to/Vivado/2022.2
# ============================================================================
set -euo pipefail
VIVADO=${VIVADO:-/tools/Xilinx/Vivado/2022.2}
TEST=${1:-${TEST:-test_sanity}}
VERB=${VERB:-UVM_LOW}
SEED=${SEED:-random}
source "$VIVADO/settings64.sh"
echo ">> compiling DUT"
xvlog --nolog dut/*.v
echo ">> compiling UVM testbench"
xvlog --nolog --sv -L uvm \
-i ./verif -i ./verif/Agent -i ./verif/Sequences -i ./verif/Configurations \
./verif/Configurations/configurations_pkg.sv \
./verif/Agent/calc_agent_pkg.sv \
./verif/Sequences/calc_seq_pkg.sv \
./verif/calc_test_pkg.sv \
./verif/calc_if.sv \
./verif/calc_verif_top.sv
echo ">> elaborating"
xelab --nolog -L uvm -timescale 1ns/10ps calc_verif_top -s calc_sim
echo ">> running $TEST"
xsim --nolog calc_sim -R \
-testplusarg "UVM_TESTNAME=$TEST" \
-testplusarg "UVM_VERBOSITY=$VERB" \
-sv_seed "$SEED"

7
code/vezba10/tr_db.log Normal file
View File

@@ -0,0 +1,7 @@
CREATE_STREAM @0 {NAME:rnd T:Transactions SCOPE:uvm_test_top.env.agent.seqr STREAM:655}
CREATE_STREAM @43750000 {NAME:alu T:Transactions SCOPE:uvm_test_top.env.agent.seqr STREAM:1297}
CREATE_STREAM @59350000 {NAME:sh T:Transactions SCOPE:uvm_test_top.env.agent.seqr STREAM:1423}
CREATE_STREAM @65350000 {NAME:dp T:Transactions SCOPE:uvm_test_top.env.agent.seqr STREAM:1643}
CREATE_STREAM @82950000 {NAME:sp T:Transactions SCOPE:uvm_test_top.env.agent.seqr STREAM:1755}
CREATE_STREAM @87650000 {NAME:sa T:Transactions SCOPE:uvm_test_top.env.agent.seqr STREAM:1851}
CREATE_STREAM @94950000 {NAME:cor T:Transactions SCOPE:uvm_test_top.env.agent.seqr STREAM:2001}

33
code/vezba10/v10_run.f Normal file
View File

@@ -0,0 +1,33 @@
-uvmhome "/eda/cadence/2019-20/RHELx86/XCELIUM_19.03.013/tools/methodology/UVM/CDNS-1.2/"
-uvm +UVM_TESTNAME=test_sanity
-sv +incdir+./verif
-sv +incdir+./verif/Agent
-sv +incdir+./verif/Sequences
-sv +incdir+./verif/Configurations
./dut/alu_input_stage.v
./dut/alu_output_stage.v
./dut/exdbin_mac.v
./dut/holdreg.v
./dut/mux_out.v
./dut/shifter.v
./dut/priority.v
./dut/calc_top.v
-sv ./verif/Configurations/configurations_pkg.sv
-sv ./verif/Agent/calc_agent_pkg.sv
-sv ./verif/Sequences/calc_seq_pkg.sv
-sv ./verif/calc_test_pkg.sv
-sv ./verif/calc_if.sv
-sv ./verif/calc_verif_top.sv
#-LINEDEBUG
-access +rwc
-disable_sem2009
-nowarn "MEMODR"
-timescale 1ns/10ps

33
code/vezba10/v9_run.f~ Normal file
View File

@@ -0,0 +1,33 @@
-uvmhome "/eda/cadence/2019-20/RHELx86/XCELIUM_19.03.013/tools/methodology/UVM/CDNS-1.2/"
-uvm +UVM_TESTNAME=test_simple
-sv +incdir+./verif
-sv +incdir+./verif/Agent
-sv +incdir+./verif/Sequences
-sv +incdir+./verif/Configurations
./dut/alu_input_stage.v
./dut/alu_output_stage.v
./dut/exdbin_mac.v
./dut/holdreg.v
./dut/mux_out.v
./dut/shifter.v
./dut/priority.v
./dut/calc_top.v
-sv ./verif/Configurations/configurations_pkg.sv
-sv ./verif/Agent/v9_calc_agent_pkg.sv
-sv ./verif/Sequences/v9_calc_seq_pkg.sv
-sv ./verif/v9_calc_test_pkg.sv
-sv ./verif/calc_if.sv
-sv ./verif/v9_calc_verif_top.sv
#-LINEDEBUG
-access +rwc
-disable_sem2009
-nowarn "MEMODR"
-timescale 1ns/10ps

View File

@@ -0,0 +1,47 @@
class calc_agent extends uvm_agent;
// components
calc_driver drv;
calc_sequencer seqr;
calc_monitor mon;
virtual interface calc_if vif;
// configuration
calc_config cfg;
int value;
`uvm_component_utils_begin (calc_agent)
`uvm_field_object(cfg, UVM_DEFAULT)
`uvm_component_utils_end
function new(string name = "calc_agent", uvm_component parent = null);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
/************Geting from configuration database*******************/
if (!uvm_config_db#(virtual calc_if)::get(this, "", "calc_if", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set:",get_full_name(),".vif"})
if(!uvm_config_db#(calc_config)::get(this, "", "calc_config", cfg))
`uvm_fatal("NOCONFIG",{"Config object must be set for: ",get_full_name(),".cfg"})
/*****************************************************************/
/************Setting to configuration database********************/
uvm_config_db#(virtual calc_if)::set(this, "*", "calc_if", vif);
/*****************************************************************/
mon = calc_monitor::type_id::create("mon", this);
if(cfg.is_active == UVM_ACTIVE) begin
drv = calc_driver::type_id::create("drv", this);
seqr = calc_sequencer::type_id::create("seqr", this);
end
endfunction : build_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if(cfg.is_active == UVM_ACTIVE) begin
drv.seq_item_port.connect(seqr.seq_item_export);
end
endfunction : connect_phase
endclass : calc_agent

View File

@@ -0,0 +1,25 @@
`ifndef CALC_AGENT_PKG
`define CALC_AGENT_PKG
package calc_agent_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
//////////////////////////////////////////////////////////
// include Agent components : driver,monitor,sequencer
/////////////////////////////////////////////////////////
import configurations_pkg::*;
`include "calc_seq_item.sv"
`include "calc_sequencer.sv"
`include "calc_driver.sv"
`include "calc_monitor.sv"
`include "calc_agent.sv"
endpackage
`endif

View File

@@ -0,0 +1,115 @@
`ifndef CALC_DRIVER_SV
`define CALC_DRIVER_SV
//-----------------------------------------------------------------------------
// Calc1 driver.
//
// Protocol (Vezba 5):
// * command + operand1 are driven in the same cycle,
// * operand2 is driven in the next cycle (command line back to 0),
// * a response appears on out_respX a few (>=3) cycles later.
//
// Only one request may be outstanding per port, so after issuing a request the
// driver waits for that port's response before completing the item. This keeps
// the very simple "bidirectional, non-pipelined" use model from Vezba 6.
//-----------------------------------------------------------------------------
class calc_driver extends uvm_driver#(calc_seq_item);
`uvm_component_utils(calc_driver)
virtual interface calc_if vif;
function new(string name = "calc_driver", uvm_component parent = null);
super.new(name,parent);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if (!uvm_config_db#(virtual calc_if)::get(this, "", "calc_if", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"})
endfunction : connect_phase
task main_phase(uvm_phase phase);
// start from a known idle state and wait until reset is released
reset_inputs();
wait_reset_done();
forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_type_name(),
$sformatf("Driving: %s", req.convert2string()), UVM_HIGH)
drive_item(req);
seq_item_port.item_done();
end
endtask : main_phase
// Drive a single transaction following the two-cycle request protocol and
// wait for the corresponding response on the same port.
task drive_item(calc_seq_item it);
int unsigned wait_cnt;
// optional idle gap before the request
repeat (it.delay) @(posedge vif.clk);
// cycle 1: command + operand1
drive_req(it.port, it.cmd, it.op1);
@(posedge vif.clk);
// cycle 2: operand2, command de-asserted
drive_req(it.port, CMD_NOP, it.op2);
@(posedge vif.clk);
// idle the port again while the pipeline produces the result
drive_req(it.port, CMD_NOP, '0);
// wait for this port's response (resp != 0), bounded so a non-responding
// DUT cannot deadlock the test
wait_cnt = 0;
do begin
@(posedge vif.clk);
wait_cnt++;
end while (get_resp(it.port) === RESP_NONE && wait_cnt < RSP_TIMEOUT);
if (get_resp(it.port) === RESP_NONE)
`uvm_warning(get_type_name(),
$sformatf("No response on port %0d within %0d cycles (cmd=%s) - the scoreboard will flag this",
it.port+1, RSP_TIMEOUT, it.cmd2string()))
endtask : drive_item
// Drive command/data onto the selected port, leaving the others untouched.
task drive_req(bit [1:0] port, bit [CMD_WIDTH-1:0] cmd, bit [DATA_WIDTH-1:0] data);
case (port)
2'd0 : begin vif.req1_cmd_in <= cmd; vif.req1_data_in <= data; end
2'd1 : begin vif.req2_cmd_in <= cmd; vif.req2_data_in <= data; end
2'd2 : begin vif.req3_cmd_in <= cmd; vif.req3_data_in <= data; end
2'd3 : begin vif.req4_cmd_in <= cmd; vif.req4_data_in <= data; end
endcase
endtask : drive_req
// Combinational read of a port's response line.
function bit [RESP_WIDTH-1:0] get_resp(bit [1:0] port);
case (port)
2'd0 : return vif.out_resp1;
2'd1 : return vif.out_resp2;
2'd2 : return vif.out_resp3;
2'd3 : return vif.out_resp4;
endcase
endfunction
// Drive all request lines to their idle (zero) state.
task reset_inputs();
vif.req1_cmd_in <= '0; vif.req1_data_in <= '0;
vif.req2_cmd_in <= '0; vif.req2_data_in <= '0;
vif.req3_cmd_in <= '0; vif.req3_data_in <= '0;
vif.req4_cmd_in <= '0; vif.req4_data_in <= '0;
endtask : reset_inputs
task wait_reset_done();
// reset is active-high (all ones); wait until it is fully released
while (vif.rst !== '0) @(posedge vif.clk);
`uvm_info(get_type_name(), "Reset released - starting to drive", UVM_LOW)
endtask : wait_reset_done
endclass : calc_driver
`endif

View File

@@ -0,0 +1,206 @@
`ifndef CALC_MONITOR_SV
`define CALC_MONITOR_SV
//-----------------------------------------------------------------------------
// Calc1 monitor.
//
// Passive component. One collector thread per port reconstructs a transaction
// from the pin activity:
// * a request starts when reqX_cmd_in != 0 -> capture cmd and operand1,
// * operand2 is the data line on the following cycle,
// * the matching response is the first cycle in which out_respX != 0.
//
// The completed transaction (stimulus + observed response/result) is broadcast
// over the analysis port to the scoreboard, and functional coverage is sampled.
//-----------------------------------------------------------------------------
class calc_monitor extends uvm_monitor;
// control fields
bit checks_enable = 1;
bit coverage_enable = 1;
uvm_analysis_port #(calc_seq_item) item_collected_port;
`uvm_component_utils_begin(calc_monitor)
`uvm_field_int(checks_enable, UVM_DEFAULT)
`uvm_field_int(coverage_enable, UVM_DEFAULT)
`uvm_component_utils_end
// The virtual interface used to view HDL signals.
virtual interface calc_if vif;
// number of transactions collected (per port and total)
int unsigned num_collected;
//--------------------------------------------------------------------------
// Functional coverage model (Vezba 11).
//--------------------------------------------------------------------------
bit [CMD_WIDTH-1:0] cov_cmd;
bit [1:0] cov_port;
bit [RESP_WIDTH-1:0] cov_resp;
bit [DATA_WIDTH-1:0] cov_op1;
bit [DATA_WIDTH-1:0] cov_op2;
covergroup calc_cg;
option.per_instance = 1;
option.name = "calc_functional_coverage";
cp_cmd : coverpoint cov_cmd {
bins add = {CMD_ADD};
bins sub = {CMD_SUB};
bins shl = {CMD_SHL};
bins shr = {CMD_SHR};
bins invalid = {[4'h3:4'h4], 4'h7, [4'h8:4'hF]};
}
cp_port : coverpoint cov_port {
bins port1 = {2'd0};
bins port2 = {2'd1};
bins port3 = {2'd2};
bins port4 = {2'd3};
}
// the monitor only emits an item once a real response is seen, so only
// SUCCESS and ERROR are ever sampled here
cp_resp : coverpoint cov_resp {
bins success = {RESP_SUCCESS};
bins error = {RESP_ERROR};
}
// interesting operand corners
cp_op1 : coverpoint cov_op1 {
bins zero = {32'h0000_0000};
bins one = {32'h0000_0001};
bins max = {32'hFFFF_FFFF};
bins msb = {32'h8000_0000};
bins others = default;
}
cp_op2 : coverpoint cov_op2 {
bins zero = {32'h0000_0000};
bins one = {32'h0000_0001};
bins max = {32'hFFFF_FFFF};
bins shamt = {[32'h2:32'h1F]}; // small shift amounts
bins others = default;
}
// every legal command must be exercised on every port
cx_cmd_port : cross cp_cmd, cp_port;
// every command must be seen producing both success and error responses
cx_cmd_resp : cross cp_cmd, cp_resp;
endgroup
function new(string name = "calc_monitor", uvm_component parent = null);
super.new(name,parent);
item_collected_port = new("item_collected_port", this);
calc_cg = new();
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if (!uvm_config_db#(virtual calc_if)::get(this, "", "calc_if", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set:",get_full_name(),".vif"})
endfunction : connect_phase
task main_phase(uvm_phase phase);
wait_reset_done();
// launch one independent collector per port
for (int p = 0; p < NUM_PORTS; p++) begin
automatic int port = p;
fork
collect_port(port[1:0]);
join_none
end
endtask : main_phase
// Collect every request/response pair seen on a single port.
task collect_port(bit [1:0] port);
calc_seq_item it;
int unsigned wait_cnt;
forever begin
// wait for the start of a request on this port
do @(posedge vif.clk); while (get_cmd(port) === CMD_NOP || vif.rst !== '0);
it = calc_seq_item::type_id::create($sformatf("it_p%0d", port));
it.port = port;
it.cmd = get_cmd(port);
it.op1 = get_data(port);
// operand2 is presented on the next cycle
@(posedge vif.clk);
it.op2 = get_data(port);
// wait for the response on this port (bounded - a non-responding DUT
// is reported, not waited on forever); resp stays NONE on timeout so
// the scoreboard flags the missing response
wait_cnt = 0;
do begin
@(posedge vif.clk);
wait_cnt++;
end while (get_resp(port) === RESP_NONE && wait_cnt < RSP_TIMEOUT);
it.resp = get_resp(port);
it.result = get_out_data(port);
num_collected++;
`uvm_info(get_type_name(),
$sformatf("Collected: %s", it.convert2string()), UVM_MEDIUM)
if (coverage_enable) sample_coverage(it);
item_collected_port.write(it);
end
endtask : collect_port
function void sample_coverage(calc_seq_item it);
cov_cmd = it.cmd;
cov_port = it.port;
cov_resp = it.resp;
cov_op1 = it.op1;
cov_op2 = it.op2;
calc_cg.sample();
endfunction
//--- per-port signal accessors -------------------------------------------
function bit [CMD_WIDTH-1:0] get_cmd(bit [1:0] port);
case (port)
2'd0 : return vif.req1_cmd_in;
2'd1 : return vif.req2_cmd_in;
2'd2 : return vif.req3_cmd_in;
2'd3 : return vif.req4_cmd_in;
endcase
endfunction
function bit [DATA_WIDTH-1:0] get_data(bit [1:0] port);
case (port)
2'd0 : return vif.req1_data_in;
2'd1 : return vif.req2_data_in;
2'd2 : return vif.req3_data_in;
2'd3 : return vif.req4_data_in;
endcase
endfunction
function bit [RESP_WIDTH-1:0] get_resp(bit [1:0] port);
case (port)
2'd0 : return vif.out_resp1;
2'd1 : return vif.out_resp2;
2'd2 : return vif.out_resp3;
2'd3 : return vif.out_resp4;
endcase
endfunction
function bit [DATA_WIDTH-1:0] get_out_data(bit [1:0] port);
case (port)
2'd0 : return vif.out_data1;
2'd1 : return vif.out_data2;
2'd2 : return vif.out_data3;
2'd3 : return vif.out_data4;
endcase
endfunction
task wait_reset_done();
while (vif.rst !== '0) @(posedge vif.clk);
endtask : wait_reset_done
function void report_phase(uvm_phase phase);
`uvm_info(get_type_name(),
$sformatf("Monitor collected %0d transactions, functional coverage = %0.2f%%",
num_collected, calc_cg.get_coverage()), UVM_LOW)
endfunction : report_phase
endclass : calc_monitor
`endif

View File

@@ -0,0 +1,120 @@
`ifndef CALC_SEQ_ITEM_SV
`define CALC_SEQ_ITEM_SV
parameter DATA_WIDTH = 32;
parameter RESP_WIDTH = 2;
parameter CMD_WIDTH = 4;
parameter NUM_PORTS = 4;
// Max clock cycles to wait for a response before declaring the request lost.
// A correct Calc1 answers in a handful of cycles; the timeout only fires on a
// DUT that never responds, so the environment reports an error instead of
// hanging forever.
parameter RSP_TIMEOUT = 64;
//-----------------------------------------------------------------------------
// Calc1 command encoding (see Vezba 5, Tabela 6). All other 4-bit values are
// treated by the design as "invalid" commands.
//-----------------------------------------------------------------------------
typedef enum bit [CMD_WIDTH-1:0] {
CMD_NOP = 4'b0000, // no operation
CMD_ADD = 4'b0001, // result = op1 + op2
CMD_SUB = 4'b0010, // result = op1 - op2
CMD_SHL = 4'b0101, // result = op1 << op2[4:0]
CMD_SHR = 4'b0110 // result = op1 >> op2[4:0]
} calc_cmd_e;
//-----------------------------------------------------------------------------
// Calc1 response encoding (see Vezba 5, Tabela 8).
//-----------------------------------------------------------------------------
typedef enum bit [RESP_WIDTH-1:0] {
RESP_NONE = 2'b00, // no response this cycle
RESP_SUCCESS = 2'b01, // operation successful, data on out_dataX
RESP_ERROR = 2'b10 // overflow / underflow / invalid command
// 2'b11 is unused
} calc_resp_e;
//-----------------------------------------------------------------------------
// Sequence item / transaction.
// - Stimulus (rand) : port, cmd, op1, op2, delay
// - Observed (non-rand) : resp, result (filled in by the monitor)
//-----------------------------------------------------------------------------
class calc_seq_item extends uvm_sequence_item;
// --- stimulus fields ---------------------------------------------------
rand bit [1:0] port; // target port 0..3 (-> req1..req4)
rand bit [CMD_WIDTH-1:0] cmd; // raw 4-bit command (allows invalid)
rand bit [DATA_WIDTH-1:0] op1; // operand 1
rand bit [DATA_WIDTH-1:0] op2; // operand 2
rand int unsigned delay; // idle cycles before issuing the request
// --- observed fields (driven by the monitor) ---------------------------
bit [RESP_WIDTH-1:0] resp; // observed out_respX
bit [DATA_WIDTH-1:0] result; // observed out_dataX
// --- constraints --------------------------------------------------------
// A real request always carries a command; NOP would produce no response.
constraint c_no_nop { cmd != CMD_NOP; }
// By default favour the four legal commands, but keep a small probability
// of an illegal command so the random regression exercises that path too.
constraint c_cmd_dist {
cmd dist {
CMD_ADD := 25,
CMD_SUB := 25,
CMD_SHL := 20,
CMD_SHR := 20,
[4'h3:4'h4] :/ 5, // illegal
4'h7 :/ 5 // illegal
};
}
constraint c_delay { delay inside {[0:6]}; }
`uvm_object_utils_begin(calc_seq_item)
`uvm_field_int (port, UVM_DEFAULT)
`uvm_field_int (cmd, UVM_DEFAULT)
`uvm_field_int (op1, UVM_DEFAULT)
`uvm_field_int (op2, UVM_DEFAULT)
`uvm_field_int (delay, UVM_DEFAULT | UVM_DEC)
`uvm_field_int (resp, UVM_DEFAULT)
`uvm_field_int (result, UVM_DEFAULT)
`uvm_object_utils_end
function new (string name = "calc_seq_item");
super.new(name);
endfunction
// True when cmd is one of the four legal Calc1 commands.
function bit is_legal_cmd();
return (cmd inside {CMD_ADD, CMD_SUB, CMD_SHL, CMD_SHR});
endfunction
// Compact one-line description, handy in logs.
function string convert2string();
return $sformatf("port=%0d cmd=%s(0x%0h) op1=0x%08h op2=0x%08h -> resp=%s data=0x%08h",
port+1, cmd2string(), cmd, op1, op2, resp2string(), result);
endfunction
function string cmd2string();
case (cmd)
CMD_NOP : return "NOP";
CMD_ADD : return "ADD";
CMD_SUB : return "SUB";
CMD_SHL : return "SHL";
CMD_SHR : return "SHR";
default : return "INVALID";
endcase
endfunction
function string resp2string();
case (resp)
RESP_NONE : return "NONE";
RESP_SUCCESS : return "SUCCESS";
RESP_ERROR : return "ERROR";
default : return "RSVD";
endcase
endfunction
endclass : calc_seq_item
`endif

Some files were not shown because too many files have changed in this diff Show More