| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| class spi_agent_cfg extends dv_base_agent_cfg; |
| |
| // agent cfg knobs |
| bit is_active = 1'b1; // active driver or passive monitor |
| bit en_cov = 1'b1; // enable coverage |
| bit en_monitor_collect_trans = 1'b1; // enable monitor to collect trans on-the-fly |
| bit en_monitor_checks = 1'b1; // enable checkers in monitor |
| if_mode_e mode; // host or device mode |
| |
| // host mode cfg knobs |
| time sck_period_ps = 50_000; // 20MHz |
| bit sck_polarity; // aka CPOL |
| bit sck_phase; // aka CPHA |
| bit host_bit_dir; // 1 - lsb -> msb, 0 - msb -> lsb |
| bit device_bit_dir; // 1 - lsb -> msb, 0 - msb -> lsb |
| bit sck_on; // keep sck on |
| // how many bytes monitor samples per transaction |
| int num_bytes_per_trans_in_mon = 4; |
| |
| // enable randomly injecting extra delay between 2 sck/word |
| bit en_extra_dly_btw_sck; |
| uint max_extra_dly_ns_btw_sck = 100; // small delay to avoid transfer timeout |
| uint extra_dly_chance_pc_btw_sck = 5; // percentage of extra delay btw each spi clock edge |
| // Note: can't handle word delay, if a word is splitted into multiple csb. |
| // In that case, control delay in seq level |
| bit en_extra_dly_btw_word; |
| uint max_extra_dly_ns_btw_word = 1000; // no timeout btw word |
| uint extra_dly_chance_pc_btw_word = 5; // percentage of extra delay btw each word |
| |
| // interface handle used by driver, monitor & the sequencer |
| virtual spi_if vif; |
| |
| `uvm_object_utils_begin(spi_agent_cfg) |
| `uvm_field_int (is_active, UVM_DEFAULT) |
| `uvm_field_int (en_cov, UVM_DEFAULT) |
| `uvm_field_enum(if_mode_e, mode, UVM_DEFAULT) |
| `uvm_field_int (sck_period_ps, UVM_DEFAULT) |
| `uvm_field_int (sck_polarity, UVM_DEFAULT) |
| `uvm_field_int (sck_phase, UVM_DEFAULT) |
| `uvm_field_int (host_bit_dir, UVM_DEFAULT) |
| `uvm_field_int (device_bit_dir, UVM_DEFAULT) |
| `uvm_field_int (en_extra_dly_btw_sck, UVM_DEFAULT) |
| `uvm_field_int (max_extra_dly_ns_btw_sck, UVM_DEFAULT) |
| `uvm_field_int (extra_dly_chance_pc_btw_sck, UVM_DEFAULT) |
| `uvm_field_int (en_extra_dly_btw_word, UVM_DEFAULT) |
| `uvm_field_int (max_extra_dly_ns_btw_word, UVM_DEFAULT) |
| `uvm_field_int (extra_dly_chance_pc_btw_word, UVM_DEFAULT) |
| `uvm_object_utils_end |
| |
| `uvm_object_new |
| |
| virtual task wait_sck_edge(sck_edge_type_e sck_edge_type); |
| bit [1:0] sck_mode = {sck_polarity, sck_phase}; |
| bit wait_posedge; |
| |
| // sck polarity slk_phase mode |
| // 0 0 0: sample at leading podedge (drive @ prev negedge) |
| // 1 0 2: sample at leading negedge (drive @ prev posedge) |
| // 0 1 1: sample at trailing negedge (drive @ curr posedge) |
| // 1 1 3: sample at trailing posedge (drive @ curr negedge) |
| case (sck_edge_type) |
| LeadingEdge: begin |
| // wait for leading edge applies to mode 1 and 3 only |
| if (sck_mode inside {2'b00, 2'b10}) return; |
| if (sck_mode == 2'b01) wait_posedge = 1'b1; |
| end |
| DrivingEdge: wait_posedge = (sck_mode inside {2'b01, 2'b10}); |
| SamplingEdge: wait_posedge = (sck_mode inside {2'b00, 2'b11}); |
| endcase |
| |
| if (wait_posedge) @(posedge vif.sck); |
| else @(negedge vif.sck); |
| endtask |
| |
| endclass |