diff --git a/hw/ip/adc_ctrl/dv/env/adc_ctrl_env.core b/hw/ip/adc_ctrl/dv/env/adc_ctrl_env.core index 42b9294cc2daf..5006379187250 100644 --- a/hw/ip/adc_ctrl/dv/env/adc_ctrl_env.core +++ b/hw/ip/adc_ctrl/dv/env/adc_ctrl_env.core @@ -21,7 +21,7 @@ filesets: - seq_lib/adc_ctrl_base_vseq.sv: {is_include_file: true} - seq_lib/adc_ctrl_common_vseq.sv: {is_include_file: true} - seq_lib/adc_ctrl_smoke_vseq.sv: {is_include_file: true} - - seq_lib/adc_ctrl_random_ramp_vseq.sv: {is_include_file: true} + - seq_lib/adc_ctrl_channel_ramp_vseq.sv: {is_include_file: true} - seq_lib/adc_ctrl_filters_polled_vseq.sv: {is_include_file: true} - seq_lib/adc_ctrl_filters_interrupt_vseq.sv: {is_include_file: true} - seq_lib/adc_ctrl_filters_wakeup_vseq.sv: {is_include_file: true} diff --git a/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_channel_ramp_vseq.sv b/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_channel_ramp_vseq.sv new file mode 100644 index 0000000000000..c6843eb38df79 --- /dev/null +++ b/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_channel_ramp_vseq.sv @@ -0,0 +1,83 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// A ramp virtual sequence that controls an ADC channel, ramping between two values. This is a +// virtual sequence because it works entirely by controlling an existing push_pull sequence through +// a config object. + +class adc_ctrl_channel_ramp_vseq extends uvm_sequence; + // A config object for the push/pull agent through which we will control the ADC channel + adc_push_pull_config_t push_pull_cfg; + // An event that the environment will trigger when a push/pull item is received on this channel. + event push_pull_ev; + + // Start value of the ramp + rand adc_value_t ramp_start; + // End value of the ramp + rand adc_value_t ramp_end; + // Minimum ramp step + rand int unsigned ramp_step_min; + // Maximum ramp step + rand int unsigned ramp_step_max; + + // Constrain the ramp start and end values to be less than (1 << ADC_CTRL_DATA_WIDTH). Constrain + // the range of step sizes (ensuring that they are bounded above by ramp_step_max, which means + // we're unlikely to jump the whole way in one go). + extern constraint ramp_constraints_c; + + extern function new(string name=""); + extern task body(); + extern task send_adc_data(adc_value_t value); + + `uvm_object_utils_begin(adc_ctrl_channel_ramp_vseq) + `uvm_field_int(ramp_start, UVM_DEFAULT | UVM_DEC) + `uvm_field_int(ramp_end, UVM_DEFAULT | UVM_DEC) + `uvm_field_int(ramp_step_min, UVM_DEFAULT | UVM_DEC) + `uvm_field_int(ramp_step_max, UVM_DEFAULT | UVM_DEC) + `uvm_object_utils_end +endclass + +constraint adc_ctrl_channel_ramp_vseq::ramp_constraints_c { + ramp_start < (1 << ADC_CTRL_DATA_WIDTH); + ramp_end < (1 << ADC_CTRL_DATA_WIDTH); + + 1 <= ramp_step_max; + ramp_step_min <= ramp_step_max; +} + +function adc_ctrl_channel_ramp_vseq::new(string name=""); + super.new(name); +endfunction + +task adc_ctrl_channel_ramp_vseq::body(); + // Current value for the channel (starts at the starting value) + adc_value_t current_value = ramp_start; + + // Send the starting value through the push/pull agent + send_adc_data(current_value); + + // Increment/decrement the ADC channel data until we get to the end value + while (current_value != ramp_end) begin + // Pick a random ramp step size in [ramp_step_min:ramp_step_max]. + int unsigned ramp_step = $urandom_range(ramp_step_min, ramp_step_max); + + // Update the current value of the ramp accordingly, clamping to ramp_end + if (current_value < ramp_end) begin + current_value += min2(ramp_step, ramp_end - current_value); + end else begin + current_value -= min2(ramp_step, current_value - ramp_end); + end + + // Send next data via ADC bus + send_adc_data(current_value); + end +endtask + +task adc_ctrl_channel_ramp_vseq::send_adc_data(adc_value_t value); + push_pull_cfg.clear_d_user_data(); + push_pull_cfg.add_d_user_data(value); + + // Wait to be told that data was received (via the scoreboard) + @push_pull_ev; +endtask diff --git a/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_filters_polled_vseq.sv b/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_filters_polled_vseq.sv index 9b6cbf7a5c091..13dc77b293ad7 100644 --- a/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_filters_polled_vseq.sv +++ b/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_filters_polled_vseq.sv @@ -9,7 +9,9 @@ class adc_ctrl_filters_polled_vseq extends adc_ctrl_base_vseq; constraint num_trans_c {num_trans inside {[1 : 3]};} - `uvm_object_new + function new (string name=""); + super.new(name); + endfunction virtual task pre_start(); super.pre_start(); @@ -25,86 +27,95 @@ class adc_ctrl_filters_polled_vseq extends adc_ctrl_base_vseq; disable check_adc_ctrl_status; endtask - virtual task body(); - uvm_reg_data_t rdata; - adc_ctrl_random_ramp_vseq random_ramp_vseq; - - repeat (num_trans) begin - - // Make sure ADC is off - csr_wr(ral.adc_en_ctl, 'h0); - - // Set up the adc_ctrl registers - configure_adc_ctrl(); - - // Clear interrupt status reg - csr_wr(ral.adc_intr_status, '1); - - // Check interrupt status is cleared - csr_rd_check(.ptr(ral.adc_intr_status), .compare_value(0), - .err_msg(called_from(`__FILE__, `__LINE__))); - - // Start ADC - ral.adc_en_ctl.adc_enable.set(1); - case (cfg.testmode) - AdcCtrlTestmodeOneShot: begin - ral.adc_en_ctl.oneshot_mode.set(1); - ral.adc_pd_ctl.lp_mode.set(0); - end - AdcCtrlTestmodeNormal: begin - ral.adc_en_ctl.oneshot_mode.set(0); - ral.adc_pd_ctl.lp_mode.set(0); - end - AdcCtrlTestmodeLowpower: begin - ral.adc_en_ctl.oneshot_mode.set(0); - ral.adc_pd_ctl.lp_mode.set(1); - end - default: `uvm_fatal(`gfn, "Undefined test mode") - endcase - csr_wr(ral.adc_pd_ctl, ral.adc_pd_ctl.get()); - csr_wr(ral.adc_en_ctl, ral.adc_en_ctl.get()); - - // Hook to do things immediately after the adc_ctrl is enabled - post_adc_ctrl_enable(); - - // Send randomized ramp on all channels - rising - `uvm_create_obj(adc_ctrl_random_ramp_vseq, random_ramp_vseq) - random_ramp_vseq.set_sequencer(p_sequencer); - // verilog_format: off - avoid bad formatting - `DV_CHECK_RANDOMIZE_WITH_FATAL(random_ramp_vseq, - ramp_min == 0; - ramp_max == adc_value_t'('1); - ramp_step_min == 0; - ramp_step_max == 5; - ramp_rising == 1;) - // verilog_format: on - random_ramp_vseq.start(p_sequencer, this); - `uvm_info(`gfn, random_ramp_vseq.sprint(uvm_default_line_printer), UVM_MEDIUM) - - // Send randomized ramp on all channels - falling - `uvm_create_obj(adc_ctrl_random_ramp_vseq, random_ramp_vseq) - random_ramp_vseq.set_sequencer(p_sequencer); - // verilog_format: off - avoid bad formatting - `DV_CHECK_RANDOMIZE_WITH_FATAL(random_ramp_vseq, - ramp_min == 0; - ramp_max == adc_value_t'('1); - ramp_step_min == 0; - ramp_step_max == 5; - ramp_rising == 0;) - // verilog_format: on - random_ramp_vseq.start(p_sequencer, this); - `uvm_info(`gfn, random_ramp_vseq.sprint(uvm_default_line_printer), UVM_MEDIUM) - // Now turn off ADC_CTRL - adc_ctrl_off(); - - // FSM reset to synchronise RTL & model - do_adc_fsm_reset(); - - // Re-randomize configuration if enabled - if (!cfg.filters_fixed) `DV_CHECK_RANDOMIZE_FATAL(cfg) + // Run a randomised vseq to ramp channel from start_value to end_value + // + // The increments each time will be randomised in the range [0, 20], so we can expect the ramp to + // take abs(end_value - start_value) / 25 steps on average. + local task ramp_channel(int unsigned channel, adc_value_t start_value, adc_value_t end_value); + adc_ctrl_channel_ramp_vseq vseq = adc_ctrl_channel_ramp_vseq::type_id::create("vseq"); + vseq.push_pull_cfg = cfg.m_adc_push_pull_cfg[channel]; + vseq.push_pull_ev = cfg.m_adc_push_pull_ev[channel]; + if (!vseq.randomize() with { + vseq.ramp_start == start_value; + vseq.ramp_end == end_value; + vseq.ramp_step_min == 0; + vseq.ramp_step_max == 50; + }) begin + `uvm_fatal(`gfn, "Failed to randomise ramp vseq") + end + vseq.start(null); + endtask + + // Ramp all channels in parallel from start_value to end_value + local task ramp_channels(adc_value_t start_value, adc_value_t end_value); + fork begin : isolation_fork + for (int i = 0; i < ADC_CTRL_CHANNELS; i++) begin + automatic int i_ = i; + fork ramp_channel(i_, start_value, end_value); join_none + end + wait fork; + end join + endtask + + task run_iteration(); + // Make sure ADC is off + csr_wr(ral.adc_en_ctl, 'h0); + + // Set up the adc_ctrl registers + configure_adc_ctrl(); + + // Clear interrupt status reg + csr_wr(ral.adc_intr_status, '1); + + // Check interrupt status is cleared + csr_rd_check(.ptr(ral.adc_intr_status), .compare_value(0), + .err_msg(called_from(`__FILE__, `__LINE__))); + + // Start ADC + ral.adc_en_ctl.adc_enable.set(1); + case (cfg.testmode) + AdcCtrlTestmodeOneShot: begin + ral.adc_en_ctl.oneshot_mode.set(1); + ral.adc_pd_ctl.lp_mode.set(0); + end + AdcCtrlTestmodeNormal: begin + ral.adc_en_ctl.oneshot_mode.set(0); + ral.adc_pd_ctl.lp_mode.set(0); + end + AdcCtrlTestmodeLowpower: begin + ral.adc_en_ctl.oneshot_mode.set(0); + ral.adc_pd_ctl.lp_mode.set(1); + end + default: `uvm_fatal(`gfn, "Undefined test mode") + endcase + csr_wr(ral.adc_pd_ctl, ral.adc_pd_ctl.get()); + csr_wr(ral.adc_en_ctl, ral.adc_en_ctl.get()); + + // Hook to do things immediately after the adc_ctrl is enabled + post_adc_ctrl_enable(); + + // Send randomized ramp on all channels - rising + ramp_channels(0, adc_value_t'('1)); + + // Send randomized ramp on all channels - falling + ramp_channels(adc_value_t'('1), 0); + + // Now turn off ADC_CTRL + adc_ctrl_off(); + + // FSM reset to synchronise RTL & model + do_adc_fsm_reset(); + endtask + + task body(); + for(int unsigned i = 1; i <= num_trans; i++) begin + // Re-randomize configuration if enabled and this is after the first iteration + if (i > 1 && !cfg.filters_fixed) `DV_CHECK_RANDOMIZE_FATAL(cfg) + + run_iteration(); end // A short delay to allow all CDC to complete - cfg.clk_aon_rst_vif.wait_clks($urandom_range(10, 15)); + cfg.clk_aon_rst_vif.wait_clks(10); endtask : body // Check the status registers after every ADC sample (all channels) @@ -126,5 +137,4 @@ class adc_ctrl_filters_polled_vseq extends adc_ctrl_base_vseq; // Hook to do things immediately after the adc_ctrl is enabled virtual task post_adc_ctrl_enable(); endtask - endclass : adc_ctrl_filters_polled_vseq diff --git a/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_random_ramp_vseq.sv b/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_random_ramp_vseq.sv deleted file mode 100644 index 57a6dc5cee5be..0000000000000 --- a/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_random_ramp_vseq.sv +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright lowRISC contributors (OpenTitan project). -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -// Send a random ramp to each of the ADC channels -class adc_ctrl_random_ramp_vseq extends adc_ctrl_base_vseq; - - // Minimum value of the ramp - rand int ramp_min; - // Maximum value of the ramp - rand int ramp_max; - // Direction 1=rising 0=falling - rand bit ramp_rising; - // Minimum ramp step - rand int ramp_step_min; - // Maximum ramp step - rand int ramp_step_max; - - - // Current values for the channels - adc_value_t current_values[ADC_CTRL_CHANNELS]; - // Next values for the channels - adc_value_t next_values[ADC_CTRL_CHANNELS]; - // Increment/decrement value for this step - int ramp_step[ADC_CTRL_CHANNELS]; - - `uvm_object_utils_begin(adc_ctrl_random_ramp_vseq) - `uvm_field_int(ramp_min, UVM_DEFAULT | UVM_DEC) - `uvm_field_int(ramp_max, UVM_DEFAULT | UVM_DEC) - `uvm_field_int(ramp_rising, UVM_DEFAULT | UVM_DEC) - `uvm_field_int(ramp_step_min, UVM_DEFAULT | UVM_DEC) - `uvm_field_int(ramp_step_max, UVM_DEFAULT | UVM_DEC) - `uvm_field_sarray_int(current_values, UVM_DEFAULT | UVM_DEC) - `uvm_field_sarray_int(next_values, UVM_DEFAULT | UVM_DEC) - `uvm_field_sarray_int(ramp_step, UVM_DEFAULT | UVM_DEC) - `uvm_object_utils_end - - `uvm_object_new - - // Check for valid inputs - constraint valid_c { - ramp_step_min inside {[0 : $]}; - ramp_step_max inside {[1 : $]}; - ramp_step_max >= ramp_step_min; - ramp_min inside {[0 : (1 << ADC_CTRL_DATA_WIDTH) - 1]}; - ramp_max inside {[0 : (1 << ADC_CTRL_DATA_WIDTH) - 1]}; - ramp_max >= ramp_min; - } - - virtual task pre_start(); - do_adc_ctrl_init = 0; - do_dut_init = 0; - super.pre_start(); - endtask - - virtual task body(); - bit all_ended; - - // Set current values set to starting value - foreach (current_values[channel]) current_values[channel] = ramp_rising ? ramp_min : ramp_max; - - // Send via push pull agents - send_adc_data(current_values); - `uvm_info(`gfn, this.sprint(uvm_default_line_printer), UVM_MEDIUM) - - // Increment or decrement the ADC channel data until - // we reach the end values for all channels - while(current_values.or() with - (ramp_rising ? (int'(item) < ramp_max) : (int'(item) > ramp_min))) begin - - `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(ramp_step, - foreach(ramp_step[channel]) { - ramp_step[channel] inside {[ramp_step_min : ramp_step_max]}; - }) - - foreach (next_values[channel]) begin - if (ramp_rising) begin - next_values[channel] = - min2((int'(current_values[channel]) + ramp_step[channel]), ramp_max); - end else begin - next_values[channel] = - max2((int'(current_values[channel]) - ramp_step[channel]), ramp_min); - end - end - - `uvm_info(`gfn, this.sprint(uvm_default_line_printer), UVM_MEDIUM) - - // Send next data via ADC bus - send_adc_data(next_values); - - // Copy next values to current values - foreach (current_values[channel]) current_values[channel] = next_values[channel]; - - end - - endtask - - task send_adc_data(adc_value_t data[ADC_CTRL_CHANNELS]); - `uvm_info(`gfn, $sformatf("send_adc_data: data=%p", data), UVM_MEDIUM) - - foreach (data[channel]) begin - cfg.m_adc_push_pull_cfg[channel].clear_d_user_data(); - cfg.m_adc_push_pull_cfg[channel].add_d_user_data(data[channel]); - end - - // Wait for data to be received by the scoreboard - wait_all_rx(); - - endtask - -endclass diff --git a/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_vseq_list.sv b/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_vseq_list.sv index 8e66c657cd9c7..9ec738ed74298 100644 --- a/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_vseq_list.sv +++ b/hw/ip/adc_ctrl/dv/env/seq_lib/adc_ctrl_vseq_list.sv @@ -5,7 +5,7 @@ `include "adc_ctrl_base_vseq.sv" `include "adc_ctrl_smoke_vseq.sv" `include "adc_ctrl_common_vseq.sv" -`include "adc_ctrl_random_ramp_vseq.sv" +`include "adc_ctrl_channel_ramp_vseq.sv" `include "adc_ctrl_filters_polled_vseq.sv" `include "adc_ctrl_filters_interrupt_vseq.sv" `include "adc_ctrl_filters_wakeup_vseq.sv"