hdl, back.rtlil: track and emit module/submodule locations.
This commit is contained in:
parent
188eb8d453
commit
6d65dc1366
|
@ -106,21 +106,22 @@ class _Builder(_BufferedBuilder, _Namer):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.emit_src = emit_src
|
self.emit_src = emit_src
|
||||||
|
|
||||||
def module(self, name=None, attrs={}):
|
def module(self, name=None, attrs={}, *, src=None):
|
||||||
name = self._make_name(name, local=False)
|
name = self._make_name(name, local=False)
|
||||||
return _ModuleBuilder(self, name, attrs)
|
return _ModuleBuilder(self, name, attrs, src=src)
|
||||||
|
|
||||||
|
|
||||||
class _ModuleBuilder(_AttrBuilder, _BufferedBuilder, _Namer):
|
class _ModuleBuilder(_AttrBuilder, _BufferedBuilder, _Namer):
|
||||||
def __init__(self, rtlil, name, attrs):
|
def __init__(self, rtlil, name, attrs, *, src=None):
|
||||||
super().__init__(emit_src=rtlil.emit_src)
|
super().__init__(emit_src=rtlil.emit_src)
|
||||||
self.rtlil = rtlil
|
self.rtlil = rtlil
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.src = src
|
||||||
self.attrs = {"generator": "Amaranth"}
|
self.attrs = {"generator": "Amaranth"}
|
||||||
self.attrs.update(attrs)
|
self.attrs.update(attrs)
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self._attributes(self.attrs)
|
self._attributes(self.attrs, src=self.src)
|
||||||
self._append("module {}\n", self.name)
|
self._append("module {}\n", self.name)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@ -512,7 +513,7 @@ class ModuleEmitter:
|
||||||
self.builder.cell(f"\\{dotted_name}", submodule.name[-1], ports={
|
self.builder.cell(f"\\{dotted_name}", submodule.name[-1], ports={
|
||||||
name: self.sigspec(value)
|
name: self.sigspec(value)
|
||||||
for name, (value, _flow) in submodule.ports.items()
|
for name, (value, _flow) in submodule.ports.items()
|
||||||
})
|
}, src=_src(submodule.cell_src_loc))
|
||||||
|
|
||||||
def emit_assignment_list(self, cell_idx, cell):
|
def emit_assignment_list(self, cell_idx, cell):
|
||||||
def emit_assignments(case, cond):
|
def emit_assignments(case, cond):
|
||||||
|
@ -997,8 +998,10 @@ def convert_fragment(fragment, name="top", *, emit_src=True):
|
||||||
for module_idx, module in enumerate(netlist.modules):
|
for module_idx, module in enumerate(netlist.modules):
|
||||||
if empty_checker.is_empty(module_idx):
|
if empty_checker.is_empty(module_idx):
|
||||||
continue
|
continue
|
||||||
attrs = {"top": 1} if module_idx == 0 else {}
|
attrs = {}
|
||||||
with builder.module(".".join(module.name), attrs=attrs) as module_builder:
|
if module_idx == 0:
|
||||||
|
attrs["top"] = 1
|
||||||
|
with builder.module(".".join(module.name), attrs=attrs, src=_src(module.src_loc)) as module_builder:
|
||||||
ModuleEmitter(module_builder, netlist, module, name_map,
|
ModuleEmitter(module_builder, netlist, module, name_map,
|
||||||
empty_checker=empty_checker).emit()
|
empty_checker=empty_checker).emit()
|
||||||
return str(builder), name_map
|
return str(builder), name_map
|
||||||
|
|
|
@ -82,15 +82,18 @@ class _ModuleBuilderSubmodules:
|
||||||
object.__setattr__(self, "_builder", builder)
|
object.__setattr__(self, "_builder", builder)
|
||||||
|
|
||||||
def __iadd__(self, modules):
|
def __iadd__(self, modules):
|
||||||
|
src_loc = tracer.get_src_loc()
|
||||||
for module in flatten([modules]):
|
for module in flatten([modules]):
|
||||||
self._builder._add_submodule(module)
|
self._builder._add_submodule(module, src_loc=src_loc)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __setattr__(self, name, submodule):
|
def __setattr__(self, name, submodule):
|
||||||
self._builder._add_submodule(submodule, name)
|
src_loc = tracer.get_src_loc()
|
||||||
|
self._builder._add_submodule(submodule, name, src_loc=src_loc)
|
||||||
|
|
||||||
def __setitem__(self, name, value):
|
def __setitem__(self, name, submodule):
|
||||||
return self.__setattr__(name, value)
|
src_loc = tracer.get_src_loc()
|
||||||
|
self._builder._add_submodule(submodule, name, src_loc=src_loc)
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
return self._builder._get_submodule(name)
|
return self._builder._get_submodule(name)
|
||||||
|
@ -175,6 +178,7 @@ class Module(_ModuleBuilderRoot, Elaboratable):
|
||||||
self._anon_submodules = []
|
self._anon_submodules = []
|
||||||
self._domains = {}
|
self._domains = {}
|
||||||
self._generated = {}
|
self._generated = {}
|
||||||
|
self._src_loc = tracer.get_src_loc()
|
||||||
|
|
||||||
def _check_context(self, construct, context):
|
def _check_context(self, construct, context):
|
||||||
if self._ctrl_context != context:
|
if self._ctrl_context != context:
|
||||||
|
@ -546,20 +550,21 @@ class Module(_ModuleBuilderRoot, Elaboratable):
|
||||||
|
|
||||||
self._statements.setdefault(domain, []).append(stmt)
|
self._statements.setdefault(domain, []).append(stmt)
|
||||||
|
|
||||||
def _add_submodule(self, submodule, name=None):
|
def _add_submodule(self, submodule, name=None, src_loc=None):
|
||||||
if not hasattr(submodule, "elaborate"):
|
if not hasattr(submodule, "elaborate"):
|
||||||
raise TypeError("Trying to add {!r}, which does not implement .elaborate(), as "
|
raise TypeError("Trying to add {!r}, which does not implement .elaborate(), as "
|
||||||
"a submodule".format(submodule))
|
"a submodule".format(submodule))
|
||||||
if name == None:
|
if name == None:
|
||||||
self._anon_submodules.append(submodule)
|
self._anon_submodules.append((submodule, src_loc))
|
||||||
else:
|
else:
|
||||||
if name in self._named_submodules:
|
if name in self._named_submodules:
|
||||||
raise NameError(f"Submodule named '{name}' already exists")
|
raise NameError(f"Submodule named '{name}' already exists")
|
||||||
self._named_submodules[name] = submodule
|
self._named_submodules[name] = (submodule, src_loc)
|
||||||
|
|
||||||
def _get_submodule(self, name):
|
def _get_submodule(self, name):
|
||||||
if name in self._named_submodules:
|
if name in self._named_submodules:
|
||||||
return self._named_submodules[name]
|
submodule, _src_loc = self._named_submodules[name]
|
||||||
|
return submodule
|
||||||
else:
|
else:
|
||||||
raise AttributeError(f"No submodule named '{name}' exists")
|
raise AttributeError(f"No submodule named '{name}' exists")
|
||||||
|
|
||||||
|
@ -575,11 +580,11 @@ class Module(_ModuleBuilderRoot, Elaboratable):
|
||||||
def elaborate(self, platform):
|
def elaborate(self, platform):
|
||||||
self._flush()
|
self._flush()
|
||||||
|
|
||||||
fragment = Fragment()
|
fragment = Fragment(src_loc=self._src_loc)
|
||||||
for name in self._named_submodules:
|
for name, (submodule, src_loc) in self._named_submodules.items():
|
||||||
fragment.add_subfragment(Fragment.get(self._named_submodules[name], platform), name)
|
fragment.add_subfragment(Fragment.get(submodule, platform), name, src_loc=src_loc)
|
||||||
for submodule in self._anon_submodules:
|
for submodule, src_loc in self._anon_submodules:
|
||||||
fragment.add_subfragment(Fragment.get(submodule, platform), None)
|
fragment.add_subfragment(Fragment.get(submodule, platform), None, src_loc=src_loc)
|
||||||
for domain, statements in self._statements.items():
|
for domain, statements in self._statements.items():
|
||||||
fragment.add_statements(domain, statements)
|
fragment.add_statements(domain, statements)
|
||||||
for signal, domain in self._driving.items():
|
for signal, domain in self._driving.items():
|
||||||
|
|
|
@ -60,7 +60,7 @@ class Fragment:
|
||||||
lineno=code.co_firstlineno)
|
lineno=code.co_firstlineno)
|
||||||
obj = new_obj
|
obj = new_obj
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, *, src_loc=None):
|
||||||
self.ports = _ast.SignalDict()
|
self.ports = _ast.SignalDict()
|
||||||
self.drivers = OrderedDict()
|
self.drivers = OrderedDict()
|
||||||
self.statements = {}
|
self.statements = {}
|
||||||
|
@ -69,6 +69,7 @@ class Fragment:
|
||||||
self.attrs = OrderedDict()
|
self.attrs = OrderedDict()
|
||||||
self.generated = OrderedDict()
|
self.generated = OrderedDict()
|
||||||
self.flatten = False
|
self.flatten = False
|
||||||
|
self.src_loc = src_loc
|
||||||
|
|
||||||
def add_ports(self, *ports, dir):
|
def add_ports(self, *ports, dir):
|
||||||
assert dir in ("i", "o", "io")
|
assert dir in ("i", "o", "io")
|
||||||
|
@ -132,18 +133,18 @@ class Fragment:
|
||||||
stmt._MustUse__used = True
|
stmt._MustUse__used = True
|
||||||
self.statements.setdefault(domain, _ast._StatementList()).append(stmt)
|
self.statements.setdefault(domain, _ast._StatementList()).append(stmt)
|
||||||
|
|
||||||
def add_subfragment(self, subfragment, name=None):
|
def add_subfragment(self, subfragment, name=None, *, src_loc=None):
|
||||||
assert isinstance(subfragment, Fragment)
|
assert isinstance(subfragment, Fragment)
|
||||||
self.subfragments.append((subfragment, name))
|
self.subfragments.append((subfragment, name, src_loc))
|
||||||
|
|
||||||
def find_subfragment(self, name_or_index):
|
def find_subfragment(self, name_or_index):
|
||||||
if isinstance(name_or_index, int):
|
if isinstance(name_or_index, int):
|
||||||
if name_or_index < len(self.subfragments):
|
if name_or_index < len(self.subfragments):
|
||||||
subfragment, name = self.subfragments[name_or_index]
|
subfragment, name, src_loc = self.subfragments[name_or_index]
|
||||||
return subfragment
|
return subfragment
|
||||||
raise NameError(f"No subfragment at index #{name_or_index}")
|
raise NameError(f"No subfragment at index #{name_or_index}")
|
||||||
else:
|
else:
|
||||||
for subfragment, name in self.subfragments:
|
for subfragment, name, src_loc in self.subfragments:
|
||||||
if name == name_or_index:
|
if name == name_or_index:
|
||||||
return subfragment
|
return subfragment
|
||||||
raise NameError(f"No subfragment with name '{name_or_index}'")
|
raise NameError(f"No subfragment with name '{name_or_index}'")
|
||||||
|
@ -172,7 +173,7 @@ class Fragment:
|
||||||
|
|
||||||
# Remove the merged subfragment.
|
# Remove the merged subfragment.
|
||||||
found = False
|
found = False
|
||||||
for i, (check_subfrag, check_name) in enumerate(self.subfragments): # :nobr:
|
for i, (check_subfrag, check_name, check_src_loc) in enumerate(self.subfragments): # :nobr:
|
||||||
if subfragment == check_subfrag:
|
if subfragment == check_subfrag:
|
||||||
del self.subfragments[i]
|
del self.subfragments[i]
|
||||||
found = True
|
found = True
|
||||||
|
@ -204,7 +205,7 @@ class Fragment:
|
||||||
add_subfrag(driver_subfrags, signal, (None, hierarchy))
|
add_subfrag(driver_subfrags, signal, (None, hierarchy))
|
||||||
|
|
||||||
flatten_subfrags = set()
|
flatten_subfrags = set()
|
||||||
for i, (subfrag, name) in enumerate(self.subfragments):
|
for i, (subfrag, name, src_loc) in enumerate(self.subfragments):
|
||||||
if name is None:
|
if name is None:
|
||||||
name = f"<unnamed #{i}>"
|
name = f"<unnamed #{i}>"
|
||||||
subfrag_hierarchy = hierarchy + (name,)
|
subfrag_hierarchy = hierarchy + (name,)
|
||||||
|
@ -270,7 +271,7 @@ class Fragment:
|
||||||
domain_subfrags = defaultdict(set)
|
domain_subfrags = defaultdict(set)
|
||||||
|
|
||||||
# For each domain defined by a subfragment, determine which subfragments define it.
|
# For each domain defined by a subfragment, determine which subfragments define it.
|
||||||
for i, (subfrag, name) in enumerate(self.subfragments):
|
for i, (subfrag, name, src_loc) in enumerate(self.subfragments):
|
||||||
# First, recurse into subfragments and let them propagate domains up as well.
|
# First, recurse into subfragments and let them propagate domains up as well.
|
||||||
hier_name = name
|
hier_name = name
|
||||||
if hier_name is None:
|
if hier_name is None:
|
||||||
|
@ -281,7 +282,7 @@ class Fragment:
|
||||||
for domain_name, domain in subfrag.domains.items():
|
for domain_name, domain in subfrag.domains.items():
|
||||||
if domain.local:
|
if domain.local:
|
||||||
continue
|
continue
|
||||||
domain_subfrags[domain_name].add((subfrag, name, i))
|
domain_subfrags[domain_name].add((subfrag, name, src_loc, i))
|
||||||
|
|
||||||
# For each domain defined by more than one subfragment, rename the domain in each
|
# For each domain defined by more than one subfragment, rename the domain in each
|
||||||
# of the subfragments such that they no longer conflict.
|
# of the subfragments such that they no longer conflict.
|
||||||
|
@ -289,29 +290,29 @@ class Fragment:
|
||||||
if len(subfrags) == 1:
|
if len(subfrags) == 1:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
names = [n for f, n, i in subfrags]
|
names = [n for f, n, s, i in subfrags]
|
||||||
if not all(names):
|
if not all(names):
|
||||||
names = sorted(f"<unnamed #{i}>" if n is None else f"'{n}'"
|
names = sorted(f"<unnamed #{i}>" if n is None else f"'{n}'"
|
||||||
for f, n, i in subfrags)
|
for f, n, s, i in subfrags)
|
||||||
raise _cd.DomainError(
|
raise _cd.DomainError(
|
||||||
"Domain '{}' is defined by subfragments {} of fragment '{}'; it is necessary "
|
"Domain '{}' is defined by subfragments {} of fragment '{}'; it is necessary "
|
||||||
"to either rename subfragment domains explicitly, or give names to subfragments"
|
"to either rename subfragment domains explicitly, or give names to subfragments"
|
||||||
.format(domain_name, ", ".join(names), ".".join(hierarchy)))
|
.format(domain_name, ", ".join(names), ".".join(hierarchy)))
|
||||||
|
|
||||||
if len(names) != len(set(names)):
|
if len(names) != len(set(names)):
|
||||||
names = sorted(f"#{i}" for f, n, i in subfrags)
|
names = sorted(f"#{i}" for f, n, s, i in subfrags)
|
||||||
raise _cd.DomainError(
|
raise _cd.DomainError(
|
||||||
"Domain '{}' is defined by subfragments {} of fragment '{}', some of which "
|
"Domain '{}' is defined by subfragments {} of fragment '{}', some of which "
|
||||||
"have identical names; it is necessary to either rename subfragment domains "
|
"have identical names; it is necessary to either rename subfragment domains "
|
||||||
"explicitly, or give distinct names to subfragments"
|
"explicitly, or give distinct names to subfragments"
|
||||||
.format(domain_name, ", ".join(names), ".".join(hierarchy)))
|
.format(domain_name, ", ".join(names), ".".join(hierarchy)))
|
||||||
|
|
||||||
for subfrag, name, i in subfrags:
|
for subfrag, name, src_loc, i in subfrags:
|
||||||
domain_name_map = {domain_name: f"{name}_{domain_name}"}
|
domain_name_map = {domain_name: f"{name}_{domain_name}"}
|
||||||
self.subfragments[i] = (DomainRenamer(domain_name_map)(subfrag), name)
|
self.subfragments[i] = (DomainRenamer(domain_name_map)(subfrag), name, src_loc)
|
||||||
|
|
||||||
# Finally, collect the (now unique) subfragment domains, and merge them into our domains.
|
# Finally, collect the (now unique) subfragment domains, and merge them into our domains.
|
||||||
for subfrag, name in self.subfragments:
|
for subfrag, name, src_loc in self.subfragments:
|
||||||
for domain_name, domain in subfrag.domains.items():
|
for domain_name, domain in subfrag.domains.items():
|
||||||
if domain.local:
|
if domain.local:
|
||||||
continue
|
continue
|
||||||
|
@ -319,7 +320,7 @@ class Fragment:
|
||||||
|
|
||||||
def _propagate_domains_down(self):
|
def _propagate_domains_down(self):
|
||||||
# For each domain defined in this fragment, ensure it also exists in all subfragments.
|
# For each domain defined in this fragment, ensure it also exists in all subfragments.
|
||||||
for subfrag, name in self.subfragments:
|
for subfrag, name, src_loc in self.subfragments:
|
||||||
for domain in self.iter_domains():
|
for domain in self.iter_domains():
|
||||||
if domain in subfrag.domains:
|
if domain in subfrag.domains:
|
||||||
assert self.domains[domain] is subfrag.domains[domain]
|
assert self.domains[domain] is subfrag.domains[domain]
|
||||||
|
@ -403,7 +404,7 @@ class Fragment:
|
||||||
add_uses(cd.rst)
|
add_uses(cd.rst)
|
||||||
|
|
||||||
# Repeat for subfragments.
|
# Repeat for subfragments.
|
||||||
for subfrag, name in self.subfragments:
|
for subfrag, name, src_loc in self.subfragments:
|
||||||
if isinstance(subfrag, Instance):
|
if isinstance(subfrag, Instance):
|
||||||
for port_name, (value, dir) in subfrag.named_ports.items():
|
for port_name, (value, dir) in subfrag.named_ports.items():
|
||||||
if dir == "i":
|
if dir == "i":
|
||||||
|
@ -627,7 +628,7 @@ class Fragment:
|
||||||
_names[self] = hierarchy
|
_names[self] = hierarchy
|
||||||
|
|
||||||
signal_names = set(self._assign_names_to_signals().values())
|
signal_names = set(self._assign_names_to_signals().values())
|
||||||
for subfragment_index, (subfragment, subfragment_name) in enumerate(self.subfragments):
|
for subfragment_index, (subfragment, subfragment_name, subfragment_src_loc) in enumerate(self.subfragments):
|
||||||
if subfragment_name is None:
|
if subfragment_name is None:
|
||||||
subfragment_name = f"U${subfragment_index}"
|
subfragment_name = f"U${subfragment_index}"
|
||||||
elif subfragment_name in signal_names:
|
elif subfragment_name in signal_names:
|
||||||
|
@ -641,12 +642,11 @@ class Fragment:
|
||||||
|
|
||||||
class Instance(Fragment):
|
class Instance(Fragment):
|
||||||
def __init__(self, type, *args, src_loc=None, src_loc_at=0, **kwargs):
|
def __init__(self, type, *args, src_loc=None, src_loc_at=0, **kwargs):
|
||||||
super().__init__()
|
super().__init__(src_loc=src_loc or tracer.get_src_loc(src_loc_at))
|
||||||
|
|
||||||
self.type = type
|
self.type = type
|
||||||
self.parameters = OrderedDict()
|
self.parameters = OrderedDict()
|
||||||
self.named_ports = OrderedDict()
|
self.named_ports = OrderedDict()
|
||||||
self.src_loc = src_loc or tracer.get_src_loc(src_loc_at)
|
|
||||||
|
|
||||||
for (kind, name, value) in args:
|
for (kind, name, value) in args:
|
||||||
if kind == "a":
|
if kind == "a":
|
||||||
|
@ -1064,7 +1064,7 @@ class NetlistEmitter:
|
||||||
init=fragment._init,
|
init=fragment._init,
|
||||||
name=name,
|
name=name,
|
||||||
attributes=fragment._attrs,
|
attributes=fragment._attrs,
|
||||||
src_loc=fragment._src_loc,
|
src_loc=fragment.src_loc,
|
||||||
)
|
)
|
||||||
return self.netlist.add_cell(cell)
|
return self.netlist.add_cell(cell)
|
||||||
|
|
||||||
|
@ -1205,7 +1205,7 @@ class NetlistEmitter:
|
||||||
if net.is_late and net not in self.netlist.connections:
|
if net.is_late and net not in self.netlist.connections:
|
||||||
self.netlist.connections[net] = _nir.Net.from_const((signal.init >> bit) & 1)
|
self.netlist.connections[net] = _nir.Net.from_const((signal.init >> bit) & 1)
|
||||||
|
|
||||||
def emit_fragment(self, fragment: _ir.Fragment, parent_module_idx: 'int | None'):
|
def emit_fragment(self, fragment: _ir.Fragment, parent_module_idx: 'int | None', *, cell_src_loc=None):
|
||||||
from . import _mem
|
from . import _mem
|
||||||
|
|
||||||
fragment_name = self.fragment_names[fragment]
|
fragment_name = self.fragment_names[fragment]
|
||||||
|
@ -1224,7 +1224,7 @@ class NetlistEmitter:
|
||||||
for port in fragment._read_ports:
|
for port in fragment._read_ports:
|
||||||
self.emit_read_port(parent_module_idx, fragment, port, memory, write_ports)
|
self.emit_read_port(parent_module_idx, fragment, port, memory, write_ports)
|
||||||
elif type(fragment) is _ir.Fragment:
|
elif type(fragment) is _ir.Fragment:
|
||||||
module_idx = self.netlist.add_module(parent_module_idx, fragment_name)
|
module_idx = self.netlist.add_module(parent_module_idx, fragment_name, src_loc=fragment.src_loc, cell_src_loc=cell_src_loc)
|
||||||
signal_names = fragment._assign_names_to_signals()
|
signal_names = fragment._assign_names_to_signals()
|
||||||
self.netlist.modules[module_idx].signal_names = signal_names
|
self.netlist.modules[module_idx].signal_names = signal_names
|
||||||
if parent_module_idx is None:
|
if parent_module_idx is None:
|
||||||
|
@ -1234,8 +1234,8 @@ class NetlistEmitter:
|
||||||
for domain, stmts in fragment.statements.items():
|
for domain, stmts in fragment.statements.items():
|
||||||
for stmt in stmts:
|
for stmt in stmts:
|
||||||
self.emit_stmt(module_idx, fragment, domain, stmt, _nir.Net.from_const(1))
|
self.emit_stmt(module_idx, fragment, domain, stmt, _nir.Net.from_const(1))
|
||||||
for subfragment, _name in fragment.subfragments:
|
for subfragment, _name, sub_src_loc in fragment.subfragments:
|
||||||
self.emit_fragment(subfragment, module_idx)
|
self.emit_fragment(subfragment, module_idx, cell_src_loc=sub_src_loc)
|
||||||
if parent_module_idx is None:
|
if parent_module_idx is None:
|
||||||
self.emit_drivers()
|
self.emit_drivers()
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -65,7 +65,7 @@ class MemoryInstance(Fragment):
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, *, identity, width, depth, init=None, attrs=None, src_loc=None):
|
def __init__(self, *, identity, width, depth, init=None, attrs=None, src_loc=None):
|
||||||
super().__init__()
|
super().__init__(src_loc=src_loc)
|
||||||
assert isinstance(identity, MemoryIdentity)
|
assert isinstance(identity, MemoryIdentity)
|
||||||
self._identity = identity
|
self._identity = identity
|
||||||
self._width = operator.index(width)
|
self._width = operator.index(width)
|
||||||
|
@ -76,7 +76,6 @@ class MemoryInstance(Fragment):
|
||||||
for x in self._init:
|
for x in self._init:
|
||||||
assert isinstance(x, int)
|
assert isinstance(x, int)
|
||||||
self._attrs = attrs or {}
|
self._attrs = attrs or {}
|
||||||
self._src_loc = src_loc
|
|
||||||
self._read_ports = []
|
self._read_ports = []
|
||||||
self._write_ports = []
|
self._write_ports = []
|
||||||
|
|
||||||
|
|
|
@ -211,9 +211,9 @@ class Netlist:
|
||||||
result.append(f"(cell {cell_idx} {cell.module_idx} {cell!r})")
|
result.append(f"(cell {cell_idx} {cell.module_idx} {cell!r})")
|
||||||
return "\n".join(result)
|
return "\n".join(result)
|
||||||
|
|
||||||
def add_module(self, parent, name: str):
|
def add_module(self, parent, name: str, *, src_loc=None, cell_src_loc=None):
|
||||||
module_idx = len(self.modules)
|
module_idx = len(self.modules)
|
||||||
self.modules.append(Module(parent, name))
|
self.modules.append(Module(parent, name, src_loc=src_loc, cell_src_loc=cell_src_loc))
|
||||||
if module_idx == 0:
|
if module_idx == 0:
|
||||||
self.modules[0].cells.append(0)
|
self.modules[0].cells.append(0)
|
||||||
if parent is not None:
|
if parent is not None:
|
||||||
|
@ -276,15 +276,18 @@ class Module:
|
||||||
|
|
||||||
parent: index of parent module, or ``None`` for top module
|
parent: index of parent module, or ``None`` for top module
|
||||||
name: a tuple of str, hierarchical name of this module (top has empty tuple)
|
name: a tuple of str, hierarchical name of this module (top has empty tuple)
|
||||||
|
src_loc: str
|
||||||
submodules: a list of nested module indices
|
submodules: a list of nested module indices
|
||||||
signal_names: a SignalDict from Signal to str, signal names visible in this module
|
signal_names: a SignalDict from Signal to str, signal names visible in this module
|
||||||
net_flow: a dict from Net to NetFlow, describes how a net is used within this module
|
net_flow: a dict from Net to NetFlow, describes how a net is used within this module
|
||||||
ports: a dict from port name to (Value, NetFlow) pair
|
ports: a dict from port name to (Value, NetFlow) pair
|
||||||
cells: a list of cell indices that belong to this module
|
cells: a list of cell indices that belong to this module
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent, name):
|
def __init__(self, parent, name, *, src_loc, cell_src_loc):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.src_loc = src_loc
|
||||||
|
self.cell_src_loc = cell_src_loc
|
||||||
self.submodules = []
|
self.submodules = []
|
||||||
self.signal_names = SignalDict()
|
self.signal_names = SignalDict()
|
||||||
self.net_flow = {}
|
self.net_flow = {}
|
||||||
|
|
|
@ -206,8 +206,8 @@ class StatementTransformer(StatementVisitor):
|
||||||
|
|
||||||
class FragmentTransformer:
|
class FragmentTransformer:
|
||||||
def map_subfragments(self, fragment, new_fragment):
|
def map_subfragments(self, fragment, new_fragment):
|
||||||
for subfragment, name in fragment.subfragments:
|
for subfragment, name, src_loc in fragment.subfragments:
|
||||||
new_fragment.add_subfragment(self(subfragment), name)
|
new_fragment.add_subfragment(self(subfragment), name, src_loc=src_loc)
|
||||||
|
|
||||||
def map_ports(self, fragment, new_fragment):
|
def map_ports(self, fragment, new_fragment):
|
||||||
for port, dir in fragment.ports.items():
|
for port, dir in fragment.ports.items():
|
||||||
|
@ -255,7 +255,7 @@ class FragmentTransformer:
|
||||||
depth=fragment._depth,
|
depth=fragment._depth,
|
||||||
init=fragment._init,
|
init=fragment._init,
|
||||||
attrs=fragment._attrs,
|
attrs=fragment._attrs,
|
||||||
src_loc=fragment._src_loc
|
src_loc=fragment.src_loc
|
||||||
)
|
)
|
||||||
new_fragment._read_ports = [
|
new_fragment._read_ports = [
|
||||||
MemoryInstance._ReadPort(
|
MemoryInstance._ReadPort(
|
||||||
|
@ -282,7 +282,7 @@ class FragmentTransformer:
|
||||||
new_fragment.parameters = OrderedDict(fragment.parameters)
|
new_fragment.parameters = OrderedDict(fragment.parameters)
|
||||||
self.map_named_ports(fragment, new_fragment)
|
self.map_named_ports(fragment, new_fragment)
|
||||||
else:
|
else:
|
||||||
new_fragment = Fragment()
|
new_fragment = Fragment(src_loc=fragment.src_loc)
|
||||||
new_fragment.flatten = fragment.flatten
|
new_fragment.flatten = fragment.flatten
|
||||||
new_fragment.attrs = OrderedDict(fragment.attrs)
|
new_fragment.attrs = OrderedDict(fragment.attrs)
|
||||||
self.map_ports(fragment, new_fragment)
|
self.map_ports(fragment, new_fragment)
|
||||||
|
@ -417,7 +417,7 @@ class DomainCollector(ValueVisitor, StatementVisitor):
|
||||||
for domain_name, statements in fragment.statements.items():
|
for domain_name, statements in fragment.statements.items():
|
||||||
self._add_used_domain(domain_name)
|
self._add_used_domain(domain_name)
|
||||||
self.on_statements(statements)
|
self.on_statements(statements)
|
||||||
for subfragment, name in fragment.subfragments:
|
for subfragment, name, src_loc in fragment.subfragments:
|
||||||
self.on_fragment(subfragment)
|
self.on_fragment(subfragment)
|
||||||
|
|
||||||
self._local_domains = old_local_domains
|
self._local_domains = old_local_domains
|
||||||
|
|
|
@ -535,7 +535,7 @@ class _FragmentCompiler:
|
||||||
|
|
||||||
processes.add(domain_process)
|
processes.add(domain_process)
|
||||||
|
|
||||||
for subfragment_index, (subfragment, subfragment_name) in enumerate(fragment.subfragments):
|
for subfragment_index, (subfragment, subfragment_name, _src_loc) in enumerate(fragment.subfragments):
|
||||||
if subfragment_name is None:
|
if subfragment_name is None:
|
||||||
subfragment_name = f"U${subfragment_index}"
|
subfragment_name = f"U${subfragment_index}"
|
||||||
processes.update(self(subfragment))
|
processes.update(self(subfragment))
|
||||||
|
|
|
@ -830,7 +830,8 @@ class DSLTestCase(FHDLTestCase):
|
||||||
m1 = Module()
|
m1 = Module()
|
||||||
m2 = Module()
|
m2 = Module()
|
||||||
m1.submodules += m2
|
m1.submodules += m2
|
||||||
self.assertEqual(m1._anon_submodules, [m2])
|
self.assertEqual(len(m1._anon_submodules), 1)
|
||||||
|
self.assertEqual(m1._anon_submodules[0][0], m2)
|
||||||
self.assertEqual(m1._named_submodules, {})
|
self.assertEqual(m1._named_submodules, {})
|
||||||
|
|
||||||
def test_submodule_anon_multi(self):
|
def test_submodule_anon_multi(self):
|
||||||
|
@ -838,7 +839,9 @@ class DSLTestCase(FHDLTestCase):
|
||||||
m2 = Module()
|
m2 = Module()
|
||||||
m3 = Module()
|
m3 = Module()
|
||||||
m1.submodules += m2, m3
|
m1.submodules += m2, m3
|
||||||
self.assertEqual(m1._anon_submodules, [m2, m3])
|
self.assertEqual(len(m1._anon_submodules), 2)
|
||||||
|
self.assertEqual(m1._anon_submodules[0][0], m2)
|
||||||
|
self.assertEqual(m1._anon_submodules[1][0], m3)
|
||||||
self.assertEqual(m1._named_submodules, {})
|
self.assertEqual(m1._named_submodules, {})
|
||||||
|
|
||||||
def test_submodule_named(self):
|
def test_submodule_named(self):
|
||||||
|
@ -846,14 +849,16 @@ class DSLTestCase(FHDLTestCase):
|
||||||
m2 = Module()
|
m2 = Module()
|
||||||
m1.submodules.foo = m2
|
m1.submodules.foo = m2
|
||||||
self.assertEqual(m1._anon_submodules, [])
|
self.assertEqual(m1._anon_submodules, [])
|
||||||
self.assertEqual(m1._named_submodules, {"foo": m2})
|
self.assertEqual(m1._named_submodules.keys(), {"foo"})
|
||||||
|
self.assertEqual(m1._named_submodules["foo"][0], m2)
|
||||||
|
|
||||||
def test_submodule_named_index(self):
|
def test_submodule_named_index(self):
|
||||||
m1 = Module()
|
m1 = Module()
|
||||||
m2 = Module()
|
m2 = Module()
|
||||||
m1.submodules["foo"] = m2
|
m1.submodules["foo"] = m2
|
||||||
self.assertEqual(m1._anon_submodules, [])
|
self.assertEqual(m1._anon_submodules, [])
|
||||||
self.assertEqual(m1._named_submodules, {"foo": m2})
|
self.assertEqual(m1._named_submodules.keys(), {"foo"})
|
||||||
|
self.assertEqual(m1._named_submodules["foo"][0], m2)
|
||||||
|
|
||||||
def test_submodule_wrong(self):
|
def test_submodule_wrong(self):
|
||||||
m = Module()
|
m = Module()
|
||||||
|
@ -943,7 +948,7 @@ class DSLTestCase(FHDLTestCase):
|
||||||
"comb": SignalSet((self.c1,))
|
"comb": SignalSet((self.c1,))
|
||||||
})
|
})
|
||||||
self.assertEqual(len(f1.subfragments), 1)
|
self.assertEqual(len(f1.subfragments), 1)
|
||||||
(f2, f2_name), = f1.subfragments
|
(f2, f2_name, _), = f1.subfragments
|
||||||
self.assertEqual(f2_name, "foo")
|
self.assertEqual(f2_name, "foo")
|
||||||
self.assertRepr(f2.statements["comb"], """
|
self.assertRepr(f2.statements["comb"], """
|
||||||
(
|
(
|
||||||
|
|
|
@ -392,7 +392,7 @@ class FragmentDomainsTestCase(FHDLTestCase):
|
||||||
|
|
||||||
f._propagate_domains_up()
|
f._propagate_domains_up()
|
||||||
self.assertEqual(f.domains, {"a_sync": cda, "b_sync": cdb})
|
self.assertEqual(f.domains, {"a_sync": cda, "b_sync": cdb})
|
||||||
(fa, _), (fb, _) = f.subfragments
|
(fa, _, _), (fb, _, _) = f.subfragments
|
||||||
self.assertEqual(fa.domains, {"a_sync": cda})
|
self.assertEqual(fa.domains, {"a_sync": cda})
|
||||||
self.assertEqual(fb.domains, {"b_sync": cdb})
|
self.assertEqual(fb.domains, {"b_sync": cdb})
|
||||||
|
|
||||||
|
@ -446,7 +446,7 @@ class FragmentDomainsTestCase(FHDLTestCase):
|
||||||
f.add_subfragment(fb, "b")
|
f.add_subfragment(fb, "b")
|
||||||
|
|
||||||
f._propagate_domains_up()
|
f._propagate_domains_up()
|
||||||
fb_new, _ = f.subfragments[1]
|
fb_new, _, _ = f.subfragments[1]
|
||||||
self.assertEqual(fb_new.drivers, OrderedDict({
|
self.assertEqual(fb_new.drivers, OrderedDict({
|
||||||
"comb": SignalSet((ResetSignal("b_sync"),))
|
"comb": SignalSet((ResetSignal("b_sync"),))
|
||||||
}))
|
}))
|
||||||
|
@ -540,7 +540,7 @@ class FragmentDomainsTestCase(FHDLTestCase):
|
||||||
self.assertEqual(f1.domains["sync"], f2.domains["sync"])
|
self.assertEqual(f1.domains["sync"], f2.domains["sync"])
|
||||||
self.assertEqual(new_domains, [])
|
self.assertEqual(new_domains, [])
|
||||||
self.assertEqual(f1.subfragments, [
|
self.assertEqual(f1.subfragments, [
|
||||||
(f2, "cd_sync")
|
(f2, "cd_sync", None)
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_propagate_create_missing_fragment_many_domains(self):
|
def test_propagate_create_missing_fragment_many_domains(self):
|
||||||
|
@ -559,7 +559,7 @@ class FragmentDomainsTestCase(FHDLTestCase):
|
||||||
self.assertEqual(f1.domains["sync"], f2.domains["sync"])
|
self.assertEqual(f1.domains["sync"], f2.domains["sync"])
|
||||||
self.assertEqual(new_domains, [])
|
self.assertEqual(new_domains, [])
|
||||||
self.assertEqual(f1.subfragments, [
|
self.assertEqual(f1.subfragments, [
|
||||||
(f2, "cd_sync")
|
(f2, "cd_sync", None)
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_propagate_create_missing_fragment_wrong(self):
|
def test_propagate_create_missing_fragment_wrong(self):
|
||||||
|
@ -606,7 +606,7 @@ class FragmentHierarchyConflictTestCase(FHDLTestCase):
|
||||||
self.setUp_self_sub()
|
self.setUp_self_sub()
|
||||||
|
|
||||||
self.f1._resolve_hierarchy_conflicts(mode="silent")
|
self.f1._resolve_hierarchy_conflicts(mode="silent")
|
||||||
self.assertEqual(self.f1.subfragments, [
|
self.assertEqual([(f, n) for f, n, _ in self.f1.subfragments], [
|
||||||
(self.f1a, "f1a"),
|
(self.f1a, "f1a"),
|
||||||
(self.f1b, "f1b"),
|
(self.f1b, "f1b"),
|
||||||
(self.f2a, "f2a"),
|
(self.f2a, "f2a"),
|
||||||
|
|
|
@ -378,7 +378,7 @@ class EnableInserterTestCase(FHDLTestCase):
|
||||||
f1.add_subfragment(f2)
|
f1.add_subfragment(f2)
|
||||||
|
|
||||||
f1 = EnableInserter(self.c1)(f1)
|
f1 = EnableInserter(self.c1)(f1)
|
||||||
(f2, _), = f1.subfragments
|
(f2, _, _), = f1.subfragments
|
||||||
self.assertRepr(f1.statements["sync"], """
|
self.assertRepr(f1.statements["sync"], """
|
||||||
(
|
(
|
||||||
(eq (sig s1) (const 1'd1))
|
(eq (sig s1) (const 1'd1))
|
||||||
|
|
Loading…
Reference in a new issue