diff --git a/hw/ip/gpio/data/gpio.hjson b/hw/ip/gpio/data/gpio.hjson index 37f426cb2f72be..deb7cc3fff1c88 100644 --- a/hw/ip/gpio/data/gpio.hjson +++ b/hw/ip/gpio/data/gpio.hjson @@ -111,6 +111,7 @@ package: "", desc: ''' This signal is pulsed high by the power manager after reset in order to sample the HW straps. + It can only be pulsed high one-time after reset. The following pulses will not be taken into consideration. ''', default: "1'b0" }, @@ -390,7 +391,14 @@ ], }, { name: "HW_STRAPS_DATA_IN", - desc: "GPIO Input data sampled as straps during cold boot read value", + desc: ''' + GPIO input data that was sampled as straps as the block came out of reset. + + This register depends on the GpioAsHwStrapsEn parameter. + - If the parameter is false then the register reads as zero. + - If the parameter is true then GPIO input data is sampled on the first cycle after reset + where the strap_en_i input is high. That sampled data is stored in this register. + ''', swaccess: "ro", hwaccess: "hrw", tags: [// Value in the register is determined by GPIO pin values that are sampled diff --git a/hw/ip/gpio/data/gpio_testplan.hjson b/hw/ip/gpio/data/gpio_testplan.hjson index c8588cb3854e63..e09ef17c3ea406 100644 --- a/hw/ip/gpio/data/gpio_testplan.hjson +++ b/hw/ip/gpio/data/gpio_testplan.hjson @@ -145,5 +145,20 @@ stage: V2 tests: ["gpio_stress_all"] } + { + name: straps_data + desc: '''Verify the straps data/valid ouput expected values based on the strap_en and gpio_i inputs: + - Drives gpio_i input with random values. + - Set the strap_en high for at least one clock cycle. + - Read the registers hw_straps_data_in and hw_straps_data_in_valid. + - The data read and sampled_straps_o will be checked in the scoreboard. + - Drive the gpio_o to make sure that has no impact on straps registers. + - Read to make sure that if does not affect the straps registers after drive the gpio_o. + - Apply reset and make sure the strap registers are clean. + - Read straps registers after reset. + - Iterate again the same flow, with new random values.''' + stage: V3 + tests: ["gpio_rand_straps"] + } ] } diff --git a/hw/ip/gpio/doc/interfaces.md b/hw/ip/gpio/doc/interfaces.md index 48630be3e28f97..3cd1a306b8aae9 100644 --- a/hw/ip/gpio/doc/interfaces.md +++ b/hw/ip/gpio/doc/interfaces.md @@ -15,11 +15,11 @@ Referring to the [Comportable guideline for peripheral device functionality](htt ## [Inter-Module Signals](https://opentitan.org/book/doc/contributing/hw/comportability/index.html#inter-signal-handling) -| Port Name | Package::Struct | Type | Act | Width | Description | -|:---------------|:----------------------|:--------|:------|--------:|:----------------------------------------------------------------------------------------------| -| strap_en | logic | uni | rcv | 1 | This signal is pulsed high by the power manager after reset in order to sample the HW straps. | -| sampled_straps | gpio_pkg::gpio_straps | uni | req | 1 | This vector contains the sampled strap values. | -| tl | tlul_pkg::tl | req_rsp | rsp | 1 | | +| Port Name | Package::Struct | Type | Act | Width | Description | +|:---------------|:----------------------|:--------|:------|--------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| strap_en | logic | uni | rcv | 1 | This signal is pulsed high by the power manager after reset in order to sample the HW straps. It can only be pulsed high one-time after reset. The following pulses will not be taken into consideration. | +| sampled_straps | gpio_pkg::gpio_straps | uni | req | 1 | This vector contains the sampled strap values. | +| tl | tlul_pkg::tl | req_rsp | rsp | 1 | | ## Interrupts diff --git a/hw/ip/gpio/doc/registers.md b/hw/ip/gpio/doc/registers.md index cde79bb27e4178..8f1f354150d7b9 100644 --- a/hw/ip/gpio/doc/registers.md +++ b/hw/ip/gpio/doc/registers.md @@ -3,26 +3,26 @@ ## Summary -| Name | Offset | Length | Description | -|:-----------------------------------------------------------|:---------|---------:|:--------------------------------------------------------------| -| gpio.[`INTR_STATE`](#intr_state) | 0x0 | 4 | Interrupt State Register | -| gpio.[`INTR_ENABLE`](#intr_enable) | 0x4 | 4 | Interrupt Enable Register | -| gpio.[`INTR_TEST`](#intr_test) | 0x8 | 4 | Interrupt Test Register | -| gpio.[`ALERT_TEST`](#alert_test) | 0xc | 4 | Alert Test Register | -| gpio.[`DATA_IN`](#data_in) | 0x10 | 4 | GPIO Input data read value | -| gpio.[`DIRECT_OUT`](#direct_out) | 0x14 | 4 | GPIO direct output data write value | -| gpio.[`MASKED_OUT_LOWER`](#masked_out_lower) | 0x18 | 4 | GPIO write data lower with mask. | -| gpio.[`MASKED_OUT_UPPER`](#masked_out_upper) | 0x1c | 4 | GPIO write data upper with mask. | -| gpio.[`DIRECT_OE`](#direct_oe) | 0x20 | 4 | GPIO Output Enable. | -| gpio.[`MASKED_OE_LOWER`](#masked_oe_lower) | 0x24 | 4 | GPIO write Output Enable lower with mask. | -| gpio.[`MASKED_OE_UPPER`](#masked_oe_upper) | 0x28 | 4 | GPIO write Output Enable upper with mask. | -| gpio.[`INTR_CTRL_EN_RISING`](#intr_ctrl_en_rising) | 0x2c | 4 | GPIO interrupt enable for GPIO, rising edge. | -| gpio.[`INTR_CTRL_EN_FALLING`](#intr_ctrl_en_falling) | 0x30 | 4 | GPIO interrupt enable for GPIO, falling edge. | -| gpio.[`INTR_CTRL_EN_LVLHIGH`](#intr_ctrl_en_lvlhigh) | 0x34 | 4 | GPIO interrupt enable for GPIO, level high. | -| gpio.[`INTR_CTRL_EN_LVLLOW`](#intr_ctrl_en_lvllow) | 0x38 | 4 | GPIO interrupt enable for GPIO, level low. | -| gpio.[`CTRL_EN_INPUT_FILTER`](#ctrl_en_input_filter) | 0x3c | 4 | filter enable for GPIO input bits. | -| gpio.[`HW_STRAPS_DATA_IN_VALID`](#hw_straps_data_in_valid) | 0x40 | 4 | Indicates whether the data in !!HW_STRAPS_DATA_IN is valid. | -| gpio.[`HW_STRAPS_DATA_IN`](#hw_straps_data_in) | 0x44 | 4 | GPIO Input data sampled as straps during cold boot read value | +| Name | Offset | Length | Description | +|:-----------------------------------------------------------|:---------|---------:|:---------------------------------------------------------------------------| +| gpio.[`INTR_STATE`](#intr_state) | 0x0 | 4 | Interrupt State Register | +| gpio.[`INTR_ENABLE`](#intr_enable) | 0x4 | 4 | Interrupt Enable Register | +| gpio.[`INTR_TEST`](#intr_test) | 0x8 | 4 | Interrupt Test Register | +| gpio.[`ALERT_TEST`](#alert_test) | 0xc | 4 | Alert Test Register | +| gpio.[`DATA_IN`](#data_in) | 0x10 | 4 | GPIO Input data read value | +| gpio.[`DIRECT_OUT`](#direct_out) | 0x14 | 4 | GPIO direct output data write value | +| gpio.[`MASKED_OUT_LOWER`](#masked_out_lower) | 0x18 | 4 | GPIO write data lower with mask. | +| gpio.[`MASKED_OUT_UPPER`](#masked_out_upper) | 0x1c | 4 | GPIO write data upper with mask. | +| gpio.[`DIRECT_OE`](#direct_oe) | 0x20 | 4 | GPIO Output Enable. | +| gpio.[`MASKED_OE_LOWER`](#masked_oe_lower) | 0x24 | 4 | GPIO write Output Enable lower with mask. | +| gpio.[`MASKED_OE_UPPER`](#masked_oe_upper) | 0x28 | 4 | GPIO write Output Enable upper with mask. | +| gpio.[`INTR_CTRL_EN_RISING`](#intr_ctrl_en_rising) | 0x2c | 4 | GPIO interrupt enable for GPIO, rising edge. | +| gpio.[`INTR_CTRL_EN_FALLING`](#intr_ctrl_en_falling) | 0x30 | 4 | GPIO interrupt enable for GPIO, falling edge. | +| gpio.[`INTR_CTRL_EN_LVLHIGH`](#intr_ctrl_en_lvlhigh) | 0x34 | 4 | GPIO interrupt enable for GPIO, level high. | +| gpio.[`INTR_CTRL_EN_LVLLOW`](#intr_ctrl_en_lvllow) | 0x38 | 4 | GPIO interrupt enable for GPIO, level low. | +| gpio.[`CTRL_EN_INPUT_FILTER`](#ctrl_en_input_filter) | 0x3c | 4 | filter enable for GPIO input bits. | +| gpio.[`HW_STRAPS_DATA_IN_VALID`](#hw_straps_data_in_valid) | 0x40 | 4 | Indicates whether the data in !!HW_STRAPS_DATA_IN is valid. | +| gpio.[`HW_STRAPS_DATA_IN`](#hw_straps_data_in) | 0x44 | 4 | GPIO input data that was sampled as straps as the block came out of reset. | ## INTR_STATE Interrupt State Register @@ -358,7 +358,12 @@ Indicates whether the data in [`HW_STRAPS_DATA_IN`](#hw_straps_data_in) is valid | 0 | ro | 0x0 | HW_STRAPS_DATA_IN_VALID | | ## HW_STRAPS_DATA_IN -GPIO Input data sampled as straps during cold boot read value +GPIO input data that was sampled as straps as the block came out of reset. + +This register depends on the GpioAsHwStrapsEn parameter. +- If the parameter is false then the register reads as zero. +- If the parameter is true then GPIO input data is sampled on the first cycle after reset +where the strap_en_i input is high. That sampled data is stored in this register. - Offset: `0x44` - Reset default: `0x0` - Reset mask: `0xffffffff` diff --git a/hw/ip/gpio/dv/env/gpio_env.core b/hw/ip/gpio/dv/env/gpio_env.core index da4d4389683e1c..7e4c39ede54418 100644 --- a/hw/ip/gpio/dv/env/gpio_env.core +++ b/hw/ip/gpio/dv/env/gpio_env.core @@ -28,6 +28,7 @@ filesets: - seq_lib/gpio_stress_all_vseq.sv: {is_include_file: true} - seq_lib/gpio_intr_rand_pgm_vseq.sv: {is_include_file: true} - seq_lib/gpio_intr_with_filter_rand_intr_event_vseq.sv: {is_include_file: true} + - seq_lib/gpio_rand_straps_vseq.sv : {is_include_file: true} file_type: systemVerilogSource generate: diff --git a/hw/ip/gpio/dv/env/gpio_env.sv b/hw/ip/gpio/dv/env/gpio_env.sv index 111ac6c7a7e161..ced2992614c1ac 100644 --- a/hw/ip/gpio/dv/env/gpio_env.sv +++ b/hw/ip/gpio/dv/env/gpio_env.sv @@ -17,6 +17,9 @@ class gpio_env extends cip_base_env #( if (!uvm_config_db#(gpio_vif)::get(this, "", "gpio_vif", cfg.gpio_vif)) begin `uvm_fatal(get_full_name(), "failed to get gpio_vif from uvm_config_db") end + if (!uvm_config_db#(straps_vif)::get(this, "", "straps_vif", cfg.straps_vif_inst)) begin + `uvm_fatal(get_full_name(), "Virtual interface straps_vif_inst is not set") + end endfunction endclass diff --git a/hw/ip/gpio/dv/env/gpio_env_cfg.sv b/hw/ip/gpio/dv/env/gpio_env_cfg.sv index c8af480a21b311..e9e269c8d4cbe9 100644 --- a/hw/ip/gpio/dv/env/gpio_env_cfg.sv +++ b/hw/ip/gpio/dv/env/gpio_env_cfg.sv @@ -13,11 +13,16 @@ class gpio_env_cfg extends cip_base_env_cfg #( rand bit pulldown_en; // gpio virtual interface gpio_vif gpio_vif; + // gpio straps interface + straps_vif straps_vif_inst; constraint pullup_pulldown_en_c {pullup_en ^ pulldown_en;} `uvm_object_utils(gpio_env_cfg) - `uvm_object_new + + function new(string name = "gpio_env_cfg"); + super.new(name); + endfunction virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1); list_of_alerts = gpio_env_pkg::LIST_OF_ALERTS; @@ -27,6 +32,9 @@ class gpio_env_cfg extends cip_base_env_cfg #( // only support 1 outstanding TL item m_tl_agent_cfg.max_outstanding_req = 1; + + // Used to allow reset operation during a stress all tests and check the CSR after that. + can_reset_with_csr_accesses = 1'b1; endfunction : initialize endclass diff --git a/hw/ip/gpio/dv/env/gpio_env_pkg.sv b/hw/ip/gpio/dv/env/gpio_env_pkg.sv index 1c94585f248353..d6d8ecb371fd2d 100644 --- a/hw/ip/gpio/dv/env/gpio_env_pkg.sv +++ b/hw/ip/gpio/dv/env/gpio_env_pkg.sv @@ -27,6 +27,7 @@ package gpio_env_pkg; parameter string LIST_OF_ALERTS[] = {"fatal_fault"}; typedef virtual pins_if #(NUM_GPIOS) gpio_vif; + typedef virtual gpio_straps_if straps_vif; typedef class gpio_env_cfg; typedef class gpio_env_cov; typedef cip_base_virtual_sequencer #(gpio_env_cfg, gpio_env_cov) gpio_virtual_sequencer; diff --git a/hw/ip/gpio/dv/env/gpio_scoreboard.sv b/hw/ip/gpio/dv/env/gpio_scoreboard.sv index 26f53a7abbe946..e58ca4b390971c 100644 --- a/hw/ip/gpio/dv/env/gpio_scoreboard.sv +++ b/hw/ip/gpio/dv/env/gpio_scoreboard.sv @@ -31,6 +31,8 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg), // (i) indicate that write to INTR_STATE register just happened, and // (ii) store information of which all interupt bits were cleared bit [TL_DW-1:0] cleared_intr_bits; + // Flag to indicate that the strap was triggered + bit first_strap_triggered; // mask are WO, store the values in scb uvm_reg_data_t masked_out_lower_mask; @@ -40,7 +42,9 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg), `uvm_component_utils(gpio_scoreboard) - `uvm_component_new + function new (string name = "gpio_scoreboard", uvm_component parent = null); + super.new (name, parent); + endfunction // Function: build_phase function void build_phase(uvm_phase phase); @@ -54,6 +58,8 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg), fork monitor_gpio_i(); monitor_gpio_interrupt_pins(); + monitor_gpio_straps(); + handle_reset(); join_none endtask @@ -360,6 +366,46 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg), end endtask : monitor_gpio_interrupt_pins + // Task: monitor_gpio_straps + virtual task monitor_gpio_straps(); + forever begin : monitor_gpio_intr + @(posedge cfg.clk_rst_vif.clk) + if(!cfg.under_reset) begin + if (|gpio_i_driven === 1'b1) begin + @(negedge cfg.straps_vif_inst.strap_en) begin + if (!first_strap_triggered) begin + // Update data_in ral register value based on result of input + `DV_CHECK_FATAL( + ral.hw_straps_data_in.predict(.value(gpio_i_driven), + .kind(UVM_PREDICT_DIRECT))); + // Update data_in valid register value based on result of input + `DV_CHECK_FATAL( + ral.hw_straps_data_in_valid.predict(.value('b1), + .kind(UVM_PREDICT_DIRECT))); + + // Checker: Compare actual values of gpio pins with straps register. + // Check the register hw_straps_data_in against gpio_i pins + `DV_CHECK_CASE_EQ(gpio_i_driven, cfg.straps_vif_inst.sampled_straps.data) + // Check the register hw_straps_data_in_valid + `DV_CHECK_CASE_EQ('b1, cfg.straps_vif_inst.sampled_straps.valid) + // Turn-off the checker after the first strap trigger. + first_strap_triggered = 1; + end + end + end + end + end + endtask : monitor_gpio_straps + + virtual protected task handle_reset(); + forever begin + @(negedge cfg.clk_rst_vif.rst_n); + cfg.under_reset = 1; + @(posedge cfg.clk_rst_vif.rst_n); + cfg.under_reset = 0; + end + endtask + // Function: actual_gpio_i_activity function bit actual_gpio_i_activity(); return ~((prv_gpio_i_pins_o === cfg.gpio_vif.pins_o) && @@ -561,6 +607,7 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg), ((|gpio_i_driven === 1'b1) && (actual_gpio_i_activity() == 1))) begin `DV_CHECK_CASE_EQ(pred_val_gpio_pins, cfg.gpio_vif.pins) end + end endfunction : gpio_predict_and_compare @@ -804,6 +851,7 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg), last_intr_update_except_clearing = '0; last_intr_test_event = '0; cleared_intr_bits = '0; + first_strap_triggered = 0; endfunction // Function: check_phase diff --git a/hw/ip/gpio/dv/env/seq_lib/gpio_rand_straps_vseq.sv b/hw/ip/gpio/dv/env/seq_lib/gpio_rand_straps_vseq.sv new file mode 100644 index 00000000000000..ba450df0a981de --- /dev/null +++ b/hw/ip/gpio/dv/env/seq_lib/gpio_rand_straps_vseq.sv @@ -0,0 +1,150 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Verify the straps data/valid ouput expected values based on the strap_en and gpio_in inputs: +// - Drive gpio_in input with random values. +// - Set the strap_en high for at least one clock cycle. +// - Read the registers hw_straps_data_in and hw_straps_data_in_valid. +// - The data read and sampled_straps_o will be checked in the scoreboard. +// - Drive the gpio_out to make sure that has no impact on straps registers. +// - Read to make sure that if does not affect the straps registers after drive the gpio_out. +// - Apply reset and make sure the strap registers are clean. +// - Read straps registers after reset. +// - Iterate again the same flow, with new random values. +class gpio_rand_straps_vseq extends gpio_base_vseq; + + `uvm_object_utils(gpio_rand_straps_vseq) + + // gpio input to drive + rand bit [NUM_GPIOS-1:0] gpio_in; + // gpio output to program in register + rand bit [NUM_GPIOS-1:0] gpio_out; + // gpio output enable to program in register + rand bit [NUM_GPIOS-1:0] gpio_oe; + + // Read straps_data_in + bit [NUM_GPIOS-1:0] rd_hw_straps_data_in; + // Read straps_data_in valid + bit rd_hw_straps_data_in_valid; + + constraint num_trans_c { + num_trans inside {[20:200]}; + } + + function new(string name = "gpio_rand_straps_vseq"); + super.new(name); + endfunction + + task test_straps_gpio_in(); + + // Drive the gpio_in + drive_gpio_in(gpio_in); + + // Wait at least one clock cycle + `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 0;) + cfg.clk_rst_vif.wait_clks(delay); + + // Trigger the snapshot of gpio_in to be stored in the straps registers + cfg.straps_vif_inst.strap_en = 1; + cfg.clk_rst_vif.wait_clks(1); + cfg.straps_vif_inst.strap_en = 0; + + // Wait at least one clock cycle to avoid race condition with the predict value + `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 1;) + cfg.clk_rst_vif.wait_clks(delay); + + // Read the hw_straps_data_in and check the expected value in the scoreboard + csr_rd(.ptr(ral.hw_straps_data_in), .value(rd_hw_straps_data_in)); + // Read the hw_straps_data_in_valid and check the expected value in the scoreboard + csr_rd(.ptr(ral.hw_straps_data_in_valid), .value(rd_hw_straps_data_in_valid)); + + // Random wait + `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 0;) + cfg.clk_rst_vif.wait_clks(delay); + + // Stop driving gpio_in + undrive_gpio_in(); + + // Random wait + `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 0;) + cfg.clk_rst_vif.wait_clks(delay); + + // Read to make sure that if does not affect the straps registers after undrive the gpio_in + csr_rd(.ptr(ral.hw_straps_data_in), .value(rd_hw_straps_data_in)); + csr_rd(.ptr(ral.hw_straps_data_in_valid), .value(rd_hw_straps_data_in_valid)); + + endtask : test_straps_gpio_in + + task test_straps_gpio_out(); + + // Additional verification + // Drive the gpio_out to make sure that has no impact on straps registers. + // then read the gpio strap registers again + cfg.gpio_vif.drive_en('0); + + ral.direct_out.set(gpio_out); + ral.direct_oe.set(gpio_oe); + csr_update(.csr(ral.direct_out)); + csr_update(.csr(ral.direct_oe)); + + // Random wait + `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 0;) + cfg.clk_rst_vif.wait_clks(delay); + + // Read to make sure that if does not affect the straps registers after drive the gpio_out + csr_rd(.ptr(ral.hw_straps_data_in), .value(rd_hw_straps_data_in)); + csr_rd(.ptr(ral.hw_straps_data_in_valid), .value(rd_hw_straps_data_in_valid)); + + endtask : test_straps_gpio_out + + task check_transaction(string txn_desc, bit is_first); + string msg_id = {`gfn, txn_desc}; + + `DV_CHECK_MEMBER_RANDOMIZE_FATAL(gpio_in) + `DV_CHECK_MEMBER_RANDOMIZE_FATAL(gpio_out) + `DV_CHECK_MEMBER_RANDOMIZE_FATAL(gpio_oe) + + // User case to test the straps output, with gpio_in data randomised + test_straps_gpio_in(); + + // User case to test the straps output/registers, with gpio_out data randomised + // The gpio_out should not affect the straps output/registers. + test_straps_gpio_out(); + + // Random wait + `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 1;) + cfg.clk_rst_vif.wait_clks(delay); + + // Apply reset and make sure the strap registers are clean + apply_reset(); + + // Random wait + `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 1;) + cfg.clk_rst_vif.wait_clks(delay); + + // Read the straps registers after reset + csr_rd(.ptr(ral.hw_straps_data_in), .value(rd_hw_straps_data_in)); + csr_rd(.ptr(ral.hw_straps_data_in_valid), .value(rd_hw_straps_data_in_valid)); + + endtask : check_transaction + + task body(); + `uvm_info(`gfn, $sformatf("num_trans = %0d", num_trans), UVM_HIGH) + + for (uint tr_num = 0; tr_num < num_trans; tr_num++) begin + string msg_id = {`gfn, $sformatf(" Transaction-%0d", tr_num)}; + `DV_CHECK_MEMBER_RANDOMIZE_FATAL(delay) + + cfg.clk_rst_vif.wait_clks(delay); + `uvm_info(msg_id, $sformatf("delay = %0d", delay), UVM_HIGH) + + check_transaction(msg_id, tr_num == 0); + + `uvm_info(msg_id, "End of Transaction", UVM_HIGH) + + end // end for + + endtask : body + +endclass : gpio_rand_straps_vseq diff --git a/hw/ip/gpio/dv/env/seq_lib/gpio_vseq_list.sv b/hw/ip/gpio/dv/env/seq_lib/gpio_vseq_list.sv index fd508cad328b8f..ab7a840ca9d854 100644 --- a/hw/ip/gpio/dv/env/seq_lib/gpio_vseq_list.sv +++ b/hw/ip/gpio/dv/env/seq_lib/gpio_vseq_list.sv @@ -14,3 +14,4 @@ `include "gpio_random_long_reg_writes_reg_reads_vseq.sv" `include "gpio_full_random_vseq.sv" `include "gpio_stress_all_vseq.sv" +`include "gpio_rand_straps_vseq.sv" diff --git a/hw/ip/gpio/dv/gpio_sim.core b/hw/ip/gpio/dv/gpio_sim.core index a33d0dc74f66e4..325079ca43de6d 100644 --- a/hw/ip/gpio/dv/gpio_sim.core +++ b/hw/ip/gpio/dv/gpio_sim.core @@ -13,6 +13,7 @@ filesets: depend: - lowrisc:dv:gpio_test - lowrisc:dv:gpio_sva + - lowrisc:dv:gpio_if files: - tb/tb.sv file_type: systemVerilogSource diff --git a/hw/ip/gpio/dv/gpio_sim_cfg.hjson b/hw/ip/gpio/dv/gpio_sim_cfg.hjson index 6a8910a7669541..0c8405987837eb 100644 --- a/hw/ip/gpio/dv/gpio_sim_cfg.hjson +++ b/hw/ip/gpio/dv/gpio_sim_cfg.hjson @@ -180,6 +180,10 @@ build_mode: en_cdc_prims run_opts: ["+no_pullup_pulldown=1"] } + { + name: gpio_rand_straps + uvm_test_seq: gpio_rand_straps_vseq + } ] // List of regressions. diff --git a/hw/ip/gpio/dv/interfaces/gpio_if.core b/hw/ip/gpio/dv/interfaces/gpio_if.core new file mode 100644 index 00000000000000..c3d4a82ce3654f --- /dev/null +++ b/hw/ip/gpio/dv/interfaces/gpio_if.core @@ -0,0 +1,18 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:dv:gpio_if:0.1" +description: "GPIO Interfaces" +filesets: + files_dv: + depend: + - lowrisc:ip:gpio:0.1 + files: + - gpio_straps_if.sv + file_type: systemVerilogSource + +targets: + default: + filesets: + - files_dv diff --git a/hw/ip/gpio/dv/interfaces/gpio_straps_if.sv b/hw/ip/gpio/dv/interfaces/gpio_straps_if.sv new file mode 100644 index 00000000000000..4d6b86d6a41c25 --- /dev/null +++ b/hw/ip/gpio/dv/interfaces/gpio_straps_if.sv @@ -0,0 +1,18 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// interface : gpio_straps_if +`ifndef GPIO_STRAPS_IF_SV +`define GPIO_STRAPS_IF_SV + +import gpio_pkg::*; + +// Interface definition +interface gpio_straps_if(); + + logic strap_en; // Signal to enable straps + gpio_straps_t sampled_straps; // Sampled gpio_i snapshot data from GPIO (DUT) + +endinterface + +`endif // GPIO_STRAPS_IF_SV diff --git a/hw/ip/gpio/dv/tb/tb.sv b/hw/ip/gpio/dv/tb/tb.sv index 94e8ebac0b7c09..7a7246b1bba142 100644 --- a/hw/ip/gpio/dv/tb/tb.sv +++ b/hw/ip/gpio/dv/tb/tb.sv @@ -11,8 +11,6 @@ module tb; import gpio_env_pkg::*; import gpio_test_pkg::*; import gpio_reg_pkg::*; - import gpio_pkg::*; - // macro includes `include "uvm_macros.svh" `include "dv_macros.svh" @@ -24,6 +22,8 @@ module tb; wire [NUM_GPIOS-1:0] gpio_oe; wire [NUM_GPIOS-1:0] gpio_intr; wire [NUM_MAX_INTERRUPTS-1:0] interrupts; + gpio_straps_t sampled_straps; + wire strap_en; `DV_ALERT_IF_CONNECT() @@ -33,6 +33,7 @@ module tb; .rst_n(rst_n) ); pins_if #(NUM_MAX_INTERRUPTS) intr_if (.pins(interrupts)); + gpio_straps_if straps_if_inst (); tl_if tl_if ( .clk (clk), .rst_n(rst_n) @@ -52,9 +53,8 @@ module tb; .clk_i (clk), .rst_ni(rst_n), - // TODO: need to test snapshot functionality - .strap_en_i(1'b0), - .sampled_straps_o(), + .strap_en_i(straps_if_inst.strap_en), + .sampled_straps_o(straps_if_inst.sampled_straps), .tl_i(tl_if.h2d), .tl_o(tl_if.d2h), @@ -85,6 +85,7 @@ module tb; uvm_config_db#(intr_vif)::set(null, "*.env", "intr_vif", intr_if); uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", tl_if); uvm_config_db#(virtual pins_if #(NUM_GPIOS))::set(null, "*.env", "gpio_vif", gpio_if); + uvm_config_db#(virtual gpio_straps_if)::set(null, "*.*", "straps_vif", straps_if_inst); $timeformat(-12, 0, " ps", 12); run_test(); end diff --git a/hw/ip/gpio/dv/tests/gpio_base_test.sv b/hw/ip/gpio/dv/tests/gpio_base_test.sv index e12c37d4c78eeb..b0484c7ec2f71c 100644 --- a/hw/ip/gpio/dv/tests/gpio_base_test.sv +++ b/hw/ip/gpio/dv/tests/gpio_base_test.sv @@ -1,16 +1,25 @@ // Copyright lowRISC contributors (OpenTitan project). // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 - class gpio_base_test extends cip_base_test #( .ENV_T(gpio_env), .CFG_T(gpio_env_cfg) ); `uvm_component_utils(gpio_base_test) - `uvm_component_new - + straps_vif straps_vif_inst; // Virtual interface + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + task reset_phase(uvm_phase phase); + phase.raise_objection(this); + // Initialize inputs + straps_vif_inst.strap_en = 0; + phase.drop_objection(this); + endtask virtual function void build_phase(uvm_phase phase); super.build_phase(phase); + if (!uvm_config_db#(straps_vif)::get(this, "*.*", "straps_vif", straps_vif_inst)) begin + `uvm_fatal("SEQ", "Virtual interface straps_vif_inst is not set") + end endfunction : build_phase - endclass : gpio_base_test diff --git a/hw/ip/gpio/rtl/gpio.sv b/hw/ip/gpio/rtl/gpio.sv index d47f5fb4f4c1fc..e2598bcfb54e23 100644 --- a/hw/ip/gpio/rtl/gpio.sv +++ b/hw/ip/gpio/rtl/gpio.sv @@ -85,7 +85,6 @@ module gpio assign hw2reg.hw_straps_data_in.d = data_in_d; assign sampled_straps_o.data = reg2hw.hw_straps_data_in.q; assign sampled_straps_o.valid = reg2hw.hw_straps_data_in_valid.q; - `ASSUME(StrapSampleOnce_A, ##1 $fell(sample_trigger) |-> always !sample_trigger) end else begin : gen_no_strap_sample assign hw2reg.hw_straps_data_in_valid.de = 1'b0; assign hw2reg.hw_straps_data_in_valid.d = 1'b0;