blob: 407fd3b709ddbf6f48bfeaee0c767418028ed98f [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
class pwm_monitor extends dv_base_monitor #(
.ITEM_T (pwm_item),
.CFG_T (pwm_monitor_cfg)
);
`uvm_component_utils(pwm_monitor)
`uvm_component_new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// get config
if (!uvm_config_db#(pwm_monitor_cfg)::get(this, "", "cfg", cfg)) begin
`uvm_fatal(`gfn, $sformatf("failed to get cfg from uvm_config_db"))
end
// get interface
if (!uvm_config_db#(virtual pwm_if)::get(this, "", "vif", cfg.vif)) begin
`uvm_fatal(`gfn, $sformatf("failed to get vif handle from uvm_config_db"))
end
endfunction
// collect transactions forever - already forked in dv_base_monitor::run_phase
virtual protected task collect_trans(uvm_phase phase);
uint count_cycles, active_cycles;
logic pwm_prev = 0;
wait(cfg.vif.rst_n);
forever begin
if (!cfg.active) begin
wait (cfg.active);
count_cycles = 0;
active_cycles = 0;
end
@(cfg.vif.cb);
count_cycles++;
if (cfg.vif.cb.pwm != pwm_prev) begin
`uvm_info(`gfn, $sformatf("Detected edge: %0b->%0b at %0d cycles (from last edge)",
pwm_prev, cfg.vif.cb.pwm, count_cycles), UVM_HIGH)
pwm_prev = cfg.vif.cb.pwm;
if (cfg.vif.cb.pwm == cfg.invert) begin
// We got to the first (active) half duty cycle point. Save the count and restart.
active_cycles = count_cycles;
end else begin
uint phase_count;
pwm_item item = pwm_item::type_id::create("item");
item.invert = cfg.invert;
item.monitor_id = cfg.monitor_id;
item.active_cnt = active_cycles;
item.inactive_cnt = count_cycles;
item.period = count_cycles + active_cycles;
item.duty_cycle = item.get_duty_cycle();
// Each PWM pulse cycle is divided into 2^DC_RESN+1 beats, per beat the 16-bit
// phase counter increments by 2^(16-DC_RESN-1)(modulo 65536)
phase_count = ((item.period / (2 ** (cfg.resolution + 1))) *
(2 ** (16 - (cfg.resolution - 1))));
item.phase = (phase_count % 65536);
analysis_port.write(item);
end
count_cycles = 0;
end
end
endtask
// update of_to_end to prevent sim finished when there is any activity on the bus
// ok_to_end = 0 (bus busy) / 1 (bus idle)
virtual task monitor_ready_to_end();
forever begin
@(cfg.vif.cb)
ok_to_end = ~cfg.active;
end
endtask
endclass