ir: allow non-Signals in Instance ports.
This commit is contained in:
parent
8cc900c4ef
commit
f7fec804ec
|
@ -16,6 +16,7 @@ class System:
|
|||
i_d_adr =self.adr,
|
||||
i_d_dat_r=self.dat_r,
|
||||
o_d_dat_w=self.dat_w,
|
||||
i_d_we =self.we,
|
||||
)
|
||||
return m.lower(platform)
|
||||
|
||||
|
|
|
@ -567,15 +567,12 @@ class _StatementCompiler(xfrm.AbstractStatementTransformer):
|
|||
|
||||
|
||||
def convert_fragment(builder, fragment, name, top):
|
||||
if fragment.black_box is not None:
|
||||
if isinstance(fragment, ir.Instance):
|
||||
port_map = OrderedDict()
|
||||
for signal in fragment.ports:
|
||||
port_map["\\{}".format(fragment.port_names[signal])] = signal
|
||||
for port_name, value in fragment.named_ports.items():
|
||||
port_map["\\{}".format(port_name)] = value
|
||||
|
||||
return "\\{}".format(fragment.black_box), port_map
|
||||
else:
|
||||
assert not fragment.port_names
|
||||
assert not fragment.parameters
|
||||
return "\\{}".format(fragment.type), port_map
|
||||
|
||||
with builder.module(name or "anonymous", attrs={"top": 1} if top else {}) as module:
|
||||
compiler_state = _ValueCompilerState(module)
|
||||
|
|
|
@ -15,10 +15,6 @@ class DriverConflict(UserWarning):
|
|||
|
||||
class Fragment:
|
||||
def __init__(self):
|
||||
self.black_box = None
|
||||
self.port_names = SignalDict()
|
||||
self.parameters = OrderedDict()
|
||||
|
||||
self.ports = SignalDict()
|
||||
self.drivers = OrderedDict()
|
||||
self.statements = []
|
||||
|
@ -241,8 +237,11 @@ class Fragment:
|
|||
def _propagate_ports(self, ports):
|
||||
# Collect all signals we're driving (on LHS of statements), and signals we're using
|
||||
# (on RHS of statements, or in clock domains).
|
||||
self_driven = union(s._lhs_signals() for s in self.statements) or SignalSet()
|
||||
self_used = union(s._rhs_signals() for s in self.statements) or SignalSet()
|
||||
self_driven = union((s._lhs_signals() for s in self.statements), start=SignalSet())
|
||||
self_used = union((s._rhs_signals() for s in self.statements), start=SignalSet())
|
||||
if isinstance(self, Instance):
|
||||
self_used |= union((p._rhs_signals() for p in self.named_ports.values()),
|
||||
start=SignalSet())
|
||||
for domain, _ in self.iter_sync():
|
||||
cd = self.domains[domain]
|
||||
self_used.add(cd.clk)
|
||||
|
@ -296,18 +295,24 @@ class Fragment:
|
|||
class Instance(Fragment):
|
||||
def __init__(self, type, **kwargs):
|
||||
super().__init__()
|
||||
self.black_box = type
|
||||
|
||||
self.type = type
|
||||
self.parameters = OrderedDict()
|
||||
self.named_ports = OrderedDict()
|
||||
|
||||
for kw, arg in kwargs.items():
|
||||
if kw.startswith("p_"):
|
||||
self.parameters[kw[2:]] = arg
|
||||
elif kw.startswith("i_"):
|
||||
self.port_names[arg] = kw[2:]
|
||||
self.add_ports(arg, dir="i")
|
||||
self.named_ports[kw[2:]] = arg
|
||||
# Unlike with "o_" and "io_", "i_" ports can be assigned an arbitrary value;
|
||||
# this includes unresolved ClockSignals etc. We rely on Fragment.prepare to
|
||||
# populate fragment ports for these named ports.
|
||||
elif kw.startswith("o_"):
|
||||
self.port_names[arg] = kw[2:]
|
||||
self.named_ports[kw[2:]] = arg
|
||||
self.add_ports(arg, dir="o")
|
||||
elif kw.startswith("io_"):
|
||||
self.port_names[arg] = kw[3:]
|
||||
self.named_ports[kw[3:]] = arg
|
||||
self.add_ports(arg, dir="io")
|
||||
else:
|
||||
raise NameError("Instance argument '{}' does not start with p_, i_, o_, or io_"
|
||||
|
|
|
@ -179,6 +179,13 @@ class FragmentTransformer:
|
|||
for port, dir in fragment.ports.items():
|
||||
new_fragment.add_ports(port, dir=dir)
|
||||
|
||||
def map_named_ports(self, fragment, new_fragment):
|
||||
if hasattr(self, "on_value"):
|
||||
for name, value in fragment.named_ports.items():
|
||||
new_fragment.named_ports[name] = self.on_value(value)
|
||||
else:
|
||||
new_fragment.named_ports = OrderedDict(fragment.named_ports.items())
|
||||
|
||||
def map_domains(self, fragment, new_fragment):
|
||||
for domain in fragment.iter_domains():
|
||||
new_fragment.add_domains(fragment.domains[domain])
|
||||
|
@ -194,10 +201,12 @@ class FragmentTransformer:
|
|||
new_fragment.add_driver(signal, domain)
|
||||
|
||||
def on_fragment(self, fragment):
|
||||
new_fragment = Fragment()
|
||||
new_fragment.black_box = fragment.black_box
|
||||
new_fragment.parameters = OrderedDict(fragment.parameters)
|
||||
new_fragment.port_names = SignalDict(fragment.port_names.items())
|
||||
if isinstance(fragment, Instance):
|
||||
new_fragment = Instance(fragment.type)
|
||||
new_fragment.parameters = OrderedDict(fragment.parameters)
|
||||
self.map_named_ports(fragment, new_fragment)
|
||||
else:
|
||||
new_fragment = Fragment()
|
||||
self.map_ports(fragment, new_fragment)
|
||||
self.map_subfragments(fragment, new_fragment)
|
||||
self.map_domains(fragment, new_fragment)
|
||||
|
|
|
@ -412,11 +412,17 @@ class InstanceTestCase(FHDLTestCase):
|
|||
rst = Signal()
|
||||
stb = Signal()
|
||||
pins = Signal(8)
|
||||
inst = Instance("cpu", p_RESET=0x1234, i_rst=rst, o_stb=stb, io_pins=pins)
|
||||
self.assertEqual(inst.black_box, "cpu")
|
||||
inst = Instance("cpu",
|
||||
p_RESET=0x1234,
|
||||
i_clk=ClockSignal(),
|
||||
i_rst=rst,
|
||||
o_stb=stb,
|
||||
io_pins=pins
|
||||
)
|
||||
self.assertEqual(inst.type, "cpu")
|
||||
self.assertEqual(inst.parameters, OrderedDict([("RESET", 0x1234)]))
|
||||
self.assertEqual(list(inst.named_ports.keys()), ["clk", "rst", "stb", "pins"])
|
||||
self.assertEqual(inst.ports, SignalDict([
|
||||
(rst, "i"),
|
||||
(stb, "o"),
|
||||
(pins, "io"),
|
||||
]))
|
||||
|
|
Loading…
Reference in a new issue