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