init
This commit is contained in:
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
|
||||
|
||||
Reference in New Issue
Block a user