Skip to content

Commit 6d65dc1

Browse files
wanda-phiwhitequark
authored andcommitted
hdl, back.rtlil: track and emit module/submodule locations.
1 parent 188eb8d commit 6d65dc1

File tree

10 files changed

+82
-67
lines changed

10 files changed

+82
-67
lines changed

amaranth/back/rtlil.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,21 +106,22 @@ def __init__(self, emit_src):
106106
super().__init__()
107107
self.emit_src = emit_src
108108

109-
def module(self, name=None, attrs={}):
109+
def module(self, name=None, attrs={}, *, src=None):
110110
name = self._make_name(name, local=False)
111-
return _ModuleBuilder(self, name, attrs)
111+
return _ModuleBuilder(self, name, attrs, src=src)
112112

113113

114114
class _ModuleBuilder(_AttrBuilder, _BufferedBuilder, _Namer):
115-
def __init__(self, rtlil, name, attrs):
115+
def __init__(self, rtlil, name, attrs, *, src=None):
116116
super().__init__(emit_src=rtlil.emit_src)
117117
self.rtlil = rtlil
118118
self.name = name
119+
self.src = src
119120
self.attrs = {"generator": "Amaranth"}
120121
self.attrs.update(attrs)
121122

122123
def __enter__(self):
123-
self._attributes(self.attrs)
124+
self._attributes(self.attrs, src=self.src)
124125
self._append("module {}\n", self.name)
125126
return self
126127

@@ -512,7 +513,7 @@ def emit_submodules(self):
512513
self.builder.cell(f"\\{dotted_name}", submodule.name[-1], ports={
513514
name: self.sigspec(value)
514515
for name, (value, _flow) in submodule.ports.items()
515-
})
516+
}, src=_src(submodule.cell_src_loc))
516517

517518
def emit_assignment_list(self, cell_idx, cell):
518519
def emit_assignments(case, cond):
@@ -997,8 +998,10 @@ def convert_fragment(fragment, name="top", *, emit_src=True):
997998
for module_idx, module in enumerate(netlist.modules):
998999
if empty_checker.is_empty(module_idx):
9991000
continue
1000-
attrs = {"top": 1} if module_idx == 0 else {}
1001-
with builder.module(".".join(module.name), attrs=attrs) as module_builder:
1001+
attrs = {}
1002+
if module_idx == 0:
1003+
attrs["top"] = 1
1004+
with builder.module(".".join(module.name), attrs=attrs, src=_src(module.src_loc)) as module_builder:
10021005
ModuleEmitter(module_builder, netlist, module, name_map,
10031006
empty_checker=empty_checker).emit()
10041007
return str(builder), name_map

amaranth/hdl/_dsl.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,18 @@ def __init__(self, builder):
8282
object.__setattr__(self, "_builder", builder)
8383

8484
def __iadd__(self, modules):
85+
src_loc = tracer.get_src_loc()
8586
for module in flatten([modules]):
86-
self._builder._add_submodule(module)
87+
self._builder._add_submodule(module, src_loc=src_loc)
8788
return self
8889

8990
def __setattr__(self, name, submodule):
90-
self._builder._add_submodule(submodule, name)
91+
src_loc = tracer.get_src_loc()
92+
self._builder._add_submodule(submodule, name, src_loc=src_loc)
9193

92-
def __setitem__(self, name, value):
93-
return self.__setattr__(name, value)
94+
def __setitem__(self, name, submodule):
95+
src_loc = tracer.get_src_loc()
96+
self._builder._add_submodule(submodule, name, src_loc=src_loc)
9497

9598
def __getattr__(self, name):
9699
return self._builder._get_submodule(name)
@@ -175,6 +178,7 @@ def __init__(self):
175178
self._anon_submodules = []
176179
self._domains = {}
177180
self._generated = {}
181+
self._src_loc = tracer.get_src_loc()
178182

179183
def _check_context(self, construct, context):
180184
if self._ctrl_context != context:
@@ -546,20 +550,21 @@ def _add_statement(self, assigns, domain, depth):
546550

547551
self._statements.setdefault(domain, []).append(stmt)
548552

549-
def _add_submodule(self, submodule, name=None):
553+
def _add_submodule(self, submodule, name=None, src_loc=None):
550554
if not hasattr(submodule, "elaborate"):
551555
raise TypeError("Trying to add {!r}, which does not implement .elaborate(), as "
552556
"a submodule".format(submodule))
553557
if name == None:
554-
self._anon_submodules.append(submodule)
558+
self._anon_submodules.append((submodule, src_loc))
555559
else:
556560
if name in self._named_submodules:
557561
raise NameError(f"Submodule named '{name}' already exists")
558-
self._named_submodules[name] = submodule
562+
self._named_submodules[name] = (submodule, src_loc)
559563

560564
def _get_submodule(self, name):
561565
if name in self._named_submodules:
562-
return self._named_submodules[name]
566+
submodule, _src_loc = self._named_submodules[name]
567+
return submodule
563568
else:
564569
raise AttributeError(f"No submodule named '{name}' exists")
565570

@@ -575,11 +580,11 @@ def _flush(self):
575580
def elaborate(self, platform):
576581
self._flush()
577582

578-
fragment = Fragment()
579-
for name in self._named_submodules:
580-
fragment.add_subfragment(Fragment.get(self._named_submodules[name], platform), name)
581-
for submodule in self._anon_submodules:
582-
fragment.add_subfragment(Fragment.get(submodule, platform), None)
583+
fragment = Fragment(src_loc=self._src_loc)
584+
for name, (submodule, src_loc) in self._named_submodules.items():
585+
fragment.add_subfragment(Fragment.get(submodule, platform), name, src_loc=src_loc)
586+
for submodule, src_loc in self._anon_submodules:
587+
fragment.add_subfragment(Fragment.get(submodule, platform), None, src_loc=src_loc)
583588
for domain, statements in self._statements.items():
584589
fragment.add_statements(domain, statements)
585590
for signal, domain in self._driving.items():

amaranth/hdl/_ir.py

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def get(obj, platform):
6060
lineno=code.co_firstlineno)
6161
obj = new_obj
6262

63-
def __init__(self):
63+
def __init__(self, *, src_loc=None):
6464
self.ports = _ast.SignalDict()
6565
self.drivers = OrderedDict()
6666
self.statements = {}
@@ -69,6 +69,7 @@ def __init__(self):
6969
self.attrs = OrderedDict()
7070
self.generated = OrderedDict()
7171
self.flatten = False
72+
self.src_loc = src_loc
7273

7374
def add_ports(self, *ports, dir):
7475
assert dir in ("i", "o", "io")
@@ -132,18 +133,18 @@ def add_statements(self, domain, *stmts):
132133
stmt._MustUse__used = True
133134
self.statements.setdefault(domain, _ast._StatementList()).append(stmt)
134135

135-
def add_subfragment(self, subfragment, name=None):
136+
def add_subfragment(self, subfragment, name=None, *, src_loc=None):
136137
assert isinstance(subfragment, Fragment)
137-
self.subfragments.append((subfragment, name))
138+
self.subfragments.append((subfragment, name, src_loc))
138139

139140
def find_subfragment(self, name_or_index):
140141
if isinstance(name_or_index, int):
141142
if name_or_index < len(self.subfragments):
142-
subfragment, name = self.subfragments[name_or_index]
143+
subfragment, name, src_loc = self.subfragments[name_or_index]
143144
return subfragment
144145
raise NameError(f"No subfragment at index #{name_or_index}")
145146
else:
146-
for subfragment, name in self.subfragments:
147+
for subfragment, name, src_loc in self.subfragments:
147148
if name == name_or_index:
148149
return subfragment
149150
raise NameError(f"No subfragment with name '{name_or_index}'")
@@ -172,7 +173,7 @@ def _merge_subfragment(self, subfragment):
172173

173174
# Remove the merged subfragment.
174175
found = False
175-
for i, (check_subfrag, check_name) in enumerate(self.subfragments): # :nobr:
176+
for i, (check_subfrag, check_name, check_src_loc) in enumerate(self.subfragments): # :nobr:
176177
if subfragment == check_subfrag:
177178
del self.subfragments[i]
178179
found = True
@@ -204,7 +205,7 @@ def add_subfrag(registry, entity, entry):
204205
add_subfrag(driver_subfrags, signal, (None, hierarchy))
205206

206207
flatten_subfrags = set()
207-
for i, (subfrag, name) in enumerate(self.subfragments):
208+
for i, (subfrag, name, src_loc) in enumerate(self.subfragments):
208209
if name is None:
209210
name = f"<unnamed #{i}>"
210211
subfrag_hierarchy = hierarchy + (name,)
@@ -270,7 +271,7 @@ def _propagate_domains_up(self, hierarchy=("top",)):
270271
domain_subfrags = defaultdict(set)
271272

272273
# For each domain defined by a subfragment, determine which subfragments define it.
273-
for i, (subfrag, name) in enumerate(self.subfragments):
274+
for i, (subfrag, name, src_loc) in enumerate(self.subfragments):
274275
# First, recurse into subfragments and let them propagate domains up as well.
275276
hier_name = name
276277
if hier_name is None:
@@ -281,45 +282,45 @@ def _propagate_domains_up(self, hierarchy=("top",)):
281282
for domain_name, domain in subfrag.domains.items():
282283
if domain.local:
283284
continue
284-
domain_subfrags[domain_name].add((subfrag, name, i))
285+
domain_subfrags[domain_name].add((subfrag, name, src_loc, i))
285286

286287
# For each domain defined by more than one subfragment, rename the domain in each
287288
# of the subfragments such that they no longer conflict.
288289
for domain_name, subfrags in domain_subfrags.items():
289290
if len(subfrags) == 1:
290291
continue
291292

292-
names = [n for f, n, i in subfrags]
293+
names = [n for f, n, s, i in subfrags]
293294
if not all(names):
294295
names = sorted(f"<unnamed #{i}>" if n is None else f"'{n}'"
295-
for f, n, i in subfrags)
296+
for f, n, s, i in subfrags)
296297
raise _cd.DomainError(
297298
"Domain '{}' is defined by subfragments {} of fragment '{}'; it is necessary "
298299
"to either rename subfragment domains explicitly, or give names to subfragments"
299300
.format(domain_name, ", ".join(names), ".".join(hierarchy)))
300301

301302
if len(names) != len(set(names)):
302-
names = sorted(f"#{i}" for f, n, i in subfrags)
303+
names = sorted(f"#{i}" for f, n, s, i in subfrags)
303304
raise _cd.DomainError(
304305
"Domain '{}' is defined by subfragments {} of fragment '{}', some of which "
305306
"have identical names; it is necessary to either rename subfragment domains "
306307
"explicitly, or give distinct names to subfragments"
307308
.format(domain_name, ", ".join(names), ".".join(hierarchy)))
308309

309-
for subfrag, name, i in subfrags:
310+
for subfrag, name, src_loc, i in subfrags:
310311
domain_name_map = {domain_name: f"{name}_{domain_name}"}
311-
self.subfragments[i] = (DomainRenamer(domain_name_map)(subfrag), name)
312+
self.subfragments[i] = (DomainRenamer(domain_name_map)(subfrag), name, src_loc)
312313

313314
# Finally, collect the (now unique) subfragment domains, and merge them into our domains.
314-
for subfrag, name in self.subfragments:
315+
for subfrag, name, src_loc in self.subfragments:
315316
for domain_name, domain in subfrag.domains.items():
316317
if domain.local:
317318
continue
318319
self.add_domains(domain)
319320

320321
def _propagate_domains_down(self):
321322
# For each domain defined in this fragment, ensure it also exists in all subfragments.
322-
for subfrag, name in self.subfragments:
323+
for subfrag, name, src_loc in self.subfragments:
323324
for domain in self.iter_domains():
324325
if domain in subfrag.domains:
325326
assert self.domains[domain] is subfrag.domains[domain]
@@ -403,7 +404,7 @@ def add_io(*sigs):
403404
add_uses(cd.rst)
404405

405406
# Repeat for subfragments.
406-
for subfrag, name in self.subfragments:
407+
for subfrag, name, src_loc in self.subfragments:
407408
if isinstance(subfrag, Instance):
408409
for port_name, (value, dir) in subfrag.named_ports.items():
409410
if dir == "i":
@@ -627,7 +628,7 @@ def _assign_names_to_fragments(self, hierarchy=("top",), *, _names=None):
627628
_names[self] = hierarchy
628629

629630
signal_names = set(self._assign_names_to_signals().values())
630-
for subfragment_index, (subfragment, subfragment_name) in enumerate(self.subfragments):
631+
for subfragment_index, (subfragment, subfragment_name, subfragment_src_loc) in enumerate(self.subfragments):
631632
if subfragment_name is None:
632633
subfragment_name = f"U${subfragment_index}"
633634
elif subfragment_name in signal_names:
@@ -641,12 +642,11 @@ def _assign_names_to_fragments(self, hierarchy=("top",), *, _names=None):
641642

642643
class Instance(Fragment):
643644
def __init__(self, type, *args, src_loc=None, src_loc_at=0, **kwargs):
644-
super().__init__()
645+
super().__init__(src_loc=src_loc or tracer.get_src_loc(src_loc_at))
645646

646647
self.type = type
647648
self.parameters = OrderedDict()
648649
self.named_ports = OrderedDict()
649-
self.src_loc = src_loc or tracer.get_src_loc(src_loc_at)
650650

651651
for (kind, name, value) in args:
652652
if kind == "a":
@@ -1064,7 +1064,7 @@ def emit_memory(self, module_idx: int, fragment: '_mem.MemoryInstance', name: st
10641064
init=fragment._init,
10651065
name=name,
10661066
attributes=fragment._attrs,
1067-
src_loc=fragment._src_loc,
1067+
src_loc=fragment.src_loc,
10681068
)
10691069
return self.netlist.add_cell(cell)
10701070

@@ -1205,7 +1205,7 @@ def emit_drivers(self):
12051205
if net.is_late and net not in self.netlist.connections:
12061206
self.netlist.connections[net] = _nir.Net.from_const((signal.init >> bit) & 1)
12071207

1208-
def emit_fragment(self, fragment: _ir.Fragment, parent_module_idx: 'int | None'):
1208+
def emit_fragment(self, fragment: _ir.Fragment, parent_module_idx: 'int | None', *, cell_src_loc=None):
12091209
from . import _mem
12101210

12111211
fragment_name = self.fragment_names[fragment]
@@ -1224,7 +1224,7 @@ def emit_fragment(self, fragment: _ir.Fragment, parent_module_idx: 'int | None')
12241224
for port in fragment._read_ports:
12251225
self.emit_read_port(parent_module_idx, fragment, port, memory, write_ports)
12261226
elif type(fragment) is _ir.Fragment:
1227-
module_idx = self.netlist.add_module(parent_module_idx, fragment_name)
1227+
module_idx = self.netlist.add_module(parent_module_idx, fragment_name, src_loc=fragment.src_loc, cell_src_loc=cell_src_loc)
12281228
signal_names = fragment._assign_names_to_signals()
12291229
self.netlist.modules[module_idx].signal_names = signal_names
12301230
if parent_module_idx is None:
@@ -1234,8 +1234,8 @@ def emit_fragment(self, fragment: _ir.Fragment, parent_module_idx: 'int | None')
12341234
for domain, stmts in fragment.statements.items():
12351235
for stmt in stmts:
12361236
self.emit_stmt(module_idx, fragment, domain, stmt, _nir.Net.from_const(1))
1237-
for subfragment, _name in fragment.subfragments:
1238-
self.emit_fragment(subfragment, module_idx)
1237+
for subfragment, _name, sub_src_loc in fragment.subfragments:
1238+
self.emit_fragment(subfragment, module_idx, cell_src_loc=sub_src_loc)
12391239
if parent_module_idx is None:
12401240
self.emit_drivers()
12411241
else:

amaranth/hdl/_mem.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def _granularity(self):
6565

6666

6767
def __init__(self, *, identity, width, depth, init=None, attrs=None, src_loc=None):
68-
super().__init__()
68+
super().__init__(src_loc=src_loc)
6969
assert isinstance(identity, MemoryIdentity)
7070
self._identity = identity
7171
self._width = operator.index(width)
@@ -76,7 +76,6 @@ def __init__(self, *, identity, width, depth, init=None, attrs=None, src_loc=Non
7676
for x in self._init:
7777
assert isinstance(x, int)
7878
self._attrs = attrs or {}
79-
self._src_loc = src_loc
8079
self._read_ports = []
8180
self._write_ports = []
8281

amaranth/hdl/_nir.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,9 @@ def __repr__(self):
211211
result.append(f"(cell {cell_idx} {cell.module_idx} {cell!r})")
212212
return "\n".join(result)
213213

214-
def add_module(self, parent, name: str):
214+
def add_module(self, parent, name: str, *, src_loc=None, cell_src_loc=None):
215215
module_idx = len(self.modules)
216-
self.modules.append(Module(parent, name))
216+
self.modules.append(Module(parent, name, src_loc=src_loc, cell_src_loc=cell_src_loc))
217217
if module_idx == 0:
218218
self.modules[0].cells.append(0)
219219
if parent is not None:
@@ -276,15 +276,18 @@ class Module:
276276
277277
parent: index of parent module, or ``None`` for top module
278278
name: a tuple of str, hierarchical name of this module (top has empty tuple)
279+
src_loc: str
279280
submodules: a list of nested module indices
280281
signal_names: a SignalDict from Signal to str, signal names visible in this module
281282
net_flow: a dict from Net to NetFlow, describes how a net is used within this module
282283
ports: a dict from port name to (Value, NetFlow) pair
283284
cells: a list of cell indices that belong to this module
284285
"""
285-
def __init__(self, parent, name):
286+
def __init__(self, parent, name, *, src_loc, cell_src_loc):
286287
self.parent = parent
287288
self.name = name
289+
self.src_loc = src_loc
290+
self.cell_src_loc = cell_src_loc
288291
self.submodules = []
289292
self.signal_names = SignalDict()
290293
self.net_flow = {}

0 commit comments

Comments
 (0)