94 Normative Rules: Includes 31 Implementation-Defined Behaviors (26 No Category, 4 WARL, 1 WLRL)
+96 Normative Rules: Includes 33 Implementation-Defined Behaviors (26 No Category, 5 WARL, 2 WLRL)
| norm:mock-ext-dep-A-on-B | |||
| FOO_ABC_WARL_LEGAL_LIST | +FOO_ABC_WARL_ENUM | csr_field | Kind | Implementation-defined behavior category |
| The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 3, or 10. An implementation can support any subset of these values. |
- norm:foo_abc_warl_legal_list | +The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 0b11, or 0xffff_ffff. Returns 0x7fff if written with an illegal value. |
+ norm:foo_abc_warl_enum |
| FOO_DEF_WARL_WIDTH_UINT4TO8 | +FOO_DEF_WARL_ENUM | +csr_field | +Kind | +
| foo.DEF | +Instance | +||
| Implementation-defined behavior | +Implementation-defined behavior | +||
| WARL | +Implementation-defined behavior category | +||
| The architecturally-defined values for the 8-bit foo.DEF CSR field are -1 or 0xf0. Ignores writes with an illegal value. |
+ norm:foo_def_warl_enum | +||
| FOO_GHI_WARL_WIDTH_UINT4TO8 | Implementation-defined behavior | Implementation-defined behavior | Implementation-defined behavior category |
| The foo.DEF CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value. | -norm:foo_def_warl_width_uint4to8 | +The foo.GHI CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value. | +norm:foo_ghi_warl_width_uint4to8 |
| BAR_WARL_READONLY_VALUE | @@ -1123,6 +1144,27 @@An implementation may treat each bit of the zort.XYZ CSR as read-only or read-write. Read-only bits can be 0 or 1. |
norm:zort_xyz_wlrl_readonly_zero | |
| QUX_QQQ_WLRL_NO_SELECTOR | +csr_field | +Kind | +|
| qux.QQQ | +Instance | +||
| Implementation-defined behavior | +Implementation-defined behavior | +||
| WLRL | +Implementation-defined behavior category | +||
| The qux.QQQ CSR field has implementation-defined behavior without an enum, width, or read-only mask selector. |
+ norm:qux_qqq_wlrl_no_selector | +
94 Normative Rules: Includes 31 Implementation-D
- WARL Category (A-Z): All 4 Implementation-Defined Behaviors
+ WARL Category (A-Z): All 5 Implementation-Defined Behaviors
@@ -1503,7 +1545,7 @@ 94 Normative Rules: Includes 31 Implementation-D
norm:bar_warl_readonly_value
- FOO_ABC_WARL_LEGAL_LIST
+ FOO_ABC_WARL_ENUM
csr_field
Kind
@@ -1512,13 +1554,26 @@ 94 Normative Rules: Includes 31 Implementation-D
Instance
- The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 3, or 10.
An implementation can support any subset of these values.
- norm:foo_abc_warl_legal_list
+ The architecturally-defined values for the 4-bit foo.ABC
CSR field are 0, 0b11, or 0xffff_ffff. Returns 0x7fff if written with an illegal value.
+ norm:foo_abc_warl_enum
+
+
+ FOO_DEF_WARL_ENUM
+ csr_field
+ Kind
+
+
+ foo.DEF
+ Instance
+
+
+ The architecturally-defined values for the 8-bit foo.DEF
CSR field are -1 or 0xf0. Ignores writes with an illegal value.
+ norm:foo_def_warl_enum
- FOO_DEF_WARL_WIDTH_UINT4TO8
- The foo.DEF CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value.
- norm:foo_def_warl_width_uint4to8
+ FOO_GHI_WARL_WIDTH_UINT4TO8
+ The foo.GHI CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value.
+ norm:foo_ghi_warl_width_uint4to8
SATP_ASID_WARL_ASIDLEN
@@ -1539,7 +1594,7 @@ 94 Normative Rules: Includes 31 Implementation-D
- WLRL Category (A-Z): All 1 Implementation-Defined Behaviors
+ WLRL Category (A-Z): All 2 Implementation-Defined Behaviors
@@ -1549,6 +1604,19 @@ 94 Normative Rules: Includes 31 Implementation-D
Name Information Information Source
+
+ QUX_QQQ_WLRL_NO_SELECTOR
+ csr_field
+ Kind
+
+
+ qux.QQQ
+ Instance
+
+
+ The qux.QQQ CSR field has implementation-defined behavior
without an enum, width, or read-only mask selector.
+ norm:qux_qqq_wlrl_no_selector
+
ZORT_XYZ_WLRL_READONLY_ZERO
csr_field
@@ -1800,7 +1868,7 @@ 94 Normative Rules: Includes 31 Implementation-D
- Chapter Two: All 15 Implementation-Defined Behaviors
+ Chapter Two: All 17 Implementation-Defined Behaviors
@@ -1946,7 +2014,7 @@ 94 Normative Rules: Includes 31 Implementation-D
norm:mock-ext-dep-A-on-B
- FOO_ABC_WARL_LEGAL_LIST
+ FOO_ABC_WARL_ENUM
csr_field
Kind
@@ -1959,17 +2027,34 @@ 94 Normative Rules: Includes 31 Implementation-D
Implementation-defined behavior category
- The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 3, or 10.
An implementation can support any subset of these values.
- norm:foo_abc_warl_legal_list
+ The architecturally-defined values for the 4-bit foo.ABC
CSR field are 0, 0b11, or 0xffff_ffff. Returns 0x7fff if written with an illegal value.
+ norm:foo_abc_warl_enum
+
+
+ FOO_DEF_WARL_ENUM
+ csr_field
+ Kind
+
+
+ foo.DEF
+ Instance
- FOO_DEF_WARL_WIDTH_UINT4TO8
WARL
Implementation-defined behavior category
- The foo.DEF CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value.
- norm:foo_def_warl_width_uint4to8
+ The architecturally-defined values for the 8-bit foo.DEF
CSR field are -1 or 0xf0. Ignores writes with an illegal value.
+ norm:foo_def_warl_enum
+
+
+ FOO_GHI_WARL_WIDTH_UINT4TO8
+ WARL
+ Implementation-defined behavior category
+
+
+ The foo.GHI CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value.
+ norm:foo_ghi_warl_width_uint4to8
BAR_WARL_READONLY_VALUE
@@ -2005,6 +2090,23 @@ 94 Normative Rules: Includes 31 Implementation-D
An implementation may treat each bit of the zort.XYZ CSR as
read-only or read-write. Read-only bits can be 0 or 1.
norm:zort_xyz_wlrl_readonly_zero
+
+ QUX_QQQ_WLRL_NO_SELECTOR
+ csr_field
+ Kind
+
+
+ qux.QQQ
+ Instance
+
+
+ WLRL
+ Implementation-defined behavior category
+
+
+ The qux.QQQ CSR field has implementation-defined behavior
without an enum, width, or read-only mask selector.
+ norm:qux_qqq_wlrl_no_selector
+
diff --git a/tests/norm-rule/expected/test-norm-rules.json b/tests/norm-rule/expected/test-norm-rules.json
index 60f034f..6249d6f 100644
--- a/tests/norm-rule/expected/test-norm-rules.json
+++ b/tests/norm-rule/expected/test-norm-rules.json
@@ -1528,7 +1528,7 @@
]
},
{
- "name": "FOO_ABC_WARL_LEGAL_LIST",
+ "name": "FOO_ABC_WARL_ENUM",
"def_filename": "tests/norm-rule/test-ch2.yaml",
"chapter_name": "Two",
"kind": "csr_field",
@@ -1539,25 +1539,45 @@
"impl-def-category": "WARL",
"tags": [
{
- "name": "norm:foo_abc_warl_legal_list",
+ "name": "norm:foo_abc_warl_enum",
"context": false,
- "text": "The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 3, or 10.\nAn implementation can support any subset of these values.",
+ "text": "The architecturally-defined values for the 4-bit foo.ABC\nCSR field are 0, 0b11, or 0xffff_ffff. Returns 0x7fff if written with an illegal value.",
"tag_filename": "/build/test-ch2-norm-tags.json",
"stds_doc_url": "test-ch2.html"
}
]
},
{
- "name": "FOO_DEF_WARL_WIDTH_UINT4TO8",
+ "name": "FOO_DEF_WARL_ENUM",
+ "def_filename": "tests/norm-rule/test-ch2.yaml",
+ "chapter_name": "Two",
+ "kind": "csr_field",
+ "impl-def-behavior": true,
+ "instances": [
+ "foo.DEF"
+ ],
+ "impl-def-category": "WARL",
+ "tags": [
+ {
+ "name": "norm:foo_def_warl_enum",
+ "context": false,
+ "text": "The architecturally-defined values for the 8-bit foo.DEF\nCSR field are -1 or 0xf0. Ignores writes with an illegal value.",
+ "tag_filename": "/build/test-ch2-norm-tags.json",
+ "stds_doc_url": "test-ch2.html"
+ }
+ ]
+ },
+ {
+ "name": "FOO_GHI_WARL_WIDTH_UINT4TO8",
"def_filename": "tests/norm-rule/test-ch2.yaml",
"chapter_name": "Two",
"impl-def-behavior": true,
"impl-def-category": "WARL",
"tags": [
{
- "name": "norm:foo_def_warl_width_uint4to8",
+ "name": "norm:foo_ghi_warl_width_uint4to8",
"context": false,
- "text": "The foo.DEF CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value.",
+ "text": "The foo.GHI CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value.",
"tag_filename": "/build/test-ch2-norm-tags.json",
"stds_doc_url": "test-ch2.html"
}
@@ -1602,6 +1622,26 @@
"stds_doc_url": "test-ch2.html"
}
]
+ },
+ {
+ "name": "QUX_QQQ_WLRL_NO_SELECTOR",
+ "def_filename": "tests/norm-rule/test-ch2.yaml",
+ "chapter_name": "Two",
+ "kind": "csr_field",
+ "impl-def-behavior": true,
+ "instances": [
+ "qux.QQQ"
+ ],
+ "impl-def-category": "WLRL",
+ "tags": [
+ {
+ "name": "norm:qux_qqq_wlrl_no_selector",
+ "context": false,
+ "text": "The qux.QQQ CSR field has implementation-defined behavior\nwithout an enum, width, or read-only mask selector.",
+ "tag_filename": "/build/test-ch2-norm-tags.json",
+ "stds_doc_url": "test-ch2.html"
+ }
+ ]
}
]
}
\ No newline at end of file
diff --git a/tests/norm-rule/test-ch2.adoc b/tests/norm-rule/test-ch2.adoc
index 510ebaa..0f7f699 100644
--- a/tests/norm-rule/test-ch2.adoc
+++ b/tests/norm-rule/test-ch2.adoc
@@ -82,13 +82,19 @@ Here's a normative rule for mock extension dependency of extension A on extensio
=== Chapter 2.3 - CSR Field Types
-[#norm:foo_abc_warl_legal_list]#The architecturally-defined values for the 4-bit `foo.ABC` CSR field are 0, 3, or 10.
-An implementation can support any subset of these values.#
+[#norm:foo_abc_warl_enum]#The architecturally-defined values for the 4-bit `foo.ABC`
+CSR field are 0, 0b11, or 0xffff_ffff. Returns 0x7fff if written with an illegal value.#
-[#norm:foo_def_warl_width_uint4to8]#The `foo.DEF` CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value.#
+[#norm:foo_def_warl_enum]#The architecturally-defined values for the 8-bit `foo.DEF`
+CSR field are -1 or 0xf0. Ignores writes with an illegal value.#
+
+[#norm:foo_ghi_warl_width_uint4to8]#The `foo.GHI` CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value.#
[#norm:zort_xyz_wlrl_readonly_zero]#An implementation may treat each bit of the `zort.XYZ` CSR as
read-only or read-write. Read-only bits can be 0 or 1.#
[#norm:bar_warl_readonly_value]#An implementation may treat each bit of the `bar` CSR as
read-only or read-write. Read-only bits are 0.#
+
+[#norm:qux_qqq_wlrl_no_selector]#The `qux.QQQ` CSR field has implementation-defined behavior
+without an enum, width, or read-only mask selector.#
diff --git a/tests/norm-rule/test-ch2.yaml b/tests/norm-rule/test-ch2.yaml
index cbc9c64..3b80474 100644
--- a/tests/norm-rule/test-ch2.yaml
+++ b/tests/norm-rule/test-ch2.yaml
@@ -71,14 +71,20 @@ normative_rule_definitions:
instance: MockExtDepAOnB
# CSR field types
- - name: FOO_ABC_WARL_LEGAL_LIST
- tag: "norm:foo_abc_warl_legal_list"
+ - name: FOO_ABC_WARL_ENUM
+ tag: "norm:foo_abc_warl_enum"
impl-def-behavior: true
impl-def-category: WARL
kind: csr_field
instance: foo.ABC
- - name: FOO_DEF_WARL_WIDTH_UINT4TO8
- tag: "norm:foo_def_warl_width_uint4to8"
+ - name: FOO_DEF_WARL_ENUM
+ tag: "norm:foo_def_warl_enum"
+ impl-def-behavior: true
+ impl-def-category: WARL
+ kind: csr_field
+ instance: foo.DEF
+ - name: FOO_GHI_WARL_WIDTH_UINT4TO8
+ tag: "norm:foo_ghi_warl_width_uint4to8"
impl-def-behavior: true
impl-def-category: WARL
- name: BAR_WARL_READONLY_VALUE
@@ -93,3 +99,9 @@ normative_rule_definitions:
impl-def-category: WLRL
kind: csr_field
instance: zort.XYZ
+ - name: QUX_QQQ_WLRL_NO_SELECTOR
+ tag: "norm:qux_qqq_wlrl_no_selector"
+ impl-def-behavior: true
+ impl-def-category: WLRL
+ kind: csr_field
+ instance: qux.QQQ
diff --git a/tests/params/expected/test-params.html b/tests/params/expected/test-params.html
index 71fa6c6..9e70863 100644
--- a/tests/params/expected/test-params.html
+++ b/tests/params/expected/test-params.html
@@ -53,13 +53,13 @@ Parameters by Chapter
WARL/WLRL by Chapter
- 42 Parameters, 5 WARL/WLRL CSRs
+ 42 Parameters, 7 WARL/WLRL CSRs
@@ -398,7 +398,7 @@ 42 Parameters, 5 WARL/WLRL CSRs
satp.MODE
- width:ASIDLEN
+ width: ASIDLEN
FLD:satp.ASID
The satp.ASID CSR field width is specified by the ASIDLEN parameter value.
@@ -408,7 +408,7 @@ 42 Parameters, 5 WARL/WLRL CSRs
- Chapter Two WARL: 3 CSRs
+ Chapter Two WARL: 4 CSRs
@@ -421,15 +421,21 @@ 42 Parameters, 5 WARL/WLRL CSRs
foo.ABC
- [0, 3, 10]
+ Enum
legal: [0, 0b11, 0xffff_ffff]
Illegal write returns: 0x7fff
FLD:foo.ABC
- The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 3, or 10.
An implementation can support any subset of these values.
+ The architecturally-defined values for the 4-bit foo.ABC
CSR field are 0, 0b11, or 0xffff_ffff. Returns 0x7fff if written with an illegal value.
foo.DEF
- width:UINT_4TO8
+ Enum
legal: [-1, 0xf0]
Ignores illegal writes
+ FLD:foo.DEF
+ The architecturally-defined values for the 8-bit foo.DEF
CSR field are -1 or 0xf0. Ignores writes with an illegal value.
+
+
+ foo.GHI
+ width: UINT_4TO8
CHAP:Two
- The foo.DEF CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value.
+ The foo.GHI CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value.
bar
@@ -443,7 +449,7 @@ 42 Parameters, 5 WARL/WLRL CSRs
- Chapter Two WLRL: 1 CSR
+ Chapter Two WLRL: 2 CSRs
@@ -460,6 +466,12 @@ 42 Parameters, 5 WARL/WLRL CSRs
FLD:zort.XYZ
An implementation may treat each bit of the zort.XYZ CSR as
read-only or read-write. Read-only bits can be 0 or 1.
+
+ qux.QQQ
+ WLRL
+ FLD:qux.QQQ
+ The qux.QQQ CSR field has implementation-defined behavior
without an enum, width, or read-only mask selector.
+
diff --git a/tests/params/expected/test-params.json b/tests/params/expected/test-params.json
index 07fe4b1..4707c64 100644
--- a/tests/params/expected/test-params.json
+++ b/tests/params/expected/test-params.json
@@ -1533,14 +1533,17 @@
"def_filename": "test-ch2.yaml",
"chapter_name": "Two",
"category": "WARL",
- "type": [
- 0,
- 3,
- 10
- ],
+ "enum": {
+ "legal": [
+ 0,
+ 3,
+ 4294967295
+ ],
+ "illegal-write-return": 32767
+ },
"impl-defs": [
{
- "name": "FOO_ABC_WARL_LEGAL_LIST",
+ "name": "FOO_ABC_WARL_ENUM",
"def_filename": "tests/norm-rule/test-ch2.yaml",
"chapter_name": "Two",
"kind": "csr_field",
@@ -1551,9 +1554,9 @@
"impl-def-category": "WARL",
"tags": [
{
- "name": "norm:foo_abc_warl_legal_list",
+ "name": "norm:foo_abc_warl_enum",
"context": false,
- "text": "The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 3, or 10.\nAn implementation can support any subset of these values.",
+ "text": "The architecturally-defined values for the 4-bit foo.ABC\nCSR field are 0, 0b11, or 0xffff_ffff. Returns 0x7fff if written with an illegal value.",
"tag_filename": "/build/test-ch2-norm-tags.json",
"stds_doc_url": "test-ch2.html"
}
@@ -1567,19 +1570,55 @@
"def_filename": "test-ch2.yaml",
"chapter_name": "Two",
"category": "WARL",
+ "enum": {
+ "legal": [
+ -1,
+ 240
+ ],
+ "illegal-write-ignore": true
+ },
+ "impl-defs": [
+ {
+ "name": "FOO_DEF_WARL_ENUM",
+ "def_filename": "tests/norm-rule/test-ch2.yaml",
+ "chapter_name": "Two",
+ "kind": "csr_field",
+ "impl-def-behavior": true,
+ "instances": [
+ "foo.DEF"
+ ],
+ "impl-def-category": "WARL",
+ "tags": [
+ {
+ "name": "norm:foo_def_warl_enum",
+ "context": false,
+ "text": "The architecturally-defined values for the 8-bit foo.DEF\nCSR field are -1 or 0xf0. Ignores writes with an illegal value.",
+ "tag_filename": "/build/test-ch2-norm-tags.json",
+ "stds_doc_url": "test-ch2.html"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "reg-name": "foo",
+ "field-name": "GHI",
+ "def_filename": "test-ch2.yaml",
+ "chapter_name": "Two",
+ "category": "WARL",
"width": "UINT_4TO8",
"impl-defs": [
{
- "name": "FOO_DEF_WARL_WIDTH_UINT4TO8",
+ "name": "FOO_GHI_WARL_WIDTH_UINT4TO8",
"def_filename": "tests/norm-rule/test-ch2.yaml",
"chapter_name": "Two",
"impl-def-behavior": true,
"impl-def-category": "WARL",
"tags": [
{
- "name": "norm:foo_def_warl_width_uint4to8",
+ "name": "norm:foo_ghi_warl_width_uint4to8",
"context": false,
- "text": "The foo.DEF CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value.",
+ "text": "The foo.GHI CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value.",
"tag_filename": "/build/test-ch2-norm-tags.json",
"stds_doc_url": "test-ch2.html"
}
@@ -1646,6 +1685,35 @@
]
}
]
+ },
+ {
+ "reg-name": "qux",
+ "field-name": "QQQ",
+ "def_filename": "test-ch2.yaml",
+ "chapter_name": "Two",
+ "category": "WLRL",
+ "impl-defs": [
+ {
+ "name": "QUX_QQQ_WLRL_NO_SELECTOR",
+ "def_filename": "tests/norm-rule/test-ch2.yaml",
+ "chapter_name": "Two",
+ "kind": "csr_field",
+ "impl-def-behavior": true,
+ "instances": [
+ "qux.QQQ"
+ ],
+ "impl-def-category": "WLRL",
+ "tags": [
+ {
+ "name": "norm:qux_qqq_wlrl_no_selector",
+ "context": false,
+ "text": "The qux.QQQ CSR field has implementation-defined behavior\nwithout an enum, width, or read-only mask selector.",
+ "tag_filename": "/build/test-ch2-norm-tags.json",
+ "stds_doc_url": "test-ch2.html"
+ }
+ ]
+ }
+ ]
}
]
}
diff --git a/tests/params/test-ch2.yaml b/tests/params/test-ch2.yaml
index 60367fe..34a988c 100644
--- a/tests/params/test-ch2.yaml
+++ b/tests/params/test-ch2.yaml
@@ -50,17 +50,31 @@ parameter_definitions:
note: This is a Mock extension dependency parameter (A depends B).
csr_definitions:
- # Case 1: CSR field with a list of possible legal values. Some values may be mandatory and some optional
- # but that isn't tracked here.
+ # Case 1a: Enum with list of potentially legal values.
+ # Some values may be mandatory and some optional for an implementation but that isn't tracked here.
+ # Returns 0x7fff if written with an illegal value.
+ # Legal values use a mix of decimal, binary (0b11), and hex (0xffff_ffff) to test multibase support.
- reg-name: foo
field-name: ABC
- impl-def: FOO_ABC_WARL_LEGAL_LIST
- type: [0, 3, 10]
+ impl-def: FOO_ABC_WARL_ENUM
+ enum:
+ legal: [0, 0b11, 0xffff_ffff]
+ illegal-write-return: 0x7fff
- # Case 2: CSR field with width specified by a named parameter's value.
+ # Case 1b: Enum with list of potentially legal values.
+ # Ignores writes of illegal values (i.e. the write has no effect).
+ # Legal values use decimal and hex (0xf0) to further test multibase support.
- reg-name: foo
field-name: DEF
- impl-def: FOO_DEF_WARL_WIDTH_UINT4TO8
+ impl-def: FOO_DEF_WARL_ENUM
+ enum:
+ legal: [-1, 0xf0]
+ illegal-write-ignore: true
+
+ # Case 2: CSR field with width specified by a named parameter's value.
+ - reg-name: foo
+ field-name: GHI
+ impl-def: FOO_GHI_WARL_WIDTH_UINT4TO8
width: UINT_4TO8
# Case 3a: CSR with some bits that are read-only and some bits that are read-write.
@@ -76,3 +90,8 @@ csr_definitions:
field-name: XYZ
impl-def: ZORT_XYZ_WLRL_READONLY_ZERO
ro-mask: 0b1111
+
+ # Case 4: CSR field with no selector property (enum/width/ro-mask all omitted).
+ - reg-name: qux
+ field-name: QQQ
+ impl-def: QUX_QQQ_WLRL_NO_SELECTOR
diff --git a/tests/shared_utils/test_shared_utils.py b/tests/shared_utils/test_shared_utils.py
index 8381f06..481f94f 100644
--- a/tests/shared_utils/test_shared_utils.py
+++ b/tests/shared_utils/test_shared_utils.py
@@ -191,6 +191,20 @@ def test_infer_param_type_string_success_cases():
)
== "[1, 2, 3]"
)
+ assert (
+ shared_utils.infer_param_type_string(
+ {
+ "reg-name": "foo",
+ "field-name": "ABC",
+ "enum": {
+ "legal": [0, 3, 10],
+ "illegal-write-return": 0,
+ },
+ },
+ lambda msg: (_ for _ in ()).throw(AssertionError(msg)),
+ )
+ == "[0, 3, 10]"
+ )
# Range and array wrapping.
assert (
@@ -265,7 +279,7 @@ def test_infer_param_type_string_all_fatal_cases():
),
(
{"name": "P"},
- "has neither a valid type nor a valid range",
+ "has neither a valid type, enum, nor a valid range",
),
(
{"name": "P", "type": "boolean", "array": [0]},
diff --git a/tools/README.md b/tools/README.md
index 4e2dd9e..c469724 100644
--- a/tools/README.md
+++ b/tools/README.md
@@ -186,8 +186,8 @@ Examples:
CSR Definition Encoding:
- Use `csr_definitions` entries for CSRs, with `reg-name` (single CSR) or `reg-names` (multiple CSRs).
-- A CSR entry must include exactly one selector property:
- - `type`
+- CSR selector properties are optional. If provided, use at most one of:
+ - `enum`
- `width`
- `ro-mask`
- `ro-value` is optional, but if present then `ro-mask` is required.
@@ -198,8 +198,11 @@ CSR Definition Encoding:
- The category is mapped into CSR category (`WARL`/`WLRL`) for output grouping.
CSR selector properties:
-- `type`: List of legal integer values for the CSR (or CSR field).
- - Format: `[v0, v1, ...]` where each value is an integer.
+- `enum`: Object specifying legal values and illegal-write behavior.
+ - `legal`: Array of one or more integers representing legal write values (required).
+ - `illegal-write-ignore`: Boolean specifying whether illegal writes are silently ignored (mutually exclusive with `illegal-write-return`).
+ - `illegal-write-return`: Integer value to return on illegal writes (mutually exclusive with `illegal-write-ignore`).
+ - Must specify `legal` and exactly one of `illegal-write-ignore` or `illegal-write-return`.
- `width`: Name of a parameter that defines CSR width.
- Format: `width: `.
- `ro-mask`/`ro-value`: Bit-mask model for read-only bits.
@@ -209,16 +212,19 @@ CSR selector properties:
- Both accept decimal integer, hex string (`0x...`), or binary string (`0b...`).
Notes on output behavior:
+- JSON output preserves the structure of the authored `enum` object in the generated `csrs` entry, but normalizes any multibase numeric values (for example hex `0x...` or binary `0b...`) to plain integers.
- JSON output stores `ro-mask`/`ro-value` as integers.
-- HTML output preserves the original authored literal text for `ro-mask`/`ro-value` when available (for example `0xF0F0` or `0b1100`).
+- HTML output uses internal underscore-prefixed fields to preserve the original authored literal text for `enum` values and `ro-mask`/`ro-value` when available (for example `0xF0F0` or `0b1100`).
Examples:
```yaml
-# Type-based CSR field (potentially legal enumerated values)
+# Enum: Legal CSR field values plus illegal-write behavior
- reg-name: mtvec
field-name: MODE
impl-def: MTVEC_MODE_WARL
- type: [0, 1]
+ enum:
+ legal: [0, 1]
+ illegal-write-ignore: true
# Width-based CSR field (width references an existing parameter)
- reg-name: satp
diff --git a/tools/create_params.py b/tools/create_params.py
index aa16f26..5926aa6 100644
--- a/tools/create_params.py
+++ b/tools/create_params.py
@@ -110,7 +110,7 @@ def load_yaml_file(pathname: str) -> Dict[str, Any]:
return load_yaml_object(pathname, fatal)
-def load_csr_literal_texts(pathname: str) -> List[Dict[str, str]]:
+def load_csr_literal_texts(pathname: str) -> List[Dict[str, Any]]:
"""Load raw scalar token text for CSR definitions from YAML source."""
yaml_module: Any = None
try:
@@ -148,10 +148,10 @@ def load_csr_literal_texts(pathname: str) -> List[Dict[str, str]]:
if not isinstance(csr_items, list):
return []
- wanted_keys = {"ro-mask", "ro-value"}
- literal_rows: List[Dict[str, str]] = []
+ wanted_scalar_keys = {"ro-mask", "ro-value"}
+ literal_rows: List[Dict[str, Any]] = []
for item_node in csr_items:
- row: Dict[str, str] = {}
+ row: Dict[str, Any] = {}
item_pairs = getattr(item_node, "value", None)
if isinstance(item_pairs, list):
for pair in item_pairs:
@@ -159,9 +159,41 @@ def load_csr_literal_texts(pathname: str) -> List[Dict[str, str]]:
continue
key_node, val_node = pair
key_text = getattr(key_node, "value", None)
- val_text = getattr(val_node, "value", None)
- if isinstance(key_text, str) and key_text in wanted_keys and isinstance(val_text, str):
- row[key_text] = val_text
+ if not isinstance(key_text, str):
+ continue
+
+ if key_text in wanted_scalar_keys:
+ val_text = getattr(val_node, "value", None)
+ if isinstance(val_text, str):
+ row[key_text] = val_text
+
+ elif key_text == "enum":
+ # Navigate into the nested enum mapping to capture raw texts.
+ enum_pairs = getattr(val_node, "value", None)
+ if isinstance(enum_pairs, list):
+ for enum_pair in enum_pairs:
+ if not isinstance(enum_pair, tuple) or len(enum_pair) != 2:
+ continue
+ enum_key_node, enum_val_node = enum_pair
+ enum_key = getattr(enum_key_node, "value", None)
+ if not isinstance(enum_key, str):
+ continue
+
+ if enum_key == "legal":
+ legal_item_nodes = getattr(enum_val_node, "value", None)
+ if isinstance(legal_item_nodes, list):
+ texts = [
+ t for node in legal_item_nodes
+ if isinstance(t := getattr(node, "value", None), str)
+ ]
+ if texts:
+ row["_enum-legal-texts"] = texts
+
+ elif enum_key == "illegal-write-return":
+ t = getattr(enum_val_node, "value", None)
+ if isinstance(t, str):
+ row["_enum-illegal-write-return-text"] = t
+
literal_rows.append(row)
return literal_rows
@@ -555,16 +587,16 @@ def parse_multibase_int(value: Any, label: str, csr_name: str) -> int:
)
return 0
- has_type = "type" in entry
+ has_enum = "enum" in entry
has_width = "width" in entry
has_read_only_mask = "ro-mask" in entry
has_read_only_value = "ro-value" in entry
- selector_count = int(has_type) + int(has_width) + int(has_read_only_mask)
- if selector_count != 1:
+ selector_count = int(has_enum) + int(has_width) + int(has_read_only_mask)
+ if selector_count > 1:
fatal(
- f"Found CSR entry in {def_filename} that must define exactly one of "
- "'type', 'width', or 'ro-mask'"
+ f"Found CSR entry in {def_filename} that cannot define more than one of "
+ "'enum', 'width', or 'ro-mask'"
)
if has_read_only_value and not has_read_only_mask:
fatal(
@@ -598,26 +630,65 @@ def parse_multibase_int(value: Any, label: str, csr_name: str) -> int:
representative_name = names[0]
- csr_type_input: Optional[List[int]] = None
csr_width_input: Optional[str] = None
csr_read_only_mask: Optional[int] = None
csr_read_only_value: Optional[int] = None
csr_read_only_mask_text: Optional[str] = None
csr_read_only_value_text: Optional[str] = None
-
- if has_type:
- raw_type = entry.get("type")
- if not isinstance(raw_type, list) or not raw_type:
- fatal(f"CSR {representative_name} in {def_filename} has invalid or empty type")
- assert isinstance(raw_type, list)
- csr_type_input = []
- for value in raw_type:
+ csr_legal_enum: Optional[List[int]] = None
+ csr_illegal_write_ignore: Optional[bool] = None
+ csr_illegal_write_return: Optional[int] = None
+
+ if has_enum:
+ raw_enum = entry.get("enum")
+ if not isinstance(raw_enum, dict):
+ fatal(f"CSR {representative_name} in {def_filename} has invalid enum (must be an object)")
+
+ # Parse legal values. YAML auto-converts hex/binary literals to integers;
+ # original text preservation is handled separately via load_csr_literal_texts.
+ raw_legal = raw_enum.get("legal")
+ if not isinstance(raw_legal, list) or not raw_legal:
+ fatal(f"CSR {representative_name} in {def_filename} has invalid or empty enum.legal")
+ csr_legal_enum = []
+ for value in raw_legal:
if not isinstance(value, int) or isinstance(value, bool):
fatal(
f"CSR {representative_name} in {def_filename} has non-integer "
- f"value in type: {value!r}"
+ f"value in enum.legal: {value!r}"
+ )
+ csr_legal_enum.append(value)
+
+ # Parse illegal-write behavior (must be one of the two)
+ raw_illegal_ignore = raw_enum.get("illegal-write-ignore")
+ raw_illegal_return = raw_enum.get("illegal-write-return")
+
+ if raw_illegal_ignore is None and raw_illegal_return is None:
+ fatal(f"CSR {representative_name} in {def_filename} must specify either 'illegal-write-ignore' or 'illegal-write-return' in enum")
+
+ if raw_illegal_ignore is not None and raw_illegal_return is not None:
+ fatal(f"CSR {representative_name} in {def_filename} must specify only one of 'illegal-write-ignore' or 'illegal-write-return' in enum")
+
+ if raw_illegal_ignore is not None:
+ if not isinstance(raw_illegal_ignore, bool):
+ fatal(f"CSR {representative_name} in {def_filename} has non-boolean illegal-write-ignore: {raw_illegal_ignore!r}")
+ if raw_illegal_ignore is not True:
+ fatal(
+ f"CSR {representative_name} in {def_filename} must set 'illegal-write-ignore' to true "
+ f"when present (got {raw_illegal_ignore!r})"
)
- csr_type_input.append(value)
+ csr_illegal_write_ignore = True
+
+ if raw_illegal_return is not None:
+ if not isinstance(raw_illegal_return, (str, int)) or isinstance(raw_illegal_return, bool):
+ fatal(
+ f"CSR {representative_name} in {def_filename} has invalid illegal-write-return "
+ f"{raw_illegal_return!r}; expected integer, hex string, or binary string"
+ )
+ csr_illegal_write_return = parse_multibase_int(
+ raw_illegal_return,
+ "illegal-write-return",
+ representative_name,
+ )
if has_width:
raw_width = entry.get("width")
@@ -738,8 +809,21 @@ def csr_id(field_name: Optional[str] = None) -> str:
"category": csr_category,
}
- if csr_type_input is not None:
- out_entry["type"] = list(csr_type_input)
+ if csr_legal_enum is not None:
+ enum_dict = {"legal": list(csr_legal_enum)}
+ if csr_illegal_write_ignore is not None:
+ enum_dict["illegal-write-ignore"] = csr_illegal_write_ignore
+ if csr_illegal_write_return is not None:
+ enum_dict["illegal-write-return"] = csr_illegal_write_return
+ out_entry["enum"] = enum_dict
+ # Preserve original literal texts from YAML AST (stripped before JSON output, used by HTML).
+ if isinstance(literal_texts, dict):
+ legal_texts = literal_texts.get("_enum-legal-texts")
+ if isinstance(legal_texts, list) and legal_texts:
+ out_entry["_enum-legal-texts"] = legal_texts
+ return_text = literal_texts.get("_enum-illegal-write-return-text")
+ if isinstance(return_text, str):
+ out_entry["_enum-illegal-write-return-text"] = return_text
if csr_width_input is not None:
out_entry["width"] = csr_width_input
@@ -1334,7 +1418,7 @@ def html_csr_table_row(f, csr: Dict[str, Any], chapter_name: Optional[str]):
csr_parts: List[str] = []
width_value = csr.get("width")
if isinstance(width_value, str):
- csr_parts.append(f"width:{width_value}")
+ csr_parts.append(f"width: {width_value}")
if "ro-mask" in csr:
mask_text_obj = csr.get("_ro-mask-text")
@@ -1354,11 +1438,46 @@ def html_csr_table_row(f, csr: Dict[str, Any], chapter_name: Optional[str]):
if csr_parts:
type_display = "
".join(csr_parts)
- elif "type" in csr:
- type_display = infer_param_type_string(
- csr,
- fatal,
- )
+ elif "enum" in csr:
+ enum_value = csr.get("enum")
+ if not isinstance(enum_value, dict):
+ fatal(f"CSR {name} has invalid enum output; expected object")
+ return
+
+ legal_values = enum_value.get("legal")
+ if not isinstance(legal_values, list) or not legal_values:
+ fatal(f"CSR {name} has invalid enum.legal output; expected non-empty list")
+ return
+ if not all(isinstance(value, int) and not isinstance(value, bool) for value in legal_values):
+ fatal(f"CSR {name} has invalid enum.legal output; expected integers")
+ return
+
+ legal_texts = csr.get("_enum-legal-texts")
+ if isinstance(legal_texts, list) and len(legal_texts) == len(legal_values):
+ legal_display = "[" + ", ".join(legal_texts) + "]"
+ else:
+ legal_display = str(legal_values)
+
+ enum_lines = ["Enum", f"legal: {legal_display}"]
+ if enum_value.get("illegal-write-ignore") is True:
+ enum_lines.append("Ignores illegal writes")
+ elif "illegal-write-return" in enum_value:
+ illegal_write_return = enum_value.get("illegal-write-return")
+ if not isinstance(illegal_write_return, int) or isinstance(illegal_write_return, bool):
+ fatal(f"CSR {name} has invalid illegal-write-return output; expected integer")
+ return
+ illegal_return_text = csr.get("_enum-illegal-write-return-text")
+ if isinstance(illegal_return_text, str):
+ enum_lines.append(f"Illegal write returns: {illegal_return_text}")
+ else:
+ enum_lines.append(f"Illegal write returns: {illegal_write_return}")
+ else:
+ fatal(
+ f"CSR {name} enum output must include illegal-write-ignore or illegal-write-return"
+ )
+ return
+
+ type_display = "
".join(enum_lines)
else:
category = csr.get("category")
if isinstance(category, str) and category:
diff --git a/tools/shared_utils.py b/tools/shared_utils.py
index f2428bd..664bf3e 100644
--- a/tools/shared_utils.py
+++ b/tools/shared_utils.py
@@ -209,6 +209,7 @@ def infer_param_type_string(
scalar type/range forms and optional array bounds.
"""
param_type = param.get("type")
+ param_enum = param.get("enum")
param_range = param.get("range")
param_array = param.get("array")
param_width = param.get("width")
@@ -245,6 +246,19 @@ def infer_param_type_string(
"or all integers"
)
+ elif isinstance(param_enum, dict):
+ enum_legal = param_enum.get("legal")
+ if not isinstance(enum_legal, list) or not enum_legal:
+ fatal(
+ f"Parameter {param_name!r} has invalid enum object; expected non-empty legal list"
+ )
+ if not all(isinstance(v, int) and not isinstance(v, bool) for v in enum_legal):
+ fatal(
+ f"Parameter {param_name!r} has invalid enum.legal array; expected all integers"
+ )
+ enum_values = ", ".join(map(str, enum_legal))
+ scalar_type = f"[{enum_values}]"
+
elif isinstance(param_type, str):
if param_type in {"boolean", "bit", "byte", "hword", "word", "dword"}:
scalar_type = param_type
@@ -296,7 +310,7 @@ def infer_param_type_string(
else:
fatal(
- f"Parameter {param_name!r} has neither a valid type nor a valid range"
+ f"Parameter {param_name!r} has neither a valid type, enum, nor a valid range"
)
if isinstance(param_array, list):
| norm:bar_warl_readonly_value | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FOO_ABC_WARL_LEGAL_LIST | +FOO_ABC_WARL_ENUM | csr_field | Kind | Instance | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 3, or 10. An implementation can support any subset of these values. |
- norm:foo_abc_warl_legal_list | +The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 0b11, or 0xffff_ffff. Returns 0x7fff if written with an illegal value. |
+ norm:foo_abc_warl_enum | +||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FOO_DEF_WARL_ENUM | +csr_field | +Kind | +|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foo.DEF | +Instance | +||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The architecturally-defined values for the 8-bit foo.DEF CSR field are -1 or 0xf0. Ignores writes with an illegal value. |
+ norm:foo_def_warl_enum | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FOO_DEF_WARL_WIDTH_UINT4TO8 | -The foo.DEF CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value. | -norm:foo_def_warl_width_uint4to8 | +FOO_GHI_WARL_WIDTH_UINT4TO8 | +The foo.GHI CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value. | +norm:foo_ghi_warl_width_uint4to8 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SATP_ASID_WARL_ASIDLEN | @@ -1539,7 +1594,7 @@
| Name | Information | Information Source | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| QUX_QQQ_WLRL_NO_SELECTOR | +csr_field | +Kind | +||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| qux.QQQ | +Instance | +|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The qux.QQQ CSR field has implementation-defined behavior without an enum, width, or read-only mask selector. |
+ norm:qux_qqq_wlrl_no_selector | +|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ZORT_XYZ_WLRL_READONLY_ZERO | csr_field | @@ -1800,7 +1868,7 @@
| norm:mock-ext-dep-A-on-B | |||
| FOO_ABC_WARL_LEGAL_LIST | +FOO_ABC_WARL_ENUM | csr_field | Kind | Implementation-defined behavior category |
| The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 3, or 10. An implementation can support any subset of these values. |
- norm:foo_abc_warl_legal_list | +The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 0b11, or 0xffff_ffff. Returns 0x7fff if written with an illegal value. |
+ norm:foo_abc_warl_enum | +
| FOO_DEF_WARL_ENUM | +csr_field | +Kind | +|
| foo.DEF | +Instance | ||
| FOO_DEF_WARL_WIDTH_UINT4TO8 | WARL | Implementation-defined behavior category | |
| The foo.DEF CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value. | -norm:foo_def_warl_width_uint4to8 | +The architecturally-defined values for the 8-bit foo.DEF CSR field are -1 or 0xf0. Ignores writes with an illegal value. |
+ norm:foo_def_warl_enum | +
| FOO_GHI_WARL_WIDTH_UINT4TO8 | +WARL | +Implementation-defined behavior category | +|
| The foo.GHI CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value. | +norm:foo_ghi_warl_width_uint4to8 | ||
| BAR_WARL_READONLY_VALUE | @@ -2005,6 +2090,23 @@An implementation may treat each bit of the zort.XYZ CSR as read-only or read-write. Read-only bits can be 0 or 1. |
norm:zort_xyz_wlrl_readonly_zero | |
| QUX_QQQ_WLRL_NO_SELECTOR | +csr_field | +Kind | +|
| qux.QQQ | +Instance | +||
| WLRL | +Implementation-defined behavior category | +||
| The qux.QQQ CSR field has implementation-defined behavior without an enum, width, or read-only mask selector. |
+ norm:qux_qqq_wlrl_no_selector | +
Parameters by Chapter
WARL/WLRL by Chapter
42 Parameters, 5 WARL/WLRL CSRs
+42 Parameters, 7 WARL/WLRL CSRs
| satp.MODE | -width:ASIDLEN | +width: ASIDLEN | FLD:satp.ASID | The satp.ASID CSR field width is specified by the ASIDLEN parameter value. |
| foo.ABC | -[0, 3, 10] | +Enum legal: [0, 0b11, 0xffff_ffff] Illegal write returns: 0x7fff |
FLD:foo.ABC | -The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 3, or 10. An implementation can support any subset of these values. |
+ The architecturally-defined values for the 4-bit foo.ABC CSR field are 0, 0b11, or 0xffff_ffff. Returns 0x7fff if written with an illegal value. |
|
| foo.DEF | -width:UINT_4TO8 | +Enum legal: [-1, 0xf0] Ignores illegal writes |
+ FLD:foo.DEF | +The architecturally-defined values for the 8-bit foo.DEF CSR field are -1 or 0xf0. Ignores writes with an illegal value. |
+ ||
| foo.GHI | +width: UINT_4TO8 | CHAP:Two | -The foo.DEF CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value. | +The foo.GHI CSR field width ranges from 4 to 8 bits as specified by the UINT_4TO8 parameter value. | ||
| bar | @@ -443,7 +449,7 @@
| FLD:zort.XYZ | An implementation may treat each bit of the zort.XYZ CSR as read-only or read-write. Read-only bits can be 0 or 1. |
+ ||
| qux.QQQ | +WLRL | +FLD:qux.QQQ | +The qux.QQQ CSR field has implementation-defined behavior without an enum, width, or read-only mask selector. |
+
".join(csr_parts) - elif "type" in csr: - type_display = infer_param_type_string( - csr, - fatal, - ) + elif "enum" in csr: + enum_value = csr.get("enum") + if not isinstance(enum_value, dict): + fatal(f"CSR {name} has invalid enum output; expected object") + return + + legal_values = enum_value.get("legal") + if not isinstance(legal_values, list) or not legal_values: + fatal(f"CSR {name} has invalid enum.legal output; expected non-empty list") + return + if not all(isinstance(value, int) and not isinstance(value, bool) for value in legal_values): + fatal(f"CSR {name} has invalid enum.legal output; expected integers") + return + + legal_texts = csr.get("_enum-legal-texts") + if isinstance(legal_texts, list) and len(legal_texts) == len(legal_values): + legal_display = "[" + ", ".join(legal_texts) + "]" + else: + legal_display = str(legal_values) + + enum_lines = ["Enum", f"legal: {legal_display}"] + if enum_value.get("illegal-write-ignore") is True: + enum_lines.append("Ignores illegal writes") + elif "illegal-write-return" in enum_value: + illegal_write_return = enum_value.get("illegal-write-return") + if not isinstance(illegal_write_return, int) or isinstance(illegal_write_return, bool): + fatal(f"CSR {name} has invalid illegal-write-return output; expected integer") + return + illegal_return_text = csr.get("_enum-illegal-write-return-text") + if isinstance(illegal_return_text, str): + enum_lines.append(f"Illegal write returns: {illegal_return_text}") + else: + enum_lines.append(f"Illegal write returns: {illegal_write_return}") + else: + fatal( + f"CSR {name} enum output must include illegal-write-ignore or illegal-write-return" + ) + return + + type_display = "
".join(enum_lines) else: category = csr.get("category") if isinstance(category, str) and category: diff --git a/tools/shared_utils.py b/tools/shared_utils.py index f2428bd..664bf3e 100644 --- a/tools/shared_utils.py +++ b/tools/shared_utils.py @@ -209,6 +209,7 @@ def infer_param_type_string( scalar type/range forms and optional array bounds. """ param_type = param.get("type") + param_enum = param.get("enum") param_range = param.get("range") param_array = param.get("array") param_width = param.get("width") @@ -245,6 +246,19 @@ def infer_param_type_string( "or all integers" ) + elif isinstance(param_enum, dict): + enum_legal = param_enum.get("legal") + if not isinstance(enum_legal, list) or not enum_legal: + fatal( + f"Parameter {param_name!r} has invalid enum object; expected non-empty legal list" + ) + if not all(isinstance(v, int) and not isinstance(v, bool) for v in enum_legal): + fatal( + f"Parameter {param_name!r} has invalid enum.legal array; expected all integers" + ) + enum_values = ", ".join(map(str, enum_legal)) + scalar_type = f"[{enum_values}]" + elif isinstance(param_type, str): if param_type in {"boolean", "bit", "byte", "hword", "word", "dword"}: scalar_type = param_type @@ -296,7 +310,7 @@ def infer_param_type_string( else: fatal( - f"Parameter {param_name!r} has neither a valid type nor a valid range" + f"Parameter {param_name!r} has neither a valid type, enum, nor a valid range" ) if isinstance(param_array, list):