//---------------------------------------------------------------------- // Copyright 2007-2010 Mentor Graphics Corporation // Copyright 2007-2011 Cadence Design Systems, Inc. // Copyright 2010 Synopsys, Inc. // All Rights Reserved Worldwide // // Licensed under the Apache License, Version 2.0 (the // "License"); you may not use this file except in // compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in // writing, software distributed under the License is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See // the License for the specific language governing // permissions and limitations under the License. //---------------------------------------------------------------------- //------------------------------------------------------------------------------ // // CLASS: ubus_slave_monitor // //------------------------------------------------------------------------------ class ubus_slave_monitor extends uvm_monitor; // This property is the virtual interface needed for this component to drive // and view HDL signals. protected virtual ubus_if vif; // The following two unsigned integer properties are used by // check_addr_range() method to detect if a transaction is for this target. protected int unsigned min_addr = 16'h0000; protected int unsigned max_addr = 16'hFFFF; // The following two bits are used to control whether checks and coverage are // done both in the monitor class and the interface. bit checks_enable = 1; bit coverage_enable = 1; uvm_analysis_port#(ubus_transfer) item_collected_port; uvm_blocking_peek_imp#(ubus_transfer,ubus_slave_monitor) addr_ph_imp; // The following property holds the transaction information currently // begin captured (by the collect_address_phase and data_phase methods). protected ubus_transfer trans_collected; // monitor notifier that the address phase (and full item) has been collected protected event address_phase_grabbed; // Events needed to trigger covergroups protected event cov_transaction; protected event cov_transaction_beat; // Fields to hold trans data and wait_state. No coverage of dynamic arrays. protected bit [15:0] addr; protected bit [7:0] data; protected int unsigned wait_state; // Transfer collected covergroup covergroup cov_trans; option.per_instance = 1; trans_start_addr : coverpoint trans_collected.addr { option.auto_bin_max = 16; } trans_dir : coverpoint trans_collected.read_write; trans_size : coverpoint trans_collected.size { bins sizes[] = {1, 2, 4, 8}; illegal_bins invalid_sizes = default; } trans_addrXdir : cross trans_start_addr, trans_dir; trans_dirXsize : cross trans_dir, trans_size; endgroup : cov_trans // Transfer collected data covergroup covergroup cov_trans_beat; option.per_instance = 1; beat_addr : coverpoint addr { option.auto_bin_max = 16; } beat_dir : coverpoint trans_collected.read_write; beat_data : coverpoint data { option.auto_bin_max = 8; } beat_wait : coverpoint wait_state { bins waits[] = { [0:9] }; bins others = { [10:$] }; } beat_addrXdir : cross beat_addr, beat_dir; beat_addrXdata : cross beat_addr, beat_data; endgroup : cov_trans_beat // Provide implementations of virtual methods such as get_type_name and create `uvm_component_utils_begin(ubus_slave_monitor) `uvm_field_int(min_addr, UVM_DEFAULT) `uvm_field_int(max_addr, UVM_DEFAULT) `uvm_field_int(checks_enable, UVM_DEFAULT) `uvm_field_int(coverage_enable, UVM_DEFAULT) `uvm_component_utils_end // new - constructor function new(string name, uvm_component parent=null); super.new(name, parent); cov_trans = new(); cov_trans.set_inst_name({get_full_name(), ".cov_trans"}); cov_trans_beat = new(); cov_trans_beat.set_inst_name({get_full_name(), ".cov_trans_beat"}); trans_collected = new(); item_collected_port = new("item_collected_port", this); addr_ph_imp = new("addr_ph_imp", this); endfunction : new function void build_phase(uvm_phase phase); if(!uvm_config_db#(virtual ubus_if)::get(this, "", "vif", vif)) `uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"}); endfunction: build_phase // set the monitor's address range function void set_addr_range(bit [15:0] min_addr, bit [15:0] max_addr); this.min_addr = min_addr; this.max_addr = max_addr; endfunction : set_addr_range // get the monitor's min addr function bit [15:0] get_min_addr(); return min_addr; endfunction : get_min_addr // get the monitor's max addr function bit [15:0] get_max_addr(); return max_addr; endfunction : get_max_addr // run phase virtual task run_phase(uvm_phase phase); fork collect_transactions(); join endtask : run_phase // collect_transactions virtual protected task collect_transactions(); bit range_check; forever begin if (m_parent != null) trans_collected.slave = m_parent.get_name(); collect_address_phase(); range_check = check_addr_range(); if (range_check) begin void'(this.begin_tr(trans_collected)); -> address_phase_grabbed; collect_data_phase(); `uvm_info(get_type_name(), $sformatf("Transfer collected :\n%s", trans_collected.sprint()), UVM_FULL) if (checks_enable) perform_transfer_checks(); if (coverage_enable) perform_transfer_coverage(); item_collected_port.write(trans_collected); end end endtask : collect_transactions // check_addr_range virtual protected function bit check_addr_range(); if ((trans_collected.addr >= min_addr) && (trans_collected.addr <= max_addr)) begin return 1; end return 0; endfunction : check_addr_range // collect_address_phase virtual protected task collect_address_phase(); @(posedge vif.sig_clock iff ( (vif.sig_read === 1) || (vif.sig_write === 1) ) ); trans_collected.addr = vif.sig_addr; case (vif.sig_size) 2'b00 : trans_collected.size = 1; 2'b01 : trans_collected.size = 2; 2'b10 : trans_collected.size = 4; 2'b11 : trans_collected.size = 8; endcase trans_collected.data = new[trans_collected.size]; case ({vif.sig_read,vif.sig_write}) 2'b00 : trans_collected.read_write = NOP; 2'b10 : trans_collected.read_write = READ; 2'b01 : trans_collected.read_write = WRITE; endcase endtask : collect_address_phase // collect_data_phase virtual protected task collect_data_phase(); if (trans_collected.read_write != NOP) begin for (int i = 0; i < trans_collected.size; i++) begin @(posedge vif.sig_clock iff vif.sig_wait === 0); trans_collected.data[i] = vif.sig_data; end end this.end_tr(trans_collected); endtask : collect_data_phase // perform_transfer_checks protected function void perform_transfer_checks(); check_transfer_size(); check_transfer_data_size(); endfunction : perform_transfer_checks // check_transfer_size protected function void check_transfer_size(); assert_transfer_size : assert(trans_collected.size == 1 || trans_collected.size == 2 || trans_collected.size == 4 || trans_collected.size == 8) else begin `uvm_error(get_type_name(), "Invalid transfer size!") end endfunction : check_transfer_size // check_transfer_data_size protected function void check_transfer_data_size(); if (trans_collected.size != trans_collected.data.size()) `uvm_error(get_type_name(), "Transfer size field / data size mismatch.") endfunction : check_transfer_data_size // perform_transfer_coverage protected function void perform_transfer_coverage(); cov_trans.sample(); for (int unsigned i = 0; i < trans_collected.size; i++) begin addr = trans_collected.addr + i; data = trans_collected.data[i]; //Wait state inforamtion is not currently monitored. // wait_state = trans_collected.wait_state[i]; cov_trans_beat.sample(); end endfunction : perform_transfer_coverage task peek(output ubus_transfer trans); @address_phase_grabbed; trans = trans_collected; endtask : peek virtual function void report_phase(uvm_phase phase); `uvm_info(get_full_name(),$sformatf("Covergroup 'cov_trans' coverage: %2f", cov_trans.get_inst_coverage()),UVM_LOW) endfunction endclass : ubus_slave_monitor