Skip to content

Commit

Permalink
[dv, aon_timer] Adding CDC-aware intr_state register
Browse files Browse the repository at this point in the history
In order to improve the model, the TB needs to keep track of the
backdoor value of intr_state fields, otherwise there are mismatches.
The CDC-timed registers from USBDEV have been re-used
for this pupose.

Signed-off-by: Antonio Martinez Zambrana <[email protected]>
  • Loading branch information
antmarzam committed Dec 9, 2024
1 parent c1ede0f commit 88e4825
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 0 deletions.
3 changes: 3 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,14 @@ filesets:
depend:
- lowrisc:dv:ralgen
- lowrisc:dv:cip_lib
- lowrisc:ip:usbdev
- 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
2 changes: 2 additions & 0 deletions hw/ip/aon_timer/dv/env/aon_timer_env_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ package aon_timer_env_pkg;
`include "aon_timer_env_cfg.sv"
`include "aon_timer_env_cov.sv"
`include "aon_timer_virtual_sequencer.sv"
`include "timed_reg.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
100 changes: 100 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,100 @@
// 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)

// `uvm_object_new
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.
int time_now = 0;

extern task read_act_data(timed_reg_e r, output uvm_reg_data_t act_data);
extern function void predict(timed_reg_e r, uvm_reg_data_t prev_data, uvm_reg_data_t new_data);
extern function uvm_reg_data_t read(timed_reg_e r, uvm_reg_data_t act_data);
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

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

// Add a timed, predicted state change to the list of expectations for the given register.
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 0x%0x",
r, new_data, prev_data, prev_data ^ new_data, time_now), UVM_MEDIUM)
`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)
timed[r].predict(time_now, new_data, prev_data);
endfunction : predict

// Check a DUT read from the specified register against any timed expectations.
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

// This process checks 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.
task aon_timer_intr_timed_regs::check_predictions(ref bit under_reset);
// Collect the initial values post-reset.
wait (clk_rst_vif.rst_n === 1'b1);
forever begin
timed_reg_e r;
// The checker cannot afford to wait a cycle for the prediction because the CSR change may
// occur within the current cycle.
@(negedge clk_rst_vif.clk);
time_now++;
// Check each of the timed registers for expired expectations.
r = r.first();
forever begin
if (under_reset) begin
`uvm_info(`gfn, $sformatf("Resetting timed register predictions at 0x%0x", time_now),
UVM_LOW)
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
if (r == r.last()) break;
r = r.next();
end
end
endtask : check_predictions

0 comments on commit 88e4825

Please sign in to comment.