diff --git a/src/integration/tb/caliptra_top_tb_services.sv b/src/integration/tb/caliptra_top_tb_services.sv index 69349e3ff..8534e5660 100644 --- a/src/integration/tb/caliptra_top_tb_services.sv +++ b/src/integration/tb/caliptra_top_tb_services.sv @@ -246,6 +246,7 @@ module caliptra_top_tb_services // 8'he7 - Reset mailbox out-of-order flag when non-fatal error is masked (allows the test to continue) // 8'he8 - Enable scan mode when DOE fsm transitions to done state // 8'he9 - Force dmi_reg_en input to clk gate to emulate JTAG accesses + // 8'hea - Set random values to WDT timer1 and timer2 // 8'heb - Inject fatal error // 8'hec - Inject randomized UDS test vector // 8'hed - Inject randomized FE test vector @@ -832,11 +833,13 @@ endgenerate //IV_NO set_wdt_timer2_period <= 'b0; end else begin - if(caliptra_top_dut.soc_ifc_top1.i_wdt.wdt_timer1_timeout_serviced) begin - set_wdt_timer1_period <= 'b1; - end - if(caliptra_top_dut.soc_ifc_top1.i_wdt.wdt_timer2_timeout_serviced) begin - set_wdt_timer2_period <= 'b1; + if (!UVM_TB) begin + if(caliptra_top_dut.soc_ifc_top1.i_wdt.wdt_timer1_timeout_serviced) begin + set_wdt_timer1_period <= 'b1; + end + if(caliptra_top_dut.soc_ifc_top1.i_wdt.wdt_timer2_timeout_serviced) begin + set_wdt_timer2_period <= 'b1; + end end if(reset_wdt_timer_period) begin set_wdt_timer1_period <= 'b0; @@ -849,15 +852,25 @@ endgenerate //IV_NO if(set_wdt_timer1_period) begin force caliptra_top_dut.soc_ifc_top1.timer1_timeout_period = 64'hFFFFFFFF_FFFFFFFF; end - else begin + else if(reset_wdt_timer_period) begin release caliptra_top_dut.soc_ifc_top1.timer1_timeout_period; end + if(set_wdt_timer2_period) begin force caliptra_top_dut.soc_ifc_top1.timer2_timeout_period = 64'hFFFFFFFF_FFFFFFFF; end - else begin + else if(reset_wdt_timer_period) begin release caliptra_top_dut.soc_ifc_top1.timer2_timeout_period; end + + end + + always @(negedge clk) begin + if((WriteData[7:0] == 8'hea) && mailbox_write) begin + force caliptra_top_dut.soc_ifc_top1.timer1_timeout_period = {32'h0000_0000, $urandom_range(32'h0000_0001,32'h0000_0FFF)}; + force caliptra_top_dut.soc_ifc_top1.timer2_timeout_period = {32'h0000_0000, $urandom_range(32'h0000_0001,32'h0000_0FFF)}; + end + //Use 'hF1 code to reset these values in the test end diff --git a/src/integration/test_suites/caliptra_fmc/caliptra_isr.h b/src/integration/test_suites/caliptra_fmc/caliptra_isr.h index 8f5779e04..542d6572b 100644 --- a/src/integration/test_suites/caliptra_fmc/caliptra_isr.h +++ b/src/integration/test_suites/caliptra_fmc/caliptra_isr.h @@ -185,6 +185,14 @@ inline void service_soc_ifc_error_intr() { *reg = SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_MBOX_ECC_UNC_STS_MASK; cptra_intr_rcv.soc_ifc_error |= SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_MBOX_ECC_UNC_STS_MASK; } + if (sts & SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER1_TIMEOUT_STS_MASK) { + *reg = SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER1_TIMEOUT_STS_MASK; + cptra_intr_rcv.soc_ifc_error |= SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER1_TIMEOUT_STS_MASK; + } + if (sts & SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER2_TIMEOUT_STS_MASK) { + *reg = SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER2_TIMEOUT_STS_MASK; + cptra_intr_rcv.soc_ifc_error |= SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER2_TIMEOUT_STS_MASK; + } if (sts == 0) { VPRINTF(ERROR,"bad soc_ifc_error_intr sts:%x\n", sts); SEND_STDOUT_CTRL(0x1); diff --git a/src/integration/test_suites/caliptra_rt/caliptra_rt.c b/src/integration/test_suites/caliptra_rt/caliptra_rt.c index 3dc4992f1..ad67a366e 100644 --- a/src/integration/test_suites/caliptra_rt/caliptra_rt.c +++ b/src/integration/test_suites/caliptra_rt/caliptra_rt.c @@ -92,6 +92,12 @@ void nmi_handler() { SEND_STDOUT_CTRL(0x1); } } + else { + VPRINTF(LOW, "In NMI handler\n"); + if (lsu_read_32(CLP_SOC_IFC_REG_CPTRA_HW_ERROR_FATAL) & SOC_IFC_REG_CPTRA_HW_ERROR_FATAL_NMI_PIN_MASK) + VPRINTF(LOW, "Saw hw_error_fatal.nmi_pin assertion\n"); + while(1); + } } void caliptra_rt() { @@ -107,6 +113,12 @@ void caliptra_rt() { uint32_t loop_iter; uint32_t temp; // multi-purpose variable + //WDT vars + int i; + int wdt_rand_t1_val; + int wdt_rand_t2_val; + int mode; + VPRINTF(MEDIUM, "----------------------------------\n"); VPRINTF(LOW, "- Caliptra Validation RT!!\n" ); VPRINTF(MEDIUM, "----------------------------------\n"); @@ -117,6 +129,43 @@ void caliptra_rt() { // Runtime flow -- set ready for RT soc_ifc_set_flow_status_field(SOC_IFC_REG_CPTRA_FLOW_STATUS_READY_FOR_RUNTIME_MASK); + VPRINTF(LOW, "Enabling WDT intr\n"); + lsu_write_32(CLP_SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTR_EN_R, SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTR_EN_R_ERROR_WDT_TIMER1_TIMEOUT_EN_MASK | SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTR_EN_R_ERROR_WDT_TIMER2_TIMEOUT_EN_MASK); + + wdt_rand_t1_val = rand() % 0xfff; + wdt_rand_t2_val = rand() % 0xfff; + mode = rand() % 2; //0 - independent mode, 1 - cascade mode + if (mode){ + VPRINTF(LOW, "Restarting WDT in cascade mode (only t1 timeout)\n"); + //TODO also add t2 timeout (NMI event) + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER1_EN, SOC_IFC_REG_CPTRA_WDT_TIMER1_EN_TIMER1_EN_MASK); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER1_TIMEOUT_PERIOD_0, wdt_rand_t1_val); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER1_TIMEOUT_PERIOD_1, 0x00000000); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER1_CTRL, SOC_IFC_REG_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART_MASK); + } + else { + VPRINTF(LOW, "Restarting WDT in independent mode\n"); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER1_EN, SOC_IFC_REG_CPTRA_WDT_TIMER1_EN_TIMER1_EN_MASK); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER1_TIMEOUT_PERIOD_0, wdt_rand_t1_val); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER1_TIMEOUT_PERIOD_1, 0x00000000); + + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER2_EN, SOC_IFC_REG_CPTRA_WDT_TIMER2_EN_TIMER2_EN_MASK); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER2_TIMEOUT_PERIOD_0, wdt_rand_t2_val); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER2_TIMEOUT_PERIOD_1, 0x00000000); + + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER1_CTRL, SOC_IFC_REG_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART_MASK); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER2_CTRL, SOC_IFC_REG_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART_MASK); + + while (!(lsu_read_32(CLP_SOC_IFC_REG_CPTRA_WDT_STATUS) & SOC_IFC_REG_CPTRA_WDT_STATUS_T1_TIMEOUT_MASK)); + //Reset timer period to avoid hangs in test + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER1_TIMEOUT_PERIOD_0, 0xffffffff); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER1_TIMEOUT_PERIOD_1, 0xffffffff); + + while (!(lsu_read_32(CLP_SOC_IFC_REG_CPTRA_WDT_STATUS) & SOC_IFC_REG_CPTRA_WDT_STATUS_T2_TIMEOUT_MASK)); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER2_TIMEOUT_PERIOD_0, 0xffffffff); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER2_TIMEOUT_PERIOD_1, 0xffffffff); + + } // Initialization init_interrupts(); diff --git a/src/integration/test_suites/caliptra_top/caliptra_isr.h b/src/integration/test_suites/caliptra_top/caliptra_isr.h index 8f5779e04..542d6572b 100644 --- a/src/integration/test_suites/caliptra_top/caliptra_isr.h +++ b/src/integration/test_suites/caliptra_top/caliptra_isr.h @@ -185,6 +185,14 @@ inline void service_soc_ifc_error_intr() { *reg = SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_MBOX_ECC_UNC_STS_MASK; cptra_intr_rcv.soc_ifc_error |= SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_MBOX_ECC_UNC_STS_MASK; } + if (sts & SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER1_TIMEOUT_STS_MASK) { + *reg = SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER1_TIMEOUT_STS_MASK; + cptra_intr_rcv.soc_ifc_error |= SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER1_TIMEOUT_STS_MASK; + } + if (sts & SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER2_TIMEOUT_STS_MASK) { + *reg = SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER2_TIMEOUT_STS_MASK; + cptra_intr_rcv.soc_ifc_error |= SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER2_TIMEOUT_STS_MASK; + } if (sts == 0) { VPRINTF(ERROR,"bad soc_ifc_error_intr sts:%x\n", sts); SEND_STDOUT_CTRL(0x1); diff --git a/src/integration/test_suites/caliptra_top/caliptra_top.c b/src/integration/test_suites/caliptra_top/caliptra_top.c index 79c02eca0..d1ebee1a0 100644 --- a/src/integration/test_suites/caliptra_top/caliptra_top.c +++ b/src/integration/test_suites/caliptra_top/caliptra_top.c @@ -69,6 +69,8 @@ void main() { VPRINTF(MEDIUM, "----------------------------------\n"); // TODO other init tasks? (interrupts later) + VPRINTF(LOW, "Starting WDT in cascade mode\n"); + lsu_write_32(CLP_SOC_IFC_REG_CPTRA_WDT_TIMER1_EN, SOC_IFC_REG_CPTRA_WDT_TIMER1_EN_TIMER1_EN_MASK); //Check the reset reason FIXME (as soc_ifc fn) reset_reason = lsu_read_32(CLP_SOC_IFC_REG_CPTRA_RESET_REASON); diff --git a/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/sequences/caliptra_top_sequences_pkg.sv b/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/sequences/caliptra_top_sequences_pkg.sv index d83fd278f..b045cc380 100644 --- a/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/sequences/caliptra_top_sequences_pkg.sv +++ b/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/sequences/caliptra_top_sequences_pkg.sv @@ -72,6 +72,7 @@ package caliptra_top_sequences_pkg; `include "src/caliptra_top_rand_sequence.svh" `include "src/caliptra_top_cmdline_sequence.svh" `include "src/caliptra_top_rom_sequence.svh" + `include "src/caliptra_top_wdt_sequence.svh" // pragma uvmf custom package_item_additional end endpackage diff --git a/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/sequences/src/caliptra_top_wdt_sequence.svh b/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/sequences/src/caliptra_top_wdt_sequence.svh new file mode 100644 index 000000000..4f38ab7d5 --- /dev/null +++ b/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/sequences/src/caliptra_top_wdt_sequence.svh @@ -0,0 +1,179 @@ +//---------------------------------------------------------------------- +// Created with uvmf_gen version 2022.3 +//---------------------------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// pragma uvmf custom header begin +// pragma uvmf custom header end +//---------------------------------------------------------------------- +// +//---------------------------------------------------------------------- +// +// DESCRIPTION: This file contains the top level sequence used in caliptra_top_wdt_test. +// +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +// + +class caliptra_top_wdt_sequence extends caliptra_top_bench_sequence_base; + + `uvm_object_utils( caliptra_top_wdt_sequence ); + + rand soc_ifc_env_bringup_sequence_t soc_ifc_env_bringup_seq; + rand soc_ifc_env_pauser_init_sequence_t soc_ifc_env_pauser_init_seq; + rand soc_ifc_env_mbox_real_fw_sequence_t soc_ifc_env_mbox_fmc_seq; + rand soc_ifc_env_mbox_real_fw_sequence_t soc_ifc_env_mbox_rt_seq; + rand soc_ifc_env_reset_warm_sequence_t soc_ifc_env_reset_warm_seq; + rand soc_ifc_env_reset_cold_sequence_t soc_ifc_env_reset_cold_seq; + // Local handle to register model for convenience + soc_ifc_reg_model_top reg_model; + + + rand int iteration_count; + int sts_rsp_count = 0; + int rsp_count = 0; + + + function new(string name = "" ); + super.new(name); + reg_model = top_configuration.soc_ifc_subenv_config.soc_ifc_rm; + endfunction + + // **************************************************************************** + virtual task run_firmware_init(soc_ifc_env_mbox_real_fw_sequence_t fmc_seq, soc_ifc_env_mbox_real_fw_sequence_t rt_seq); + bit ready_for_fw = 0; + bit ready_for_rt = 0; + while (!ready_for_fw) begin + while(!sts_rsp_count)soc_ifc_subenv_soc_ifc_ctrl_agent_config.wait_for_num_clocks(1); // Wait for new status updates + `uvm_info("CALIPTRA_TOP_WDT_TEST", "Observed status response, checking contents", UVM_DEBUG) + sts_rsp_count = 0; // We only care about the latest rsp, so even if count > 1, reset back to 0 + ready_for_fw = soc_ifc_subenv_soc_ifc_status_agent_responder_seq.rsp.ready_for_fw_push; + end + if (!fmc_seq.randomize() with { fmc_seq.mbox_op_rand.cmd == mbox_cmd_e'(MBOX_CMD_FMC_UPDATE); }) + `uvm_fatal("CALIPTRA_TOP_WDT_TEST", "caliptra_top_wdt_sequence::body() - fmc_seq randomization failed") + fmc_seq.start(top_configuration.soc_ifc_subenv_config.vsqr); + if (!rt_seq.randomize() with { rt_seq.mbox_op_rand.cmd == mbox_cmd_e'(MBOX_CMD_RT_UPDATE); }) + `uvm_fatal("CALIPTRA_TOP_WDT_TEST", "caliptra_top_wdt_sequence::body() - rt_seq randomization failed") + rt_seq.start(top_configuration.soc_ifc_subenv_config.vsqr); + + // Wait for RT image to set the ready_for_rt bit + while (!ready_for_rt) begin + while(!sts_rsp_count)soc_ifc_subenv_soc_ifc_ctrl_agent_config.wait_for_num_clocks(1); // Wait for new status updates + `uvm_info("CALIPTRA_TOP_WDT_TEST", "Observed status response, checking contents", UVM_DEBUG) + sts_rsp_count = 0; // We only care about the latest rsp, so even if count > 1, reset back to 0 + ready_for_rt = soc_ifc_subenv_soc_ifc_status_agent_responder_seq.rsp.ready_for_runtime; + end + endtask + + // **************************************************************************** + virtual task body(); + // pragma uvmf custom body begin + // Construct sequences here + bit pauser_valid_initialized = 1'b0; + uvm_object obj; + int ii; + bit nmi_intr; + bit hw_error_fatal; + uvm_status_e reg_sts; + uvm_reg_data_t wdt_status_data; + + caliptra_top_env_seq = caliptra_top_env_sequence_base_t::type_id::create("caliptra_top_env_seq"); + soc_ifc_env_bringup_seq = soc_ifc_env_bringup_sequence_t::type_id::create("soc_ifc_env_bringup_seq"); + soc_ifc_env_pauser_init_seq = soc_ifc_env_pauser_init_sequence_t::type_id::create("soc_ifc_env_pauser_init_seq"); + soc_ifc_env_mbox_fmc_seq = soc_ifc_env_mbox_real_fw_sequence_t::type_id::create("soc_ifc_env_mbox_fmc_seq"); + soc_ifc_env_mbox_rt_seq = soc_ifc_env_mbox_real_fw_sequence_t::type_id::create("soc_ifc_env_mbox_rt_seq"); + soc_ifc_env_reset_warm_seq = soc_ifc_env_reset_warm_sequence_t::type_id::create("soc_ifc_env_reset_warm_seq"); + soc_ifc_env_reset_cold_seq = soc_ifc_env_reset_cold_sequence_t::type_id::create("soc_ifc_env_reset_cold_seq"); + + soc_ifc_subenv_soc_ifc_ctrl_agent_random_seq = soc_ifc_subenv_soc_ifc_ctrl_agent_random_seq_t::type_id::create("soc_ifc_subenv_soc_ifc_ctrl_agent_random_seq"); + soc_ifc_subenv_soc_ifc_status_agent_responder_seq = soc_ifc_subenv_soc_ifc_status_agent_responder_seq_t::type_id::create("soc_ifc_subenv_soc_ifc_status_agent_responder_seq"); + soc_ifc_subenv_mbox_sram_agent_responder_seq = soc_ifc_subenv_mbox_sram_agent_responder_seq_t::type_id::create("soc_ifc_subenv_mbox_sram_agent_responder_seq"); + + // Handle to the responder sequence for getting response transactions + soc_ifc_env_bringup_seq.soc_ifc_status_agent_rsp_seq = soc_ifc_subenv_soc_ifc_status_agent_responder_seq; + soc_ifc_env_pauser_init_seq.soc_ifc_status_agent_rsp_seq = soc_ifc_subenv_soc_ifc_status_agent_responder_seq; + soc_ifc_env_mbox_fmc_seq.soc_ifc_status_agent_rsp_seq = soc_ifc_subenv_soc_ifc_status_agent_responder_seq; + soc_ifc_env_mbox_rt_seq.soc_ifc_status_agent_rsp_seq = soc_ifc_subenv_soc_ifc_status_agent_responder_seq; + soc_ifc_env_reset_warm_seq.soc_ifc_status_agent_rsp_seq = soc_ifc_subenv_soc_ifc_status_agent_responder_seq; + soc_ifc_env_reset_cold_seq.soc_ifc_status_agent_rsp_seq = soc_ifc_subenv_soc_ifc_status_agent_responder_seq; + + reg_model.reset(); + // Start RESPONDER sequences here + fork + soc_ifc_subenv_soc_ifc_status_agent_responder_seq.start(soc_ifc_subenv_soc_ifc_status_agent_sequencer); + soc_ifc_subenv_mbox_sram_agent_responder_seq.start(soc_ifc_subenv_mbox_sram_agent_sequencer); + join_none + + fork + forever @(soc_ifc_subenv_soc_ifc_status_agent_responder_seq.new_rsp) begin + sts_rsp_count++; + rsp_count++; + end + join_none + + if(!soc_ifc_env_bringup_seq.randomize()) + `uvm_fatal("CALIPTRA_TOP_WDT_TEST", "caliptra_top_wdt_sequence::body() - soc_ifc_env_bringup_seq randomization failed") + soc_ifc_env_bringup_seq.start(top_configuration.soc_ifc_subenv_config.vsqr); + + `uvm_info("CALIPTRA_TOP_BRINGUP", "SoC completed poweron and observed reset deassertion to system", UVM_LOW) + + run_firmware_init(soc_ifc_env_mbox_fmc_seq,soc_ifc_env_mbox_rt_seq); + + // //-------------------------------- + // //Wait for NMI to occur - TODO + // `uvm_info("KNU", $sformatf("FW init done, hw_error_fatal = %0d", hw_error_fatal),UVM_MEDIUM); + // while (!hw_error_fatal) begin + // `uvm_info("KNU", "Inside while loop",UVM_MEDIUM); + // while(!rsp_count)soc_ifc_subenv_soc_ifc_ctrl_agent_config.wait_for_num_clocks(1); // Wait for new status updates + // `uvm_info("CALIPTRA_TOP_WDT_TEST", "Observed status response, checking contents", UVM_MEDIUM) + // `uvm_info("CALIPTRA_TOP_WDT_TEST", soc_ifc_subenv_soc_ifc_status_agent_responder_seq.rsp.convert2string(), UVM_MEDIUM) + // // `uvm_info("CALIPTRA_TOP_WDT_TEST", $sformatf("response error fatal = %0d",soc_ifc_subenv_soc_ifc_status_agent_responder_seq.rsp.cptra_error_fatal_intr_pending), UVM_MEDIUM) + // rsp_count = 0; // We only care about the latest rsp, so even if count > 1, reset back to 0 + // hw_error_fatal = soc_ifc_subenv_soc_ifc_status_agent_responder_seq.rsp.cptra_error_fatal_intr_pending; + // end + // `uvm_info("KNU", $sformatf("Outside while loop, hw_error_fatal = %h", hw_error_fatal),UVM_MEDIUM); + + // // //TODO: add APB seq to read hw_error_fatal reg to see if it's NMI or not + // `uvm_info("CALIPTRA_TOP_WDT_TEST", "Encountered NMI, issuing reset", UVM_MEDIUM); + // //soc_ifc_env_bringup_seq.start(top_configuration.soc_ifc_subenv_config.vsqr); + // reg_model.reset(); //TODO needed? + // // if (!soc_ifc_env_reset_cold_seq.randomize()) + // // `uvm_fatal("CALIPTRA_TOP_WDT_TEST", "caliptra_top_wdt_sequence::body() - soc_ifc_env_bringup_seq randomization failed") + // // soc_ifc_env_reset_cold_seq.start(top_configuration.soc_ifc_subenv_config.vsqr); + // // reg_model.reset(); //TODO needed? + // if(!soc_ifc_env_bringup_seq.randomize()) + // `uvm_fatal("CALIPTRA_TOP_WDT_TEST", "caliptra_top_wdt_sequence::body() - soc_ifc_env_bringup_seq randomization failed") + // soc_ifc_env_bringup_seq.start(top_configuration.soc_ifc_subenv_config.vsqr); + //-------------------------------- + + // UVMF_CHANGE_ME : Extend the simulation XXX number of clocks after + // the last sequence to allow for the last sequence item to flow + // through the design. + fork + soc_ifc_subenv_soc_ifc_ctrl_agent_config.wait_for_num_clocks(10000); + soc_ifc_subenv_cptra_ctrl_agent_config.wait_for_num_clocks(10000); + soc_ifc_subenv_soc_ifc_status_agent_config.wait_for_num_clocks(10000); + soc_ifc_subenv_cptra_status_agent_config.wait_for_num_clocks(10000); + soc_ifc_subenv_mbox_sram_agent_config.wait_for_num_clocks(10000); + join + + // pragma uvmf custom body end + endtask + +endclass + +// pragma uvmf custom external begin +// pragma uvmf custom external end + diff --git a/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/tests/caliptra_top_tests_pkg.sv b/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/tests/caliptra_top_tests_pkg.sv index 4523e9579..051084252 100644 --- a/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/tests/caliptra_top_tests_pkg.sv +++ b/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/tests/caliptra_top_tests_pkg.sv @@ -65,6 +65,7 @@ package caliptra_top_tests_pkg; `include "src/register_test.svh" `include "src/example_derived_test.svh" `include "src/caliptra_top_rand_test.svh" + `include "src/caliptra_top_wdt_test.svh" `include "src/caliptra_top_cmdline_test.svh" `include "src/caliptra_top_rom_test.svh" diff --git a/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/tests/src/caliptra_top_wdt_test.svh b/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/tests/src/caliptra_top_wdt_test.svh new file mode 100644 index 000000000..504820b6c --- /dev/null +++ b/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/tests/src/caliptra_top_wdt_test.svh @@ -0,0 +1,72 @@ +//---------------------------------------------------------------------- +// Created with uvmf_gen version 2022.3 +//---------------------------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// pragma uvmf custom header begin +// pragma uvmf custom header end +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +// +// DESCRIPTION: This test extends test_top and makes +// changes to test_top using the UVM factory type_override: +// +// Test scenario: +// Randomized activity to Caliptra +// +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +// + +class caliptra_top_wdt_test extends test_top; + + `uvm_component_utils( caliptra_top_wdt_test ); + + function new( string name = "", uvm_component parent = null ); + super.new( name, parent ); + endfunction + + virtual function void build_phase(uvm_phase phase); + // The factory override below is an example of how to replace the caliptra_top_bench_sequence_base + // sequence with the example_derived_test_sequence. + caliptra_top_bench_sequence_base::type_id::set_type_override(caliptra_top_wdt_sequence::get_type()); + // Execute the build_phase of test_top AFTER all factory overrides have been created. + super.build_phase(phase); + // pragma uvmf custom configuration_settings_post_randomize begin + // UVMF_CHANGE_ME Test specific configuration values can be set here. + // The configuration structure has already been randomized. + // pragma uvmf custom configuration_settings_post_randomize end + endfunction + + // FIXME this disables uvm_warning messages! We should fix the warnings, but for + // now this reduces sim.log (for regressions) to a manageable level + // NOTE: UVM_WARNING now re-enabled, need to clean this up after some regression cycles + virtual function void start_of_simulation_phase(uvm_phase phase); + super.start_of_simulation_phase(phase); + if ($test$plusargs("CLP_REGRESSION")) begin + uvm_top.set_report_verbosity_level_hier(UVM_NONE); +// this.environment.soc_ifc_subenv.soc_ifc_pred.set_report_severity_action(UVM_WARNING,UVM_NO_ACTION); +// this.environment.soc_ifc_subenv.soc_ifc_sb.set_report_severity_action(UVM_WARNING,UVM_NO_ACTION); + // Since en_sb is recently set to 0, this is unavailable and gives null-object + //this.environment.soc_ifc_subenv.qvip_apb5_slave_subenv.apb5_master_0.get_analysis_component("checker").set_report_severity_id_action(UVM_WARNING,"scoreboard_debug",UVM_NO_ACTION); + end + endfunction + +endclass + +// pragma uvmf custom external begin +// pragma uvmf custom external end + + diff --git a/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/tests/src/caliptra_top_wdt_test.yml b/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/tests/src/caliptra_top_wdt_test.yml new file mode 100644 index 000000000..1f1af25ad --- /dev/null +++ b/src/integration/uvmf_caliptra_top/uvmf_template_output/project_benches/caliptra_top/tb/tests/src/caliptra_top_wdt_test.yml @@ -0,0 +1,6 @@ +--- +# Random seed desired... +seed: ${PLAYBOOK_RANDOM_SEED} +plusargs: +- '+UVM_TESTNAME=caliptra_top_wdt_test' +testname: caliptra_top_wdt_test diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/registers/soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/registers/soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART.svh new file mode 100644 index 000000000..bb2af36b0 --- /dev/null +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/registers/soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART.svh @@ -0,0 +1,82 @@ +//---------------------------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------- + +class soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART extends uvm_reg_cbs; + + `uvm_object_utils(soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART) + + string AHB_map_name = "soc_ifc_AHB_map"; + string APB_map_name = "soc_ifc_APB_map"; + + // Function: post_predict + // + // Called by the method + // after a successful UVM_PREDICT_READ or UVM_PREDICT_WRITE prediction. + // + // ~previous~ is the previous value in the mirror and + // ~value~ is the latest predicted value. Any change to ~value~ will + // modify the predicted mirror value. + // + virtual function void post_predict(input uvm_reg_field fld, + input uvm_reg_data_t previous, + inout uvm_reg_data_t value, + input uvm_predict_e kind, + input uvm_path_e path, + input uvm_reg_map map); + // uvm_reg_block rm; + // string event_name; + // uvm_reg sts_reg; + // uvm_reg_field sts_fld; + + // rm = fld.get_parent().get_parent(); /* intr_block_rf_ext */ + // // Get a base-name for the event by truncating the '_trig' suffix + // event_name = fld.get_name().substr(0,fld.get_name().len()-6); + // sts_reg = rm.get_reg_by_name("error_internal_intr_r"); + // sts_fld = sts_reg.get_field_by_name({event_name, "_sts"}); + + if (map.get_name() == this.APB_map_name) begin + if (kind == UVM_PREDICT_WRITE) + `uvm_warning("SOC_IFC_REG_CBS", "Unexpected write to WDT_TIMER1_CTRL register through APB interface!") + else + `uvm_info("SOC_IFC_REG_CBS", "Unexpected read to WDT_TIMER1_CTRL register through APB interface!", UVM_LOW) + end + `uvm_info("SOC_IFC_REG_CBS", $sformatf("Access to %s with path %p", fld.get_full_name(), path), UVM_FULL) + + if (kind == UVM_PREDICT_WRITE) begin + // On rising edge of field trigger value, predict interrupt status will + // be set + if (value & ~previous) begin + `uvm_info("SOC_IFC_REG_CBS", {"Predicted update to ", fld.get_name()}, UVM_MEDIUM) + // - Use UVM_PREDICT_READ kind so that all the callbacks associated with + // notif__sts are also called to detect interrupt pin assertion + // - Use UVM_PREDICT_READ instead of UVM_PREDICT_WRITE so that + // "do_predict" bypasses the access-check and does not enforce W1C + // behavior on this attempt to set interrupt status to 1 + end + + // Because WDT timer restart is single-pulse, it should auto-clear immediately on + // being written. + // So set predicted value to 0. + value = 0; + `uvm_info("SOC_IFC_REG_CBS", + $sformatf("Write to %s results in mirrored value forcibly predicted to [%x]", + fld.get_name(), + value), + UVM_HIGH) + end + endfunction + +endclass diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/registers/soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/registers/soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART.svh new file mode 100644 index 000000000..129a5e19c --- /dev/null +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/registers/soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART.svh @@ -0,0 +1,82 @@ +//---------------------------------------------------------------------- +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//---------------------------------------------------------------------- + +class soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART extends uvm_reg_cbs; + + `uvm_object_utils(soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART) + + string AHB_map_name = "soc_ifc_AHB_map"; + string APB_map_name = "soc_ifc_APB_map"; + + // Function: post_predict + // + // Called by the method + // after a successful UVM_PREDICT_READ or UVM_PREDICT_WRITE prediction. + // + // ~previous~ is the previous value in the mirror and + // ~value~ is the latest predicted value. Any change to ~value~ will + // modify the predicted mirror value. + // + virtual function void post_predict(input uvm_reg_field fld, + input uvm_reg_data_t previous, + inout uvm_reg_data_t value, + input uvm_predict_e kind, + input uvm_path_e path, + input uvm_reg_map map); + // uvm_reg_block rm; + // string event_name; + // uvm_reg sts_reg; + // uvm_reg_field sts_fld; + + // rm = fld.get_parent().get_parent(); /* intr_block_rf_ext */ + // // Get a base-name for the event by truncating the '_trig' suffix + // event_name = fld.get_name().substr(0,fld.get_name().len()-6); + // sts_reg = rm.get_reg_by_name("error_internal_intr_r"); + // sts_fld = sts_reg.get_field_by_name({event_name, "_sts"}); + + if (map.get_name() == this.APB_map_name) begin + if (kind == UVM_PREDICT_WRITE) + `uvm_warning("SOC_IFC_REG_CBS", "Unexpected write to WDT_TIMER2_CTRL register through APB interface!") + else + `uvm_info("SOC_IFC_REG_CBS", "Unexpected read to WDT_TIMER2_CTRL register through APB interface!", UVM_LOW) + end + `uvm_info("SOC_IFC_REG_CBS", $sformatf("Access to %s with path %p", fld.get_full_name(), path), UVM_FULL) + + if (kind == UVM_PREDICT_WRITE) begin + // On rising edge of field trigger value, predict interrupt status will + // be set + if (value & ~previous) begin + `uvm_info("SOC_IFC_REG_CBS", {"Predicted update to ", fld.get_name(), " triggers interrupt output pin assertion"}, UVM_MEDIUM) + // - Use UVM_PREDICT_READ kind so that all the callbacks associated with + // notif__sts are also called to detect interrupt pin assertion + // - Use UVM_PREDICT_READ instead of UVM_PREDICT_WRITE so that + // "do_predict" bypasses the access-check and does not enforce W1C + // behavior on this attempt to set interrupt status to 1 + end + + // Because WDT timer restart is single-pulse, it should auto-clear immediately on + // being written. + // So set predicted value to 0. + value = 0; + `uvm_info("SOC_IFC_REG_CBS", + $sformatf("Write to %s results in mirrored value forcibly predicted to [%x]", + fld.get_name(), + value), + UVM_HIGH) + end + endfunction + +endclass diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/registers/soc_ifc_reg_model_top_pkg.sv b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/registers/soc_ifc_reg_model_top_pkg.sv index 2c0a0ffa8..5722d9c89 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/registers/soc_ifc_reg_model_top_pkg.sv +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/registers/soc_ifc_reg_model_top_pkg.sv @@ -552,6 +552,8 @@ package soc_ifc_reg_model_top_pkg; `include "soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_REQ.svh" `include "soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_WR_DONE.svh" `include "soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_TRNG_VALID_PAUSER_PAUSER.svh" + `include "soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART.svh" + `include "soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART.svh" `include "soc_ifc_reg_cbs_soc_ifc_reg_secret.svh" `include "soc_ifc_reg_cbs_soc_ifc_reg_fuse.svh" `include "soc_ifc_reg_cbs_soc_ifc_reg_key.svh" @@ -694,6 +696,8 @@ package soc_ifc_reg_model_top_pkg; soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_REQ soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_REQ_cb; soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_WR_DONE soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_WR_DONE_cb; soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_TRNG_VALID_PAUSER_PAUSER soc_ifc_reg_CPTRA_TRNG_VALID_PAUSER_PAUSER_cb; + soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART soc_ifc_reg_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART_cb; + soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART soc_ifc_reg_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART_cb; soc_ifc_reg_cbs_soc_ifc_reg_secret soc_ifc_reg_secret_cb; soc_ifc_reg_cbs_soc_ifc_reg_fuse soc_ifc_reg_fuse_cb; @@ -802,6 +806,8 @@ package soc_ifc_reg_model_top_pkg; soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_REQ_cb = soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_REQ ::type_id::create("soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_REQ_cb" ); soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_WR_DONE_cb = soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_WR_DONE::type_id::create("soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_WR_DONE_cb"); soc_ifc_reg_CPTRA_TRNG_VALID_PAUSER_PAUSER_cb = soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_TRNG_VALID_PAUSER_PAUSER::type_id::create("soc_ifc_reg_CPTRA_TRNG_VALID_PAUSER_PAUSER_cb"); + soc_ifc_reg_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART_cb = soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART::type_id::create("soc_ifc_reg_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART_cb"); + soc_ifc_reg_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART_cb = soc_ifc_reg_cbs_soc_ifc_reg_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART::type_id::create("soc_ifc_reg_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART_cb"); soc_ifc_reg_secret_cb = soc_ifc_reg_cbs_soc_ifc_reg_secret ::type_id::create("soc_ifc_reg_secret_cb"); soc_ifc_reg_fuse_cb = soc_ifc_reg_cbs_soc_ifc_reg_fuse ::type_id::create("soc_ifc_reg_fuse_cb"); @@ -921,6 +927,8 @@ package soc_ifc_reg_model_top_pkg; uvm_reg_field_cb::add(soc_ifc_reg_rm.CPTRA_TRNG_STATUS .DATA_WR_DONE, soc_ifc_reg_CPTRA_TRNG_STATUS_DATA_WR_DONE_cb ); uvm_reg_field_cb::add(soc_ifc_reg_rm.CPTRA_TRNG_VALID_PAUSER .PAUSER , soc_ifc_reg_CPTRA_TRNG_VALID_PAUSER_PAUSER_cb ); uvm_reg_field_cb::add(soc_ifc_reg_rm.CPTRA_TRNG_CTRL .clear , soc_ifc_reg_CPTRA_TRNG_CTRL_CLEAR_cb ); + uvm_reg_field_cb::add(soc_ifc_reg_rm.CPTRA_WDT_TIMER1_CTRL .timer1_restart, soc_ifc_reg_CPTRA_WDT_TIMER1_CTRL_TIMER1_RESTART_cb ); + uvm_reg_field_cb::add(soc_ifc_reg_rm.CPTRA_WDT_TIMER2_CTRL .timer2_restart, soc_ifc_reg_CPTRA_WDT_TIMER2_CTRL_TIMER2_RESTART_cb ); foreach (soc_ifc_reg_rm.fuse_uds_seed[ii]) uvm_reg_field_cb::add(soc_ifc_reg_rm.fuse_uds_seed[ii].seed , soc_ifc_reg_secret_cb); foreach (soc_ifc_reg_rm.fuse_field_entropy[ii]) uvm_reg_field_cb::add(soc_ifc_reg_rm.fuse_field_entropy[ii].seed , soc_ifc_reg_secret_cb); diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/src/soc_ifc_predictor.svh b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/src/soc_ifc_predictor.svh index 49a06b30c..529a09c6b 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/src/soc_ifc_predictor.svh +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/environment_packages/soc_ifc_env_pkg/src/soc_ifc_predictor.svh @@ -171,6 +171,7 @@ class soc_ifc_predictor #( bit sha_err_intr_pending = 1'b0; // TODO bit sha_notif_intr_pending = 1'b0; // TODO bit timer_intr_pending = 1'b1; + bit nmi_intr_pending = 1'b0; bit cptra_error_fatal = 1'b0; bit cptra_error_non_fatal = 1'b0; bit fuse_update_enabled = 1'b1; @@ -214,6 +215,15 @@ class soc_ifc_predictor #( reset_flag hard_reset_flag; reset_flag soft_reset_flag; + //WDT vars: + bit [63:0] t1_count, t2_count; + bit wdt_error_intr_sent; + bit wdt_t2_error_intr_sent; + bit wdt_nmi_intr_sent; + bit reset_wdt_count; + bit wdt_t1_restart; + bit wdt_t2_restart; + extern task poll_and_run_delay_jobs(); extern function void send_delayed_expected_transactions(); extern function bit check_mbox_no_lock_error(soc_ifc_sb_apb_ap_output_transaction_t txn, uvm_reg axs_reg); @@ -222,6 +232,8 @@ class soc_ifc_predictor #( extern task update_mtime_mirrors(); extern task mtime_counter_task(); extern function bit mtime_lt_mtimecmp(); + extern task wdt_counter_task(); + extern task wdt_counter_trial(); extern function bit valid_requester(input uvm_transaction txn); extern function bit valid_receiver(input uvm_transaction txn); extern function bit sha_valid_user(input uvm_transaction txn); @@ -276,6 +288,7 @@ class soc_ifc_predictor #( fork poll_and_run_delay_jobs(); mtime_counter_task(); + wdt_counter_task(); join_none super.run_phase(phase); endtask @@ -390,6 +403,7 @@ class soc_ifc_predictor #( bootfsm_breakpoint = t.set_bootfsm_breakpoint; send_soc_ifc_sts_txn = 1; send_cptra_sts_txn = 0; // cptra sts transaction not expected until after CPTRA_FUSE_WR_DONE + reset_wdt_count = 1'b0; end // Normal operation else begin @@ -629,6 +643,10 @@ class soc_ifc_predictor #( bit send_cptra_sts_txn = 0; bit send_ahb_txn = 1; bit send_apb_txn = 0; + bit wdt_cascade = 0; + bit wdt_independent = 0; + bit wdt_t1_timeout = 0; + bit wdt_t2_timeout = 0; ahb_slave_0_ae_debug = t; `uvm_info("PRED_AHB", "Transaction Received through ahb_slave_0_ae", UVM_MEDIUM) @@ -1206,19 +1224,47 @@ class soc_ifc_predictor #( `uvm_info("PRED_AHB", {"Read to ", axs_reg.get_name(), " has no effect on system"}, UVM_MEDIUM) end end - "CPTRA_WDT_TIMER1_EN", - "CPTRA_WDT_TIMER1_CTRL", + "CPTRA_WDT_TIMER1_EN": begin + if (ahb_txn.RnW == AHB_WRITE) begin + `uvm_info("PRED_AHB", {"Detected write to ", axs_reg.get_name()," register on AHB interface, starting WDT timer1"}, UVM_MEDIUM); + end + end + "CPTRA_WDT_TIMER1_CTRL": begin + if (ahb_txn.RnW == AHB_WRITE) begin + // Handled in callbacks via reg predictor + `uvm_info("PRED_AHB", $sformatf("Handling access to %s. This will restart WDT timer1", axs_reg.get_name()), UVM_MEDIUM); + //Capture restart bit so the counters can be updated + wdt_t1_restart = ahb_txn.data[0]; + end + end "CPTRA_WDT_TIMER1_TIMEOUT_PERIOD[0]", - "CPTRA_WDT_TIMER1_TIMEOUT_PERIOD[1]", - "CPTRA_WDT_TIMER2_EN", - "CPTRA_WDT_TIMER2_CTRL", + "CPTRA_WDT_TIMER1_TIMEOUT_PERIOD[1]": begin + if (ahb_txn.RnW == AHB_WRITE) begin + `uvm_info("PRED_AHB", {"Detected write to ", axs_reg.get_name()," register on AHB interface"}, UVM_MEDIUM); + end + end + "CPTRA_WDT_TIMER2_EN": begin + if (ahb_txn.RnW == AHB_WRITE) begin + `uvm_info("PRED_AHB", {"Detected write to ", axs_reg.get_name(), " register on AHB interface, starting WDT timer2"}, UVM_MEDIUM); + end + end + "CPTRA_WDT_TIMER2_CTRL": begin + if (ahb_txn.RnW == AHB_WRITE) begin + // Handled in callbacks via reg predictor + `uvm_info("PRED_AHB", $sformatf("Handling access to %s. This will restart WDT timer2", axs_reg.get_name()), UVM_MEDIUM); + //Capture restart bit so the counters can be updated + wdt_t2_restart = ahb_txn.data[0]; + end + end "CPTRA_WDT_TIMER2_TIMEOUT_PERIOD[0]", - "CPTRA_WDT_TIMER2_TIMEOUT_PERIOD[1]", - "CPTRA_WDT_STATUS": begin + "CPTRA_WDT_TIMER2_TIMEOUT_PERIOD[1]": begin if (ahb_txn.RnW == AHB_WRITE) begin - `uvm_error("PRED_AHB", {"Add prediction for write to ",axs_reg.get_name()," register on AHB interface"}) // TODO + `uvm_info("PRED_AHB", {"Detected write to ",axs_reg.get_name()," register on AHB interface"}, UVM_LOW) // TODO end end + "CPTRA_WDT_STATUS": begin + `uvm_info("PRED_AHB", "AHB access of WDT status\n", UVM_MEDIUM); + end "CPTRA_FUSE_VALID_PAUSER", "CPTRA_FUSE_PAUSER_LOCK": begin if (ahb_txn.RnW == AHB_WRITE) begin @@ -1366,6 +1412,30 @@ class soc_ifc_predictor #( // but this does not result in a cptra status transaction because we only // capture rising edges as a transaction `uvm_info("PRED_AHB", {"Write to ", axs_reg.get_name(), " attempts to clear an interrupt"}, UVM_HIGH) + + //If the WDT timeout interrupt bits are being cleared, also reset the t1/t2 count values and the corresponding + //interrupt flags (used in wdt_counter_task) + wdt_cascade = (p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER1_EN.timer1_en.get_mirrored_value() && !(p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER2_EN.timer2_en.get_mirrored_value())); + wdt_independent = p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER2_EN.timer2_en.get_mirrored_value(); + wdt_t1_timeout = (this.t1_count == {p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER1_TIMEOUT_PERIOD[1].timer1_timeout_period.get_mirrored_value(), p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER1_TIMEOUT_PERIOD[0].timer1_timeout_period.get_mirrored_value()}); + wdt_t2_timeout = (this.t2_count == {p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER2_TIMEOUT_PERIOD[1].timer2_timeout_period.get_mirrored_value(), p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER2_TIMEOUT_PERIOD[0].timer2_timeout_period.get_mirrored_value()}); + + if (wdt_cascade && wdt_t1_timeout && data_active[`SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER1_TIMEOUT_STS_LOW]) begin + this.t1_count = 'h0; + this.t2_count = 'h0; + this.wdt_error_intr_sent = 1'b0; + end + else if (wdt_independent) begin + if (wdt_t1_timeout && data_active[`SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER1_TIMEOUT_STS_LOW]) begin + this.t1_count = 'h0; + this.wdt_error_intr_sent = 1'b0; + end + if (wdt_t2_timeout && data_active[`SOC_IFC_REG_INTR_BLOCK_RF_ERROR_INTERNAL_INTR_R_ERROR_WDT_TIMER2_TIMEOUT_STS_LOW]) begin + this.t2_count = 'h0; + this.wdt_t2_error_intr_sent = 1'b0; + end + end + end end "error_internal_intr_count_r", @@ -2332,6 +2402,13 @@ function void soc_ifc_predictor::send_delayed_expected_transactions(); send_cptra_sts_txn = 1; end + // // Check for NMI Interrupt + // if (!nmi_intr_pending && p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_HW_ERROR_FATAL.nmi_pin.get_mirrored_value()) begin + // `uvm_info("PRED_DLY", "Delay job triggers nmi interrupt output", UVM_MEDIUM) + // nmi_intr_pending = 1'b1; + // send_cptra_sts_txn = 1'b1; + // end + // SHA Accel Notification Interrupt // Expect a status transition on sha_notif_intr_pending // whenever a write changes the value of SHA Accelerator Execute @@ -2624,6 +2701,143 @@ function bit soc_ifc_predictor::mtime_lt_mtimecmp(); return mtime < mtimecmp; endfunction +//If WDT is enabled via reg write, emulate behavior here +task soc_ifc_predictor::wdt_counter_task(); + forever begin + uvm_reg_data_t wdt_reg_data; + logic wdt_t1_en; + logic wdt_t2_en; + logic cascade, independent; + logic [63:0] wdt_t1_period, wdt_t2_period; + bit wdt_t1_restart_temp; + + cptra_sb_ap_output_transaction = cptra_sb_ap_output_transaction_t::type_id::create("cptra_sb_ap_output_transaction"); + + //Poll for WDT enable bits + wdt_reg_data = p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER1_EN.timer1_en.get(); //_mirrored_value(); + wdt_t1_en = wdt_reg_data[0]; + + wdt_reg_data = p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER2_EN.timer2_en.get(); //_mirrored_value(); + wdt_t2_en = wdt_reg_data[0]; + + cascade = (wdt_t1_en && !wdt_t2_en); + independent = wdt_t2_en; + + wdt_reg_data = p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER1_TIMEOUT_PERIOD[0].timer1_timeout_period.get(); + wdt_t1_period[31:0] = wdt_reg_data[31:0]; + wdt_reg_data = p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER1_TIMEOUT_PERIOD[1].timer1_timeout_period.get(); + wdt_t1_period[63:32] = wdt_reg_data[31:0]; + + wdt_reg_data = p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER2_TIMEOUT_PERIOD[0].timer2_timeout_period.get(); + wdt_t2_period[31:0] = wdt_reg_data[31:0]; + wdt_reg_data = p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_WDT_TIMER2_TIMEOUT_PERIOD[1].timer2_timeout_period.get(); + wdt_t2_period[63:32] = wdt_reg_data[31:0]; + + //Reset event + if (this.reset_wdt_count) begin + `uvm_info("PRED", "Resetting WDT t1 and t2 counts due to a reset event", UVM_MEDIUM) + this.t1_count = 'h0; + this.t2_count = 'h0; + this.wdt_error_intr_sent = 1'b0; + this.wdt_t2_error_intr_sent = 1'b0; + this.wdt_nmi_intr_sent = 1'b0; + end + + //Cascade mode + if (cascade) begin + if (this.wdt_t1_restart) begin + this.t1_count = 'h0; + `uvm_info("PRED", "Cascade mode, received t1 pet - restarting t1 count", UVM_MEDIUM) + this.wdt_t1_restart = 1'b0; //Reset flag so we can capture another restart event + end + else if (this.t1_count != wdt_t1_period) begin + this.t1_count++; + end + else begin + //T1 expired, so send out soc error intr, and start t2 counter + if (!this.wdt_error_intr_sent) begin + `uvm_info("PRED", "Timer1 expired in cascade mode. Starting timer2", UVM_MEDIUM) + p_soc_ifc_rm.soc_ifc_reg_rm.intr_block_rf_ext.error_internal_intr_r.error_wdt_timer1_timeout_sts.predict(1'b1, -1, UVM_PREDICT_READ, UVM_PREDICT, p_soc_ifc_AHB_map); + + //Set a flag so we don't keep sending transactions while the timer holds value until interrupt + //is serviced or reset + this.wdt_error_intr_sent = 1'b1; + end + + if (this.wdt_t2_restart) begin + `uvm_error("PRED", "Cascade mode, received t2 pet - unexpected t2 pet!") + end + else if (this.t2_count != wdt_t2_period) begin + this.t2_count++; + end + else begin + if (!this.wdt_nmi_intr_sent) begin + `uvm_info("PRED", "Timer2 expired in cascade mode. Expecting NMI to be handled", UVM_MEDIUM); + p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_HW_ERROR_FATAL.nmi_pin.predict(1'b1, -1, UVM_PREDICT_READ, UVM_PREDICT, p_soc_ifc_AHB_map); //TODO: use default map? + + //Sending cptra_status_txn in the same clock as NMI + nmi_intr_pending = 1'b1; + populate_expected_cptra_status_txn(cptra_sb_ap_output_transaction); + cptra_sb_ap.write(cptra_sb_ap_output_transaction); + + //Set a flag so we don't keep sending transactions while the timer holds value until interrupt + //is serviced or reset + this.wdt_nmi_intr_sent = 1'b1; + end + end + end + end //Cascade mode + else if (independent) begin + if (this.wdt_t1_restart) begin + this.t1_count = 'h0; + `uvm_info("PRED", "Independent mode, received t1 pet - restarting t1 count", UVM_MEDIUM) + this.wdt_t1_restart = 1'b0; //Reset flag so we can capture another restart event + end + else if (this.t1_count != wdt_t1_period) begin + this.t1_count++; + end + else begin + //T1 expired, so send out soc error intr, and start t2 counter + if (!this.wdt_error_intr_sent) begin + `uvm_info("PRED", "Independent mode, T1 expired", UVM_MEDIUM) + p_soc_ifc_rm.soc_ifc_reg_rm.intr_block_rf_ext.error_internal_intr_r.error_wdt_timer1_timeout_sts.predict(1'b1, -1, UVM_PREDICT_READ, UVM_PREDICT, p_soc_ifc_AHB_map); + + //Set a flag so we don't keep sending transactions while the timer holds value until interrupt + //is serviced or reset + this.wdt_error_intr_sent = 1'b1; + end + end + //------------------------------------------------- + //Timer 2 + //------------------------------------------------- + if (this.wdt_t2_restart) begin + this.t2_count = 'h0; + `uvm_info("PRED", "Independent mode, received t2 pet - restarting t2 count", UVM_MEDIUM) + this.wdt_t2_restart = 1'b0; //Reset flag so we can capture another restart event + end + else if (this.t2_count != wdt_t2_period) begin + this.t2_count++; + end + else begin + //T1 expired, so send out soc error intr, and start t2 counter + if (!this.wdt_t2_error_intr_sent) begin + `uvm_info("PRED", "Independent mode, T2 expired", UVM_MEDIUM) + p_soc_ifc_rm.soc_ifc_reg_rm.intr_block_rf_ext.error_internal_intr_r.error_wdt_timer2_timeout_sts.predict(1'b1, -1, UVM_PREDICT_READ, UVM_PREDICT, p_soc_ifc_AHB_map); + + //Set a flag so we don't keep sending transactions while the timer holds value until interrupt + //is serviced or reset + this.wdt_t2_error_intr_sent = 1'b1; + end + end + + end //Independent mode + + configuration.soc_ifc_ctrl_agent_config.wait_for_num_clocks(1); + + end //forever +endtask + + function bit soc_ifc_predictor::soc_ifc_status_txn_expected_after_warm_reset(); /* FIXME calculate this from the reg-model somehow? */ return p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_FLOW_STATUS.ready_for_fuses.get_mirrored_value() || ready_for_fw_push || ready_for_runtime || mailbox_data_avail || |generic_output_wires /*|| trng_req_pending*/; /* only expect a soc_ifc_status_transaction if some signal will transition */ @@ -2819,6 +3033,10 @@ function void soc_ifc_predictor::predict_reset(input string kind = "HARD"); generic_output_wires = '0; + //WDT + nmi_intr_pending = 1'b0; //Reset nmi_intr on reset assertion + reset_wdt_count = 1'b1; + // FIXME get rid of this variable? mbox_valid_users = '{p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_MBOX_VALID_PAUSER[0].PAUSER.get_reset(kind), p_soc_ifc_rm.soc_ifc_reg_rm.CPTRA_MBOX_VALID_PAUSER[1].PAUSER.get_reset(kind), @@ -2930,7 +3148,7 @@ function void soc_ifc_predictor::populate_expected_cptra_status_txn(ref cptra_sb txn.obf_field_entropy = this.get_expected_obf_field_entropy(); txn.obf_uds_seed = this.get_expected_obf_uds_seed(); txn.nmi_vector = this.nmi_vector; - txn.nmi_intr_pending = 1'b0/*FIXME*/; + txn.nmi_intr_pending = this.nmi_intr_pending; txn.iccm_locked = this.iccm_locked; txn.set_key(cptra_status_txn_key++); endfunction diff --git a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/interface_packages/soc_ifc_status_pkg/src/soc_ifc_status_monitor_bfm.sv b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/interface_packages/soc_ifc_status_pkg/src/soc_ifc_status_monitor_bfm.sv index ff71b0e9b..f4ed4b30a 100644 --- a/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/interface_packages/soc_ifc_status_pkg/src/soc_ifc_status_monitor_bfm.sv +++ b/src/soc_ifc/uvmf_soc_ifc/uvmf_template_output/verification_ip/interface_packages/soc_ifc_status_pkg/src/soc_ifc_status_monitor_bfm.sv @@ -258,6 +258,7 @@ end soc_ifc_status_monitor_struct.trng_req_pending = trng_req_i; soc_ifc_status_monitor_struct.generic_output_val = generic_output_wires_i; end + // pragma uvmf custom do_monitor end endtask