vendor._altera: implement lib.io
buffer primitives.
This commit is contained in:
parent
7dd93bea57
commit
1b9290188b
|
@ -1,9 +1,184 @@
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
|
||||||
from ..hdl import *
|
from ..hdl import *
|
||||||
|
from ..hdl import _ast
|
||||||
|
from ..lib import io, wiring
|
||||||
from ..build import *
|
from ..build import *
|
||||||
|
|
||||||
|
|
||||||
|
# The altiobuf_* and altddio_* primitives are explained in the following Intel documents:
|
||||||
|
# * https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_altiobuf.pdf
|
||||||
|
# * https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_altddio.pdf
|
||||||
|
# See also errata mentioned in: https://www.intel.com/content/www/us/en/programmable/support/support-resources/knowledge-base/solutions/rd11192012_735.html.
|
||||||
|
|
||||||
|
|
||||||
|
# Horrible hack here. To get Quartus to pack FFs into IOEs, the port needs to have an
|
||||||
|
# ``useioff`` attribute. Unfortunately, this means that FF packing can only be controlled
|
||||||
|
# with port granularity, not bit granularity. However, Quartus doesn't seem to mind
|
||||||
|
# this attribute being set when it's not possible to pack a FF — it's just ignored with
|
||||||
|
# a warning. So, we just set it on whatever is passed to ``FFBuffer`` — at worst, we'll
|
||||||
|
# cause some extra random FFs to be opportunistically packed into the IOE for other bits
|
||||||
|
# of a sliced port.
|
||||||
|
#
|
||||||
|
# This function is also used by ``DDRBuffer`` to pack the output enable FF.
|
||||||
|
def _add_useioff(value):
|
||||||
|
if isinstance(value, _ast.IOPort):
|
||||||
|
value.attrs["useioff"] = 1
|
||||||
|
elif isinstance(value, _ast.IOConcat):
|
||||||
|
for part in value.parts:
|
||||||
|
_add_useioff(part)
|
||||||
|
elif isinstance(value, _ast.IOSlice):
|
||||||
|
_add_useioff(value.value)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError # :nocov:
|
||||||
|
|
||||||
|
|
||||||
|
class InnerBuffer(wiring.Component):
|
||||||
|
"""A private component used to implement ``lib.io`` buffers.
|
||||||
|
|
||||||
|
Works like ``lib.io.Buffer``, with the following differences:
|
||||||
|
|
||||||
|
- ``port.invert`` is ignored (handling the inversion is the outer buffer's responsibility)
|
||||||
|
- output enable is per-pin
|
||||||
|
"""
|
||||||
|
def __init__(self, direction, port, *, useioff=False):
|
||||||
|
self.direction = direction
|
||||||
|
self.port = port
|
||||||
|
members = {}
|
||||||
|
if direction is not io.Direction.Output:
|
||||||
|
members["i"] = wiring.In(len(port))
|
||||||
|
if direction is not io.Direction.Input:
|
||||||
|
members["o"] = wiring.Out(len(port))
|
||||||
|
members["oe"] = wiring.Out(len(port))
|
||||||
|
super().__init__(wiring.Signature(members).flip())
|
||||||
|
if useioff:
|
||||||
|
if isinstance(port, io.SingleEndedPort):
|
||||||
|
_add_useioff(port.io)
|
||||||
|
elif isinstance(port, io.DifferentialPort):
|
||||||
|
_add_useioff(port.p)
|
||||||
|
_add_useioff(port.n)
|
||||||
|
|
||||||
|
def elaborate(self, platform):
|
||||||
|
kwargs = dict(
|
||||||
|
p_enable_bus_hold="FALSE",
|
||||||
|
p_number_of_channels=len(self.port),
|
||||||
|
)
|
||||||
|
if isinstance(self.port, io.SingleEndedPort):
|
||||||
|
kwargs["p_use_differential_mode"] = "FALSE"
|
||||||
|
elif isinstance(self.port, io.DifferentialPort):
|
||||||
|
kwargs["p_use_differential_mode"] = "TRUE"
|
||||||
|
else:
|
||||||
|
raise TypeError(f"Unknown port type {self.port!r}")
|
||||||
|
|
||||||
|
if self.direction is io.Direction.Input:
|
||||||
|
if isinstance(self.port, io.SingleEndedPort):
|
||||||
|
kwargs["i_datain"] = self.port.io
|
||||||
|
else:
|
||||||
|
kwargs["i_datain"] = self.port.p,
|
||||||
|
kwargs["i_datain_b"] = self.port.n,
|
||||||
|
return Instance("altiobuf_in",
|
||||||
|
o_dataout=self.i,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
elif self.direction is io.Direction.Output:
|
||||||
|
if isinstance(self.port, io.SingleEndedPort):
|
||||||
|
kwargs["o_dataout"] = self.port.io
|
||||||
|
else:
|
||||||
|
kwargs["o_dataout"] = self.port.p,
|
||||||
|
kwargs["o_dataout_b"] = self.port.n,
|
||||||
|
return Instance("altiobuf_out",
|
||||||
|
p_use_oe="TRUE",
|
||||||
|
i_datain=self.o,
|
||||||
|
i_oe=self.oe,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
elif self.direction is io.Direction.Bidir:
|
||||||
|
if isinstance(self.port, io.SingleEndedPort):
|
||||||
|
kwargs["io_dataio"] = self.port.io
|
||||||
|
else:
|
||||||
|
kwargs["io_dataio"] = self.port.p,
|
||||||
|
kwargs["io_dataio_b"] = self.port.n,
|
||||||
|
return Instance("altiobuf_bidir",
|
||||||
|
i_datain=self.o,
|
||||||
|
i_oe=self.oe,
|
||||||
|
o_dataout=self.i,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
assert False # :nocov:
|
||||||
|
|
||||||
|
|
||||||
|
class IOBuffer(io.Buffer):
|
||||||
|
def elaborate(self, platform):
|
||||||
|
m = Module()
|
||||||
|
|
||||||
|
m.submodules.buf = buf = InnerBuffer(self.direction, self.port)
|
||||||
|
inv_mask = sum(inv << bit for bit, inv in enumerate(self.port.invert))
|
||||||
|
|
||||||
|
if self.direction is not io.Direction.Output:
|
||||||
|
m.d.comb += self.i.eq(buf.i ^ inv_mask)
|
||||||
|
|
||||||
|
if self.direction is not io.Direction.Input:
|
||||||
|
m.d.comb += buf.o.eq(self.o ^ inv_mask)
|
||||||
|
m.d.comb += buf.oe.eq(self.oe.replicate(len(self.port)))
|
||||||
|
|
||||||
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
class FFBuffer(io.FFBuffer):
|
||||||
|
def elaborate(self, platform):
|
||||||
|
m = Module()
|
||||||
|
|
||||||
|
m.submodules.buf = buf = InnerBuffer(self.direction, self.port, useioff=True)
|
||||||
|
inv_mask = sum(inv << bit for bit, inv in enumerate(self.port.invert))
|
||||||
|
|
||||||
|
if self.direction is not io.Direction.Output:
|
||||||
|
i_inv = Signal.like(self.i)
|
||||||
|
m.d[self.i_domain] += i_inv.eq(buf.i)
|
||||||
|
m.d.comb += self.i.eq(i_inv ^ inv_mask)
|
||||||
|
|
||||||
|
if self.direction is not io.Direction.Input:
|
||||||
|
m.d[self.o_domain] += buf.o.eq(self.o ^ inv_mask)
|
||||||
|
m.d[self.o_domain] += buf.oe.eq(self.oe.replicate(len(self.port)))
|
||||||
|
|
||||||
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
class DDRBuffer(io.DDRBuffer):
|
||||||
|
def elaborate(self, platform):
|
||||||
|
m = Module()
|
||||||
|
|
||||||
|
m.submodules.buf = buf = InnerBuffer(self.direction, self.port, useioff=True)
|
||||||
|
inv_mask = sum(inv << bit for bit, inv in enumerate(self.port.invert))
|
||||||
|
|
||||||
|
if self.direction is not io.Direction.Output:
|
||||||
|
i0_reg = Signal(len(self.port))
|
||||||
|
i0_inv = Signal(len(self.port))
|
||||||
|
i1_inv = Signal(len(self.port))
|
||||||
|
m.submodules.i_ddr = Instance("altddio_in",
|
||||||
|
p_width=len(self.port),
|
||||||
|
i_datain=buf.i,
|
||||||
|
i_inclock=ClockSignal(self.i_domain),
|
||||||
|
o_dataout_h=i0_inv,
|
||||||
|
o_dataout_l=i1_inv,
|
||||||
|
)
|
||||||
|
m.d[self.i_domain] += i0_reg.eq(i0_inv)
|
||||||
|
m.d.comb += self.i[0].eq(i0_reg ^ inv_mask)
|
||||||
|
m.d.comb += self.i[1].eq(i1_inv ^ inv_mask)
|
||||||
|
|
||||||
|
if self.direction is not io.Direction.Input:
|
||||||
|
m.submodules.o_ddr = Instance("altddio_out",
|
||||||
|
p_width=len(self.port),
|
||||||
|
o_dataout=buf.o,
|
||||||
|
i_outclock=ClockSignal(self.o_domain),
|
||||||
|
i_datain_h=self.o[0] ^ inv_mask,
|
||||||
|
i_datain_l=self.o[1] ^ inv_mask,
|
||||||
|
)
|
||||||
|
m.d[self.o_domain] += buf.oe.eq(self.oe.replicate(len(self.port)))
|
||||||
|
|
||||||
|
return m
|
||||||
|
|
||||||
|
|
||||||
class AlteraPlatform(TemplatedPlatform):
|
class AlteraPlatform(TemplatedPlatform):
|
||||||
"""
|
"""
|
||||||
.. rubric:: Quartus toolchain
|
.. rubric:: Quartus toolchain
|
||||||
|
@ -67,6 +242,9 @@ class AlteraPlatform(TemplatedPlatform):
|
||||||
10935, # Verilog casex/casez overlaps with a previous casex/vasez item expression
|
10935, # Verilog casex/casez overlaps with a previous casex/vasez item expression
|
||||||
12125, # Using design file which is not specified as a design file for the current project, but contains definitions used in project
|
12125, # Using design file which is not specified as a design file for the current project, but contains definitions used in project
|
||||||
18236, # Number of processors not specified in QSF
|
18236, # Number of processors not specified in QSF
|
||||||
|
176225, # Can't pack node <node> to I/O pin
|
||||||
|
176250, # Ignoring invalid fast I/O register assignments.
|
||||||
|
176272, # Can't pack node <node> and I/O cell
|
||||||
292013, # Feature is only available with a valid subscription license
|
292013, # Feature is only available with a valid subscription license
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -293,247 +471,21 @@ class AlteraPlatform(TemplatedPlatform):
|
||||||
else:
|
else:
|
||||||
return super().create_missing_domain(name)
|
return super().create_missing_domain(name)
|
||||||
|
|
||||||
# The altiobuf_* and altddio_* primitives are explained in the following Intel documents:
|
def get_io_buffer(self, buffer):
|
||||||
# * https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_altiobuf.pdf
|
if isinstance(buffer, io.Buffer):
|
||||||
# * https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_altddio.pdf
|
result = IOBuffer(buffer.direction, buffer.port)
|
||||||
# See also errata mentioned in: https://www.intel.com/content/www/us/en/programmable/support/support-resources/knowledge-base/solutions/rd11192012_735.html.
|
elif isinstance(buffer, io.FFBuffer):
|
||||||
|
result = FFBuffer(buffer.direction, buffer.port)
|
||||||
@staticmethod
|
elif isinstance(buffer, io.DDRBuffer):
|
||||||
def _get_ireg(m, pin, invert):
|
result = DDRBuffer(buffer.direction, buffer.port)
|
||||||
def get_ineg(i):
|
else:
|
||||||
if invert:
|
raise TypeError(f"Unsupported buffer type {buffer!r}") # :nocov:
|
||||||
i_neg = Signal.like(i, name_suffix="_neg")
|
if buffer.direction is not io.Direction.Output:
|
||||||
m.d.comb += i.eq(~i_neg)
|
result.i = buffer.i
|
||||||
return i_neg
|
if buffer.direction is not io.Direction.Input:
|
||||||
else:
|
result.o = buffer.o
|
||||||
return i
|
result.oe = buffer.oe
|
||||||
|
return result
|
||||||
if pin.xdr == 0:
|
|
||||||
return get_ineg(pin.i)
|
|
||||||
elif pin.xdr == 1:
|
|
||||||
i_sdr = Signal(pin.width, name="{}_i_sdr")
|
|
||||||
i_neg = get_ineg(pin.i)
|
|
||||||
for bit in range(pin.width):
|
|
||||||
m.submodules += Instance("dff",
|
|
||||||
i_clk=pin.i_clk,
|
|
||||||
i_d=i_sdr[bit],
|
|
||||||
o_q=i_neg[bit],
|
|
||||||
o_clrn=Const(1),
|
|
||||||
o_prn=Const(1),
|
|
||||||
)
|
|
||||||
return i_sdr
|
|
||||||
elif pin.xdr == 2:
|
|
||||||
i_ddr = Signal(pin.width, name=f"{pin.name}_i_ddr")
|
|
||||||
m.submodules[f"{pin.name}_i_ddr"] = Instance("altddio_in",
|
|
||||||
p_width=pin.width,
|
|
||||||
i_datain=i_ddr,
|
|
||||||
i_inclock=pin.i_clk,
|
|
||||||
o_dataout_h=get_ineg(pin.i0),
|
|
||||||
o_dataout_l=get_ineg(pin.i1),
|
|
||||||
)
|
|
||||||
return i_ddr
|
|
||||||
assert False
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_oreg(m, pin, invert):
|
|
||||||
def get_oneg(o):
|
|
||||||
if invert:
|
|
||||||
o_neg = Signal.like(o, name_suffix="_neg")
|
|
||||||
m.d.comb += o_neg.eq(~o)
|
|
||||||
return o_neg
|
|
||||||
else:
|
|
||||||
return o
|
|
||||||
|
|
||||||
if pin.xdr == 0:
|
|
||||||
return get_oneg(pin.o)
|
|
||||||
elif pin.xdr == 1:
|
|
||||||
o_sdr = Signal(pin.width, name=f"{pin.name}_o_sdr")
|
|
||||||
for bit in range(pin.width):
|
|
||||||
o_neg = get_oneg(pin.o)
|
|
||||||
m.submodules += Instance("dff",
|
|
||||||
i_clk=pin.o_clk,
|
|
||||||
i_d=o_neg[bit],
|
|
||||||
o_q=o_sdr[bit],
|
|
||||||
o_clrn=Const(1),
|
|
||||||
o_prn=Const(1),
|
|
||||||
)
|
|
||||||
return o_sdr
|
|
||||||
elif pin.xdr == 2:
|
|
||||||
o_ddr = Signal(pin.width, name=f"{pin.name}_o_ddr")
|
|
||||||
m.submodules[f"{pin.name}_o_ddr"] = Instance("altddio_out",
|
|
||||||
p_width=pin.width,
|
|
||||||
o_dataout=o_ddr,
|
|
||||||
i_outclock=pin.o_clk,
|
|
||||||
i_datain_h=get_oneg(pin.o0),
|
|
||||||
i_datain_l=get_oneg(pin.o1),
|
|
||||||
)
|
|
||||||
return o_ddr
|
|
||||||
assert False
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_oereg(m, pin):
|
|
||||||
# altiobuf_ requires an output enable signal for each pin, but pin.oe is 1 bit wide.
|
|
||||||
if pin.xdr == 0:
|
|
||||||
return pin.oe.replicate(pin.width)
|
|
||||||
elif pin.xdr in (1, 2):
|
|
||||||
oe_reg = Signal(pin.width, name=f"{pin.name}_oe_reg")
|
|
||||||
oe_reg.attrs["useioff"] = "1"
|
|
||||||
for bit in range(pin.width):
|
|
||||||
m.submodules += Instance("dff",
|
|
||||||
i_clk=pin.o_clk,
|
|
||||||
i_d=pin.oe,
|
|
||||||
o_q=oe_reg[bit],
|
|
||||||
o_clrn=Const(1),
|
|
||||||
o_prn=Const(1),
|
|
||||||
)
|
|
||||||
return oe_reg
|
|
||||||
assert False
|
|
||||||
|
|
||||||
def get_input(self, pin, port, attrs, invert):
|
|
||||||
self._check_feature("single-ended input", pin, attrs,
|
|
||||||
valid_xdrs=(0, 1, 2), valid_attrs=True)
|
|
||||||
if pin.xdr == 1:
|
|
||||||
port.attrs["useioff"] = 1
|
|
||||||
|
|
||||||
m = Module()
|
|
||||||
m.submodules[pin.name] = Instance("altiobuf_in",
|
|
||||||
p_enable_bus_hold="FALSE",
|
|
||||||
p_number_of_channels=pin.width,
|
|
||||||
p_use_differential_mode="FALSE",
|
|
||||||
i_datain=port.io,
|
|
||||||
o_dataout=self._get_ireg(m, pin, invert)
|
|
||||||
)
|
|
||||||
return m
|
|
||||||
|
|
||||||
def get_output(self, pin, port, attrs, invert):
|
|
||||||
self._check_feature("single-ended output", pin, attrs,
|
|
||||||
valid_xdrs=(0, 1, 2), valid_attrs=True)
|
|
||||||
if pin.xdr == 1:
|
|
||||||
port.attrs["useioff"] = 1
|
|
||||||
|
|
||||||
m = Module()
|
|
||||||
m.submodules[pin.name] = Instance("altiobuf_out",
|
|
||||||
p_enable_bus_hold="FALSE",
|
|
||||||
p_number_of_channels=pin.width,
|
|
||||||
p_use_differential_mode="FALSE",
|
|
||||||
p_use_oe="FALSE",
|
|
||||||
i_datain=self._get_oreg(m, pin, invert),
|
|
||||||
o_dataout=port.io,
|
|
||||||
)
|
|
||||||
return m
|
|
||||||
|
|
||||||
def get_tristate(self, pin, port, attrs, invert):
|
|
||||||
self._check_feature("single-ended tristate", pin, attrs,
|
|
||||||
valid_xdrs=(0, 1, 2), valid_attrs=True)
|
|
||||||
if pin.xdr == 1:
|
|
||||||
port.attrs["useioff"] = 1
|
|
||||||
|
|
||||||
m = Module()
|
|
||||||
m.submodules[pin.name] = Instance("altiobuf_out",
|
|
||||||
p_enable_bus_hold="FALSE",
|
|
||||||
p_number_of_channels=pin.width,
|
|
||||||
p_use_differential_mode="FALSE",
|
|
||||||
p_use_oe="TRUE",
|
|
||||||
i_datain=self._get_oreg(m, pin, invert),
|
|
||||||
o_dataout=port.io,
|
|
||||||
i_oe=self._get_oereg(m, pin)
|
|
||||||
)
|
|
||||||
return m
|
|
||||||
|
|
||||||
def get_input_output(self, pin, port, attrs, invert):
|
|
||||||
self._check_feature("single-ended input/output", pin, attrs,
|
|
||||||
valid_xdrs=(0, 1, 2), valid_attrs=True)
|
|
||||||
if pin.xdr == 1:
|
|
||||||
port.attrs["useioff"] = 1
|
|
||||||
|
|
||||||
m = Module()
|
|
||||||
m.submodules[pin.name] = Instance("altiobuf_bidir",
|
|
||||||
p_enable_bus_hold="FALSE",
|
|
||||||
p_number_of_channels=pin.width,
|
|
||||||
p_use_differential_mode="FALSE",
|
|
||||||
i_datain=self._get_oreg(m, pin, invert),
|
|
||||||
io_dataio=port.io,
|
|
||||||
o_dataout=self._get_ireg(m, pin, invert),
|
|
||||||
i_oe=self._get_oereg(m, pin),
|
|
||||||
)
|
|
||||||
return m
|
|
||||||
|
|
||||||
def get_diff_input(self, pin, port, attrs, invert):
|
|
||||||
self._check_feature("differential input", pin, attrs,
|
|
||||||
valid_xdrs=(0, 1, 2), valid_attrs=True)
|
|
||||||
if pin.xdr == 1:
|
|
||||||
port.p.attrs["useioff"] = 1
|
|
||||||
port.n.attrs["useioff"] = 1
|
|
||||||
|
|
||||||
m = Module()
|
|
||||||
m.submodules[pin.name] = Instance("altiobuf_in",
|
|
||||||
p_enable_bus_hold="FALSE",
|
|
||||||
p_number_of_channels=pin.width,
|
|
||||||
p_use_differential_mode="TRUE",
|
|
||||||
i_datain=port.p,
|
|
||||||
i_datain_b=port.n,
|
|
||||||
o_dataout=self._get_ireg(m, pin, invert)
|
|
||||||
)
|
|
||||||
return m
|
|
||||||
|
|
||||||
def get_diff_output(self, pin, port, attrs, invert):
|
|
||||||
self._check_feature("differential output", pin, attrs,
|
|
||||||
valid_xdrs=(0, 1, 2), valid_attrs=True)
|
|
||||||
if pin.xdr == 1:
|
|
||||||
port.p.attrs["useioff"] = 1
|
|
||||||
port.n.attrs["useioff"] = 1
|
|
||||||
|
|
||||||
m = Module()
|
|
||||||
m.submodules[pin.name] = Instance("altiobuf_out",
|
|
||||||
p_enable_bus_hold="FALSE",
|
|
||||||
p_number_of_channels=pin.width,
|
|
||||||
p_use_differential_mode="TRUE",
|
|
||||||
p_use_oe="FALSE",
|
|
||||||
i_datain=self._get_oreg(m, pin, invert),
|
|
||||||
o_dataout=port.p,
|
|
||||||
o_dataout_b=port.n,
|
|
||||||
)
|
|
||||||
return m
|
|
||||||
|
|
||||||
def get_diff_tristate(self, pin, port, attrs, invert):
|
|
||||||
self._check_feature("differential tristate", pin, attrs,
|
|
||||||
valid_xdrs=(0, 1, 2), valid_attrs=True)
|
|
||||||
if pin.xdr == 1:
|
|
||||||
port.p.attrs["useioff"] = 1
|
|
||||||
port.n.attrs["useioff"] = 1
|
|
||||||
|
|
||||||
m = Module()
|
|
||||||
m.submodules[pin.name] = Instance("altiobuf_out",
|
|
||||||
p_enable_bus_hold="FALSE",
|
|
||||||
p_number_of_channels=pin.width,
|
|
||||||
p_use_differential_mode="TRUE",
|
|
||||||
p_use_oe="TRUE",
|
|
||||||
i_datain=self._get_oreg(m, pin, invert),
|
|
||||||
o_dataout=port.p,
|
|
||||||
o_dataout_b=port.n,
|
|
||||||
i_oe=self._get_oereg(m, pin),
|
|
||||||
)
|
|
||||||
return m
|
|
||||||
|
|
||||||
def get_diff_input_output(self, pin, port, attrs, invert):
|
|
||||||
self._check_feature("differential input/output", pin, attrs,
|
|
||||||
valid_xdrs=(0, 1, 2), valid_attrs=True)
|
|
||||||
if pin.xdr == 1:
|
|
||||||
port.p.attrs["useioff"] = 1
|
|
||||||
port.n.attrs["useioff"] = 1
|
|
||||||
|
|
||||||
m = Module()
|
|
||||||
m.submodules[pin.name] = Instance("altiobuf_bidir",
|
|
||||||
p_enable_bus_hold="FALSE",
|
|
||||||
p_number_of_channels=pin.width,
|
|
||||||
p_use_differential_mode="TRUE",
|
|
||||||
i_datain=self._get_oreg(m, pin, invert),
|
|
||||||
io_dataio=port.p,
|
|
||||||
io_dataio_b=port.n,
|
|
||||||
o_dataout=self._get_ireg(m, pin, invert),
|
|
||||||
i_oe=self._get_oereg(m, pin),
|
|
||||||
)
|
|
||||||
return m
|
|
||||||
|
|
||||||
# The altera_std_synchronizer{,_bundle} megafunctions embed SDC constraints that mark false
|
# The altera_std_synchronizer{,_bundle} megafunctions embed SDC constraints that mark false
|
||||||
# paths, so use them instead of our default implementation.
|
# paths, so use them instead of our default implementation.
|
||||||
|
|
Loading…
Reference in a new issue