|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | class spi_monitor extends dv_base_monitor#( | 
|  | .ITEM_T (spi_item), | 
|  | .CFG_T  (spi_agent_cfg), | 
|  | .COV_T  (spi_agent_cov) | 
|  | ); | 
|  | `uvm_component_utils(spi_monitor) | 
|  |  | 
|  | spi_item host_item; | 
|  | spi_item device_item; | 
|  |  | 
|  | // Analysis port for the collected transfer. | 
|  | uvm_analysis_port #(spi_item) host_analysis_port; | 
|  | uvm_analysis_port #(spi_item) device_analysis_port; | 
|  |  | 
|  | `uvm_component_new | 
|  |  | 
|  | function void build_phase(uvm_phase phase); | 
|  | super.build_phase(phase); | 
|  | host_analysis_port   = new("host_analysis_port", this); | 
|  | device_analysis_port = new("device_analysis_port", this); | 
|  | endfunction | 
|  |  | 
|  | virtual task run_phase(uvm_phase phase); | 
|  | collect_trans(phase); | 
|  | endtask | 
|  |  | 
|  | // collect transactions forever | 
|  | virtual protected task collect_trans(uvm_phase phase); | 
|  | host_item   = spi_item::type_id::create("host_item", this); | 
|  | device_item = spi_item::type_id::create("device_item", this); | 
|  |  | 
|  | forever begin | 
|  | @(negedge cfg.vif.csb); | 
|  | collect_curr_trans(); | 
|  | end | 
|  | endtask : collect_trans | 
|  |  | 
|  | virtual protected task collect_curr_trans(); | 
|  | fork | 
|  | begin: isolation_thread | 
|  | fork | 
|  | begin: csb_deassert_thread | 
|  | wait(cfg.vif.csb[0] == 1'b1); | 
|  | end | 
|  | begin: sample_thread | 
|  | // for mode 1 and 3, get the leading edges out of the way | 
|  | cfg.wait_sck_edge(LeadingEdge); | 
|  | forever begin | 
|  | bit [7:0] host_byte;    // from sio | 
|  | bit [7:0] device_byte;  // from sio | 
|  | int       which_bit; | 
|  | for (int i = 0; i < 8; i++) begin | 
|  | // wait for the sampling edge | 
|  | cfg.wait_sck_edge(SamplingEdge); | 
|  | // check sio not x or z | 
|  | if (cfg.en_monitor_checks) begin | 
|  | `DV_CHECK_CASE_NE(cfg.vif.sio[1:0], 2'bxx) | 
|  | `DV_CHECK_CASE_NE(cfg.vif.sio[1:0], 2'bxx) | 
|  | end | 
|  | // sample sio[0] for tx | 
|  | which_bit = cfg.host_bit_dir ? i : 7 - i; | 
|  | host_byte[which_bit] = cfg.vif.sio[0]; | 
|  | cfg.vif.host_bit  = which_bit; | 
|  | cfg.vif.host_byte = host_byte; | 
|  | // sample sio[1] for rx | 
|  | which_bit = cfg.device_bit_dir ? i : 7 - i; | 
|  | device_byte[which_bit] = cfg.vif.sio[1]; | 
|  | cfg.vif.device_bit = which_bit; | 
|  | cfg.vif.device_byte = device_byte; | 
|  | end | 
|  | host_item.data.push_back(host_byte); | 
|  | device_item.data.push_back(device_byte); | 
|  |  | 
|  | // sending transactions when collect a word data | 
|  | if (host_item.data.size == cfg.num_bytes_per_trans_in_mon && | 
|  | device_item.data.size == cfg.num_bytes_per_trans_in_mon) begin | 
|  | `uvm_info(`gfn, $sformatf("spi_monitor: host packet:\n%0s", host_item.sprint()), | 
|  | UVM_HIGH) | 
|  | `uvm_info(`gfn, $sformatf("spi_monitor: device packet:\n%0s", device_item.sprint()), | 
|  | UVM_HIGH) | 
|  | host_analysis_port.write(host_item); | 
|  | device_analysis_port.write(device_item); | 
|  | host_item   = spi_item::type_id::create("host_item", this); | 
|  | device_item = spi_item::type_id::create("device_item", this); | 
|  | end | 
|  | end // forever | 
|  | end: sample_thread | 
|  | join_any | 
|  | disable fork; | 
|  | end | 
|  | join | 
|  | endtask : collect_curr_trans | 
|  |  | 
|  | virtual task monitor_ready_to_end(); | 
|  | forever begin | 
|  | @(cfg.vif.csb); | 
|  | ok_to_end = !cfg.vif.csb; | 
|  | end | 
|  | endtask : monitor_ready_to_end | 
|  |  | 
|  | endclass : spi_monitor |