Skip to content

Commit d202e4e

Browse files
Lore0599claude
andcommitted
floogen: Add possibility of generating multiple RDL address maps.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent cb7b2ba commit d202e4e

6 files changed

Lines changed: 143 additions & 10 deletions

File tree

docs/floogen/cli.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ Generates the **SystemRDL** description for the endpoint address regions. This i
107107
floogen rdl -c <config_file> -o <output_dir>
108108
```
109109

110+
By default, this produces a single `<name>_addrmap.rdl` file containing all endpoints.
111+
If any endpoint declares [`rdl_addrmap_grp`](endpoints.md#systemrdl-addrmap-groups), one
112+
`<name>_addrmap_<group>.rdl` file is generated per distinct group instead, each
113+
containing only the endpoints tagged with that group (endpoints without
114+
`rdl_addrmap_grp` are included in every group).
115+
110116
-----
111117

112118
### `query`

docs/floogen/endpoints.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,37 @@ endpoints:
112112
sbr_port_protocol:
113113
- "axi_out"
114114
```
115+
116+
### SystemRDL Addrmap Groups
117+
118+
Each address range can be tagged with one or more `rdl_addrmap_grp` values to control
119+
which generated SystemRDL addrmap(s) it appears in (see the [`rdl` CLI
120+
command](cli.md#rdl)). This is a per-`addr_range` field, not a per-endpoint one, since
121+
different address ranges of the *same* endpoint (e.g. its main registers vs. a
122+
debug-only region) may need to be reachable from different views. A single group can
123+
be given as a plain string, or multiple groups as a list. Address ranges without
124+
`rdl_addrmap_grp` are considered common and are included in every group's file.
125+
126+
```yaml
127+
endpoints:
128+
- name: "cluster"
129+
addr_range:
130+
- base: 0x1000_0000
131+
size: 0x0004_0000
132+
rdl_name: "cluster_regs"
133+
rdl_addrmap_grp: ["32b", "64b"] # visible in both the 32b and 64b addrmaps
134+
- base: 0x1000_4000
135+
size: 0x0000_1000
136+
rdl_name: "cluster_debug_regs"
137+
rdl_addrmap_grp: "64b" # only visible in the 64b addrmap
138+
sbr_port_protocol:
139+
- "axi_out"
140+
- name: "hbm"
141+
addr_range:
142+
base: 0x8000_0000
143+
size: 0x1000_0000
144+
rdl_name: "hbm_regs"
145+
rdl_addrmap_grp: "64b" # only visible in the 64b addrmap
146+
sbr_port_protocol:
147+
- "axi_out"
148+
```

floogen/cli.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,6 @@ def main():
219219
context["name"] = args.name or network.name
220220
pkg_file_name = f"floo_{args.name or network.name}_noc_pkg.sv"
221221
top_file_name = f"floo_{args.name or network.name}_noc.sv"
222-
case "rdl":
223-
rdl_file_name = f"{network.name}_addrmap.rdl"
224222

225223

226224
match args.command:
@@ -250,11 +248,16 @@ def main():
250248
case "rdl":
251249
context["rdl_as_mem"] = args.as_mem
252250
context["rdl_memwidth"] = args.memwidth
253-
render_template(context,
254-
tpl=tpl_dir / "floo_addrmap.rdl.mako",
255-
file_name=rdl_file_name,
256-
**render_kwargs,
257-
)
251+
groups = network.routing.sam.distinct_groups() or [None]
252+
for group in groups:
253+
suffix = f"_{group}" if group else ""
254+
context["sam"] = network.routing.sam.filter_by_group(group) if group else network.routing.sam
255+
context["addrmap_name"] = f"{network.name}_addrmap{suffix}"
256+
render_template(context,
257+
tpl=tpl_dir / "floo_addrmap.rdl.mako",
258+
file_name=f"{network.name}_addrmap{suffix}.rdl",
259+
**render_kwargs,
260+
)
258261
case "template":
259262
for tpl in args.template:
260263
render_template(context,

floogen/model/routing.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,20 @@ class AddrRange(BaseModel):
389389
rdl_as_mem: Optional[bool] = None
390390
en_collective: bool = False
391391
desc: Optional[str] = None
392+
rdl_addrmap_grp: Optional[List[str]] = None
393+
"""One or more SystemRDL addrmap group tags this address range belongs to."""
392394

393395
def __str__(self):
394396
return f"[{self.start:X}:{self.end:X}]"
395397

398+
@field_validator("rdl_addrmap_grp", mode="before")
399+
@classmethod
400+
def rdl_addrmap_grp_to_list(cls, v):
401+
"""Convert a single group name to a list."""
402+
if isinstance(v, str):
403+
return [v]
404+
return v
405+
396406
@model_validator(mode="before")
397407
def validate_input(self):
398408
"""Validate the address range."""
@@ -789,6 +799,20 @@ def render_rdl_inc(self):
789799
string += f"`include \"{rule}.rdl\"\n"
790800
return string
791801

802+
def distinct_groups(self) -> List[str]:
803+
"""Return the sorted list of distinct RDL addrmap groups used by any rule."""
804+
groups = set()
805+
for rule in self.rules:
806+
if rule.addr_range.rdl_addrmap_grp:
807+
groups.update(rule.addr_range.rdl_addrmap_grp)
808+
return sorted(groups)
809+
810+
def filter_by_group(self, group: str) -> "RouteMap":
811+
"""Return a new RouteMap with only rules in `group` (untagged rules included)."""
812+
rules = [r for r in self.rules
813+
if not r.addr_range.rdl_addrmap_grp or group in r.addr_range.rdl_addrmap_grp]
814+
return RouteMap(name=self.name, rules=rules)
815+
792816
def pprint(self):
793817
"""Pretty print the routing table."""
794818
for rule in self.rules:

floogen/templates/floo_addrmap.rdl.mako

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010

1111
// AUTOMATICALLY GENERATED! DO NOT EDIT!
1212

13-
${noc.routing.sam.render_rdl_inc()}
13+
${sam.render_rdl_inc()}
1414

15-
addrmap ${noc.name}_addrmap {
15+
addrmap ${addrmap_name} {
1616

17-
${noc.routing.sam.render_rdl(rdl_as_mem, rdl_memwidth)}
17+
${sam.render_rdl(rdl_as_mem, rdl_memwidth)}
1818

1919
};

floogen/tests/address_test.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,69 @@ def test_trim():
154154
RouteMapRule(addr_range=AddrRange(start=31, end=40), dest=SimpleId(id=2)),
155155
]
156156
assert routing_table.rules == expected_rules
157+
158+
159+
def test_rdl_addrmap_grp_addr_range_scalar_and_list():
160+
"""Test that a scalar or list rdl_addrmap_grp both normalize to a List[str]."""
161+
ar_scalar = AddrRange(start=0, end=0x1000, rdl_addrmap_grp="32b")
162+
ar_list = AddrRange(start=0, end=0x1000, rdl_addrmap_grp=["32b", "64b"])
163+
assert ar_scalar.rdl_addrmap_grp == ["32b"]
164+
assert ar_list.rdl_addrmap_grp == ["32b", "64b"]
165+
166+
167+
def test_route_map_distinct_groups():
168+
"""Test that distinct_groups() collects the sorted set of groups across all rules."""
169+
rule1 = RouteMapRule(addr_range=AddrRange(start=0, end=10, rdl_addrmap_grp=["32b", "64b"]),
170+
dest=SimpleId(id=1))
171+
rule2 = RouteMapRule(addr_range=AddrRange(start=10, end=20, rdl_addrmap_grp=["32b"]),
172+
dest=SimpleId(id=2))
173+
rule3 = RouteMapRule(addr_range=AddrRange(start=20, end=30), dest=SimpleId(id=3))
174+
route_map = RouteMap(name="sam", rules=[rule1, rule2, rule3])
175+
assert route_map.distinct_groups() == ["32b", "64b"]
176+
177+
178+
def test_route_map_filter_by_group():
179+
"""Test filtering a RouteMap by group, keeping untagged rules in every group."""
180+
rule1 = RouteMapRule(addr_range=AddrRange(start=0, end=10, rdl_addrmap_grp=["32b", "64b"]),
181+
dest=SimpleId(id=1), desc="endpoint1")
182+
rule2 = RouteMapRule(addr_range=AddrRange(start=10, end=20, rdl_addrmap_grp=["32b"]),
183+
dest=SimpleId(id=2), desc="endpoint2")
184+
rule3 = RouteMapRule(addr_range=AddrRange(start=20, end=30, rdl_addrmap_grp=["64b"]),
185+
dest=SimpleId(id=3), desc="endpoint3")
186+
route_map = RouteMap(name="sam", rules=[rule1, rule2, rule3])
187+
188+
grp_32b = route_map.filter_by_group("32b")
189+
assert {r.desc for r in grp_32b.rules} == {"endpoint1", "endpoint2"}
190+
191+
grp_64b = route_map.filter_by_group("64b")
192+
assert {r.desc for r in grp_64b.rules} == {"endpoint1", "endpoint3"}
193+
194+
195+
def test_route_map_filter_by_group_includes_untagged():
196+
"""Test that untagged rules are included in every group's filtered RouteMap."""
197+
tagged = RouteMapRule(addr_range=AddrRange(start=0, end=10, rdl_addrmap_grp=["32b"]),
198+
dest=SimpleId(id=1), desc="tagged")
199+
untagged = RouteMapRule(addr_range=AddrRange(start=10, end=20), dest=SimpleId(id=2),
200+
desc="untagged")
201+
route_map = RouteMap(name="sam", rules=[tagged, untagged])
202+
203+
grp_32b = route_map.filter_by_group("32b")
204+
assert {r.desc for r in grp_32b.rules} == {"tagged", "untagged"}
205+
206+
grp_64b = route_map.filter_by_group("64b")
207+
assert {r.desc for r in grp_64b.rules} == {"untagged"}
208+
209+
210+
def test_rdl_addrmap_grp_differs_per_addr_range_of_same_endpoint():
211+
"""Test that two addr_ranges of the same endpoint can belong to different groups."""
212+
narrow_range = RouteMapRule(addr_range=AddrRange(start=0, end=10, rdl_addrmap_grp="32b"),
213+
dest=SimpleId(id=1), desc="ep_narrow")
214+
wide_range = RouteMapRule(addr_range=AddrRange(start=10, end=20, rdl_addrmap_grp="64b"),
215+
dest=SimpleId(id=1), desc="ep_wide")
216+
route_map = RouteMap(name="sam", rules=[narrow_range, wide_range])
217+
218+
grp_32b = route_map.filter_by_group("32b")
219+
assert {r.desc for r in grp_32b.rules} == {"ep_narrow"}
220+
221+
grp_64b = route_map.filter_by_group("64b")
222+
assert {r.desc for r in grp_64b.rules} == {"ep_wide"}

0 commit comments

Comments
 (0)