rggen-systemrdl 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,264 @@
1
+ # SystemRDL → RgGen Mapping: Design Notes
2
+
3
+ This document records confirmed design decisions for the SystemRDL front-end to RgGen
4
+ register-map conversion. The SystemRDL support is an add-on feature; perfect coverage is a
5
+ non-goal. Deferred / not-yet-supported items are tracked separately in `systemrdl_to_rggen_TODO.md`.
6
+
7
+ ## Scope
8
+ - Root `addrmap` → RgGen register_block
9
+ - `regfile` → RgGen register_file
10
+ - `reg` → RgGen register
11
+ - `field` → RgGen bit_field
12
+ - Nested `addrmap` → RgGen `external` region on the enclosing map; the addrmap is also converted
13
+ to its own register_block through the normal flow (see "External components" below).
14
+ - External `reg`/`regfile` → ERROR in the first release (deferred; see "External components").
15
+ - `mem` → RgGen `external` register (region reservation only; see "mem" below).
16
+
17
+ ## Layer correspondence
18
+
19
+ | SystemRDL | RgGen |
20
+ | ---------------------- | ------------------------------ |
21
+ | root `addrmap` | register_block |
22
+ | `regfile` | register_file |
23
+ | `reg` | register |
24
+ | `field` | bit_field |
25
+ | nested `addrmap` | `external` region + its own register_block |
26
+ | external `reg`/`regfile` | ERROR (first release; deferred) |
27
+ | `mem` | `external` register (region reservation only) |
28
+
29
+ ## Array handling & name conversion
30
+ - `reg`, `regfile`, and `addrmap` can be arrays. **`field` is never an array**: in a
31
+ field declaration `foo[4]` specifies bit WIDTH (and `foo[7:0]` specifies msb:lsb), NOT an array
32
+ subscript. So the flatten/`__`-subscript handling below does not apply to fields; a field's
33
+ `[...]` maps to bit_assignment `lsb`/`width` instead (see field layer).
34
+ - Arrays are flattened into individual elements. No reconstruction back into RgGen
35
+ `size` / `sequence_size`.
36
+ - Subscripts are rendered into the name with a double-underscore `__` separator:
37
+ - `foo[0]` → `foo__0`
38
+ - multi-dimensional `foo[1][0]` → `foo__1__0` (all dimensions use `__`, consistently)
39
+ - Conversion-time validation: any SystemRDL instance name (all layers, arrayed or not) that
40
+ itself contains `__` is an ERROR. This reserves `__` exclusively as the array-expansion
41
+ separator, eliminating name-collision ambiguity at its root (rather than merely
42
+ lowering collision probability).
43
+ - SystemRDL lexical rules (spec 5.1.1) permit `__` in identifiers; this restriction is an
44
+ extra constraint imposed only when using the RgGen-conversion add-on feature.
45
+ - Post-conversion duplicate-name detection is delegated to RgGen's existing validation; the
46
+ converter does NOT re-implement duplicate checking.
47
+
48
+ ## addrmap (root) → register_block
49
+
50
+ | RgGen register_block | SystemRDL addrmap | Conversion / notes |
51
+ | -------------------- | ------------------------ | ------------------ |
52
+ | `name` | instance name (`name`) | Apply `__` restriction check. Root addrmap is non-arrayed, so no subscript conversion normally. |
53
+ | `byte_size` | addrmap occupied size | Uses the occupied-size value provided by the gem directly (front-end fix requested; see feedback). The converter does not compute it from child placement. |
54
+ | `bus_width` | — | No corresponding concept in SystemRDL. Not mapped; deferred to RgGen config. |
55
+ | `protocol` | — | No corresponding concept in SystemRDL. Not mapped; deferred to RgGen config. |
56
+ | `comment` | `desc` property | Used directly. `display_name` (SystemRDL `name` property) is a short label, not used for comment. |
57
+
58
+ ### addrmap: properties that cause an ERROR
59
+ These SystemRDL properties have no corresponding concept in RgGen. If encountered, the converter
60
+ errors out rather than silently ignoring them (silent drop would change the design intent).
61
+ - `sharedextbus` — combines multiple external components into a single bus interface (creates a
62
+ single set of control signals for the whole addrmap instead of per-component). Only meaningful
63
+ when the addrmap contains external components. This is about external-component bus-interface
64
+ generation, NOT the 13.5 multiple-view/bridge feature. RgGen has no feature to combine external
65
+ interfaces into one, so this is a **permanent ERROR** (independent of the external-scope
66
+ decision): even once external components are supported, RgGen still cannot merge their
67
+ interfaces, so `sharedextbus` remains unsupported.
68
+ - bridge / multiple-view related properties (spec 13.5) in general — e.g. `bridge`. No RgGen concept.
69
+ - `bigendian` / `littleendian` — ERROR if either is explicitly true. Even `littleendian` is an
70
+ error: although RgGen is also little-endian, its word-placement model for registers spanning
71
+ multiple words differs from SystemRDL 17.3.2 (Byte ordering), so passing `littleendian` through
72
+ by name would misplace words. If neither is specified, pass through using RgGen's default
73
+ (little-endian).
74
+ - Residual caveat: for registers that span multiple words (`regwidth > accesswidth`), the
75
+ word-placement model differs from SystemRDL 17.3.2 (Byte ordering). This difference is a
76
+ confirmed property of the conversion, not a maybe. The converter does NOT detect or correct
77
+ it; instead, the README states this word-ordering difference as a documented limitation of
78
+ the add-on conversion.
79
+ - `rsvdset` / `rsvdsetX` — control the read value of reserved / unassigned regions (whether
80
+ unassigned bits read as 1, or as X/undefined). RgGen has no mechanism to specify the read value
81
+ of unassigned regions, so there is nowhere to map these. ERROR if set.
82
+ - `msb0` — ERROR if set (true). `msb0` reverses bit numbering so that `regwidth-1` is the least
83
+ significant bit (spec 13.4.1), the opposite of the default `lsb0` mode. RgGen assumes `lsb0`
84
+ numbering; under `msb0` the field `lsb`/`msb` positions would be interpreted in reverse and
85
+ would be misplaced, so the mode cannot be represented. (`lsb0` is the default and needs no
86
+ action; it is not an error. `msb0` and `lsb0` are mutually exclusive per spec 13.4.1.)
87
+ Inference of `msb0` from the first field's explicit bit indices (spec 13.4.2) is unsupported by
88
+ the front-end, so only an explicitly set `msb0` property reaches the converter.
89
+
90
+ ### addrmap: properties that are IGNORED (safe to drop)
91
+ - `errextbus` — indicates the (external) addrmap instance has an error input. RgGen's
92
+ `rggen_bus_if` has an error input by default, so RgGen always satisfies the `errextbus`
93
+ behavior. Ignoring the property therefore does not lose design intent (unlike the error-listed
94
+ properties above).
95
+ - `accesswidth` — IGNORED. RgGen derives access width from its `bus_width` (RgGen config, not
96
+ mapped from SystemRDL). Safe to ignore: if `accesswidth` disagrees with `bus_width`, the
97
+ resulting addresses violate RgGen's `address % bus_width == 0` rule and are caught by the later
98
+ address check.
99
+
100
+ ## reg → register
101
+
102
+ | RgGen register | SystemRDL reg | Conversion / notes |
103
+ | ---------------- | ----------------------- | ------------------ |
104
+ | `name` | instance name (`name`) | Apply `__` restriction check; arrayed regs are flattened with `__` subscript conversion into individual registers. |
105
+ | `offset_address` | `address` property | Direct copy. Both RgGen `offset_address` and SystemRDL `address` are offsets from the block start, so they coincide and `address` is used as-is. |
106
+ | `size` | (basically unused) | Arrays are flattened, so repetition `size` is not used. First release: single element. |
107
+ | `type` | (fixed `default`) | Normal regs map to `default`. See register-type notes below. |
108
+ | `comment` | `desc` property | Used directly. |
109
+
110
+ ### register-type notes
111
+ - `default` — normal reg. Supported (fixed for first release).
112
+ - `external` — an external `reg` (`Reg#external` = true) is NOT supported in the first release →
113
+ ERROR. See the "External components" section (deferred design in `external_reg_regfile_mapping.md`).
114
+ - `indirect` — **permanently not applicable.** RgGen `indirect` multiplexes multiple registers
115
+ at one address, selected by index bit fields. SystemRDL has NO indirect-access mechanism, and
116
+ SystemRDL `alias` is a DIFFERENT concept (a second name/address onto the same storage, not
117
+ index-based multiplexing). `indirect` can therefore never be produced by the conversion.
118
+ - `reserved` / `maskable` / `rw` — SystemRDL-side trigger for these is TBD; not used in first release.
119
+
120
+ ### reg: properties that cause an ERROR
121
+ These SystemRDL reg properties have no corresponding concept in RgGen. If encountered, the
122
+ converter errors out rather than silently ignoring them.
123
+ - `shared` — shared component (spec 13.5, bridges / multiple-view address maps). RgGen has a
124
+ single-address-space-per-block model with no multiple-view/shared-storage concept, so there is
125
+ nowhere to map this. Even once the front-end supports it, the converter must error.
126
+
127
+ ### reg: properties that are IGNORED (safe to drop)
128
+ - `errextbus` — indicates the (external) regfile has an error input. Same rationale as the
129
+ addrmap `errextbus`: RgGen's `rggen_bus_if` has an error input by default, so ignoring it loses
130
+ no design intent.
131
+ - `accesswidth` — IGNORED (same rationale as addrmap: bus_width is RgGen config; a mismatch is
132
+ caught by the later `address % bus_width == 0` check).
133
+
134
+ ## regfile → register_file
135
+
136
+ | RgGen register_file | SystemRDL regfile | Conversion / notes |
137
+ | ------------------- | ------------------------ | ------------------ |
138
+ | `name` | instance name (`name`) | Apply `__` restriction check; arrayed regfiles are flattened with `__` subscript conversion. |
139
+ | `offset_address` | `address` property | Direct copy (offset from the parent). |
140
+ | `size` | (not used) | Arrays are flattened, so repetition `size` is not used. |
141
+ | `comment` | `desc` property | Used directly. |
142
+
143
+ ### regfile: properties handled like addrmap/reg
144
+ - `sharedextbus` — ERROR (no RgGen feature to merge external interfaces; same as addrmap).
145
+ - `errextbus` — IGNORED (rggen_bus_if has an error input by default; same as addrmap/reg).
146
+ - `accesswidth` — IGNORED (same as addrmap/reg; bus_width is RgGen config, mismatch caught by the address check).
147
+ - `external` — an external regfile is NOT supported in the first release → ERROR. See the
148
+ "External components" section (deferred design in `external_reg_regfile_mapping.md`).
149
+
150
+ ## field → bit_field
151
+
152
+ Bit positions are resolved by the front-end during elaboration, so the model's `msb` / `lsb`
153
+ give the final positions.
154
+
155
+ | RgGen bit_field | SystemRDL field | Conversion / notes |
156
+ | -------------------------------- | ----------------------- | ------------------ |
157
+ | `name` | instance name (`name`) | Apply `__` restriction check. No subscript conversion (fields are not arrays). |
158
+ | `bit_assignment` `lsb` | `lsb` | Direct copy (front-end-assigned). |
159
+ | `bit_assignment` `width` | field width (model accessor) | Use a `width` accessor on the model (front-end fix requested; see feedback) rather than computing `msb - lsb + 1` on the converter side. |
160
+ | `bit_assignment` `sequence_size` / `step` | — | Not used; fields are not arrays. |
161
+ | `initial_value` | `reset` property | Maps the reset value (constant only). If `reset` is absent, `initial_value` is left unset — the converter does NOT substitute 0; RgGen's own validation errors if a type that requires an initial value has none. A `reset` given as a reference (to another field) is unsupported → ERROR. A user-defined `resetsignal` is unsupported → ERROR. See field error list below. |
162
+ | `type` | (sw/hw/onread/onwrite/hwset/hwclr/swwe/swwel/we/swacc/singlepulse/… combination) | Main conversion. See `bit_field_type_mapping.md` for the full RgGen-type ← SystemRDL-property table and the cross-cutting property policies. |
163
+ | `reference` | instance reference (e.g. `next`, swwe/swwel/hwclr/hwset target) | Only SystemRDL **instance** references map to RgGen `reference`. **Property** references → ERROR. Mask-purpose references (`rc`/`w0c`/`w1c`/`wc`) are not specifiable from SystemRDL. See `bit_field_type_mapping.md`. |
164
+ | `comment` | `desc` property | Used directly. |
165
+
166
+ ### field: properties / values that cause an ERROR
167
+ - `reset` given as a **reference** (to another field's value) rather than a constant — RgGen
168
+ `initial_value` accepts a constant value only and has no dynamic/reference reset, so a
169
+ reference reset cannot be represented. ERROR.
170
+ - `resetsignal` (user-defined reset signal) — RgGen does not support user-defined reset signals,
171
+ so specifying `resetsignal` is unsupported. ERROR.
172
+ - Properties/values with no corresponding RgGen feature — ERROR if used: `wel`, `swmod`, `anded`,
173
+ `ored`, `xored`, `hwenable`, `hwmask`, `paritycheck`, `ruser` (onread=ruser),
174
+ `wuser` (onwrite=wuser), and `hw = rw1` / `hw = w1` (hardware-side write-once).
175
+ - Property reference used anywhere — ERROR. SystemRDL references come in two kinds: instance
176
+ references and property references (e.g. `other->prop`). RgGen supports instance references
177
+ only. (Applies wherever a reference is used: `ro`/next, rwl/rwe swwe/swwel, rwc/rws hwclr/hwset,
178
+ etc.)
179
+ - Combinations that fit no named RgGen type — ERROR in the first release (`custom` is not used
180
+ yet; see `bit_field_type_mapping.md`).
181
+
182
+ ### field: checks delegated to RgGen core (not done by the converter)
183
+ - Bit-field overlap — two or more fields at the same bit position in a register (SystemRDL allows
184
+ this when read/write are mutually exclusive). The converter does NOT detect this; it just emits
185
+ each field's `bit_assignment`, and RgGen's own bit_assignment validation rejects the overlap
186
+ (RgGen has no merged read-only+write-only field — `rowo` is not supported). Listed here so the
187
+ behavior is documented, but it is not a converter-side error.
188
+
189
+ ### field: precedence handling
190
+ Handled per a project-level "precedence ignore mode" flag (see rggen/rggen-systemrdl
191
+ `notes/precedence_handling_policy.md`). RgGen fixes hardware precedence; the SystemRDL default is
192
+ `sw`. The flag is set via RgGen configuration, not per-field/per-register.
193
+ - Ignore mode OFF (default): field with effective `precedence=sw` → ERROR; `precedence=hw` →
194
+ accepted. (Elaboration cannot tell an explicit value from a defaulted one, so `sw` is rejected
195
+ regardless; users set `default precedence = hw;` at a scope.)
196
+ - Ignore mode ON: `precedence` is not consulted; all fields generated with hw precedence, no
197
+ diagnostic.
198
+
199
+ ## External components
200
+
201
+ ### Nested addrmap → external region
202
+
203
+ A nested (non-root) `addrmap` instance represents an independent implementation boundary.
204
+ (`AddrMap` has no `external` property; external/internal does not apply to an addrmap itself, so
205
+ the trigger is structural: any addrmap below the root counts.)
206
+
207
+ For a nested addrmap, the only thing this conversion does is reserve its address region on the
208
+ enclosing map as an RgGen `external` register (its `address`/`size` come from the model).
209
+
210
+ The addrmap's own contents do NOT need a special carve-out step here: an addrmap is itself an RTL
211
+ generation unit with its own definition, so running that definition through the normal
212
+ register_block conversion (the same path used for the root addrmap) produces its register_block.
213
+
214
+ `bridge` is NOT part of the trigger; it only indicates whether the external boundary involves
215
+ bus/protocol conversion.
216
+
217
+ ### External reg / external regfile → ERROR (first release)
218
+
219
+ An external `reg` (`Reg#external` = true) and an external `regfile` (`RegFile#external` = true)
220
+ are NOT supported in the first release and are ERRORs. Silently dropping them would lose design
221
+ intent, so the converter errors out rather than ignoring the external boundary.
222
+
223
+ The conversion scheme worked out for them — reserve the region on the enclosing map and wrap the
224
+ contents in a separately-converted register_block (RgGen cannot generate at reg/regfile
225
+ granularity, so the wrapping is required) — is recorded separately in
226
+ `external_reg_regfile_mapping.md` for when the feature is picked up later.
227
+
228
+
229
+ ## mem → external register
230
+
231
+ A SystemRDL `mem` is mapped to an RgGen `external` register. `external` is exactly the RgGen
232
+ construct intended for this purpose: it reserves an address region whose contents are provided by
233
+ a user implementation. The memory contents are therefore not generated by RgGen (and not by the
234
+ converter); the converter only reserves the region.
235
+
236
+ Because the contents are a user implementation, a `mem` is NOT handled like the "External
237
+ components" above: it produces no carved-out register_block, only the region reservation on the
238
+ enclosing map.
239
+
240
+ | RgGen external | SystemRDL mem | Conversion / notes |
241
+ | -------------- | ---------------------- | ------------------ |
242
+ | `name` | instance name (`name`) | Apply `__` restriction check; arrayed mems are flattened with `__` subscript conversion. |
243
+ | `offset_address` | `address` property | Direct copy (offset from the parent), same as reg/regfile. |
244
+ | `size` | model `size` (byte size), converted | Element count in `bus_width` units; see below. |
245
+ | `comment` | `desc` property | Used directly. |
246
+
247
+ ### mem: size calculation
248
+ RgGen's `external` `size` is an element count expressed in `bus_width` units (how many
249
+ `bus_width`-wide accesses the region occupies), NOT a byte size. The front-end already provides
250
+ the mem's occupied byte size as the model's `size`, so the converter does not compute it from
251
+ `memwidth`/`mementries`; it only converts that byte size into `bus_width` units:
252
+
253
+ ```
254
+ size = byte_size / (bus_width / 8)
255
+ ```
256
+
257
+ where `byte_size` is the model's `size` (the front-end computes it from `entry_width` — `memwidth`
258
+ rounded up to a power-of-two number of bits — times `mementries`).
259
+
260
+ - `bus_width` is an RgGen config value, not taken from SystemRDL (same policy as `accesswidth`,
261
+ which is IGNORED elsewhere).
262
+ - If `byte_size` is not an integer multiple of `bus_width / 8`, the region cannot be expressed as
263
+ a whole number of `bus_width`-wide elements → ERROR.
264
+
@@ -0,0 +1,34 @@
1
+ # SystemRDL → RgGen Mapping: TODO
2
+
3
+ Not-yet-supported / deferred items. Confirmed design decisions live in
4
+ `systemrdl_to_rggen_mapping.md`.
5
+
6
+ ## Deferred
7
+
8
+ ### SystemRDL `alias` handling (scope decision)
9
+ - RgGen `alias` register support is tracked in rggen/rggen#287. The original proposal there
10
+ includes field-level attribute overrides (N:1 decoder-to-bitfield connection, per-field access
11
+ attribute arrays).
12
+ - Current stance: full support is not worth the RTL-generation complexity. If implemented at all,
13
+ scope is limited to address multiplexing and register-level r/w switching only. Field-level
14
+ attribute re-assignment will NOT be done.
15
+ - Consequence for SystemRDL conversion: SystemRDL `alias` per spec 10.5.1 rule (e) allows
16
+ per-field overrides of `sw`/`onread`/`onwrite`/`rclr`/`rset`/`woclr`/`woset`. Because the
17
+ intended RgGen scope stops at register-level r/w, SystemRDL alias inputs that vary attributes
18
+ per field cannot be fully represented → such inputs are out of scope (not supported / not
19
+ losslessly convertible). Note this is separate from RgGen `indirect`, which is permanently
20
+ not applicable (see mapping notes).
21
+
22
+ ## Open dependencies
23
+
24
+ ### `counter` / `intr` field types
25
+ - SystemRDL has `counter` and `intr`, but the front-end does not support them yet → out of
26
+ first-release scope. The RgGen target type is deferred (not decided now); record only as
27
+ "unsupported, front-end does not support them yet".
28
+
29
+ ### `custom` bit_field type (held)
30
+ - First release does not use RgGen `custom`. Property combinations that fit no named RgGen type
31
+ are errors in v1. Using `custom` to catch such combinations is possible but the verification
32
+ cost (confirming each combination is faithfully representable) is too high for v1 → future work.
33
+
34
+
@@ -0,0 +1,181 @@
1
+ # UDP Handling Policy for rggen-systemrdl
2
+
3
+ ## Background
4
+
5
+ SystemRDL provides a User-Defined Property (UDP) mechanism (Section 15 of the SystemRDL 2.0 specification) that allows tools and users to extend the language with custom properties beyond the standard set. In practice, UDPs are widely used by various SystemRDL tools to implement features that are not covered by the standard:
6
+
7
+ - PeakRDL-regblock uses UDPs such as `buffer_writes`, `wbuffer_trigger`, and others to express features like write-buffered registers, read-buffered registers, signed fields, and fixed-point fields.
8
+ - Commercial EDA tools define their own UDPs for vendor-specific features such as encrypted registers, TMR registers, and shadow registers.
9
+ - Internal company conventions often introduce custom UDPs to capture domain-specific requirements.
10
+
11
+ Since UDPs are vendor-specific and not portable across tools, any SystemRDL adapter must define a clear policy for how to handle them. This document describes the UDP handling policy adopted by rggen-systemrdl.
12
+
13
+ ## Design Principles
14
+
15
+ ### 1. Core Adapter Handles SystemRDL Standard Only
16
+
17
+ The core of rggen-systemrdl is responsible for converting only the SystemRDL standard range (properties defined in the language specification). It does not interpret any UDP semantics on its own.
18
+
19
+ This keeps the core adapter:
20
+
21
+ - Simple and focused on the standard
22
+ - Independent of any vendor-specific UDP definition
23
+ - Free from the lock-in problems associated with UDP-based extensions
24
+
25
+ ### 2. UDP Handling via User-Defined Hooks (Plugins)
26
+
27
+ When the conversion process encounters a node that has any UDP attached, the entire conversion of that node is delegated to a user-defined hook. The hook is responsible for producing the corresponding RgGen data structure for that node.
28
+
29
+ This delegation model:
30
+
31
+ - Respects the SystemRDL property model, where UDPs may interact with other properties in arbitrary ways
32
+ - Keeps the core adapter's responsibility cleanly separated from UDP semantics
33
+ - Allows users to extend support for any UDP without modifying the core
34
+ - Makes the lock-in implications of using a UDP explicit and opt-in
35
+
36
+ Hooks are registered via the plugin mechanism that RgGen already uses for extension, following the existing RgGen conventions for plugin authoring.
37
+
38
+ ### 3. Hierarchy-Independent Judgment
39
+
40
+ UDP detection and hook delegation are determined independently at each hierarchy level (addrmap, regfile, reg, field, etc.). The presence of a UDP at one level does not change the conversion behavior of other levels.
41
+
42
+ This is consistent with the SystemRDL scoping rules: a lower component cannot reference properties of its enclosing component, so a UDP at one hierarchy level cannot legitimately alter the semantics of another level.
43
+
44
+ Concretely:
45
+
46
+ - If a register has a UDP but its fields do not, the register conversion is delegated to a hook, while the fields are converted by the default mechanism.
47
+ - If a field has a UDP but its parent register does not, the register conversion uses the default mechanism, while the field conversion is delegated.
48
+ - Each level makes its own decision based only on its own UDPs.
49
+
50
+ In the rare case where a UDP is intended to affect multiple hierarchy levels, the plugin may need to express claim conditions that look beyond a single node (for example, to claim a field based on a UDP attached to its parent register). Allowing plugins to define such cross-hierarchy claim conditions is technically possible but is considered a low-priority extension: well-designed UDPs respect the SystemRDL scoping rules, and the common case is fully covered by hierarchy-independent judgment.
51
+
52
+ ### 4. Single Active UDP Plugin
53
+
54
+ Only one UDP plugin may be active at a time. If multiple UDP plugins are loaded simultaneously, rggen-systemrdl rejects the configuration with an error at startup.
55
+
56
+ This constraint reflects the practical reality that a given SystemRDL codebase typically targets a single tool (such as PeakRDL) or a single internal convention, and therefore needs exactly one UDP plugin. Allowing multiple UDP plugins would introduce the need for conflict resolution between competing claims on the same node, with no clear benefit for any realistic use case.
57
+
58
+ If a user genuinely needs to combine multiple UDP sets, the recommended approach is to write a combined plugin that handles both sets coherently. This keeps the single-plugin invariant intact while allowing flexibility for unusual situations.
59
+
60
+ ### 5. Strict by Default
61
+
62
+ The default behavior when a UDP is encountered but no hook is registered to handle it is to raise an error. This prevents silent fallback to ill-defined behavior and forces users to make explicit decisions about UDP support.
63
+
64
+ A configuration option may allow this behavior to be relaxed (e.g., to warn or ignore unknown UDPs), but the default is strict.
65
+
66
+ ## Conversion Flow
67
+
68
+ For each node in the elaborated SystemRDL hierarchy, the conversion proceeds as follows:
69
+
70
+ 1. Check whether the node has any UDP attached to it.
71
+ 2. If no UDP is present, perform the default conversion:
72
+ - Translate standard SystemRDL properties to the corresponding RgGen data structure.
73
+ - Recursively process child nodes using the same procedure.
74
+ 3. If a UDP is present, look up a registered hook that matches the node:
75
+ - If a matching hook is found, delegate the conversion of this node entirely to the hook.
76
+ - If no matching hook is found, raise an error (in strict mode) or fall back to the configured alternative behavior.
77
+
78
+ The hook receives:
79
+
80
+ - The SystemRDL node, with full access to its standard properties, UDP values, and children.
81
+ - A conversion context that provides access to the default conversion routine, so the hook can choose to invoke the default conversion for child nodes if desired.
82
+
83
+ The hook is expected to return a fully constructed RgGen data structure for the node it handled. The hook is responsible for processing child nodes as appropriate, either by invoking the default conversion via the context or by implementing custom handling.
84
+
85
+ ## Plugin Architecture
86
+
87
+ UDP handlers are organized as plugins, separate from the rggen-systemrdl core. This means:
88
+
89
+ - The core adapter ships without any built-in UDP knowledge.
90
+ - Support for specific UDPs (e.g., PeakRDL UDPs, vendor-specific UDPs, internal company UDPs) is provided by independent plugins.
91
+ - Users can install only the UDP plugins they need, and the dependencies between rggen-systemrdl and any specific UDP definition are made explicit.
92
+
93
+ Each plugin declares:
94
+
95
+ - Which UDPs it handles (by name and optionally by combination)
96
+ - The conditions under which it applies (e.g., component type, presence of related UDPs)
97
+ - The conversion logic that produces RgGen data structures
98
+
99
+ This structure allows the community to contribute UDP support for various tools and conventions without burdening the core adapter with vendor-specific code.
100
+
101
+ ## Plugin Registration
102
+
103
+ Plugins register UDP hooks following the conventions of the RgGen plugin system. A hook registration declares:
104
+
105
+ - A matching condition that determines when the hook applies to a node
106
+ - A conversion routine that produces the RgGen data structure for that node
107
+
108
+ The exact API is determined at implementation time, but the general shape follows RgGen's existing plugin patterns.
109
+
110
+ ## Behavior on Unknown UDPs
111
+
112
+ When a UDP is encountered but no plugin provides a matching hook, the configured behavior applies:
113
+
114
+ - **error** (default): Raise an error indicating that the UDP is not supported, with location information from the SystemRDL source.
115
+ - **warn**: Emit a warning and proceed without applying the UDP's semantics. The default conversion is used as if the UDP were absent.
116
+ - **ignore**: Silently proceed without applying the UDP's semantics.
117
+
118
+ The `warn` and `ignore` modes are provided for cases such as bulk migration from existing SystemRDL codebases, where a complete UDP handler set may not yet be available. They should be used with awareness that the resulting RgGen data may not reflect the original intent.
119
+
120
+ ## Rationale for the "Whole-Node Delegation" Choice
121
+
122
+ When a UDP is present at a given node, the adapter delegates the entire conversion of that node, rather than performing a partial conversion and asking the hook to augment it. This choice is motivated by the way SystemRDL is structured:
123
+
124
+ - SystemRDL defines behavior through combinations of properties, and UDPs may participate in those combinations in arbitrary ways.
125
+ - A UDP may change how standard properties at the same level should be interpreted (e.g., `buffer_writes` changes how SW writes to the register are realized).
126
+ - A partial conversion would force the hook to reconcile a half-formed result with the UDP's semantics, leading to complex and error-prone hook implementations.
127
+
128
+ By delegating the whole node, the hook has full control and is responsible for producing a coherent result. If the hook wishes to use the default conversion as a starting point, it may do so explicitly by invoking the conversion context.
129
+
130
+ ## Implications and Trade-offs
131
+
132
+ ### Lock-In Awareness
133
+
134
+ A SystemRDL file that uses UDPs is, in effect, tool-specific. By making UDP handling explicit through plugins and requiring opt-in, this policy makes the lock-in implications visible to the user. Users adopting a UDP-based feature are also adopting the plugin (and its maintenance burden) needed to interpret that UDP.
135
+
136
+ This is preferable to silent compatibility shims that hide the lock-in.
137
+
138
+ ### Migration Path
139
+
140
+ For users migrating SystemRDL files that use vendor-specific UDPs (e.g., PeakRDL UDPs) to rggen-systemrdl:
141
+
142
+ 1. They can either install a community-provided plugin that supports those UDPs, or
143
+ 2. They can write their own plugin to interpret their UDPs in the way they prefer, or
144
+ 3. They can modify the SystemRDL source to remove UDP usage and rewrite the equivalent behavior using RgGen's native facilities.
145
+
146
+ The third option is encouraged as the long-term path, since it removes the SystemRDL-induced lock-in entirely.
147
+
148
+ ### No Built-In UDP Knowledge in the Core
149
+
150
+ rggen-systemrdl itself does not ship with any UDP definitions or handlers. This is intentional:
151
+
152
+ - Bundling specific vendor UDP support would implicitly endorse those vendors' design choices.
153
+ - It would also tie the core to the maintenance lifecycle of those vendors' tools.
154
+ - The plugin model lets each community of users maintain the UDP handlers they need, independently from the core's release schedule.
155
+
156
+ ## Open Questions
157
+
158
+ The following aspects are deferred to implementation and may be revisited as the adapter evolves:
159
+
160
+ - The exact shape of the plugin registration API
161
+ - Whether plugins can introduce new RgGen types or are limited to existing ones
162
+ - The precise interface through which hooks invoke the default conversion on child nodes
163
+
164
+ The following extension is acknowledged but considered low priority:
165
+
166
+ - Allowing plugins to define claim conditions that span multiple hierarchy levels (for example, claiming a field based on a UDP attached to its parent register). This would extend the adapter's reach to UDPs that intentionally violate SystemRDL's scoping conventions, but the common case is fully covered by hierarchy-independent judgment, so this is not a near-term priority.
167
+
168
+ ## Summary
169
+
170
+ | Aspect | Decision |
171
+ | --- | --- |
172
+ | Core adapter scope | SystemRDL standard range only |
173
+ | UDP handling | Delegated to user-defined hooks via plugins |
174
+ | Delegation granularity | Whole-node delegation when a UDP is present |
175
+ | Hierarchy treatment | Independent judgment at each level |
176
+ | Number of active UDP plugins | One at a time; multiple loaded plugins cause a startup error |
177
+ | Default behavior on unknown UDP | Error (strict by default) |
178
+ | UDP definitions in core | None; all UDP support is plugin-provided |
179
+ | Cross-hierarchy claim by plugins | Low-priority extension; not in scope for initial implementation |
180
+
181
+ This policy keeps the rggen-systemrdl core simple, principled, and aligned with RgGen's overall design philosophy of explicit type-based safety, while leaving the door open for the community to provide UDP support through the plugin mechanism.
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rggen-systemrdl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Taichi Ishitani
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: systemrdl
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 0.2.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 0.2.0
26
+ description: SystemRDL loader plugin for RgGen
27
+ email:
28
+ - rggen@googlegroups.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - LICENSE
34
+ - README.md
35
+ - lib/rggen/systemrdl.rb
36
+ - lib/rggen/systemrdl/converter/addrmap.rb
37
+ - lib/rggen/systemrdl/converter/base.rb
38
+ - lib/rggen/systemrdl/converter/field.rb
39
+ - lib/rggen/systemrdl/converter/mem.rb
40
+ - lib/rggen/systemrdl/converter/reg.rb
41
+ - lib/rggen/systemrdl/converter/regfile.rb
42
+ - lib/rggen/systemrdl/global/ignore_precedence.rb
43
+ - lib/rggen/systemrdl/loader.rb
44
+ - lib/rggen/systemrdl/version.rb
45
+ - notes/bit_field_type_mapping.md
46
+ - notes/bit_field_type_matrix.md
47
+ - notes/external_reg_regfile_mapping.md
48
+ - notes/interrupt_aggregation_policy.md
49
+ - notes/precedence_handling_policy.md
50
+ - notes/systemrdl_rggen_gap_analysis.md
51
+ - notes/systemrdl_to_rggen_mapping.md
52
+ - notes/systemrdl_to_rggen_todo.md
53
+ - notes/udp_handling_policy.md
54
+ homepage: https://github.com/rggen/rggen-systemrdl
55
+ licenses:
56
+ - MIT
57
+ metadata:
58
+ bug_tracker_uri: https://github.com/rggen/rggen/issues
59
+ mailing_list_uri: https://groups.google.com/d/forum/rggen
60
+ rubygems_mfa_required: 'true'
61
+ source_code_uri: https://github.com/rggen/rggen-systemrdl
62
+ wiki_uri: https://github.com/rggen/rggen/wiki
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '3.2'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubygems_version: 4.0.3
78
+ specification_version: 4
79
+ summary: rggen-systemrdl-0.1.0
80
+ test_files: []