From c59e1ac55f4491127abc85bf6c2066f2af6c2d67 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 13:57:37 +0000 Subject: [PATCH 01/16] [pattgen,dv] Use extern definitions in pattgen_env_cfg No functional change, but this adds some documentation comments and also sets list_of_alerts a bit earlier (in the constructor instead of initialize()). Signed-off-by: Rupert Swarbrick --- hw/ip/pattgen/dv/env/pattgen_env_cfg.sv | 38 ++++++++++++++----------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/hw/ip/pattgen/dv/env/pattgen_env_cfg.sv b/hw/ip/pattgen/dv/env/pattgen_env_cfg.sv index c38e77c636199..5d42c0a0e6fc7 100644 --- a/hw/ip/pattgen/dv/env/pattgen_env_cfg.sv +++ b/hw/ip/pattgen/dv/env/pattgen_env_cfg.sv @@ -3,33 +3,39 @@ // SPDX-License-Identifier: Apache-2.0 class pattgen_env_cfg extends cip_base_env_cfg #(.RAL_T(pattgen_reg_block)); - // drained time of phase_ready_to_end + // Drain time of phase_ready_to_end uint ok_to_end_delay_ns = 8000; - // pattgen_agent_cfg + // Configuration for the pattgen agent (stored in the environment as m_pattgen_agent). rand pattgen_agent_cfg m_pattgen_agent_cfg; - // seq cfg + // Configuration that applies to the virtual sequences that run in the environment pattgen_seq_cfg seq_cfg; + extern function new (string name=""); + + // Implements a function from dv_base_env_cfg. The base class version creates RAL models. This + // extension uses the type of the RAL model to set num_interrupts. + extern virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); + `uvm_object_utils_begin(pattgen_env_cfg) `uvm_field_object(m_pattgen_agent_cfg, UVM_DEFAULT) `uvm_object_utils_end +endclass + +function pattgen_env_cfg::new (string name=""); + super.new(name); - `uvm_object_new + list_of_alerts = pattgen_env_pkg::LIST_OF_ALERTS; - virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); - list_of_alerts = pattgen_env_pkg::LIST_OF_ALERTS; - super.initialize(csr_base_addr); + m_pattgen_agent_cfg = pattgen_agent_cfg::type_id::create("m_pattgen_agent_cfg"); + m_pattgen_agent_cfg.if_mode = Device; // setup agent in Device mode - // create pattgen_agent_cfg - m_pattgen_agent_cfg = pattgen_agent_cfg::type_id::create("m_pattgen_agent_cfg"); - m_pattgen_agent_cfg.if_mode = Device; // setup agent in Device mode + seq_cfg = pattgen_seq_cfg::type_id::create("seq_cfg"); +endfunction - // create the seq_cfg - seq_cfg = pattgen_seq_cfg::type_id::create("seq_cfg"); +function void pattgen_env_cfg::initialize(bit [TL_AW-1:0] csr_base_addr = '1); + super.initialize(csr_base_addr); - // set num_interrupts & num_alerts - num_interrupts = ral.intr_state.get_n_used_bits(); - endfunction -endclass : pattgen_env_cfg + num_interrupts = ral.intr_state.get_n_used_bits(); +endfunction From 0159232fd29eb5fba6fd4ffdacb4967bbb4b1825 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 14:48:22 +0000 Subject: [PATCH 02/16] [pattgen,dv] Move num_runs to pattgen_stress_all_vseq The variable is only used in the stress sequence, so it probably makes more sense to define it there, instead of the base vseq. Signed-off-by: Rupert Swarbrick --- hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv | 5 ----- hw/ip/pattgen/dv/env/seq_lib/pattgen_stress_all_vseq.sv | 6 ++++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index 9a15f965daa94..a2310be1a00dd 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -26,7 +26,6 @@ class pattgen_base_vseq extends cip_base_vseq #( bit [NUM_PATTGEN_CHANNELS-1:0] channel_grant = 'h1; // random variables - rand uint num_runs; rand uint b2b_pattern_dly; rand uint clear_intr_dly; // if start_all_channels bit is set: both channels can start simmultaneously @@ -37,9 +36,6 @@ class pattgen_base_vseq extends cip_base_vseq #( constraint num_trans_c { num_trans inside {[cfg.seq_cfg.pattgen_min_num_trans : cfg.seq_cfg.pattgen_max_num_trans]}; } - constraint num_runs_c { - num_runs inside {[cfg.seq_cfg.pattgen_min_num_runs : cfg.seq_cfg.pattgen_max_num_runs]}; - } constraint start_all_channels_c { start_all_channels dist { 1'b1 :/ cfg.seq_cfg.pattgen_sync_channels_pct, @@ -63,7 +59,6 @@ class pattgen_base_vseq extends cip_base_vseq #( cfg.m_pattgen_agent_cfg.en_monitor = cfg.en_scb; `uvm_info(`gfn, $sformatf("\n--> %s monitor and scoreboard", cfg.en_scb ? "enable" : "disable"), UVM_DEBUG) - num_runs.rand_mode(0); // env_cfg must be reset after vseq completion cfg.seq_cfg.error_injected_enb = 1'b0; cfg.seq_cfg.pattgen_min_prediv = 0; diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_stress_all_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_stress_all_vseq.sv index f2154289a7733..942be75354679 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_stress_all_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_stress_all_vseq.sv @@ -13,6 +13,12 @@ class pattgen_stress_all_vseq extends pattgen_base_vseq; local string str, seq_name; local int seq_run_hist[string]; + local rand int unsigned num_runs; + + constraint num_runs_c { + num_runs inside {[cfg.seq_cfg.pattgen_min_num_runs : cfg.seq_cfg.pattgen_max_num_runs]}; + } + string seq_names[] = { "pattgen_common_vseq", // for intr_test "pattgen_smoke_vseq", From 214b406687e975eefbde5c42ef106bea16846ddb Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 15:07:08 +0000 Subject: [PATCH 03/16] [pattgen,dv] Tidy up how some sequence delays get configured Signed-off-by: Rupert Swarbrick --- hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv | 4 --- .../dv/env/seq_lib/pattgen_base_vseq.sv | 30 +++++++++---------- .../env/seq_lib/pattgen_cnt_rollover_vseq.sv | 10 +++---- .../dv/env/seq_lib/pattgen_perf_vseq.sv | 10 +++---- 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv b/hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv index e7e1bfacd1d43..076a7479ff28a 100644 --- a/hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv +++ b/hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv @@ -16,10 +16,6 @@ class pattgen_seq_cfg extends uvm_object; uint pattgen_min_num_runs = 1; uint pattgen_max_num_runs = 5; - // knobs for pattgen channel - uint pattgen_min_dly = 0; - uint pattgen_max_dly = 5; - // see the specification document, the effective values of prediv, len, and reps // are incremented from the coresponding register values diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index a2310be1a00dd..27915d07f188f 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -25,13 +25,13 @@ class pattgen_base_vseq extends cip_base_vseq #( // this vector is initialized to 1 (the channel 0 is granted by default) bit [NUM_PATTGEN_CHANNELS-1:0] channel_grant = 'h1; - // random variables - rand uint b2b_pattern_dly; - rand uint clear_intr_dly; // if start_all_channels bit is set: both channels can start simmultaneously rand bit start_all_channels; rand bit do_error_injected; + // A constraint for the gaps between items in the sequence of pattgen commands + int unsigned pattgen_max_dly = 5; + // constraints constraint num_trans_c { num_trans inside {[cfg.seq_cfg.pattgen_min_num_trans : cfg.seq_cfg.pattgen_max_num_trans]}; @@ -48,12 +48,6 @@ class pattgen_base_vseq extends cip_base_vseq #( 1'b0:/ (100 - cfg.seq_cfg.error_injected_pct) }; } - constraint b2b_pattern_dly_c { - b2b_pattern_dly inside {[cfg.seq_cfg.pattgen_min_dly : cfg.seq_cfg.pattgen_max_dly]}; - } - constraint clear_intr_dly_c { - clear_intr_dly inside {[cfg.seq_cfg.pattgen_min_dly : cfg.seq_cfg.pattgen_max_dly]}; - } virtual task pre_start(); cfg.m_pattgen_agent_cfg.en_monitor = cfg.en_scb; @@ -143,6 +137,15 @@ class pattgen_base_vseq extends cip_base_vseq #( end endtask : setup_pattgen_channel_1 + // Wait a short time (up to pattgen_max_dly) + // + // Completes early on reset. + local task short_delay(); + int unsigned dly; + `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(dly, dly inside {[0:pattgen_max_dly]};) + cfg.clk_rst_vif.wait_clks_or_rst(dly); + endtask + virtual task start_pattgen_channels(); if (num_pattern_req < num_trans) begin `DV_CHECK_MEMBER_RANDOMIZE_FATAL(start_all_channels) @@ -151,8 +154,7 @@ class pattgen_base_vseq extends cip_base_vseq #( // once start_all_channels is set, temporaly disable its randomization to sync all channels start_all_channels.rand_mode(0); if (channel_setup[0] && !channel_start[0] && channel_setup[1] && !channel_start[1]) begin - `DV_CHECK_MEMBER_RANDOMIZE_FATAL(b2b_pattern_dly) - cfg.clk_rst_vif.wait_clks(b2b_pattern_dly); + short_delay(); control_channels(AllChannels, Enable); {channel_start[0], channel_start[1]} = {1'b1, 1'b1}; `uvm_info(`gfn, "\n all channels: activated", UVM_DEBUG) @@ -165,8 +167,7 @@ class pattgen_base_vseq extends cip_base_vseq #( if (channel_setup[i] && !channel_start[i]) begin channel_select_e ch_select; `downcast(ch_select, i+1) - `DV_CHECK_MEMBER_RANDOMIZE_FATAL(b2b_pattern_dly) - cfg.clk_rst_vif.wait_clks(b2b_pattern_dly); + short_delay(); control_channels(ch_select, Enable); channel_start[i]= 1'b1; `uvm_info(`gfn, $sformatf("\n channel %0d: activated", i), UVM_DEBUG) @@ -334,8 +335,7 @@ class pattgen_base_vseq extends cip_base_vseq #( AllChannels: intr_clear = (1 << DoneCh1) | (1 << DoneCh0); default: `uvm_fatal(`gfn, " invalid argument") endcase - `DV_CHECK_MEMBER_RANDOMIZE_FATAL(clear_intr_dly) - cfg.clk_rst_vif.wait_clks(clear_intr_dly); + short_delay(); csr_wr(.ptr(ral.intr_state), .value(intr_clear)); end else begin `uvm_info(`gfn, $sformatf("\n channel error, no clear interrupts %b", intr_clear), UVM_DEBUG) diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_cnt_rollover_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_cnt_rollover_vseq.sv index 4579092625786..8f2aa211a9560 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_cnt_rollover_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_cnt_rollover_vseq.sv @@ -5,14 +5,14 @@ // Count rollover test vseq class pattgen_cnt_rollover_vseq extends pattgen_base_vseq; `uvm_object_utils(pattgen_cnt_rollover_vseq) - `uvm_object_new // reduce num_trans due to long running simulations constraint num_trans_c { num_trans inside {[2 : 3]}; } - // fast clear interrupt - constraint clear_intr_dly_c { clear_intr_dly == 0; } - // fast stop/start channel - constraint b2b_pattern_dly_c { b2b_pattern_dly == 0; } + + function new (string name=""); + super.new(name); + pattgen_max_dly = 0; + endfunction // override this function for pattgen_cnt_rollover test function pattgen_channel_cfg get_random_channel_config(uint channel); diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv index 8149a1d240394..4682e66fa1218 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv @@ -5,14 +5,14 @@ // basic perf test vseq class pattgen_perf_vseq extends pattgen_base_vseq; `uvm_object_utils(pattgen_perf_vseq) - `uvm_object_new // reduce num_trans due to long running simulations constraint num_trans_c { num_trans inside {[3:6]}; } - // fast clear interrupt - constraint clear_intr_dly_c { clear_intr_dly == 0; } - // fast stop/start channel - constraint b2b_pattern_dly_c { b2b_pattern_dly == 0; } + + function new (string name=""); + super.new(name); + pattgen_max_dly = 0; + endfunction // override this function for pattgen_perf test function pattgen_channel_cfg get_random_channel_config(uint channel); From a813dedfbd56ed4d4fdb67fe3affde15b1f1c2ae Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 15:12:53 +0000 Subject: [PATCH 04/16] [pattgen,dv] Simplify how channels get started This is just getting rid of a class variable. Signed-off-by: Rupert Swarbrick --- .../dv/env/seq_lib/pattgen_base_vseq.sv | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index 27915d07f188f..acab773f8c830 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -25,8 +25,6 @@ class pattgen_base_vseq extends cip_base_vseq #( // this vector is initialized to 1 (the channel 0 is granted by default) bit [NUM_PATTGEN_CHANNELS-1:0] channel_grant = 'h1; - // if start_all_channels bit is set: both channels can start simmultaneously - rand bit start_all_channels; rand bit do_error_injected; // A constraint for the gaps between items in the sequence of pattgen commands @@ -36,12 +34,6 @@ class pattgen_base_vseq extends cip_base_vseq #( constraint num_trans_c { num_trans inside {[cfg.seq_cfg.pattgen_min_num_trans : cfg.seq_cfg.pattgen_max_num_trans]}; } - constraint start_all_channels_c { - start_all_channels dist { - 1'b1 :/ cfg.seq_cfg.pattgen_sync_channels_pct, - 1'b0 :/ (100 - cfg.seq_cfg.pattgen_sync_channels_pct) - }; - } constraint do_error_injected_c { do_error_injected dist { 1'b1:/ cfg.seq_cfg.error_injected_pct, @@ -148,18 +140,14 @@ class pattgen_base_vseq extends cip_base_vseq #( virtual task start_pattgen_channels(); if (num_pattern_req < num_trans) begin - `DV_CHECK_MEMBER_RANDOMIZE_FATAL(start_all_channels) - // if start_all_channels is set, then activate both channels if they are setup and not busy - if (start_all_channels) begin - // once start_all_channels is set, temporaly disable its randomization to sync all channels - start_all_channels.rand_mode(0); + if ($urandom_range(0, 99) < cfg.seq_cfg.pattgen_sync_channels_pct) begin + // For some percentage of the time, we start all the channels at the same instant (ensuring + // that they stay in sync) if (channel_setup[0] && !channel_start[0] && channel_setup[1] && !channel_start[1]) begin short_delay(); control_channels(AllChannels, Enable); {channel_start[0], channel_start[1]} = {1'b1, 1'b1}; `uvm_info(`gfn, "\n all channels: activated", UVM_DEBUG) - // re-enable start_all_channels's randomization after all channels have been started - start_all_channels.rand_mode(1); end end else begin // otherwise, activate channels independently From 3b15362f3ffdca574394abdbc03eeaa4d043fc3a Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 15:18:46 +0000 Subject: [PATCH 05/16] [pattgen,dv] Simplify how we control if errors are injected Signed-off-by: Rupert Swarbrick --- hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index acab773f8c830..c112db77cea09 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -25,8 +25,6 @@ class pattgen_base_vseq extends cip_base_vseq #( // this vector is initialized to 1 (the channel 0 is granted by default) bit [NUM_PATTGEN_CHANNELS-1:0] channel_grant = 'h1; - rand bit do_error_injected; - // A constraint for the gaps between items in the sequence of pattgen commands int unsigned pattgen_max_dly = 5; @@ -34,13 +32,6 @@ class pattgen_base_vseq extends cip_base_vseq #( constraint num_trans_c { num_trans inside {[cfg.seq_cfg.pattgen_min_num_trans : cfg.seq_cfg.pattgen_max_num_trans]}; } - constraint do_error_injected_c { - do_error_injected dist { - 1'b1:/ cfg.seq_cfg.error_injected_pct, - 1'b0:/ (100 - cfg.seq_cfg.error_injected_pct) - }; - } - virtual task pre_start(); cfg.m_pattgen_agent_cfg.en_monitor = cfg.en_scb; `uvm_info(`gfn, $sformatf("\n--> %s monitor and scoreboard", @@ -189,8 +180,7 @@ class pattgen_base_vseq extends cip_base_vseq #( // 11 (CH1) 00 11 CH0 error injected CH1 error injected* channel_stop = intr_status; // default setting if (cfg.seq_cfg.error_injected_enb) begin - `DV_CHECK_MEMBER_RANDOMIZE_FATAL(do_error_injected) - if (do_error_injected) begin + if ($urandom_range(0, 99) < cfg.seq_cfg.error_injected_pct) begin if (intr_status != channel_start) begin channel_stop = channel_start; error_injected = 1'b1; From 09d7d69cf5a53fa9ab1c4bcc45ff0b7acc3bf95a Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 15:27:39 +0000 Subject: [PATCH 06/16] [pattgen,dv] Move error_injected_enb from cfg object to sequence Signed-off-by: Rupert Swarbrick --- hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv | 1 - hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv | 6 ++++-- hw/ip/pattgen/dv/env/seq_lib/pattgen_error_vseq.sv | 7 +++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv b/hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv index 076a7479ff28a..133cccb7f2e04 100644 --- a/hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv +++ b/hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv @@ -30,7 +30,6 @@ class pattgen_seq_cfg extends uvm_object; uint pattgen_sync_channels_pct = 30; // in percentage // for error_vseq - bit error_injected_enb = 1'b0; uint error_injected_pct = 10; // in percentage uint data_top_pct = 10; uint data_bottom_pct = 80; diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index c112db77cea09..e8d7a5d16f82e 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -28,6 +28,9 @@ class pattgen_base_vseq extends cip_base_vseq #( // A constraint for the gaps between items in the sequence of pattgen commands int unsigned pattgen_max_dly = 5; + // If this true then the sequence might inject errors in stop_pattgen_channels. + bit error_injected_enb = 1'b0; + // constraints constraint num_trans_c { num_trans inside {[cfg.seq_cfg.pattgen_min_num_trans : cfg.seq_cfg.pattgen_max_num_trans]}; @@ -37,7 +40,6 @@ class pattgen_base_vseq extends cip_base_vseq #( `uvm_info(`gfn, $sformatf("\n--> %s monitor and scoreboard", cfg.en_scb ? "enable" : "disable"), UVM_DEBUG) // env_cfg must be reset after vseq completion - cfg.seq_cfg.error_injected_enb = 1'b0; cfg.seq_cfg.pattgen_min_prediv = 0; cfg.seq_cfg.pattgen_min_len = 0; cfg.seq_cfg.pattgen_min_reps = 0; @@ -179,7 +181,7 @@ class pattgen_base_vseq extends cip_base_vseq #( // 11 (CH1) 11 11 CH0 finished CH1 finished // 11 (CH1) 00 11 CH0 error injected CH1 error injected* channel_stop = intr_status; // default setting - if (cfg.seq_cfg.error_injected_enb) begin + if (error_injected_enb) begin if ($urandom_range(0, 99) < cfg.seq_cfg.error_injected_pct) begin if (intr_status != channel_start) begin channel_stop = channel_start; diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_error_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_error_vseq.sv index c50dce97a391f..fa524692962cb 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_error_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_error_vseq.sv @@ -8,11 +8,14 @@ // must be detected and dropped in scoreboard and agent_monitor class pattgen_error_vseq extends pattgen_base_vseq; `uvm_object_utils(pattgen_error_vseq) - `uvm_object_new + + function new(string name=""); + super.new(name); + error_injected_enb = 1'b1; + endfunction virtual task pre_start(); super.pre_start(); - cfg.seq_cfg.error_injected_enb = 1'b1; // in order to inject error, the generated patterns should be long enough because // completed interrupts can be triggerred before enable bit is unset in the last bit // which indicates a correct correct patterns From e004afda7abe0056033a13128f8460c6a87dcc86 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 15:41:48 +0000 Subject: [PATCH 07/16] [pattgen,dv] Inline trivial task into pattgen_base_vseq::body Signed-off-by: Rupert Swarbrick --- hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index e8d7a5d16f82e..9a783814bdf21 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -46,19 +46,14 @@ class pattgen_base_vseq extends cip_base_vseq #( super.pre_start(); endtask : pre_start - // setup basic pattgen features - virtual task initialize_dut(); - csr_wr(.ptr(ral.intr_enable), .value({TL_DW{1'b1}})); - `uvm_info(`gfn, "\n call pattgen_init", UVM_DEBUG) - endtask : initialize_dut - // TODO: consider optimize the base_vseq to make each channel // cfg, start, stop independently with semaphore (PR #4040) virtual task body(); `uvm_info(`gfn, "\n--> start of sequence", UVM_DEBUG) `uvm_info(`gfn, $sformatf("\n--> total required patterns %0d", num_trans), UVM_DEBUG) - initialize_dut(); + csr_wr(.ptr(ral.intr_enable), .value({TL_DW{1'b1}})); + while (num_pattern_req < num_trans || // not send all pattern configs num_pattern_gen < num_trans || // not get all pattern done interrupts channel_start) begin // at least one channel is running From 116bc5a45325a5434ec53dfaca3b97d7f02fe74f Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 16:37:15 +0000 Subject: [PATCH 08/16] [pattgen,dv] Replace pattgen_base_vseq::right_rotation Rather than a function that operates in place on a reference, just use a task: there's only ever one thing being modified. Also, change the naming to "left rotate", which matches how things look in MSB-first SystemVerilog. Signed-off-by: Rupert Swarbrick --- hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index 9a783814bdf21..cde3c5be4db09 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -88,8 +88,7 @@ class pattgen_base_vseq extends cip_base_vseq #( update_pattgen_agent_cfg(.channel(0)); csr_update(ral.ctrl); channel_setup[0] = 1'b1; - void'(right_rotation(channel_grant)); - `uvm_info(`gfn, "\n channel 0: programmed", UVM_DEBUG) + rol_grant(); end endtask : setup_pattgen_channel_0 @@ -112,7 +111,7 @@ class pattgen_base_vseq extends cip_base_vseq #( update_pattgen_agent_cfg(.channel(1)); csr_update(ral.ctrl); channel_setup[1] = 1'b1; - void'(right_rotation(channel_grant)); + rol_grant(); `uvm_info(`gfn, "\n channel 1: programmed", UVM_DEBUG) end endtask : setup_pattgen_channel_1 @@ -372,10 +371,11 @@ class pattgen_base_vseq extends cip_base_vseq #( cfg.m_pattgen_agent_cfg.length[channel]), UVM_DEBUG) endfunction : update_pattgen_agent_cfg - // right rotate a one-hot vector - virtual function right_rotation(ref bit [NUM_PATTGEN_CHANNELS-1:0] x); - x = {x[NUM_PATTGEN_CHANNELS-2:0], x[NUM_PATTGEN_CHANNELS-1]}; - endfunction : right_rotation + // Left rotate the one-hot channel_grant bitmask by one place + local task rol_grant(); + channel_grant = {channel_grant[NUM_PATTGEN_CHANNELS-2:0], + channel_grant[NUM_PATTGEN_CHANNELS-1]}; + endtask task wait_host_for_idle(); csr_spinwait(.ptr(ral.ctrl.enable_ch0), .exp_data(1'b0)); From 9fd0e1d66627addb61b20b374688767783f58e1f Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 16:12:21 +0000 Subject: [PATCH 09/16] [pattgen,dv] Merge pattgen_base_vseq::setup_pattgen_channel_* We now have a setup_pattgen_channel task, which takes the channel index as an argument. Signed-off-by: Rupert Swarbrick --- .../dv/env/seq_lib/pattgen_base_vseq.sv | 138 ++++++++++++------ 1 file changed, 91 insertions(+), 47 deletions(-) diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index cde3c5be4db09..dd2f348b249c2 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -60,8 +60,8 @@ class pattgen_base_vseq extends cip_base_vseq #( wait(cfg.clk_rst_vif.rst_n); // wait until reset is de-asserted fork // all channels are completely independent (programm, start w/ or wo/ sync, and stop) - setup_pattgen_channel_0(); - setup_pattgen_channel_1(); + setup_pattgen_channel(0); + setup_pattgen_channel(1); start_pattgen_channels(); stop_pattgen_channels(); join @@ -69,52 +69,96 @@ class pattgen_base_vseq extends cip_base_vseq #( `uvm_info(`gfn, "\n--> end of sequence", UVM_DEBUG) endtask : body - virtual task setup_pattgen_channel_0(); - if (num_pattern_req < num_trans && - channel_grant[0] && // ch0 setup is granted - !channel_setup[0] && // ch0 has not been programmed - !channel_start[1]) begin // ch1 is not under start (avoid re-programming regs) - wait_for_channel_ready(Channel0); - channel_cfg[0] = get_random_channel_config(.channel(0)); - ral.size.len_ch0.set(channel_cfg[0].len); - ral.size.reps_ch0.set(channel_cfg[0].reps); - csr_update(ral.size); - csr_wr(.ptr(ral.prediv_ch0), .value(channel_cfg[0].prediv)); - csr_wr(.ptr(ral.data_ch0[0]), .value(channel_cfg[0].data[31:0])); - csr_wr(.ptr(ral.data_ch0[1]), .value(channel_cfg[0].data[63:32])); - ral.ctrl.polarity_ch0.set(channel_cfg[0].polarity); - ral.ctrl.inactive_level_pcl_ch0.set(channel_cfg[0].inactive_level_pcl); - ral.ctrl.inactive_level_pda_ch0.set(channel_cfg[0].inactive_level_pda); - update_pattgen_agent_cfg(.channel(0)); - csr_update(ral.ctrl); - channel_setup[0] = 1'b1; - rol_grant(); - end - endtask : setup_pattgen_channel_0 - - virtual task setup_pattgen_channel_1(); - if (num_pattern_req < num_trans && - channel_grant[1] && // ch1 setup is granted - !channel_setup[1] && // ch1 has not been programmed - !channel_start[0]) begin // ch0 is not under start (avoid re-programming regs) - wait_for_channel_ready(Channel1); - channel_cfg[1] = get_random_channel_config(.channel(1)); - ral.size.len_ch1.set(channel_cfg[1].len); - ral.size.reps_ch1.set(channel_cfg[1].reps); - csr_update(ral.size); - csr_wr(.ptr(ral.prediv_ch1), .value(channel_cfg[1].prediv)); - csr_wr(.ptr(ral.data_ch1[0]), .value(channel_cfg[1].data[31:0])); - csr_wr(.ptr(ral.data_ch1[1]), .value(channel_cfg[1].data[63:32])); - ral.ctrl.polarity_ch1.set(channel_cfg[1].polarity); - ral.ctrl.inactive_level_pcl_ch1.set(channel_cfg[1].inactive_level_pcl); - ral.ctrl.inactive_level_pda_ch1.set(channel_cfg[1].inactive_level_pda); - update_pattgen_agent_cfg(.channel(1)); - csr_update(ral.ctrl); - channel_setup[1] = 1'b1; - rol_grant(); - `uvm_info(`gfn, "\n channel 1: programmed", UVM_DEBUG) + // Return the named register, but with a suffix to get the version for the requested channel. + local function uvm_reg get_channel_reg(string name, int unsigned ch); + uvm_reg r = ral.get_reg_by_name($sformatf("%s_ch%0d", name, ch)); + `DV_CHECK_FATAL(r !== null) + return r; + endfunction + + // Update the SIZE register as it applies to the requested channel (setting LEN_CH* and REPS_CH*) + local task update_size_for_channel(int unsigned ch, int unsigned len, int unsigned reps); + uvm_reg_field len_field = ral.size.get_field_by_name($sformatf("len_ch%0d", ch)); + uvm_reg_field reps_field = ral.size.get_field_by_name($sformatf("reps_ch%0d", ch)); + + `DV_CHECK_FATAL(len_field !== null) + `DV_CHECK_FATAL(reps_field !== null) + + len_field.set(len); + reps_field.set(reps); + csr_update(ral.size); + endtask + + // Update the CTRL register to specify the polarity and inactive levels for the given channel + // (setting INACTIVE_LEVEL_PCL_CH* and INACTIVE_LEVEL_PDA_CH*) + local task update_ctrl_for_channel(int unsigned ch, bit polarity, bit pcl, bit pda); + uvm_reg_field pol_fld = ral.ctrl.get_field_by_name($sformatf("polarity_ch%0d", ch)); + uvm_reg_field pcl_fld = ral.ctrl.get_field_by_name($sformatf("inactive_level_pcl_ch%0d", ch)); + uvm_reg_field pda_fld = ral.ctrl.get_field_by_name($sformatf("inactive_level_pcl_ch%0d", ch)); + + `DV_CHECK_FATAL(pol_fld !== null) + `DV_CHECK_FATAL(pcl_fld !== null) + `DV_CHECK_FATAL(pda_fld !== null) + + pol_fld.set(polarity); + pcl_fld.set(pcl); + pda_fld.set(pda); + + csr_update(ral.ctrl); + endtask + + // Write a PREDIV_CH* register to set the requested pre-divider + local task write_prediv_for_channel(int unsigned ch, bit [31:0] value); + csr_wr(.ptr(get_channel_reg("prediv", ch)), .value(value)); + endtask + + // Write the DATA_CH* multireg with the given pattern + local task write_data_for_channel(int unsigned ch, bit [63:0] data); + for (int unsigned i = 0; i < 2; i++) begin + uvm_reg r = ral.get_reg_by_name($sformatf("data_ch%0d_%0d", ch, i)); + `DV_CHECK_FATAL(r !== null) + csr_wr(.ptr(r), .value((data >> (32 * i)) & 32'hffffffff)); end - endtask : setup_pattgen_channel_1 + endtask + + // Set up the requested channel if this is a good time (there are still more patterns to request; + // setup is granted; the channel is not yet set up; no other channel is running). + local task setup_pattgen_channel(int unsigned ch); + channel_select_e ch_select = channel_select_e'(1 << ch); + + // If we have already requested enough patterns, there's nothing to do on the channel. + if (num_pattern_req >= num_trans) return; + + // We can only do something if the channel's setup is granted but the channel has not yet been + // programmed. + if (!channel_grant[ch] || channel_setup[ch]) return; + + // We don't want to do something if another channel is running. (This avoids re-programming + // registers) + if (channel_start & ~(1 << ch)) return; + + // Wait to make sure that the channel isn't currently enabled + wait_for_channel_ready(ch_select); + + // Pick a random configuration for the channel, storing it into channel_cfg + channel_cfg[ch] = get_random_channel_config(.channel(ch)); + + ral.size.get_field_by_name($sformatf("len_ch%0d", ch)); + + // Now perform register writes to configure the channel as desired. Annoyingly, this always uses + // registers or fields with the index in their name, so lots of the work is done by child tasks. + update_size_for_channel(ch, channel_cfg[ch].len, channel_cfg[ch].reps); + write_prediv_for_channel(ch, channel_cfg[ch].prediv); + write_data_for_channel(ch, channel_cfg[ch].data); + update_ctrl_for_channel(ch, + channel_cfg[ch].polarity, + channel_cfg[ch].inactive_level_pcl, + channel_cfg[ch].inactive_level_pda); + + update_pattgen_agent_cfg(.channel(ch)); + channel_setup[ch] = 1'b1; + rol_grant(); + endtask // Wait a short time (up to pattgen_max_dly) // From b4208760cb7154889209d715d8d01b2ddfe7741f Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 17:55:52 +0000 Subject: [PATCH 10/16] [pattgen,dv] Make pattgen_base_vseq::wait_for_channel_ready simpler It's dramatically easier to use this with the channel index instead of the enum that we were using. Write the simpler version and add a documentation comment. Signed-off-by: Rupert Swarbrick --- .../dv/env/seq_lib/pattgen_base_vseq.sv | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index dd2f348b249c2..3c43fc1759de2 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -124,8 +124,6 @@ class pattgen_base_vseq extends cip_base_vseq #( // Set up the requested channel if this is a good time (there are still more patterns to request; // setup is granted; the channel is not yet set up; no other channel is running). local task setup_pattgen_channel(int unsigned ch); - channel_select_e ch_select = channel_select_e'(1 << ch); - // If we have already requested enough patterns, there's nothing to do on the channel. if (num_pattern_req >= num_trans) return; @@ -138,7 +136,7 @@ class pattgen_base_vseq extends cip_base_vseq #( if (channel_start & ~(1 << ch)) return; // Wait to make sure that the channel isn't currently enabled - wait_for_channel_ready(ch_select); + wait_for_channel_ready(ch); // Pick a random configuration for the channel, storing it into channel_cfg channel_cfg[ch] = get_random_channel_config(.channel(ch)); @@ -271,7 +269,12 @@ class pattgen_base_vseq extends cip_base_vseq #( end endtask : stop_pattgen_channels - virtual task wait_for_channel_ready(channel_select_e ch_select); + // Wait (using multiple reads of the channel's enable register) until the requested channel is not + // enabled. + local task wait_for_channel_ready(int unsigned ch); + uvm_reg_field fld = ral.ctrl.get_field_by_name($sformatf("enable_ch%0d", ch)); + `DV_CHECK_FATAL(fld != null) + // Wait for at least one clock cycle so that the csr_update for the // channel setup don't happen in the same cycle. This avoids a warning in // VCS saying: Setting the value of field while containing register is @@ -279,17 +282,10 @@ class pattgen_base_vseq extends cip_base_vseq #( // condition between threads concurrently accessing the register model is // the likely cause of the problem. cfg.clk_rst_vif.wait_clks(1); - case (ch_select) - Channel0: begin - csr_spinwait(.ptr(ral.ctrl.enable_ch0), .exp_data(1'b0)); - `uvm_info(`gfn, $sformatf("\n channel 0 is ready for programmed"), UVM_DEBUG) - end - Channel1: begin - csr_spinwait(.ptr(ral.ctrl.enable_ch1), .exp_data(1'b0)); - `uvm_info(`gfn, $sformatf("\n channel 1 is ready for programmed"), UVM_DEBUG) - end - endcase - endtask : wait_for_channel_ready + + csr_spinwait(.ptr(fld), .exp_data(1'b0)); + `uvm_info(`gfn, $sformatf("\n channel %0d is ready for programming", ch), UVM_DEBUG) + endtask // this task allows channels to be activated or stopped independently/simultaneously virtual task control_channels(channel_select_e ch_select, channel_status_e status); From 9324c95e5fd1f7070c4d5fd9b6bb2294bf30adcc Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 21:27:40 +0000 Subject: [PATCH 11/16] [pattgen,dv] Tweak pattgen_base_vseq::control_channels This should be a little less tied in with the two channel setup and avoid a bit of repetition. Signed-off-by: Rupert Swarbrick --- .../dv/env/seq_lib/pattgen_base_vseq.sv | 77 +++++++++++-------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index 3c43fc1759de2..8a3a39f24cdfb 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -287,47 +287,56 @@ class pattgen_base_vseq extends cip_base_vseq #( `uvm_info(`gfn, $sformatf("\n channel %0d is ready for programming", ch), UVM_DEBUG) endtask - // this task allows channels to be activated or stopped independently/simultaneously - virtual task control_channels(channel_select_e ch_select, channel_status_e status); + // A masked write to the channel enable fields. Set the status in the RAL for the channels that + // are true in the mask to match the status argument. + function void add_desired_enables(bit [NUM_PATTGEN_CHANNELS-1:0] mask, channel_status_e status); + for (int unsigned ch = 0; ch < NUM_PATTGEN_CHANNELS; ch++) begin + if (mask[ch]) begin + uvm_reg_field len_field = ral.ctrl.get_field_by_name($sformatf("enable_ch%0d", ch)); + `DV_CHECK_FATAL(len_field != null) + len_field.set(status); + end + end + endfunction + + // Update all the channels selected by ch_select with the enable status in the status argument. + local task control_channels(channel_select_e ch_select, channel_status_e status); + bit [NUM_PATTGEN_CHANNELS-1:0] mask; + string verb; + int unsigned counter; + + case (ch_select) + Channel0: mask = 2'b01; + Channel1: mask = 2'b10; + AllChannels: mask = 2'b11; + default: `uvm_fatal(`gfn, "Unknown select") + endcase + // wait for no register access on bus before enable channels to avoid the race condition // (i.e. concurrent access to update ctrl.polarity on the other channel) wait_no_outstanding_access(); - case (ch_select) - Channel0: begin - ral.ctrl.enable_ch0.set(status); - if (status == Enable) begin - num_pattern_req++; - `uvm_info(`gfn, $sformatf("\n channel 0: request %0d/%0d\n%s", - num_pattern_req, num_trans, channel_cfg[0].convert2string()), UVM_DEBUG) - end - end - Channel1: begin - ral.ctrl.enable_ch1.set(status); - if (status == Enable) begin + + add_desired_enables(mask, status); + + if (status == Enable) begin + for (int unsigned i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin + if (mask[i]) begin num_pattern_req++; - `uvm_info(`gfn, $sformatf("\n channel 1: request %0d/%0d\n%s", - num_pattern_req, num_trans, channel_cfg[1].convert2string()), UVM_DEBUG) - end - end - AllChannels: begin - ral.ctrl.enable_ch0.set(status); - ral.ctrl.enable_ch1.set(status); - if (status == Enable) begin - num_pattern_req += 2; - `uvm_info(`gfn, $sformatf("\n sync channel 0: request %0d/%0d\n%s", - num_pattern_req - 1, num_trans, channel_cfg[0].convert2string()), UVM_DEBUG) - `uvm_info(`gfn, $sformatf("\n sync channel 1: request %0d/%0d\n%s", - num_pattern_req, num_trans, channel_cfg[0].convert2string()), UVM_DEBUG) + `uvm_info(`gfn, + $sformatf("\n channel %0d: request %0d/%0d\n%s", + i, num_pattern_req, num_trans, channel_cfg[i].convert2string()), + UVM_DEBUG) end end - endcase - if (status == Enable) begin - `uvm_info(`gfn, $sformatf("\n requested %0d/%0d patterns", - num_pattern_req, num_trans), UVM_DEBUG) - end else begin - `uvm_info(`gfn, $sformatf("\n received %0d/%0d patterns", - num_pattern_gen, num_trans), UVM_DEBUG) end + + `uvm_info(`gfn, + $sformatf("\n %s %0d/%0d patterns", + (status == Enable) ? "requested" : "received", + (status == Enable) ? num_pattern_req : num_pattern_gen, + num_trans), + UVM_DEBUG) + csr_update(ral.ctrl); endtask : control_channels From d1eab5ea9f2025d7b63b6f542ea3322738a06123 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 21:39:13 +0000 Subject: [PATCH 12/16] [pattgen,dv] Define a function for channel select enum -> mask Signed-off-by: Rupert Swarbrick --- hw/ip/pattgen/dv/env/pattgen_env_pkg.sv | 10 ++++++ .../dv/env/seq_lib/pattgen_base_vseq.sv | 32 ++++++------------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/hw/ip/pattgen/dv/env/pattgen_env_pkg.sv b/hw/ip/pattgen/dv/env/pattgen_env_pkg.sv index 04bd02a6865ba..9fda38b9bf968 100644 --- a/hw/ip/pattgen/dv/env/pattgen_env_pkg.sv +++ b/hw/ip/pattgen/dv/env/pattgen_env_pkg.sv @@ -39,6 +39,16 @@ package pattgen_env_pkg; Disable = 1'b0 } channel_status_e; + // Return a bitmask of the channels selected by ch_select. + function bit[NUM_PATTGEN_CHANNELS-1:0] channel_select_mask(channel_select_e ch_select); + case (ch_select) + Channel0: return 2'b01; + Channel1: return 2'b10; + AllChannels: return 2'b11; + default: `uvm_fatal("channel_select_mask", "invalid ch_select") + endcase + endfunction + // alerts parameter uint NUM_ALERTS = 1; parameter string LIST_OF_ALERTS[] = {"fatal_fault"}; diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index 8a3a39f24cdfb..38978c27433d8 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -301,17 +301,10 @@ class pattgen_base_vseq extends cip_base_vseq #( // Update all the channels selected by ch_select with the enable status in the status argument. local task control_channels(channel_select_e ch_select, channel_status_e status); - bit [NUM_PATTGEN_CHANNELS-1:0] mask; + bit [NUM_PATTGEN_CHANNELS-1:0] mask = channel_select_mask(ch_select); string verb; int unsigned counter; - case (ch_select) - Channel0: mask = 2'b01; - Channel1: mask = 2'b10; - AllChannels: mask = 2'b11; - default: `uvm_fatal(`gfn, "Unknown select") - endcase - // wait for no register access on bus before enable channels to avoid the race condition // (i.e. concurrent access to update ctrl.polarity on the other channel) wait_no_outstanding_access(); @@ -347,23 +340,16 @@ class pattgen_base_vseq extends cip_base_vseq #( `uvm_info(`gfn, $sformatf("\n intr_state %b", intr_bits), UVM_DEBUG) endtask : get_interrupt_states - // this task allows the interrupts of channels to be cleared independently/simultaneously + // Clear the interrupts for all selected channels virtual task clear_interrupts(channel_select_e ch_select, bit error = 1'b0); - bit [TL_DW-1:0] intr_clear ='h0; - - if (!error) begin - case (ch_select) - Channel0: intr_clear = 1 << DoneCh0; - Channel1: intr_clear = 1 << DoneCh1; - AllChannels: intr_clear = (1 << DoneCh1) | (1 << DoneCh0); - default: `uvm_fatal(`gfn, " invalid argument") - endcase - short_delay(); - csr_wr(.ptr(ral.intr_state), .value(intr_clear)); - end else begin - `uvm_info(`gfn, $sformatf("\n channel error, no clear interrupts %b", intr_clear), UVM_DEBUG) + if (error) begin + `uvm_info(`gfn, $sformatf("\n channel error, no clear interrupts"), UVM_DEBUG) + return; end - endtask : clear_interrupts + + short_delay(); + csr_wr(.ptr(ral.intr_state), .value(channel_select_mask(ch_select))); + endtask // this function randomizes the channel config virtual function pattgen_channel_cfg get_random_channel_config(uint channel); From 2e05a0363f0a96a1d8456ae77fd5b33b79633bbc Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Sun, 16 Feb 2025 13:47:44 +0000 Subject: [PATCH 13/16] [pattgen,dv] Simplify clear_interrupts task The call sites already had the "is an error injected?" logic. Use that. Signed-off-by: Rupert Swarbrick --- .../dv/env/seq_lib/pattgen_base_vseq.sv | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index 38978c27433d8..cf09ad8de832b 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -231,8 +231,10 @@ class pattgen_base_vseq extends cip_base_vseq #( case (channel_stop) Channel0: begin - if (!error_injected) cfg.m_pattgen_agent_cfg.channel_done = Channel0; - clear_interrupts(Channel0, error_injected); + if (!error_injected) begin + cfg.m_pattgen_agent_cfg.channel_done = Channel0; + clear_interrupts(Channel0); + end control_channels(Channel0, Disable); if (error_injected) cfg.m_pattgen_agent_cfg.error_injected[0] = 1'b0; num_pattern_gen++; @@ -241,8 +243,10 @@ class pattgen_base_vseq extends cip_base_vseq #( error_injected ? "error" : "completed", num_pattern_gen, num_trans), UVM_DEBUG) end Channel1: begin - if (!error_injected) cfg.m_pattgen_agent_cfg.channel_done = Channel1; - clear_interrupts(Channel1, error_injected); + if (!error_injected) begin + cfg.m_pattgen_agent_cfg.channel_done = Channel1; + clear_interrupts(Channel1); + end control_channels(Channel1, Disable); if (error_injected) cfg.m_pattgen_agent_cfg.error_injected[1] = 1'b0; num_pattern_gen++; @@ -251,8 +255,10 @@ class pattgen_base_vseq extends cip_base_vseq #( error_injected ? "error" : "completed", num_pattern_gen, num_trans), UVM_DEBUG) end AllChannels: begin - if (!error_injected) cfg.m_pattgen_agent_cfg.channel_done = AllChannels; - clear_interrupts(AllChannels, error_injected); + if (!error_injected) begin + cfg.m_pattgen_agent_cfg.channel_done = AllChannels; + clear_interrupts(AllChannels); + end control_channels(AllChannels, Disable); if (error_injected) begin cfg.m_pattgen_agent_cfg.error_injected = NoChannels; @@ -341,12 +347,7 @@ class pattgen_base_vseq extends cip_base_vseq #( endtask : get_interrupt_states // Clear the interrupts for all selected channels - virtual task clear_interrupts(channel_select_e ch_select, bit error = 1'b0); - if (error) begin - `uvm_info(`gfn, $sformatf("\n channel error, no clear interrupts"), UVM_DEBUG) - return; - end - + local task clear_interrupts(channel_select_e ch_select); short_delay(); csr_wr(.ptr(ral.intr_state), .value(channel_select_mask(ch_select))); endtask From 44b8b48a3774c830934523a785fddc728d56f3d5 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 14 Feb 2025 15:29:07 +0000 Subject: [PATCH 14/16] [pattgen,dv] Add docs and use extern methods in pattgen_base_vseq Signed-off-by: Rupert Swarbrick --- .../dv/env/seq_lib/pattgen_base_vseq.sv | 767 ++++++++++-------- 1 file changed, 412 insertions(+), 355 deletions(-) diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index cf09ad8de832b..1642e9143f600 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -11,18 +11,26 @@ class pattgen_base_vseq extends cip_base_vseq #( `uvm_object_utils(pattgen_base_vseq) `uvm_object_new - // variables + // A count of how many patterns have been requested so far uint num_pattern_req = 0; + + // A count of how many patterns have been generated so far uint num_pattern_gen = 0; - // channel config + + // Configuration for each of the channels rand pattgen_channel_cfg channel_cfg[NUM_PATTGEN_CHANNELS-1:0]; + + // If set, remove a constraint that forces the inactive level feature to be disabled. bit inactive_level_en = 1'b0; - // indicate channels are setup before enabled + // A bitmask that shows which channels have been set up. bit [NUM_PATTGEN_CHANNELS-1:0] channel_setup = 'h0; + + // A bitmask that shows which channels have been enabled. bit [NUM_PATTGEN_CHANNELS-1:0] channel_start = 'h0; - // this one-hot vector is used for round-robin arbitrating the accesses to the shared registers - // this vector is initialized to 1 (the channel 0 is granted by default) + + // This one-hot vector is used for round-robin arbitrating accesses to the shared registers. It is + // initialized to 1 (the channel 0 is granted by default) bit [NUM_PATTGEN_CHANNELS-1:0] channel_grant = 'h1; // A constraint for the gaps between items in the sequence of pattgen commands @@ -35,389 +43,438 @@ class pattgen_base_vseq extends cip_base_vseq #( constraint num_trans_c { num_trans inside {[cfg.seq_cfg.pattgen_min_num_trans : cfg.seq_cfg.pattgen_max_num_trans]}; } - virtual task pre_start(); - cfg.m_pattgen_agent_cfg.en_monitor = cfg.en_scb; - `uvm_info(`gfn, $sformatf("\n--> %s monitor and scoreboard", - cfg.en_scb ? "enable" : "disable"), UVM_DEBUG) - // env_cfg must be reset after vseq completion - cfg.seq_cfg.pattgen_min_prediv = 0; - cfg.seq_cfg.pattgen_min_len = 0; - cfg.seq_cfg.pattgen_min_reps = 0; - super.pre_start(); - endtask : pre_start - - // TODO: consider optimize the base_vseq to make each channel - // cfg, start, stop independently with semaphore (PR #4040) - virtual task body(); - `uvm_info(`gfn, "\n--> start of sequence", UVM_DEBUG) - `uvm_info(`gfn, $sformatf("\n--> total required patterns %0d", num_trans), UVM_DEBUG) - - csr_wr(.ptr(ral.intr_enable), .value({TL_DW{1'b1}})); - - while (num_pattern_req < num_trans || // not send all pattern configs - num_pattern_gen < num_trans || // not get all pattern done interrupts - channel_start) begin // at least one channel is running - wait(cfg.clk_rst_vif.rst_n); // wait until reset is de-asserted - fork - // all channels are completely independent (programm, start w/ or wo/ sync, and stop) - setup_pattgen_channel(0); - setup_pattgen_channel(1); - start_pattgen_channels(); - stop_pattgen_channels(); - join - end - `uvm_info(`gfn, "\n--> end of sequence", UVM_DEBUG) - endtask : body - // Return the named register, but with a suffix to get the version for the requested channel. - local function uvm_reg get_channel_reg(string name, int unsigned ch); - uvm_reg r = ral.get_reg_by_name($sformatf("%s_ch%0d", name, ch)); - `DV_CHECK_FATAL(r !== null) - return r; - endfunction + // Code that runs before pre_body. (A task from uvm_sequence_base) + extern virtual task pre_start(); - // Update the SIZE register as it applies to the requested channel (setting LEN_CH* and REPS_CH*) - local task update_size_for_channel(int unsigned ch, int unsigned len, int unsigned reps); - uvm_reg_field len_field = ral.size.get_field_by_name($sformatf("len_ch%0d", ch)); - uvm_reg_field reps_field = ral.size.get_field_by_name($sformatf("reps_ch%0d", ch)); + // The body of the sequence. (A task from uvm_sequence_base) + extern virtual task body(); - `DV_CHECK_FATAL(len_field !== null) - `DV_CHECK_FATAL(reps_field !== null) + // Return the named register, but with a suffix to get the version for the requested channel. + extern local function uvm_reg get_channel_reg(string name, int unsigned ch); - len_field.set(len); - reps_field.set(reps); - csr_update(ral.size); - endtask + // Update the SIZE register as it applies to the requested channel (setting LEN_CH* and REPS_CH*) + extern local task update_size_for_channel(int unsigned ch, int unsigned len, int unsigned reps); // Update the CTRL register to specify the polarity and inactive levels for the given channel // (setting INACTIVE_LEVEL_PCL_CH* and INACTIVE_LEVEL_PDA_CH*) - local task update_ctrl_for_channel(int unsigned ch, bit polarity, bit pcl, bit pda); - uvm_reg_field pol_fld = ral.ctrl.get_field_by_name($sformatf("polarity_ch%0d", ch)); - uvm_reg_field pcl_fld = ral.ctrl.get_field_by_name($sformatf("inactive_level_pcl_ch%0d", ch)); - uvm_reg_field pda_fld = ral.ctrl.get_field_by_name($sformatf("inactive_level_pcl_ch%0d", ch)); - - `DV_CHECK_FATAL(pol_fld !== null) - `DV_CHECK_FATAL(pcl_fld !== null) - `DV_CHECK_FATAL(pda_fld !== null) - - pol_fld.set(polarity); - pcl_fld.set(pcl); - pda_fld.set(pda); - - csr_update(ral.ctrl); - endtask + extern local task update_ctrl_for_channel(int unsigned ch, bit polarity, bit pcl, bit pda); // Write a PREDIV_CH* register to set the requested pre-divider - local task write_prediv_for_channel(int unsigned ch, bit [31:0] value); - csr_wr(.ptr(get_channel_reg("prediv", ch)), .value(value)); - endtask + extern local task write_prediv_for_channel(int unsigned ch, bit [31:0] value); // Write the DATA_CH* multireg with the given pattern - local task write_data_for_channel(int unsigned ch, bit [63:0] data); - for (int unsigned i = 0; i < 2; i++) begin - uvm_reg r = ral.get_reg_by_name($sformatf("data_ch%0d_%0d", ch, i)); - `DV_CHECK_FATAL(r !== null) - csr_wr(.ptr(r), .value((data >> (32 * i)) & 32'hffffffff)); - end - endtask + extern local task write_data_for_channel(int unsigned ch, bit [63:0] data); // Set up the requested channel if this is a good time (there are still more patterns to request; // setup is granted; the channel is not yet set up; no other channel is running). - local task setup_pattgen_channel(int unsigned ch); - // If we have already requested enough patterns, there's nothing to do on the channel. - if (num_pattern_req >= num_trans) return; + extern local task setup_pattgen_channel(int unsigned ch); - // We can only do something if the channel's setup is granted but the channel has not yet been - // programmed. - if (!channel_grant[ch] || channel_setup[ch]) return; + // Wait a short time (up to pattgen_max_dly) + // + // Completes early on reset. + extern local task short_delay(); - // We don't want to do something if another channel is running. (This avoids re-programming - // registers) - if (channel_start & ~(1 << ch)) return; + // Start the channels that have been set up but not yet started. Potentially wait until all + // channels have been set up and then start them all at once. + extern local task start_pattgen_channels(); - // Wait to make sure that the channel isn't currently enabled - wait_for_channel_ready(ch); + // Look at the interrupt status bits to see which channels have completed. For each of these + // channels, clear the local channel_setup and channel_start flags, resetting the model of the + // channel to the "ready" state. + extern local task stop_pattgen_channels(); + + // Wait (using multiple reads of the channel's enable register) until the requested channel is not + // enabled. + extern local task wait_for_channel_ready(int unsigned ch); - // Pick a random configuration for the channel, storing it into channel_cfg - channel_cfg[ch] = get_random_channel_config(.channel(ch)); + // A masked write to the channel enable fields. Set the status in the RAL for the channels that + // are true in the mask to match the status argument. + extern function void add_desired_enables(bit [NUM_PATTGEN_CHANNELS-1:0] mask, + channel_status_e status); - ral.size.get_field_by_name($sformatf("len_ch%0d", ch)); + // Update all the channels selected by ch_select with the enable status in the status argument. + extern local task control_channels(channel_select_e ch_select, channel_status_e status); - // Now perform register writes to configure the channel as desired. Annoyingly, this always uses - // registers or fields with the index in their name, so lots of the work is done by child tasks. - update_size_for_channel(ch, channel_cfg[ch].len, channel_cfg[ch].reps); - write_prediv_for_channel(ch, channel_cfg[ch].prediv); - write_data_for_channel(ch, channel_cfg[ch].data); - update_ctrl_for_channel(ch, - channel_cfg[ch].polarity, - channel_cfg[ch].inactive_level_pcl, - channel_cfg[ch].inactive_level_pda); + // Write a bitmask of the channels that have stopped and generated an interrupt to the intr_bits + // output argument. + extern local task get_interrupt_status(output bit[NUM_PATTGEN_CHANNELS-1:0] intr_bits); - update_pattgen_agent_cfg(.channel(ch)); - channel_setup[ch] = 1'b1; - rol_grant(); - endtask + // Clear the interrupts for all selected channels + extern local task clear_interrupts(channel_select_e ch_select); - // Wait a short time (up to pattgen_max_dly) - // - // Completes early on reset. - local task short_delay(); - int unsigned dly; - `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(dly, dly inside {[0:pattgen_max_dly]};) - cfg.clk_rst_vif.wait_clks_or_rst(dly); - endtask - - virtual task start_pattgen_channels(); - if (num_pattern_req < num_trans) begin - if ($urandom_range(0, 99) < cfg.seq_cfg.pattgen_sync_channels_pct) begin - // For some percentage of the time, we start all the channels at the same instant (ensuring - // that they stay in sync) - if (channel_setup[0] && !channel_start[0] && channel_setup[1] && !channel_start[1]) begin + // Return a randomised channel configuration. The channel index argument is just used to construct + // the name of the object. + extern protected virtual function pattgen_channel_cfg get_random_channel_config(uint channel); + + // Update m_pattgen_agent_cfg for the given channel, based on channel_cfg[channel]. + extern local function void update_pattgen_agent_cfg(int channel); + + // Left rotate the one-hot channel_grant bitmask by one place + extern local task rol_grant(); + + // Wait until neither channel is enabled and both have triggered the done interrupt. + extern protected task wait_host_for_idle(); +endclass + +task pattgen_base_vseq::pre_start(); + cfg.m_pattgen_agent_cfg.en_monitor = cfg.en_scb; + `uvm_info(`gfn, $sformatf("\n--> %s monitor and scoreboard", + cfg.en_scb ? "enable" : "disable"), UVM_DEBUG) + // env_cfg must be reset after vseq completion + cfg.seq_cfg.pattgen_min_prediv = 0; + cfg.seq_cfg.pattgen_min_len = 0; + cfg.seq_cfg.pattgen_min_reps = 0; + super.pre_start(); +endtask + +// TODO: consider optimize the base_vseq to make each channel +// cfg, start, stop independently with semaphore (PR #4040) +task pattgen_base_vseq::body(); + csr_wr(.ptr(ral.intr_enable), .value({TL_DW{1'b1}})); + + while (num_pattern_req < num_trans || // not send all pattern configs + num_pattern_gen < num_trans || // not get all pattern done interrupts + channel_start) begin // at least one channel is running + wait(cfg.clk_rst_vif.rst_n); // wait until reset is de-asserted + fork + // all channels are completely independent (programm, start w/ or wo/ sync, and stop) + setup_pattgen_channel(0); + setup_pattgen_channel(1); + start_pattgen_channels(); + stop_pattgen_channels(); + join + end +endtask + +function uvm_reg pattgen_base_vseq::get_channel_reg(string name, int unsigned ch); + uvm_reg r = ral.get_reg_by_name($sformatf("%s_ch%0d", name, ch)); + `DV_CHECK_FATAL(r !== null) + return r; +endfunction + +task pattgen_base_vseq::update_size_for_channel(int unsigned ch, + int unsigned len, + int unsigned reps); + uvm_reg_field len_field = ral.size.get_field_by_name($sformatf("len_ch%0d", ch)); + uvm_reg_field reps_field = ral.size.get_field_by_name($sformatf("reps_ch%0d", ch)); + + `DV_CHECK_FATAL(len_field !== null) + `DV_CHECK_FATAL(reps_field !== null) + + len_field.set(len); + reps_field.set(reps); + csr_update(ral.size); +endtask + +task pattgen_base_vseq::update_ctrl_for_channel(int unsigned ch, bit polarity, bit pcl, bit pda); + uvm_reg_field pol_fld = ral.ctrl.get_field_by_name($sformatf("polarity_ch%0d", ch)); + uvm_reg_field pcl_fld = ral.ctrl.get_field_by_name($sformatf("inactive_level_pcl_ch%0d", ch)); + uvm_reg_field pda_fld = ral.ctrl.get_field_by_name($sformatf("inactive_level_pcl_ch%0d", ch)); + + `DV_CHECK_FATAL(pol_fld !== null) + `DV_CHECK_FATAL(pcl_fld !== null) + `DV_CHECK_FATAL(pda_fld !== null) + + pol_fld.set(polarity); + pcl_fld.set(pcl); + pda_fld.set(pda); + + csr_update(ral.ctrl); +endtask + +task pattgen_base_vseq::write_prediv_for_channel(int unsigned ch, bit [31:0] value); + csr_wr(.ptr(get_channel_reg("prediv", ch)), .value(value)); +endtask + +task pattgen_base_vseq::write_data_for_channel(int unsigned ch, bit [63:0] data); + for (int unsigned i = 0; i < 2; i++) begin + uvm_reg r = ral.get_reg_by_name($sformatf("data_ch%0d_%0d", ch, i)); + `DV_CHECK_FATAL(r !== null) + csr_wr(.ptr(r), .value((data >> (32 * i)) & 32'hffffffff)); + end +endtask + +task pattgen_base_vseq::setup_pattgen_channel(int unsigned ch); + // If we have already requested enough patterns, there's nothing to do on the channel. + if (num_pattern_req >= num_trans) return; + + // We can only do something if the channel's setup is granted but the channel has not yet been + // programmed. + if (!channel_grant[ch] || channel_setup[ch]) return; + + // We don't want to do something if another channel is running. (This avoids re-programming + // registers) + if (channel_start & ~(1 << ch)) return; + + // Wait to make sure that the channel isn't currently enabled + wait_for_channel_ready(ch); + + // Pick a random configuration for the channel, storing it into channel_cfg + channel_cfg[ch] = get_random_channel_config(.channel(ch)); + + ral.size.get_field_by_name($sformatf("len_ch%0d", ch)); + + // Now perform register writes to configure the channel as desired. Annoyingly, this always uses + // registers or fields with the index in their name, so lots of the work is done by child tasks. + update_size_for_channel(ch, channel_cfg[ch].len, channel_cfg[ch].reps); + write_prediv_for_channel(ch, channel_cfg[ch].prediv); + write_data_for_channel(ch, channel_cfg[ch].data); + update_ctrl_for_channel(ch, + channel_cfg[ch].polarity, + channel_cfg[ch].inactive_level_pcl, + channel_cfg[ch].inactive_level_pda); + + update_pattgen_agent_cfg(.channel(ch)); + channel_setup[ch] = 1'b1; + rol_grant(); +endtask + +task pattgen_base_vseq::short_delay(); + int unsigned dly; + `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(dly, dly inside {[0:pattgen_max_dly]};) + cfg.clk_rst_vif.wait_clks_or_rst(dly); +endtask + +task pattgen_base_vseq::start_pattgen_channels(); + if (num_pattern_req < num_trans) begin + if ($urandom_range(0, 99) < cfg.seq_cfg.pattgen_sync_channels_pct) begin + // For some percentage of the time, we start all the channels at the same instant (ensuring + // that they stay in sync) + if (channel_setup[0] && !channel_start[0] && channel_setup[1] && !channel_start[1]) begin + short_delay(); + control_channels(AllChannels, Enable); + {channel_start[0], channel_start[1]} = {1'b1, 1'b1}; + `uvm_info(`gfn, "\n all channels: activated", UVM_DEBUG) + end + end else begin + // otherwise, activate channels independently + for (uint i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin + if (channel_setup[i] && !channel_start[i]) begin + channel_select_e ch_select; + `downcast(ch_select, i+1) short_delay(); - control_channels(AllChannels, Enable); - {channel_start[0], channel_start[1]} = {1'b1, 1'b1}; - `uvm_info(`gfn, "\n all channels: activated", UVM_DEBUG) - end - end else begin - // otherwise, activate channels independently - for (uint i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin - if (channel_setup[i] && !channel_start[i]) begin - channel_select_e ch_select; - `downcast(ch_select, i+1) - short_delay(); - control_channels(ch_select, Enable); - channel_start[i]= 1'b1; - `uvm_info(`gfn, $sformatf("\n channel %0d: activated", i), UVM_DEBUG) - end + control_channels(ch_select, Enable); + channel_start[i]= 1'b1; + `uvm_info(`gfn, $sformatf("\n channel %0d: activated", i), UVM_DEBUG) end end end - endtask : start_pattgen_channels - - // this task allows channels to be stopped independently/simultaneously - virtual task stop_pattgen_channels(); - bit error_injected; - bit [NUM_PATTGEN_CHANNELS-1:0] intr_status; - bit [NUM_PATTGEN_CHANNELS-1:0] channel_stop; - - if (channel_start) begin - error_injected = 1'b0; - get_interrupt_states(intr_status); - //-------------------------------------------------------------------------------- - // inject error - //-------------------------------------------------------------------------------- - // ch_start intr_status ch_stop description - //-------------------------------------------------------------------------------- - // 01 (CH0) 01 01 CH0 finished CH1 not started - // 01 (CH0) 00 01 CH0 error injected* CH1 not started - // 10 (CH1) 10 10 CH0 not started CH1 finished - // 10 (CH1) 00 10 CH0 not started CH1 error injected* - // 11 (CH1) 01 01 CH0 finished CH1 error injected* - // 11 (CH1) 10 10 CH0 error injected* CH1 finished - // 11 (CH1) 11 11 CH0 finished CH1 finished - // 11 (CH1) 00 11 CH0 error injected CH1 error injected* - channel_stop = intr_status; // default setting - if (error_injected_enb) begin - if ($urandom_range(0, 99) < cfg.seq_cfg.error_injected_pct) begin - if (intr_status != channel_start) begin - channel_stop = channel_start; - error_injected = 1'b1; - cfg.m_pattgen_agent_cfg.error_injected = channel_stop; - `uvm_info(`gfn, $sformatf("\n error inject: intr_status %b ch_stop %b ch_start %b", - intr_status, channel_stop, channel_start), UVM_DEBUG) - end + end +endtask + +task pattgen_base_vseq::stop_pattgen_channels(); + bit error_injected; + bit [NUM_PATTGEN_CHANNELS-1:0] intr_status; + bit [NUM_PATTGEN_CHANNELS-1:0] channel_stop; + + if (channel_start) begin + error_injected = 1'b0; + get_interrupt_status(intr_status); + //-------------------------------------------------------------------------------- + // inject error + //-------------------------------------------------------------------------------- + // ch_start intr_status ch_stop description + //-------------------------------------------------------------------------------- + // 01 (CH0) 01 01 CH0 finished CH1 not started + // 01 (CH0) 00 01 CH0 error injected* CH1 not started + // 10 (CH1) 10 10 CH0 not started CH1 finished + // 10 (CH1) 00 10 CH0 not started CH1 error injected* + // 11 (CH1) 01 01 CH0 finished CH1 error injected* + // 11 (CH1) 10 10 CH0 error injected* CH1 finished + // 11 (CH1) 11 11 CH0 finished CH1 finished + // 11 (CH1) 00 11 CH0 error injected CH1 error injected* + channel_stop = intr_status; // default setting + if (error_injected_enb) begin + if ($urandom_range(0, 99) < cfg.seq_cfg.error_injected_pct) begin + if (intr_status != channel_start) begin + channel_stop = channel_start; + error_injected = 1'b1; + cfg.m_pattgen_agent_cfg.error_injected = channel_stop; + `uvm_info(`gfn, $sformatf("\n error inject: intr_status %b ch_stop %b ch_start %b", + intr_status, channel_stop, channel_start), UVM_DEBUG) end end + end - case (channel_stop) - Channel0: begin - if (!error_injected) begin - cfg.m_pattgen_agent_cfg.channel_done = Channel0; - clear_interrupts(Channel0); - end - control_channels(Channel0, Disable); - if (error_injected) cfg.m_pattgen_agent_cfg.error_injected[0] = 1'b0; - num_pattern_gen++; - {channel_setup[0], channel_start[0]} = {1'b0, 1'b0}; - `uvm_info(`gfn, $sformatf("\n channel 0: %s %0d/%0d", - error_injected ? "error" : "completed", num_pattern_gen, num_trans), UVM_DEBUG) + case (channel_stop) + Channel0: begin + if (!error_injected) begin + cfg.m_pattgen_agent_cfg.channel_done = Channel0; + clear_interrupts(Channel0); end - Channel1: begin - if (!error_injected) begin - cfg.m_pattgen_agent_cfg.channel_done = Channel1; - clear_interrupts(Channel1); - end - control_channels(Channel1, Disable); - if (error_injected) cfg.m_pattgen_agent_cfg.error_injected[1] = 1'b0; - num_pattern_gen++; - {channel_setup[1], channel_start[1]} = {1'b0, 1'b0}; - `uvm_info(`gfn, $sformatf("\n channel 1: %s %0d/%0d", - error_injected ? "error" : "completed", num_pattern_gen, num_trans), UVM_DEBUG) - end - AllChannels: begin - if (!error_injected) begin - cfg.m_pattgen_agent_cfg.channel_done = AllChannels; - clear_interrupts(AllChannels); - end - control_channels(AllChannels, Disable); - if (error_injected) begin - cfg.m_pattgen_agent_cfg.error_injected = NoChannels; - `uvm_info(`gfn, $sformatf("\n update m_pattgen_agent_cfg.error_injected"), UVM_DEBUG) - end - num_pattern_gen += 2; - channel_setup = {NUM_PATTGEN_CHANNELS{1'b0}}; - channel_start = {NUM_PATTGEN_CHANNELS{1'b0}}; - `uvm_info(`gfn, $sformatf("\n all channels: %s %0d/%0d", - error_injected ? "error" : "completed", num_pattern_gen, num_trans), UVM_DEBUG) + control_channels(Channel0, Disable); + if (error_injected) cfg.m_pattgen_agent_cfg.error_injected[0] = 1'b0; + num_pattern_gen++; + {channel_setup[0], channel_start[0]} = {1'b0, 1'b0}; + `uvm_info(`gfn, $sformatf("\n channel 0: %s %0d/%0d", + error_injected ? "error" : "completed", num_pattern_gen, num_trans), UVM_DEBUG) + end + Channel1: begin + if (!error_injected) begin + cfg.m_pattgen_agent_cfg.channel_done = Channel1; + clear_interrupts(Channel1); end - endcase - cfg.m_pattgen_agent_cfg.channel_done = NoChannels; - end - endtask : stop_pattgen_channels - - // Wait (using multiple reads of the channel's enable register) until the requested channel is not - // enabled. - local task wait_for_channel_ready(int unsigned ch); - uvm_reg_field fld = ral.ctrl.get_field_by_name($sformatf("enable_ch%0d", ch)); - `DV_CHECK_FATAL(fld != null) - - // Wait for at least one clock cycle so that the csr_update for the - // channel setup don't happen in the same cycle. This avoids a warning in - // VCS saying: Setting the value of field while containing register is - // being accessed may result in loss of desired field value. A race - // condition between threads concurrently accessing the register model is - // the likely cause of the problem. - cfg.clk_rst_vif.wait_clks(1); - - csr_spinwait(.ptr(fld), .exp_data(1'b0)); - `uvm_info(`gfn, $sformatf("\n channel %0d is ready for programming", ch), UVM_DEBUG) - endtask - - // A masked write to the channel enable fields. Set the status in the RAL for the channels that - // are true in the mask to match the status argument. - function void add_desired_enables(bit [NUM_PATTGEN_CHANNELS-1:0] mask, channel_status_e status); - for (int unsigned ch = 0; ch < NUM_PATTGEN_CHANNELS; ch++) begin - if (mask[ch]) begin - uvm_reg_field len_field = ral.ctrl.get_field_by_name($sformatf("enable_ch%0d", ch)); - `DV_CHECK_FATAL(len_field != null) - len_field.set(status); + control_channels(Channel1, Disable); + if (error_injected) cfg.m_pattgen_agent_cfg.error_injected[1] = 1'b0; + num_pattern_gen++; + {channel_setup[1], channel_start[1]} = {1'b0, 1'b0}; + `uvm_info(`gfn, $sformatf("\n channel 1: %s %0d/%0d", + error_injected ? "error" : "completed", num_pattern_gen, num_trans), UVM_DEBUG) end - end - endfunction - - // Update all the channels selected by ch_select with the enable status in the status argument. - local task control_channels(channel_select_e ch_select, channel_status_e status); - bit [NUM_PATTGEN_CHANNELS-1:0] mask = channel_select_mask(ch_select); - string verb; - int unsigned counter; - - // wait for no register access on bus before enable channels to avoid the race condition - // (i.e. concurrent access to update ctrl.polarity on the other channel) - wait_no_outstanding_access(); - - add_desired_enables(mask, status); - - if (status == Enable) begin - for (int unsigned i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin - if (mask[i]) begin - num_pattern_req++; - `uvm_info(`gfn, - $sformatf("\n channel %0d: request %0d/%0d\n%s", - i, num_pattern_req, num_trans, channel_cfg[i].convert2string()), - UVM_DEBUG) + AllChannels: begin + if (!error_injected) begin + cfg.m_pattgen_agent_cfg.channel_done = AllChannels; + clear_interrupts(AllChannels); + end + control_channels(AllChannels, Disable); + if (error_injected) begin + cfg.m_pattgen_agent_cfg.error_injected = NoChannels; + `uvm_info(`gfn, $sformatf("\n update m_pattgen_agent_cfg.error_injected"), UVM_DEBUG) end + num_pattern_gen += 2; + channel_setup = {NUM_PATTGEN_CHANNELS{1'b0}}; + channel_start = {NUM_PATTGEN_CHANNELS{1'b0}}; + `uvm_info(`gfn, $sformatf("\n all channels: %s %0d/%0d", + error_injected ? "error" : "completed", num_pattern_gen, num_trans), UVM_DEBUG) end + endcase + cfg.m_pattgen_agent_cfg.channel_done = NoChannels; + end +endtask + +task pattgen_base_vseq::wait_for_channel_ready(int unsigned ch); + uvm_reg_field fld = ral.ctrl.get_field_by_name($sformatf("enable_ch%0d", ch)); + `DV_CHECK_FATAL(fld != null) + + // Wait for at least one clock cycle so that the csr_update for the + // channel setup don't happen in the same cycle. This avoids a warning in + // VCS saying: Setting the value of field while containing register is + // being accessed may result in loss of desired field value. A race + // condition between threads concurrently accessing the register model is + // the likely cause of the problem. + cfg.clk_rst_vif.wait_clks(1); + + csr_spinwait(.ptr(fld), .exp_data(1'b0)); + `uvm_info(`gfn, $sformatf("\n channel %0d is ready for programming", ch), UVM_DEBUG) +endtask + +function void pattgen_base_vseq::add_desired_enables(bit [NUM_PATTGEN_CHANNELS-1:0] mask, + channel_status_e status); + for (int unsigned ch = 0; ch < NUM_PATTGEN_CHANNELS; ch++) begin + if (mask[ch]) begin + uvm_reg_field len_field = ral.ctrl.get_field_by_name($sformatf("enable_ch%0d", ch)); + `DV_CHECK_FATAL(len_field != null) + len_field.set(status); end - - `uvm_info(`gfn, - $sformatf("\n %s %0d/%0d patterns", - (status == Enable) ? "requested" : "received", - (status == Enable) ? num_pattern_req : num_pattern_gen, - num_trans), - UVM_DEBUG) - - csr_update(ral.ctrl); - endtask : control_channels - - virtual task get_interrupt_states(output bit[NUM_PATTGEN_CHANNELS-1:0] intr_bits); - bit [TL_DW-1:0] intr_state; - csr_rd(.ptr(ral.intr_state), .value(intr_state)); - intr_bits = NUM_PATTGEN_CHANNELS'(intr_state); - `uvm_info(`gfn, $sformatf("\n intr_state %b", intr_bits), UVM_DEBUG) - endtask : get_interrupt_states - - // Clear the interrupts for all selected channels - local task clear_interrupts(channel_select_e ch_select); - short_delay(); - csr_wr(.ptr(ral.intr_state), .value(channel_select_mask(ch_select))); - endtask - - // this function randomizes the channel config - virtual function pattgen_channel_cfg get_random_channel_config(uint channel); - pattgen_channel_cfg ch_cfg; - ch_cfg = pattgen_channel_cfg::type_id::create($sformatf("channel_cfg_%0d", channel)); - if (inactive_level_en) begin - // TODO(#23219): Remove this when the scoreboard supports the inactive_level feature. - ch_cfg.inactive_level_disabled_c.constraint_mode(0); + end +endfunction + +task pattgen_base_vseq::control_channels(channel_select_e ch_select, channel_status_e status); + bit [NUM_PATTGEN_CHANNELS-1:0] mask = channel_select_mask(ch_select); + string verb; + int unsigned counter; + + // wait for no register access on bus before enable channels to avoid the race condition (i.e. + // concurrent access to update ctrl.polarity on the other channel) + wait_no_outstanding_access(); + + add_desired_enables(mask, status); + + if (status == Enable) begin + for (int unsigned i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin + if (mask[i]) begin + num_pattern_req++; + `uvm_info(`gfn, + $sformatf("\n channel %0d: request %0d/%0d\n%s", + i, num_pattern_req, num_trans, channel_cfg[i].convert2string()), + UVM_DEBUG) + end end - `DV_CHECK_RANDOMIZE_WITH_FATAL(ch_cfg, - ch_cfg.polarity dist { - 1'b0 :/ cfg.seq_cfg.pattgen_low_polarity_pct, - 1'b1 :/ (100 - cfg.seq_cfg.pattgen_low_polarity_pct) - }; - ch_cfg.data[31:0] dist { - DataMax :/ cfg.seq_cfg.data_top_pct, - DataMin :/ cfg.seq_cfg.data_bottom_pct, - [DataMin + 1:DataMax - 1] :/ cfg.seq_cfg.data_middle_pct - }; - ch_cfg.data[63:32] dist { - DataMax :/ cfg.seq_cfg.data_top_pct, - DataMin :/ cfg.seq_cfg.data_bottom_pct, - [DataMin:DataMax] :/ cfg.seq_cfg.data_middle_pct - }; - ch_cfg.prediv dist { - cfg.seq_cfg.pattgen_max_prediv :/ cfg.seq_cfg.data_top_pct, - cfg.seq_cfg.pattgen_min_prediv :/ cfg.seq_cfg.data_bottom_pct, - [cfg.seq_cfg.pattgen_min_prediv + 1 : - cfg.seq_cfg.pattgen_max_prediv - 1] :/ cfg.seq_cfg.data_middle_pct - }; - ch_cfg.reps dist { - cfg.seq_cfg.pattgen_max_reps :/ cfg.seq_cfg.data_top_pct, - cfg.seq_cfg.pattgen_min_reps :/ cfg.seq_cfg.data_bottom_pct, - [cfg.seq_cfg.pattgen_min_reps:cfg.seq_cfg.pattgen_max_reps] :/ cfg.seq_cfg.data_middle_pct - }; - ch_cfg.len dist { - cfg.seq_cfg.pattgen_max_len :/ cfg.seq_cfg.data_top_pct, - cfg.seq_cfg.pattgen_min_len :/ cfg.seq_cfg.data_bottom_pct, - [cfg.seq_cfg.pattgen_min_len:cfg.seq_cfg.pattgen_max_len] :/ cfg.seq_cfg.data_middle_pct - }; - ) - return ch_cfg; - endfunction : get_random_channel_config - - // this function allows update the pattgen_agent_config - virtual function void update_pattgen_agent_cfg(int channel); - cfg.m_pattgen_agent_cfg.polarity[channel] = channel_cfg[channel].polarity; - // see the specification document, the effective values of prediv, len, and reps - // are incremented from the coresponding register values - cfg.m_pattgen_agent_cfg.length[channel] = (channel_cfg[channel].len + 1) * - (channel_cfg[channel].reps + 1); - `uvm_info(`gfn, $sformatf("\n--> pattgen_agent_cfg: channel %0d, polarity %0b, length %0d", - channel, cfg.m_pattgen_agent_cfg.polarity[channel], - cfg.m_pattgen_agent_cfg.length[channel]), UVM_DEBUG) - endfunction : update_pattgen_agent_cfg - - // Left rotate the one-hot channel_grant bitmask by one place - local task rol_grant(); - channel_grant = {channel_grant[NUM_PATTGEN_CHANNELS-2:0], - channel_grant[NUM_PATTGEN_CHANNELS-1]}; - endtask - - task wait_host_for_idle(); - csr_spinwait(.ptr(ral.ctrl.enable_ch0), .exp_data(1'b0)); - csr_spinwait(.ptr(ral.ctrl.enable_ch1), .exp_data(1'b0)); - csr_spinwait(.ptr(ral.intr_state.done_ch0), .exp_data(1'b0)); - csr_spinwait(.ptr(ral.intr_state.done_ch1), .exp_data(1'b0)); - endtask : wait_host_for_idle - -endclass : pattgen_base_vseq + end + + `uvm_info(`gfn, + $sformatf("\n %s %0d/%0d patterns", + (status == Enable) ? "requested" : "received", + (status == Enable) ? num_pattern_req : num_pattern_gen, + num_trans), + UVM_DEBUG) + + csr_update(ral.ctrl); +endtask + +task pattgen_base_vseq::get_interrupt_status(output bit[NUM_PATTGEN_CHANNELS-1:0] intr_bits); + bit [TL_DW-1:0] intr_state; + csr_rd(.ptr(ral.intr_state), .value(intr_state)); + intr_bits = NUM_PATTGEN_CHANNELS'(intr_state); + `uvm_info(`gfn, $sformatf("\n intr_state %b", intr_bits), UVM_DEBUG) +endtask + +task pattgen_base_vseq::clear_interrupts(channel_select_e ch_select); + short_delay(); + csr_wr(.ptr(ral.intr_state), .value(channel_select_mask(ch_select))); +endtask + +function pattgen_channel_cfg pattgen_base_vseq::get_random_channel_config(uint channel); + pattgen_channel_cfg ch_cfg; + ch_cfg = pattgen_channel_cfg::type_id::create($sformatf("channel_cfg_%0d", channel)); + if (inactive_level_en) begin + // TODO(#23219): Remove this when the scoreboard supports the inactive_level feature. + ch_cfg.inactive_level_disabled_c.constraint_mode(0); + end + `DV_CHECK_RANDOMIZE_WITH_FATAL(ch_cfg, + ch_cfg.polarity dist { + 1'b0 :/ cfg.seq_cfg.pattgen_low_polarity_pct, + 1'b1 :/ (100 - cfg.seq_cfg.pattgen_low_polarity_pct) + }; + ch_cfg.data[31:0] dist { + DataMax :/ cfg.seq_cfg.data_top_pct, + DataMin :/ cfg.seq_cfg.data_bottom_pct, + [DataMin + 1:DataMax - 1] :/ cfg.seq_cfg.data_middle_pct + }; + ch_cfg.data[63:32] dist { + DataMax :/ cfg.seq_cfg.data_top_pct, + DataMin :/ cfg.seq_cfg.data_bottom_pct, + [DataMin:DataMax] :/ cfg.seq_cfg.data_middle_pct + }; + ch_cfg.prediv dist { + cfg.seq_cfg.pattgen_max_prediv :/ cfg.seq_cfg.data_top_pct, + cfg.seq_cfg.pattgen_min_prediv :/ cfg.seq_cfg.data_bottom_pct, + [cfg.seq_cfg.pattgen_min_prediv + 1 : + cfg.seq_cfg.pattgen_max_prediv - 1] :/ cfg.seq_cfg.data_middle_pct + }; + ch_cfg.reps dist { + cfg.seq_cfg.pattgen_max_reps :/ cfg.seq_cfg.data_top_pct, + cfg.seq_cfg.pattgen_min_reps :/ cfg.seq_cfg.data_bottom_pct, + [cfg.seq_cfg.pattgen_min_reps:cfg.seq_cfg.pattgen_max_reps] :/ cfg.seq_cfg.data_middle_pct + }; + ch_cfg.len dist { + cfg.seq_cfg.pattgen_max_len :/ cfg.seq_cfg.data_top_pct, + cfg.seq_cfg.pattgen_min_len :/ cfg.seq_cfg.data_bottom_pct, + [cfg.seq_cfg.pattgen_min_len:cfg.seq_cfg.pattgen_max_len] :/ cfg.seq_cfg.data_middle_pct + }; + ) + return ch_cfg; +endfunction + +function void pattgen_base_vseq::update_pattgen_agent_cfg(int channel); + cfg.m_pattgen_agent_cfg.polarity[channel] = channel_cfg[channel].polarity; + // see the specification document, the effective values of prediv, len, and reps + // are incremented from the coresponding register values + cfg.m_pattgen_agent_cfg.length[channel] = (channel_cfg[channel].len + 1) * + (channel_cfg[channel].reps + 1); + `uvm_info(`gfn, $sformatf("\n--> pattgen_agent_cfg: channel %0d, polarity %0b, length %0d", + channel, cfg.m_pattgen_agent_cfg.polarity[channel], + cfg.m_pattgen_agent_cfg.length[channel]), UVM_DEBUG) +endfunction + +task pattgen_base_vseq::rol_grant(); + channel_grant = {channel_grant[NUM_PATTGEN_CHANNELS-2:0], channel_grant[NUM_PATTGEN_CHANNELS-1]}; +endtask + +task pattgen_base_vseq::wait_host_for_idle(); + csr_spinwait(.ptr(ral.ctrl.enable_ch0), .exp_data(1'b0)); + csr_spinwait(.ptr(ral.ctrl.enable_ch1), .exp_data(1'b0)); + csr_spinwait(.ptr(ral.intr_state.done_ch0), .exp_data(1'b0)); + csr_spinwait(.ptr(ral.intr_state.done_ch1), .exp_data(1'b0)); +endtask From 712420a270978e7a76e5abcf3eb7b2a48d7afe6a Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Sun, 16 Feb 2025 17:40:30 +0000 Subject: [PATCH 15/16] [pattgen,dv] Get rid of channel_select_e This was an enum representing the four possibilities for a 2-bit bitmask in a rather confusing way. Get rid of it. Signed-off-by: Rupert Swarbrick --- hw/ip/pattgen/dv/env/pattgen_env_pkg.sv | 17 ------ .../dv/env/seq_lib/pattgen_base_vseq.sv | 53 ++++++++++--------- 2 files changed, 28 insertions(+), 42 deletions(-) diff --git a/hw/ip/pattgen/dv/env/pattgen_env_pkg.sv b/hw/ip/pattgen/dv/env/pattgen_env_pkg.sv index 9fda38b9bf968..8177ba93a1b22 100644 --- a/hw/ip/pattgen/dv/env/pattgen_env_pkg.sv +++ b/hw/ip/pattgen/dv/env/pattgen_env_pkg.sv @@ -27,28 +27,11 @@ package pattgen_env_pkg; NumPattgenIntr = 2 } pattgen_intr_e; - typedef enum bit[1:0] { - NoChannels = 2'b00, - Channel0 = 2'b01, - Channel1 = 2'b10, - AllChannels = 2'b11 - } channel_select_e; - typedef enum bit { Enable = 1'b1, Disable = 1'b0 } channel_status_e; - // Return a bitmask of the channels selected by ch_select. - function bit[NUM_PATTGEN_CHANNELS-1:0] channel_select_mask(channel_select_e ch_select); - case (ch_select) - Channel0: return 2'b01; - Channel1: return 2'b10; - AllChannels: return 2'b11; - default: `uvm_fatal("channel_select_mask", "invalid ch_select") - endcase - endfunction - // alerts parameter uint NUM_ALERTS = 1; parameter string LIST_OF_ALERTS[] = {"fatal_fault"}; diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index 1642e9143f600..1bda54940af09 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -93,15 +93,15 @@ class pattgen_base_vseq extends cip_base_vseq #( extern function void add_desired_enables(bit [NUM_PATTGEN_CHANNELS-1:0] mask, channel_status_e status); - // Update all the channels selected by ch_select with the enable status in the status argument. - extern local task control_channels(channel_select_e ch_select, channel_status_e status); + // Update all the channels selected by mask with the enable status in the status argument. + extern local task control_channels(bit [NUM_PATTGEN_CHANNELS-1:0] mask, channel_status_e status); // Write a bitmask of the channels that have stopped and generated an interrupt to the intr_bits // output argument. extern local task get_interrupt_status(output bit[NUM_PATTGEN_CHANNELS-1:0] intr_bits); // Clear the interrupts for all selected channels - extern local task clear_interrupts(channel_select_e ch_select); + extern local task clear_interrupts(bit [NUM_PATTGEN_CHANNELS-1:0] mask); // Return a randomised channel configuration. The channel index argument is just used to construct // the name of the object. @@ -243,7 +243,7 @@ task pattgen_base_vseq::start_pattgen_channels(); // that they stay in sync) if (channel_setup[0] && !channel_start[0] && channel_setup[1] && !channel_start[1]) begin short_delay(); - control_channels(AllChannels, Enable); + control_channels(2'b11, Enable); {channel_start[0], channel_start[1]} = {1'b1, 1'b1}; `uvm_info(`gfn, "\n all channels: activated", UVM_DEBUG) end @@ -251,10 +251,8 @@ task pattgen_base_vseq::start_pattgen_channels(); // otherwise, activate channels independently for (uint i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin if (channel_setup[i] && !channel_start[i]) begin - channel_select_e ch_select; - `downcast(ch_select, i+1) short_delay(); - control_channels(ch_select, Enable); + control_channels(1 << i, Enable); channel_start[i]= 1'b1; `uvm_info(`gfn, $sformatf("\n channel %0d: activated", i), UVM_DEBUG) end @@ -298,38 +296,42 @@ task pattgen_base_vseq::stop_pattgen_channels(); end case (channel_stop) - Channel0: begin + 2'b00: begin + // If no channels have stopped yet and we don't want to inject an error by stopping one + // early then there is nothing to do. + end + 2'b01: begin if (!error_injected) begin - cfg.m_pattgen_agent_cfg.channel_done = Channel0; - clear_interrupts(Channel0); + cfg.m_pattgen_agent_cfg.channel_done = 2'b01; + clear_interrupts(2'b01); end - control_channels(Channel0, Disable); + control_channels(2'b01, Disable); if (error_injected) cfg.m_pattgen_agent_cfg.error_injected[0] = 1'b0; num_pattern_gen++; {channel_setup[0], channel_start[0]} = {1'b0, 1'b0}; `uvm_info(`gfn, $sformatf("\n channel 0: %s %0d/%0d", error_injected ? "error" : "completed", num_pattern_gen, num_trans), UVM_DEBUG) end - Channel1: begin + 2'b10: begin if (!error_injected) begin - cfg.m_pattgen_agent_cfg.channel_done = Channel1; - clear_interrupts(Channel1); + cfg.m_pattgen_agent_cfg.channel_done = 2'b10; + clear_interrupts(2'b10); end - control_channels(Channel1, Disable); + control_channels(2'b10, Disable); if (error_injected) cfg.m_pattgen_agent_cfg.error_injected[1] = 1'b0; num_pattern_gen++; {channel_setup[1], channel_start[1]} = {1'b0, 1'b0}; `uvm_info(`gfn, $sformatf("\n channel 1: %s %0d/%0d", error_injected ? "error" : "completed", num_pattern_gen, num_trans), UVM_DEBUG) end - AllChannels: begin + 2'b11: begin if (!error_injected) begin - cfg.m_pattgen_agent_cfg.channel_done = AllChannels; - clear_interrupts(AllChannels); + cfg.m_pattgen_agent_cfg.channel_done = 2'b11; + clear_interrupts(2'b11); end - control_channels(AllChannels, Disable); + control_channels(2'b11, Disable); if (error_injected) begin - cfg.m_pattgen_agent_cfg.error_injected = NoChannels; + cfg.m_pattgen_agent_cfg.error_injected = 2'b00; `uvm_info(`gfn, $sformatf("\n update m_pattgen_agent_cfg.error_injected"), UVM_DEBUG) end num_pattern_gen += 2; @@ -338,8 +340,9 @@ task pattgen_base_vseq::stop_pattgen_channels(); `uvm_info(`gfn, $sformatf("\n all channels: %s %0d/%0d", error_injected ? "error" : "completed", num_pattern_gen, num_trans), UVM_DEBUG) end + default: `uvm_fatal(`gfn, $sformatf("unknown value for channel_stop: 0x%0h", channel_stop)) endcase - cfg.m_pattgen_agent_cfg.channel_done = NoChannels; + cfg.m_pattgen_agent_cfg.channel_done = 2'b00; end endtask @@ -370,8 +373,8 @@ function void pattgen_base_vseq::add_desired_enables(bit [NUM_PATTGEN_CHANNELS-1 end endfunction -task pattgen_base_vseq::control_channels(channel_select_e ch_select, channel_status_e status); - bit [NUM_PATTGEN_CHANNELS-1:0] mask = channel_select_mask(ch_select); +task pattgen_base_vseq::control_channels(bit [NUM_PATTGEN_CHANNELS-1:0] mask, + channel_status_e status); string verb; int unsigned counter; @@ -410,9 +413,9 @@ task pattgen_base_vseq::get_interrupt_status(output bit[NUM_PATTGEN_CHANNELS-1:0 `uvm_info(`gfn, $sformatf("\n intr_state %b", intr_bits), UVM_DEBUG) endtask -task pattgen_base_vseq::clear_interrupts(channel_select_e ch_select); +task pattgen_base_vseq::clear_interrupts(bit [NUM_PATTGEN_CHANNELS-1:0] mask); short_delay(); - csr_wr(.ptr(ral.intr_state), .value(channel_select_mask(ch_select))); + csr_wr(.ptr(ral.intr_state), .value(mask)); endtask function pattgen_channel_cfg pattgen_base_vseq::get_random_channel_config(uint channel); From ab0092512539294f6a643b0f2a988732f4138fba Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Sun, 16 Feb 2025 22:12:54 +0000 Subject: [PATCH 16/16] [pattgen,dv] Get rid of pattgen_low_polarity_pct This is only ever set to 50% and is used to weight the random choice of a bit (and it seems unlikely we'll ever care more about one polarity). Get rid of the unused customizability. Signed-off-by: Rupert Swarbrick --- hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv | 1 - hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv | 4 ---- hw/ip/pattgen/dv/env/seq_lib/pattgen_cnt_rollover_vseq.sv | 4 ---- hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv | 4 ---- 4 files changed, 13 deletions(-) diff --git a/hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv b/hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv index 133cccb7f2e04..bab60c53f141f 100644 --- a/hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv +++ b/hw/ip/pattgen/dv/env/pattgen_seq_cfg.sv @@ -26,7 +26,6 @@ class pattgen_seq_cfg extends uvm_object; uint pattgen_min_reps = RepsMinValue; uint pattgen_max_reps = RepsMaxValue; - uint pattgen_low_polarity_pct = 50; // in percentage uint pattgen_sync_channels_pct = 30; // in percentage // for error_vseq diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv index 1bda54940af09..de61203c0b8ba 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv @@ -426,10 +426,6 @@ function pattgen_channel_cfg pattgen_base_vseq::get_random_channel_config(uint c ch_cfg.inactive_level_disabled_c.constraint_mode(0); end `DV_CHECK_RANDOMIZE_WITH_FATAL(ch_cfg, - ch_cfg.polarity dist { - 1'b0 :/ cfg.seq_cfg.pattgen_low_polarity_pct, - 1'b1 :/ (100 - cfg.seq_cfg.pattgen_low_polarity_pct) - }; ch_cfg.data[31:0] dist { DataMax :/ cfg.seq_cfg.data_top_pct, DataMin :/ cfg.seq_cfg.data_bottom_pct, diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_cnt_rollover_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_cnt_rollover_vseq.sv index 8f2aa211a9560..3bbf4fa5f861c 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_cnt_rollover_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_cnt_rollover_vseq.sv @@ -20,10 +20,6 @@ class pattgen_cnt_rollover_vseq extends pattgen_base_vseq; pattgen_channel_cfg ch_cfg; ch_cfg = pattgen_channel_cfg::type_id::create($sformatf("channel_cfg_%0d", channel)); `DV_CHECK_RANDOMIZE_WITH_FATAL(ch_cfg, - polarity dist { - 1'b0 :/ cfg.seq_cfg.pattgen_low_polarity_pct, - 1'b1 :/ (100 - cfg.seq_cfg.pattgen_low_polarity_pct) - }; prediv dist {0 :/ 1, [1 : 'hfffe] :/ 1, 'hffff :/ 1}; len dist {0 :/ 1, [1 : 'he] :/ 1, 'hf :/ 1}; reps dist {0 :/ 1, [1 : 'h3e] :/ 1, 'h3f :/ 1}; diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv index 4682e66fa1218..c1f68b6c4cad6 100644 --- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv +++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_perf_vseq.sv @@ -19,10 +19,6 @@ class pattgen_perf_vseq extends pattgen_base_vseq; pattgen_channel_cfg ch_cfg; ch_cfg = pattgen_channel_cfg::type_id::create($sformatf("channel_cfg_%0d", channel)); `DV_CHECK_RANDOMIZE_WITH_FATAL(ch_cfg, - ch_cfg.polarity dist { - 1'b0 :/ cfg.seq_cfg.pattgen_low_polarity_pct, - 1'b1 :/ (100 - cfg.seq_cfg.pattgen_low_polarity_pct) - }; ch_cfg.prediv dist {0 :/ 1, 1024 :/ 1}; ch_cfg.len dist {0 :/ 1, 1023 :/ 1}; ch_cfg.reps dist {0 :/ 1, 63 :/ 1};