| // 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 |