From 7c7f9e3233bd7c4af0394e65d6492a2d8359cfba Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Sat, 4 May 2024 21:29:18 +0200 Subject: [PATCH] vendor._lattice: OFS1P3DX -> OFD1P3DX and IFS1P3DX -> IFD1P3DX for nexus More specialized buffers required --- amaranth/vendor/_lattice.py | 65 +++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/amaranth/vendor/_lattice.py b/amaranth/vendor/_lattice.py index 43212285d..4e6125f00 100644 --- a/amaranth/vendor/_lattice.py +++ b/amaranth/vendor/_lattice.py @@ -77,7 +77,7 @@ def elaborate(self, platform): return m -def _make_oereg(m, domain, oe, q): +def _make_oereg_ecp5_machxo2(m, domain, oe, q): for bit in range(len(q)): m.submodules[f"oe_ff{bit}"] = Instance("OFS1P3DX", i_SCLK=ClockSignal(domain), @@ -88,7 +88,18 @@ def _make_oereg(m, domain, oe, q): ) -class FFBuffer(io.FFBuffer): +def _make_oereg_nexus(m, domain, oe, q): + for bit in range(len(q)): + m.submodules[f"oe_ff{bit}"] = Instance("OFD1P3DX", + i_CK=ClockSignal(domain), + i_SP=Const(1), + i_CD=Const(0), + i_D=oe, + o_Q=q[bit], + ) + + +class FFBufferECP5(io.FFBuffer): def elaborate(self, platform): m = Module() @@ -118,7 +129,42 @@ def elaborate(self, platform): i_D=o_inv[bit], o_Q=buf.o[bit], ) - _make_oereg(m, self.o_domain, ~self.oe, buf.t) + _make_oereg_ecp5_machxo2(m, self.o_domain, ~self.oe, buf.t) + + return m + + +class FFBufferNexus(io.FFBuffer): + 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: + i_inv = Signal.like(self.i) + for bit in range(len(self.port)): + m.submodules[f"i_ff{bit}"] = Instance("IFD1P3DX", + i_CK=ClockSignal(self.i_domain), + i_SP=Const(1), + i_CD=Const(0), + i_D=buf.i[bit], + o_Q=i_inv[bit], + ) + m.d.comb += self.i.eq(i_inv ^ inv_mask) + + if self.direction is not io.Direction.Input: + o_inv = Signal.like(self.o) + m.d.comb += o_inv.eq(self.o ^ inv_mask) + for bit in range(len(self.port)): + m.submodules[f"o_ff{bit}"] = Instance("OFD1P3DX", + i_CK=ClockSignal(self.o_domain), + i_SP=Const(1), + i_CD=Const(0), + i_D=o_inv[bit], + o_Q=buf.o[bit], + ) + _make_oereg_nexus(m, self.o_domain, ~self.oe, buf.t) return m @@ -159,7 +205,7 @@ def elaborate(self, platform): i_D1=o1_inv[bit], o_Q=buf.o[bit], ) - _make_oereg(m, self.o_domain, ~self.oe, buf.t) + _make_oereg_ecp5_machxo2(m, self.o_domain, ~self.oe, buf.t) return m @@ -200,7 +246,7 @@ def elaborate(self, platform): i_D1=o1_inv[bit], o_Q=buf.o[bit], ) - _make_oereg(m, self.o_domain, ~self.oe, buf.t) + _make_oereg_ecp5_machxo2(m, self.o_domain, ~self.oe, buf.t) return m @@ -241,7 +287,7 @@ def elaborate(self, platform): i_D1=o1_inv[bit], o_Q=buf.o[bit], ) - _make_oereg(m, self.o_domain, ~self.oe, buf.t) + _make_oereg_nexus(m, self.o_domain, ~self.oe, buf.t) return m @@ -951,7 +997,12 @@ def get_io_buffer(self, buffer): if isinstance(buffer, io.Buffer): result = IOBuffer(buffer.direction, buffer.port) elif isinstance(buffer, io.FFBuffer): - result = FFBuffer(buffer.direction, buffer.port) + if self.family in ("ecp5", "machxo2"): + result = FFBufferECP5(buffer.direction, buffer.port) + elif self.family == "nexus": + result = FFBufferNexus(buffer.direction, buffer.port) + else: + raise NotImplementedError # :nocov: elif isinstance(buffer, io.DDRBuffer): if self.family == "ecp5": result = DDRBufferECP5(buffer.direction, buffer.port)