Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aon timer v3 dv changes #25559

Merged
merged 5 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions hw/ip/aon_timer/dv/env/aon_timer_env.core
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ filesets:
depend:
- lowrisc:dv:ralgen
- lowrisc:dv:cip_lib
- lowrisc:dv:usbdev_env
files:
- aon_timer_env_pkg.sv
- aon_timer_env_cfg.sv: {is_include_file: true}
- aon_timer_env_cov.sv: {is_include_file: true}
- aon_timer_virtual_sequencer.sv: {is_include_file: true}
- aon_timer_intr_timed_regs.sv: {is_include_file: true}
- aon_timer_scoreboard.sv: {is_include_file: true}
- aon_timer_env.sv: {is_include_file: true}
- seq_lib/aon_timer_vseq_list.sv: {is_include_file: true}
Expand Down
52 changes: 52 additions & 0 deletions hw/ip/aon_timer/dv/env/aon_timer_env_cfg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,27 @@ class aon_timer_env_cfg extends cip_base_env_cfg #(.RAL_T(aon_timer_reg_block));
virtual pins_if #(1) sleep_vif;

// ext component cfgs
string path_to_rtl = "tb.dut";

`uvm_object_utils_begin(aon_timer_env_cfg)
`uvm_object_utils_end

extern function new (string name="");
extern virtual function void initialize(bit [31:0] csr_base_addr = '1);
// Set the 'has_prediction' field flag for all the intr_state fields so the comparison
// on reads can be carried out in cip_base_scoreboard
extern function void set_intr_state_has_prediction();
rswarbrick marked this conversation as resolved.
Show resolved Hide resolved

// Convenience wrapper function to avoid calling explictly uvm_hdl_read multiple times
// It takes a path relative to the RTL and appends the RTL instance to it
extern function bit hdl_read_bit(string path);
// Waits for AON signal to become 'value'
extern task wait_for_aon_signal(string path, bit value);
// Waits for the WE to rise and fall after a TL-UL write access
// Does HDL reads to be in sync with when the values are visible in the RTL
// It needs to be called the moment the TL-access occurs, otherwise the thread may hang if the WE
// has risen and dropped again already
extern task wait_for_we_pulse(input string path);

endclass : aon_timer_env_cfg

Expand All @@ -31,4 +46,41 @@ function void aon_timer_env_cfg::initialize(bit [31:0] csr_base_addr = '1);

// set num_interrupts & num_alerts
num_interrupts = ral.intr_state.get_n_used_bits();
set_intr_state_has_prediction();
endfunction : initialize

function bit aon_timer_env_cfg::hdl_read_bit(string path);
bit hdl_bit;
if (! uvm_hdl_read({path_to_rtl,path}, hdl_bit))
`uvm_error ($sformatf("%m"), $sformatf("HDL Read from %s failed", path))
return hdl_bit;
endfunction

task aon_timer_env_cfg::wait_for_aon_signal(string path, bit value);
bit actual_value;
do begin
actual_value = hdl_read_bit(path);
if (actual_value !== value)
aon_clk_rst_vif.wait_clks(1);
end while (actual_value !== value);
endtask

task aon_timer_env_cfg::wait_for_we_pulse(input string path);
wait_for_aon_signal(path, 1);
wait_for_aon_signal(path, 0);
endtask

function void aon_timer_env_cfg::set_intr_state_has_prediction();
foreach (ral_model_names[i]) begin
dv_base_reg regs_q[$];
ral_models[ral_model_names[i]].get_dv_base_regs(regs_q);
foreach (regs_q[j]) begin
if (!uvm_re_match("intr_state*", regs_q[j].get_name())) begin
dv_base_reg_field fields_q[$];
regs_q[j].get_dv_base_reg_fields(fields_q);
foreach (fields_q[k])// Setting all fields to be compared in the base scoreboard
fields_q[k].has_prediction = 1;
end
end
end
endfunction
3 changes: 2 additions & 1 deletion hw/ip/aon_timer/dv/env/aon_timer_env_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ package aon_timer_env_pkg;
import dv_base_reg_pkg::*;
import csr_utils_pkg::*;
import aon_timer_ral_pkg::*;

import usbdev_env_pkg::*;
// macro includes
`include "uvm_macros.svh"
`include "dv_macros.svh"
Expand All @@ -31,6 +31,7 @@ package aon_timer_env_pkg;
`include "aon_timer_env_cfg.sv"
`include "aon_timer_env_cov.sv"
`include "aon_timer_virtual_sequencer.sv"
`include "aon_timer_intr_timed_regs.sv"
`include "aon_timer_scoreboard.sv"
`include "aon_timer_env.sv"
`include "aon_timer_vseq_list.sv"
Expand Down
96 changes: 96 additions & 0 deletions hw/ip/aon_timer/dv/env/aon_timer_intr_timed_regs.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

// `Timed registers` cannot be guaranteed to change at an exact time, so a certain amount of
// variability must be expected in the timing.
class aon_timer_intr_timed_regs extends uvm_object;
`uvm_object_utils(aon_timer_intr_timed_regs)

extern function new (string name="");

typedef enum {
TimedIntrStateWkupExpired = 0,
TimedIntrStateWdogBark
} timed_reg_e;

// Access to DUT clock.
virtual clk_rst_if clk_rst_vif;
// Access to DUT registers.
aon_timer_reg_block ral;

timed_reg timed[timed_reg_e];

// Monotonic, wrapping cycle count; used to detect when expectations have not been met.
antmarzam marked this conversation as resolved.
Show resolved Hide resolved
// Incremented in 'check_predictions' task
int time_now = 0;

// Perform a read of the actual DUT register state, for checking against expectations.
// Note: we perform a backdoor read to avoid impacting the timing of the DUT and DV.
extern task read_act_data(timed_reg_e r, output uvm_reg_data_t act_data);
// Add a timed, predicted state change to the list of expectations for the given register.
extern function void predict(timed_reg_e r, uvm_reg_data_t prev_data, uvm_reg_data_t new_data);
// Check a DUT read from the specified register against any timed expectations.
rswarbrick marked this conversation as resolved.
Show resolved Hide resolved
extern function uvm_reg_data_t read(timed_reg_e r, uvm_reg_data_t act_data);
// This process runs forever checking every prediction that is made, using backdoor csr_rd in zero
// time to avoid interfering with actual CSR reads and the timing of the simulation.
// It also resets the registers if a reset is seen.
extern task check_predictions(ref bit under_reset);

endclass : aon_timer_intr_timed_regs

function aon_timer_intr_timed_regs::new (string name="");
super.new(name);
endfunction : new

task aon_timer_intr_timed_regs::read_act_data(timed_reg_e r, output uvm_reg_data_t act_data);
case (r)
TimedIntrStateWkupExpired : begin
csr_rd(.ptr(ral.intr_state.wkup_timer_expired), .value(act_data), .backdoor(1));
end
TimedIntrStateWdogBark : begin
csr_rd(.ptr(ral.intr_state.wdog_timer_bark), .value(act_data), .backdoor(1));
end
default: `uvm_fatal(`gfn, "Invalid/unrecognized register")
endcase
`uvm_info(`gfn, $sformatf("Backdoor read of reg %p yielded 0x%0x", r, act_data), UVM_HIGH)
endtask : read_act_data

function void aon_timer_intr_timed_regs::predict(timed_reg_e r, uvm_reg_data_t prev_data,
uvm_reg_data_t new_data);
`uvm_info(`gfn, $sformatf("Expecting reg %p <= 0x%0x, from 0x%0x (mask 0x%0x), time_now %0d",
r, new_data, prev_data, prev_data ^ new_data, time_now), UVM_MEDIUM)
antmarzam marked this conversation as resolved.
Show resolved Hide resolved
timed[r].predict(time_now, new_data, prev_data);
endfunction : predict

function uvm_reg_data_t aon_timer_intr_timed_regs::read(timed_reg_e r, uvm_reg_data_t act_data);
`uvm_info(`gfn, $sformatf("Producing prediction for %p, act_data 0x%0x", r, act_data),
UVM_MEDIUM)
return timed[r].read(time_now, act_data);
endfunction : read

task aon_timer_intr_timed_regs::check_predictions(ref bit under_reset);
antmarzam marked this conversation as resolved.
Show resolved Hide resolved
// Collect the initial values post-reset.
wait (clk_rst_vif.rst_n === 1'b1);
forever begin
timed_reg_e r;
// Check on every negedge to avoid races with CSR changes
@(negedge clk_rst_vif.clk);
time_now++;
// Check each of the timed registers for expired expectations.
r = r.first();
for (int i=0; i < r.num(); i++) begin
rswarbrick marked this conversation as resolved.
Show resolved Hide resolved
if (under_reset) begin
`uvm_info(`gfn, $sformatf("Resetting timed register predictions at 0x%0x", time_now),
UVM_MEDIUM)
timed[r].reset();
end else if (timed[r].preds_pending()) begin
uvm_reg_data_t act_data;
// Something is expected to happen to this register field.
read_act_data(r, act_data);
timed[r].check_pred(time_now, $sformatf("%p", r), act_data);
end
r = r.next();
end // for (int i=0; i < r.num(); i++)
end
endtask : check_predictions
Loading
Loading