init
This commit is contained in:
BIN
code/Vezba 13 - prateci materijal/apb_uvc/docs/APB_UVC.pdf
Normal file
BIN
code/Vezba 13 - prateci materijal/apb_uvc/docs/APB_UVC.pdf
Normal file
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
|
||||
36
code/Vezba 13 - prateci materijal/apb_uvc/examples/dut.sv
Normal file
36
code/Vezba 13 - prateci materijal/apb_uvc/examples/dut.sv
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
29
code/Vezba 13 - prateci materijal/apb_uvc/sim/run.do
Normal file
29
code/Vezba 13 - prateci materijal/apb_uvc/sim/run.do
Normal 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
|
||||
|
||||
117
code/Vezba 13 - prateci materijal/apb_uvc/sv/apb_config.sv
Normal file
117
code/Vezba 13 - prateci materijal/apb_uvc/sv/apb_config.sv
Normal 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
|
||||
75
code/Vezba 13 - prateci materijal/apb_uvc/sv/apb_env.sv
Normal file
75
code/Vezba 13 - prateci materijal/apb_uvc/sv/apb_env.sv
Normal 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
|
||||
|
||||
48
code/Vezba 13 - prateci materijal/apb_uvc/sv/apb_if.sv
Normal file
48
code/Vezba 13 - prateci materijal/apb_uvc/sv/apb_if.sv
Normal 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
|
||||
83
code/Vezba 13 - prateci materijal/apb_uvc/sv/apb_pkg.sv
Normal file
83
code/Vezba 13 - prateci materijal/apb_uvc/sv/apb_pkg.sv
Normal 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
|
||||
@@ -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
|
||||
22
code/Vezba 13 - prateci materijal/apb_uvc/sv/apb_types.sv
Normal file
22
code/Vezba 13 - prateci materijal/apb_uvc/sv/apb_types.sv
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
BIN
code/Vezba 13 - prateci materijal/i2c_uvc/docs/I2C_UVC.pdf
Normal file
BIN
code/Vezba 13 - prateci materijal/i2c_uvc/docs/I2C_UVC.pdf
Normal file
Binary file not shown.
Binary file not shown.
30
code/Vezba 13 - prateci materijal/i2c_uvc/examples/dut.sv
Normal file
30
code/Vezba 13 - prateci materijal/i2c_uvc/examples/dut.sv
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
29
code/Vezba 13 - prateci materijal/i2c_uvc/sim/run.do
Normal file
29
code/Vezba 13 - prateci materijal/i2c_uvc/sim/run.do
Normal 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
|
||||
|
||||
88
code/Vezba 13 - prateci materijal/i2c_uvc/sv/i2c_config.sv
Normal file
88
code/Vezba 13 - prateci materijal/i2c_uvc/sv/i2c_config.sv
Normal 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
|
||||
70
code/Vezba 13 - prateci materijal/i2c_uvc/sv/i2c_env.sv
Normal file
70
code/Vezba 13 - prateci materijal/i2c_uvc/sv/i2c_env.sv
Normal 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
|
||||
|
||||
40
code/Vezba 13 - prateci materijal/i2c_uvc/sv/i2c_if.sv
Normal file
40
code/Vezba 13 - prateci materijal/i2c_uvc/sv/i2c_if.sv
Normal 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
|
||||
|
||||
208
code/Vezba 13 - prateci materijal/i2c_uvc/sv/i2c_monitor.sv
Normal file
208
code/Vezba 13 - prateci materijal/i2c_uvc/sv/i2c_monitor.sv
Normal 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
|
||||
|
||||
62
code/Vezba 13 - prateci materijal/i2c_uvc/sv/i2c_pkg.sv
Normal file
62
code/Vezba 13 - prateci materijal/i2c_uvc/sv/i2c_pkg.sv
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
26
code/Vezba 13 - prateci materijal/i2c_uvc/sv/i2c_types.sv
Normal file
26
code/Vezba 13 - prateci materijal/i2c_uvc/sv/i2c_types.sv
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
22
code/Vezba 13 - prateci materijal/reset_agent/sv/reset_if.sv
Normal file
22
code/Vezba 13 - prateci materijal/reset_agent/sv/reset_if.sv
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
56
code/v11_simple_coverage.sv
Normal file
56
code/v11_simple_coverage.sv
Normal 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
|
||||
100
code/v12_gotchas_examples.sv
Normal file
100
code/v12_gotchas_examples.sv
Normal 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
75
code/v3_fork_examples.sv
Normal 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
|
||||
5
code/vezba1/v1_build_file.f
Normal file
5
code/vezba1/v1_build_file.f
Normal file
@@ -0,0 +1,5 @@
|
||||
v1_counter.sv
|
||||
v1_simple_tb.sv
|
||||
-gui
|
||||
-access +rwc
|
||||
|
||||
26
code/vezba1/v1_counter.sv
Normal file
26
code/vezba1/v1_counter.sv
Normal 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
|
||||
47
code/vezba1/v1_simple_tb.sv
Normal file
47
code/vezba1/v1_simple_tb.sv
Normal 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
70
code/vezba10/Makefile
Normal 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
133
code/vezba10/README.md
Normal 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 5–11). 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
BIN
code/vezba10/calc_sim.wdb
Normal file
Binary file not shown.
36
code/vezba10/dut/alu_input_stage.v
Normal file
36
code/vezba10/dut/alu_input_stage.v
Normal 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
|
||||
47
code/vezba10/dut/alu_output_stage.v
Normal file
47
code/vezba10/dut/alu_output_stage.v
Normal 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
278
code/vezba10/dut/calc_top.v
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1279
code/vezba10/dut/exdbin_mac.v
Normal file
1279
code/vezba10/dut/exdbin_mac.v
Normal file
File diff suppressed because it is too large
Load Diff
56
code/vezba10/dut/holdreg.v
Normal file
56
code/vezba10/dut/holdreg.v
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
27
code/vezba10/dut/mux_out.v
Normal file
27
code/vezba10/dut/mux_out.v
Normal 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
155
code/vezba10/dut/priority.v
Normal 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
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
44
code/vezba10/run.do
Normal 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
40
code/vezba10/run_vivado.sh
Executable 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
7
code/vezba10/tr_db.log
Normal 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
33
code/vezba10/v10_run.f
Normal 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
33
code/vezba10/v9_run.f~
Normal 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
|
||||
47
code/vezba10/verif/Agent/calc_agent.sv
Normal file
47
code/vezba10/verif/Agent/calc_agent.sv
Normal 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
|
||||
25
code/vezba10/verif/Agent/calc_agent_pkg.sv
Normal file
25
code/vezba10/verif/Agent/calc_agent_pkg.sv
Normal 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
|
||||
|
||||
|
||||
|
||||
115
code/vezba10/verif/Agent/calc_driver.sv
Normal file
115
code/vezba10/verif/Agent/calc_driver.sv
Normal 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
|
||||
206
code/vezba10/verif/Agent/calc_monitor.sv
Normal file
206
code/vezba10/verif/Agent/calc_monitor.sv
Normal 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
|
||||
120
code/vezba10/verif/Agent/calc_seq_item.sv
Normal file
120
code/vezba10/verif/Agent/calc_seq_item.sv
Normal 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
Reference in New Issue
Block a user