| // 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 uvm_monitor; |
| `uvm_component_utils(spi_monitor) |
| |
| spi_agent_cfg cfg; |
| 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); |
| phase.raise_objection(this); |
| if (cfg.en_monitor_collect_trans) collect_curr_trans(); |
| phase.drop_objection(this); |
| end |
| endtask |
| |
| virtual protected task collect_curr_trans(); |
| // for mode 1 and 3, get the leading edges out of the way |
| cfg.wait_sck_edge(LeadingEdge); |
| |
| fork |
| begin: isolation_thread |
| fork |
| begin: csb_deassert_thread |
| wait(cfg.vif.csb == 1'b1); |
| end |
| forever begin: sample_thread |
| logic [7:0] host_byte; // from mosi |
| logic [7:0] device_byte; // from miso |
| int which_bit; |
| for (int i = 0; i < 8; i++) begin |
| // wait for the sampling edge |
| cfg.wait_sck_edge(SamplingEdge); |
| // check mosi/miso not x or z |
| if (cfg.en_monitor_checks) begin |
| `DV_CHECK_CASE_NE(cfg.vif.mosi, 1'bx) |
| `DV_CHECK_CASE_NE(cfg.vif.mosi, 1'bz) |
| `DV_CHECK_CASE_NE(cfg.vif.miso, 1'bx) |
| `DV_CHECK_CASE_NE(cfg.vif.miso, 1'bz) |
| end |
| // sample mosi |
| which_bit = cfg.host_bit_dir ? i : 7 - i; |
| host_byte[which_bit] = cfg.vif.mosi; |
| cfg.vif.host_bit = which_bit; |
| cfg.vif.host_byte = host_byte; |
| // sample miso |
| which_bit = cfg.device_bit_dir ? i : 7 - i; |
| device_byte[which_bit] = cfg.vif.miso; |
| 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 |
| join_any |
| disable fork; |
| end |
| join |
| endtask |
| |
| endclass |