diff --git a/hw/ip/gpio/data/gpio.hjson b/hw/ip/gpio/data/gpio.hjson index 37f426cb2f72b..4011705b42250 100644 --- a/hw/ip/gpio/data/gpio.hjson +++ b/hw/ip/gpio/data/gpio.hjson @@ -390,7 +390,9 @@ ], }, { name: "HW_STRAPS_DATA_IN", - desc: "GPIO Input data sampled as straps during cold boot read value", + desc: '''GPIO Input data sampled as straps during cold boot read value + The GPIO input data is sampled after the first one pulse cycle of straps_en input after reset. + ''', 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 c8588cb3854e6..761e8d45d0fdc 100644 --- a/hw/ip/gpio/data/gpio_testplan.hjson +++ b/hw/ip/gpio/data/gpio_testplan.hjson @@ -145,5 +145,17 @@ 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 expected strap_data_in based on the condition if is the first triggered strap_en or not + - Updates the RAL model with the expected strap_data_in and strap_data_in_valid + - Trigger the strap_en with one clock cycle + - Read the registers hw_straps_data_in and hw_straps_data_in_valid + - Check the expected behavior in the scoreboard and also on csr checks''' + stage: V3 + tests: ["gpio_rand_straps"] + } ] } diff --git a/hw/ip/gpio/doc/registers.md b/hw/ip/gpio/doc/registers.md index cde79bb27e417..41432354ce24e 100644 --- a/hw/ip/gpio/doc/registers.md +++ b/hw/ip/gpio/doc/registers.md @@ -1,31 +1,35 @@ # Registers + ## 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 sampled as straps during cold boot read value. 
The register only stores the gpio_i values for the first pulse straps_en after the reset. | ## INTR_STATE + Interrupt State Register + - Offset: `0x0` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -36,12 +40,15 @@ Interrupt State Register {"reg": [{"name": "gpio", "bits": 32, "attr": ["rw1c"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:-------|:------------------------------------------------------------| -| 31:0 | rw1c | 0x0 | gpio | raised if any of GPIO pin detects configured interrupt mode | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :--- | :---------------------------------------------------------- | +| 31:0 | rw1c | 0x0 | gpio | raised if any of GPIO pin detects configured interrupt mode | ## INTR_ENABLE + Interrupt Enable Register + - Offset: `0x4` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -52,12 +59,15 @@ Interrupt Enable Register {"reg": [{"name": "gpio", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:-------|:------------------------------------------------------------------------------------| -| 31:0 | rw | 0x0 | gpio | Enable interrupt when corresponding bit in [`INTR_STATE.gpio`](#intr_state) is set. | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :--- | :--------------------------------------------------------------------------------- | +| 31:0 | rw | 0x0 | gpio | Enable interrupt when corresponding bit in[`INTR_STATE.gpio`](#intr_state) is set. | ## INTR_TEST + Interrupt Test Register + - Offset: `0x8` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -68,12 +78,15 @@ Interrupt Test Register {"reg": [{"name": "gpio", "bits": 32, "attr": ["wo"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:-------|:-----------------------------------------------------------------------------| -| 31:0 | wo | 0x0 | gpio | Write 1 to force corresponding bit in [`INTR_STATE.gpio`](#intr_state) to 1. | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :--- | :-------------------------------------------------------------------------- | +| 31:0 | wo | 0x0 | gpio | Write 1 to force corresponding bit in[`INTR_STATE.gpio`](#intr_state) to 1. | ## ALERT_TEST + Alert Test Register + - Offset: `0xc` - Reset default: `0x0` - Reset mask: `0x1` @@ -84,13 +97,16 @@ Alert Test Register {"reg": [{"name": "fatal_fault", "bits": 1, "attr": ["wo"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 130}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:------------|:-------------------------------------------------| -| 31:1 | | | | Reserved | -| 0 | wo | 0x0 | fatal_fault | Write 1 to trigger one alert event of this kind. | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :---------- | :----------------------------------------------- | +| 31:1 | | | | Reserved | +| 0 | wo | 0x0 | fatal_fault | Write 1 to trigger one alert event of this kind. | ## DATA_IN + GPIO Input data read value + - Offset: `0x10` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -101,12 +117,15 @@ GPIO Input data read value {"reg": [{"name": "DATA_IN", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:--------|:--------------| -| 31:0 | ro | x | DATA_IN | | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :------ | :---------- | +| 31:0 | ro | x | DATA_IN | | ## DIRECT_OUT + GPIO direct output data write value + - Offset: `0x14` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -117,11 +136,13 @@ GPIO direct output data write value {"reg": [{"name": "DIRECT_OUT", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:-----------|:--------------| -| 31:0 | rw | x | DIRECT_OUT | | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :--------- | :---------- | +| 31:0 | rw | x | DIRECT_OUT | | ## MASKED_OUT_LOWER + GPIO write data lower with mask. Masked write for DATA_OUT[15:0]. @@ -132,6 +153,7 @@ if mask bits are set. Read-back of this register returns upper 16 bits as zero and lower 16 bits as DATA_OUT[15:0]. + - Offset: `0x18` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -142,12 +164,14 @@ and lower 16 bits as DATA_OUT[15:0]. {"reg": [{"name": "data", "bits": 16, "attr": ["rw"], "rotate": 0}, {"name": "mask", "bits": 16, "attr": ["wo"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:-------|:------------------------------------------------------------------------------------------------| -| 31:16 | wo | x | mask | Write data mask[15:0]. A value of 1 in mask[i] allows the updating of DATA_OUT[i], 0 <= i <= 15 | -| 15:0 | rw | x | data | Write data value[15:0]. Value to write into DATA_OUT[i], valid in the presence of mask[i]==1 | + +| Bits | Type | Reset | Name | Description | +| :---: | :--: | :---: | :--- | :---------------------------------------------------------------------------------------------- | +| 31:16 | wo | x | mask | Write data mask[15:0]. A value of 1 in mask[i] allows the updating of DATA_OUT[i], 0 <= i <= 15 | +| 15:0 | rw | x | data | Write data value[15:0]. Value to write into DATA_OUT[i], valid in the presence of mask[i]==1 | ## MASKED_OUT_UPPER + GPIO write data upper with mask. Masked write for DATA_OUT[31:16]. @@ -158,6 +182,7 @@ if mask bits are set. Read-back of this register returns upper 16 bits as zero and lower 16 bits as DATA_OUT[31:16]. + - Offset: `0x1c` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -168,15 +193,18 @@ and lower 16 bits as DATA_OUT[31:16]. {"reg": [{"name": "data", "bits": 16, "attr": ["rw"], "rotate": 0}, {"name": "mask", "bits": 16, "attr": ["wo"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:-------|:--------------------------------------------------------------------------------------------------| -| 31:16 | wo | x | mask | Write data mask[31:16]. A value of 1 in mask[i] allows the updating of DATA_OUT[i], 16 <= i <= 31 | -| 15:0 | rw | x | data | Write data value[31:16]. Value to write into DATA_OUT[i], valid in the presence of mask[i]==1 | + +| Bits | Type | Reset | Name | Description | +| :---: | :--: | :---: | :--- | :------------------------------------------------------------------------------------------------ | +| 31:16 | wo | x | mask | Write data mask[31:16]. A value of 1 in mask[i] allows the updating of DATA_OUT[i], 16 <= i <= 31 | +| 15:0 | rw | x | data | Write data value[31:16]. Value to write into DATA_OUT[i], valid in the presence of mask[i]==1 | ## DIRECT_OE + GPIO Output Enable. Setting direct_oe[i] to 1 enables output mode for GPIO[i] + - Offset: `0x20` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -187,11 +215,13 @@ Setting direct_oe[i] to 1 enables output mode for GPIO[i] {"reg": [{"name": "DIRECT_OE", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:----------|:--------------| -| 31:0 | rw | x | DIRECT_OE | | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :-------- | :---------- | +| 31:0 | rw | x | DIRECT_OE | | ## MASKED_OE_LOWER + GPIO write Output Enable lower with mask. Masked write for DATA_OE[15:0], the register that controls @@ -203,6 +233,7 @@ if mask bits are set. Read-back of this register returns upper 16 bits as zero and lower 16 bits as DATA_OE[15:0]. + - Offset: `0x24` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -213,12 +244,14 @@ and lower 16 bits as DATA_OE[15:0]. {"reg": [{"name": "data", "bits": 16, "attr": ["rw"], "rotate": 0}, {"name": "mask", "bits": 16, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:-------|:---------------------------------------------------------------------------------------------| -| 31:16 | rw | x | mask | Write OE mask[15:0]. A value of 1 in mask[i] allows the updating of DATA_OE[i], 0 <= i <= 15 | -| 15:0 | rw | x | data | Write OE value[15:0]. Value to write into DATA_OE[i], valid in the presence of mask[i]==1 | + +| Bits | Type | Reset | Name | Description | +| :---: | :--: | :---: | :--- | :------------------------------------------------------------------------------------------- | +| 31:16 | rw | x | mask | Write OE mask[15:0]. A value of 1 in mask[i] allows the updating of DATA_OE[i], 0 <= i <= 15 | +| 15:0 | rw | x | data | Write OE value[15:0]. Value to write into DATA_OE[i], valid in the presence of mask[i]==1 | ## MASKED_OE_UPPER + GPIO write Output Enable upper with mask. Masked write for DATA_OE[31:16], the register that controls @@ -230,6 +263,7 @@ if mask bits are set. Read-back of this register returns upper 16 bits as zero and lower 16 bits as DATA_OE[31:16]. + - Offset: `0x28` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -240,16 +274,19 @@ and lower 16 bits as DATA_OE[31:16]. {"reg": [{"name": "data", "bits": 16, "attr": ["rw"], "rotate": 0}, {"name": "mask", "bits": 16, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:-------|:-----------------------------------------------------------------------------------------------| -| 31:16 | rw | x | mask | Write OE mask[31:16]. A value of 1 in mask[i] allows the updating of DATA_OE[i], 16 <= i <= 31 | -| 15:0 | rw | x | data | Write OE value[31:16]. Value to write into DATA_OE[i], valid in the presence of mask[i]==1 | + +| Bits | Type | Reset | Name | Description | +| :---: | :--: | :---: | :--- | :--------------------------------------------------------------------------------------------- | +| 31:16 | rw | x | mask | Write OE mask[31:16]. A value of 1 in mask[i] allows the updating of DATA_OE[i], 16 <= i <= 31 | +| 15:0 | rw | x | data | Write OE value[31:16]. Value to write into DATA_OE[i], valid in the presence of mask[i]==1 | ## INTR_CTRL_EN_RISING + GPIO interrupt enable for GPIO, rising edge. If [`INTR_ENABLE`](#intr_enable)[i] is true, a value of 1 on [`INTR_CTRL_EN_RISING`](#intr_ctrl_en_rising)[i] enables rising-edge interrupt detection on GPIO[i]. + - Offset: `0x2c` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -260,15 +297,18 @@ enables rising-edge interrupt detection on GPIO[i]. {"reg": [{"name": "INTR_CTRL_EN_RISING", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:--------------------|:--------------| -| 31:0 | rw | 0x0 | INTR_CTRL_EN_RISING | | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :------------------ | :---------- | +| 31:0 | rw | 0x0 | INTR_CTRL_EN_RISING | | ## INTR_CTRL_EN_FALLING + GPIO interrupt enable for GPIO, falling edge. If [`INTR_ENABLE`](#intr_enable)[i] is true, a value of 1 on [`INTR_CTRL_EN_FALLING`](#intr_ctrl_en_falling)[i] enables falling-edge interrupt detection on GPIO[i]. + - Offset: `0x30` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -279,15 +319,18 @@ enables falling-edge interrupt detection on GPIO[i]. {"reg": [{"name": "INTR_CTRL_EN_FALLING", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:---------------------|:--------------| -| 31:0 | rw | 0x0 | INTR_CTRL_EN_FALLING | | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :------------------- | :---------- | +| 31:0 | rw | 0x0 | INTR_CTRL_EN_FALLING | | ## INTR_CTRL_EN_LVLHIGH + GPIO interrupt enable for GPIO, level high. If [`INTR_ENABLE`](#intr_enable)[i] is true, a value of 1 on [`INTR_CTRL_EN_LVLHIGH`](#intr_ctrl_en_lvlhigh)[i] enables level high interrupt detection on GPIO[i]. + - Offset: `0x34` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -298,15 +341,18 @@ enables level high interrupt detection on GPIO[i]. {"reg": [{"name": "INTR_CTRL_EN_LVLHIGH", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:---------------------|:--------------| -| 31:0 | rw | 0x0 | INTR_CTRL_EN_LVLHIGH | | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :------------------- | :---------- | +| 31:0 | rw | 0x0 | INTR_CTRL_EN_LVLHIGH | | ## INTR_CTRL_EN_LVLLOW + GPIO interrupt enable for GPIO, level low. If [`INTR_ENABLE`](#intr_enable)[i] is true, a value of 1 on [`INTR_CTRL_EN_LVLLOW`](#intr_ctrl_en_lvllow)[i] enables level low interrupt detection on GPIO[i]. + - Offset: `0x38` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -317,15 +363,18 @@ enables level low interrupt detection on GPIO[i]. {"reg": [{"name": "INTR_CTRL_EN_LVLLOW", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:--------------------|:--------------| -| 31:0 | rw | 0x0 | INTR_CTRL_EN_LVLLOW | | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :------------------ | :---------- | +| 31:0 | rw | 0x0 | INTR_CTRL_EN_LVLLOW | | ## CTRL_EN_INPUT_FILTER + filter enable for GPIO input bits. If [`CTRL_EN_INPUT_FILTER`](#ctrl_en_input_filter)[i] is true, a value of input bit [i] must be stable for 16 cycles before transitioning. + - Offset: `0x3c` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -336,12 +385,15 @@ must be stable for 16 cycles before transitioning. {"reg": [{"name": "CTRL_EN_INPUT_FILTER", "bits": 32, "attr": ["rw"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:---------------------|:--------------| -| 31:0 | rw | 0x0 | CTRL_EN_INPUT_FILTER | | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :------------------- | :---------- | +| 31:0 | rw | 0x0 | CTRL_EN_INPUT_FILTER | | ## HW_STRAPS_DATA_IN_VALID + Indicates whether the data in [`HW_STRAPS_DATA_IN`](#hw_straps_data_in) is valid. + - Offset: `0x40` - Reset default: `0x0` - Reset mask: `0x1` @@ -352,13 +404,16 @@ Indicates whether the data in [`HW_STRAPS_DATA_IN`](#hw_straps_data_in) is valid {"reg": [{"name": "HW_STRAPS_DATA_IN_VALID", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 250}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:------------------------|:--------------| -| 31:1 | | | | Reserved | -| 0 | ro | 0x0 | HW_STRAPS_DATA_IN_VALID | | + +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :---------------------- | :---------- | +| 31:1 | | | | Reserved | +| 0 | ro | 0x0 | HW_STRAPS_DATA_IN_VALID | | ## HW_STRAPS_DATA_IN + GPIO Input data sampled as straps during cold boot read value + - Offset: `0x44` - Reset default: `0x0` - Reset mask: `0xffffffff` @@ -369,9 +424,9 @@ GPIO Input data sampled as straps during cold boot read value {"reg": [{"name": "HW_STRAPS_DATA_IN", "bits": 32, "attr": ["ro"], "rotate": 0}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} ``` -| Bits | Type | Reset | Name | Description | -|:------:|:------:|:-------:|:------------------|:--------------| -| 31:0 | ro | 0x0 | HW_STRAPS_DATA_IN | | +| Bits | Type | Reset | Name | Description | +| :--: | :--: | :---: | :---------------- | :---------- | +| 31:0 | ro | 0x0 | HW_STRAPS_DATA_IN | | diff --git a/hw/ip/gpio/dv/env/gpio_env.core b/hw/ip/gpio/dv/env/gpio_env.core index da4d4389683e1..7e4c39ede5441 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 111ac6c7a7e16..ced2992614c1a 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 c8af480a21b31..af36313b2d844 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; diff --git a/hw/ip/gpio/dv/env/gpio_env_pkg.sv b/hw/ip/gpio/dv/env/gpio_env_pkg.sv index 1c94585f24835..d6d8ecb371fd2 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 26f53a7abbe94..d3d8eba7cbefa 100644 --- a/hw/ip/gpio/dv/env/gpio_scoreboard.sv +++ b/hw/ip/gpio/dv/env/gpio_scoreboard.sv @@ -31,6 +31,12 @@ 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; + // hw straps_data_in_valid register + bit straps_data_in_valid; + // hw straps_data_in register + bit [NUM_GPIOS-1:0] straps_data_in; + // Flag to indicate that the strap was trigered + bit first_strap_trigged; // mask are WO, store the values in scb uvm_reg_data_t masked_out_lower_mask; @@ -40,7 +46,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 +62,7 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg), fork monitor_gpio_i(); monitor_gpio_interrupt_pins(); + monitor_gpio_straps(); join_none endtask @@ -360,6 +369,38 @@ 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) + `uvm_info(`gfn, "Monitor gpio_straps on!", UVM_HIGH) + if (|gpio_i_driven === 1'b1) begin + @(negedge cfg.straps_vif_inst.strap_en_i) begin + if (first_strap_trigged == 0) begin + // Update data_in ral register value based on result of input + void'(ral.hw_straps_data_in.predict(.value(gpio_i_driven), .kind(UVM_PREDICT_DIRECT))); + // Update data_in register value based on result of input + void'(ral.hw_straps_data_in_valid.predict(.value('b1), .kind(UVM_PREDICT_DIRECT))); + check_straps(); + end + end + end + end + endtask : monitor_gpio_straps + + // Function: check_straps + // Used to check the behavior of the straps register data. + // Based on strap_en input value, the straps register data should contains the snapshot of the data_in pins + function void check_straps(); + // 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_o.data) + // Check the register hw_straps_data_in_valid + `DV_CHECK_CASE_EQ('b1, cfg.straps_vif_inst.sampled_straps_o.valid) + // Turn-off the checker after the first strap trigger. + first_strap_trigged = 'b1; + endfunction : check_straps + // Function: actual_gpio_i_activity function bit actual_gpio_i_activity(); return ~((prv_gpio_i_pins_o === cfg.gpio_vif.pins_o) && @@ -478,6 +519,16 @@ class gpio_scoreboard extends cip_base_scoreboard #(.CFG_T (gpio_env_cfg), end "ctrl_en_input_filter": begin end + "hw_straps_data_in_valid": begin + straps_data_in_valid = csr.get_mirrored_value(); + `uvm_info(`gfn, $sformatf("straps_data_in_valid updated to 0x%0h", straps_data_in_valid), + UVM_HIGH) + end + "hw_straps_data_in": begin + straps_data_in = csr.get_mirrored_value(); + `uvm_info(`gfn, $sformatf("straps_data_in updated to 0x%0h", straps_data_in), + UVM_HIGH) + end default: begin `uvm_fatal(`gfn, $sformatf("invalid csr: %0s", csr.get_full_name())) end @@ -561,6 +612,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 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 0000000000000..0a5db76ab635b --- /dev/null +++ b/hw/ip/gpio/dv/env/seq_lib/gpio_rand_straps_vseq.sv @@ -0,0 +1,121 @@ +// 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_rand_straps_vseq +// This gpio random test sequence performs following in each of multiple iterations: +// - Drives gpio_i input with random values +// - Set the expected strap_data_in based on the condition if is the first triggered strap_en or not +// - Updates the RAL model with the expected strap_data_in and strap_data_in_valid +// - Trigger the strap_en with one clock cycles +// - Read the registers hw_straps_data_in and hw_straps_data_in_valid +// - Check the expected behavior in the scoreboard and also on csr checks +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_i; + // gpio output to program in register + rand bit [NUM_GPIOS-1:0] gpio_o; + // gpio output enable to program in register + rand bit [NUM_GPIOS-1:0] gpio_oe; + // Flag to indicate that the first trigger straps happened + bit straps_triggered; + // 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; + // Expected strap data_in + bit [NUM_GPIOS-1:0] exp_strap_data_in; + + constraint num_trans_c { + num_trans inside {[20:200]}; + } + + function new(string name = "gpio_rand_straps_vseq"); + super.new(name); + endfunction + + 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) + `DV_CHECK_MEMBER_RANDOMIZE_FATAL(gpio_i) + `DV_CHECK_MEMBER_RANDOMIZE_FATAL(gpio_o) + `DV_CHECK_MEMBER_RANDOMIZE_FATAL(gpio_oe) + + cfg.clk_rst_vif.wait_clks(delay); + `uvm_info(msg_id, $sformatf("delay = %0d", delay), UVM_HIGH) + // Step-1 Drive the gpio_i + drive_gpio_in(gpio_i); + + // If is not the first strap triggered, it should be the gpio_i input (that is the first one after reset), + // for the following interations keep the same value as the first strap already happened. + // No more updates in gpio_i should be taken + // into consideration for the strap_data_in register. + if(straps_triggered) begin + exp_strap_data_in = rd_hw_straps_data_in; + end else begin + exp_strap_data_in = gpio_i; + end + + // Wait at least one clock cycle + `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 1;) + + // Step-2 Trigger the snapshot of gpio_i 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; + straps_triggered = 'b1; + + // Step-3 Read the HW_STRAPS_DATA_IN register + // Reading straps data_in will trigger a check inside scoreboard + + // Wait at least one clock cycle + `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 1;) + + // Step-4 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)); + + // Stop driving gpio_i + undrive_gpio_in(); + + // Step-5 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)); + + // Additional verification + // Drive the gpio_o to make sure that has no impact on straps registers. + // test gpio outputs + cfg.gpio_vif.drive_en('0); + + ral.direct_out.set(gpio_o); + ral.direct_oe.set(gpio_oe); + csr_update(.csr(ral.direct_out)); + csr_update(.csr(ral.direct_oe)); + + `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 1;) + + // Step-6 Drive again the strap_en + cfg.straps_vif_inst.strap_en = 1; + cfg.clk_rst_vif.wait_clks(1); + cfg.straps_vif_inst.strap_en = 0; + + `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(delay, delay >= 1;) + + // Step-7 Read to make sure that if does not affect the straps registers after drive the gpio_o + 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)); + + `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 fd508cad328b8..ab7a840ca9d85 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 a33d0dc74f66e..325079ca43de6 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 6a8910a766954..0c8405987837e 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 0000000000000..c3d4a82ce3654 --- /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 0000000000000..25afe21242491 --- /dev/null +++ b/hw/ip/gpio/dv/interfaces/gpio_straps_if.sv @@ -0,0 +1,21 @@ +// 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 ( + inout strap_en_i, // Input signal to enable straps + input gpio_straps_t sampled_straps_o // Output signal of type gpio_straps_t +); + + logic strap_en; + assign strap_en_i = strap_en; + +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 94e8ebac0b7c0..dc77d348be857 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_i; `DV_ALERT_IF_CONNECT() @@ -33,6 +33,8 @@ module tb; .rst_n(rst_n) ); pins_if #(NUM_MAX_INTERRUPTS) intr_if (.pins(interrupts)); + gpio_straps_if straps_if_inst (.strap_en_i(strap_en_i), + .sampled_straps_o(sampled_straps)); tl_if tl_if ( .clk (clk), .rst_n(rst_n) @@ -52,9 +54,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(strap_en_i), + .sampled_straps_o(sampled_straps), .tl_i(tl_if.h2d), .tl_o(tl_if.d2h), @@ -85,6 +86,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 e12c37d4c78ee..da86a19cdad08 100644 --- a/hw/ip/gpio/dv/tests/gpio_base_test.sv +++ b/hw/ip/gpio/dv/tests/gpio_base_test.sv @@ -7,10 +7,22 @@ class gpio_base_test extends cip_base_test #( .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