From 88e4825f3b99d82e9a1350b35a1a59d6e9eeac1f Mon Sep 17 00:00:00 2001 From: Antonio Martinez Zambrana Date: Mon, 9 Dec 2024 18:52:45 +0000 Subject: [PATCH] [dv, aon_timer] Adding CDC-aware intr_state register 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 --- hw/ip/aon_timer/dv/env/aon_timer_env.core | 3 + hw/ip/aon_timer/dv/env/aon_timer_env_pkg.sv | 2 + .../dv/env/aon_timer_intr_timed_regs.sv | 100 ++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 hw/ip/aon_timer/dv/env/aon_timer_intr_timed_regs.sv diff --git a/hw/ip/aon_timer/dv/env/aon_timer_env.core b/hw/ip/aon_timer/dv/env/aon_timer_env.core index 84b2fe4219cef0..9c212b012543ea 100644 --- a/hw/ip/aon_timer/dv/env/aon_timer_env.core +++ b/hw/ip/aon_timer/dv/env/aon_timer_env.core @@ -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} diff --git a/hw/ip/aon_timer/dv/env/aon_timer_env_pkg.sv b/hw/ip/aon_timer/dv/env/aon_timer_env_pkg.sv index dd7f14f70cf9b1..11f1978a6fd562 100644 --- a/hw/ip/aon_timer/dv/env/aon_timer_env_pkg.sv +++ b/hw/ip/aon_timer/dv/env/aon_timer_env_pkg.sv @@ -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" diff --git a/hw/ip/aon_timer/dv/env/aon_timer_intr_timed_regs.sv b/hw/ip/aon_timer/dv/env/aon_timer_intr_timed_regs.sv new file mode 100644 index 00000000000000..e224791564c362 --- /dev/null +++ b/hw/ip/aon_timer/dv/env/aon_timer_intr_timed_regs.sv @@ -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