From: Konrad Beckmann Date: Mon, 6 Jul 2020 14:01:19 +0000 (+0200) Subject: vendor.lattice_ecp5: Add support for io with xdr=4 X-Git-Tag: 24jan2021_ls180~39 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=981e67408111fbfcf9bd0df1f41feeb03212ce12;p=nmigen.git vendor.lattice_ecp5: Add support for io with xdr=4 This adds support for IOs with xdr=4 using the IDDRX2F and ODDRX2F primitives. --- diff --git a/nmigen/lib/io.py b/nmigen/lib/io.py index 7c950ae..9776eff 100644 --- a/nmigen/lib/io.py +++ b/nmigen/lib/io.py @@ -26,6 +26,8 @@ def pin_layout(width, dir, xdr=0): if dir in ("i", "io"): if xdr > 0: fields.append(("i_clk", 1)) + if xdr > 2: + fields.append(("i_fclk", 1)) if xdr in (0, 1): fields.append(("i", width)) else: @@ -34,6 +36,8 @@ def pin_layout(width, dir, xdr=0): if dir in ("o", "oe", "io"): if xdr > 0: fields.append(("o_clk", 1)) + if xdr > 2: + fields.append(("o_fclk", 1)) if xdr in (0, 1): fields.append(("o", width)) else: @@ -78,6 +82,9 @@ class Pin(Record): ---------- i_clk: I/O buffer input clock. Synchronizes `i*`. Present if ``xdr`` is nonzero. + i_fclk: + I/O buffer input fast clock. Synchronizes `i*` on higer gearbox ratios. Present if ``xdr`` + is greater than 2. i : Signal, out I/O buffer input, without gearing. Present if ``dir="i"`` or ``dir="io"``, and ``xdr`` is equal to 0 or 1. @@ -86,6 +93,9 @@ class Pin(Record): greater than 1. o_clk: I/O buffer output clock. Synchronizes `o*`, including `oe`. Present if ``xdr`` is nonzero. + o_fclk: + I/O buffer output fast clock. Synchronizes `o*` on higher gearbox ratios. Present if + ``xdr`` is greater than 2. o : Signal, in I/O buffer output, without gearing. Present if ``dir="o"`` or ``dir="io"``, and ``xdr`` is equal to 0 or 1. diff --git a/nmigen/vendor/lattice_ecp5.py b/nmigen/vendor/lattice_ecp5.py index c1a1366..0abeba9 100644 --- a/nmigen/vendor/lattice_ecp5.py +++ b/nmigen/vendor/lattice_ecp5.py @@ -389,6 +389,16 @@ class LatticeECP5Platform(TemplatedPlatform): o_Q0=q0[bit], o_Q1=q1[bit] ) + def get_iddrx2(sclk, eclk, d, q0, q1, q2, q3): + for bit in range(len(d)): + m.submodules += Instance("IDDRX2F", + i_SCLK=sclk, + i_ECLK=eclk, + i_RST=Const(0), + i_D=d[bit], + o_Q0=q0[bit], o_Q1=q1[bit], o_Q2=q2[bit], o_Q3=q3[bit] + ) + def get_oddr(sclk, d0, d1, q): for bit in range(len(q)): m.submodules += Instance("ODDRX1F", @@ -398,6 +408,16 @@ class LatticeECP5Platform(TemplatedPlatform): o_Q=q[bit] ) + def get_oddrx2(sclk, eclk, d0, d1, d2, d3, q): + for bit in range(len(q)): + m.submodules += Instance("ODDRX2F", + i_SCLK=sclk, + i_ECLK=eclk, + i_RST=Const(0), + i_D0=d0[bit], i_D1=d1[bit], i_D2=d2[bit], i_D3=d3[bit], + o_Q=q[bit] + ) + def get_ineg(z, invert): if invert: a = Signal.like(z, name_suffix="_n") @@ -420,12 +440,22 @@ class LatticeECP5Platform(TemplatedPlatform): elif pin.xdr == 2: pin_i0 = get_ineg(pin.i0, i_invert) pin_i1 = get_ineg(pin.i1, i_invert) + elif pin.xdr == 4: + pin_i0 = get_ineg(pin.i0, i_invert) + pin_i1 = get_ineg(pin.i1, i_invert) + pin_i2 = get_ineg(pin.i2, i_invert) + pin_i3 = get_ineg(pin.i3, i_invert) if "o" in pin.dir: if pin.xdr < 2: pin_o = get_oneg(pin.o, o_invert) elif pin.xdr == 2: pin_o0 = get_oneg(pin.o0, o_invert) pin_o1 = get_oneg(pin.o1, o_invert) + elif pin.xdr == 4: + pin_o0 = get_oneg(pin.o0, o_invert) + pin_o1 = get_oneg(pin.o1, o_invert) + pin_o2 = get_oneg(pin.o2, o_invert) + pin_o3 = get_oneg(pin.o3, o_invert) i = o = t = None if "i" in pin.dir: @@ -460,6 +490,13 @@ class LatticeECP5Platform(TemplatedPlatform): # It is not clear what is the recommended set of primitives for this task. # Similarly, nextpnr will not pack anything as a tristate register in a DDR PIO. get_oreg(pin.o_clk, ~pin.oe, t) + elif pin.xdr == 4: + if "i" in pin.dir: + get_iddrx2(pin.i_clk, pin.i_fclk, i, pin_i0, pin_i1, pin_i2, pin_i3) + if "o" in pin.dir: + get_oddrx2(pin.o_clk, pin.o_fclk, pin_o0, pin_o1, pin_o2, pin_o3, o) + if pin.dir in ("oe", "io"): + get_oreg(pin.o_clk, ~pin.oe, t) else: assert False @@ -467,7 +504,7 @@ class LatticeECP5Platform(TemplatedPlatform): def get_input(self, pin, port, attrs, invert): self._check_feature("single-ended input", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) + valid_xdrs=(0, 1, 2, 4), valid_attrs=True) m = Module() i, o, t = self._get_xdr_buffer(m, pin, i_invert=invert) for bit in range(len(port)): @@ -479,7 +516,7 @@ class LatticeECP5Platform(TemplatedPlatform): def get_output(self, pin, port, attrs, invert): self._check_feature("single-ended output", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) + valid_xdrs=(0, 1, 2, 4), valid_attrs=True) m = Module() i, o, t = self._get_xdr_buffer(m, pin, o_invert=invert) for bit in range(len(port)): @@ -491,7 +528,7 @@ class LatticeECP5Platform(TemplatedPlatform): def get_tristate(self, pin, port, attrs, invert): self._check_feature("single-ended tristate", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) + valid_xdrs=(0, 1, 2, 4), valid_attrs=True) m = Module() i, o, t = self._get_xdr_buffer(m, pin, o_invert=invert) for bit in range(len(port)): @@ -504,7 +541,7 @@ class LatticeECP5Platform(TemplatedPlatform): 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) + valid_xdrs=(0, 1, 2, 4), valid_attrs=True) m = Module() i, o, t = self._get_xdr_buffer(m, pin, i_invert=invert, o_invert=invert) for bit in range(len(port)): @@ -518,7 +555,7 @@ class LatticeECP5Platform(TemplatedPlatform): def get_diff_input(self, pin, p_port, n_port, attrs, invert): self._check_feature("differential input", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) + valid_xdrs=(0, 1, 2, 4), valid_attrs=True) m = Module() i, o, t = self._get_xdr_buffer(m, pin, i_invert=invert) for bit in range(len(p_port)): @@ -530,7 +567,7 @@ class LatticeECP5Platform(TemplatedPlatform): def get_diff_output(self, pin, p_port, n_port, attrs, invert): self._check_feature("differential output", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) + valid_xdrs=(0, 1, 2, 4), valid_attrs=True) m = Module() i, o, t = self._get_xdr_buffer(m, pin, o_invert=invert) for bit in range(len(p_port)): @@ -542,7 +579,7 @@ class LatticeECP5Platform(TemplatedPlatform): def get_diff_tristate(self, pin, p_port, n_port, attrs, invert): self._check_feature("differential tristate", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) + valid_xdrs=(0, 1, 2, 4), valid_attrs=True) m = Module() i, o, t = self._get_xdr_buffer(m, pin, o_invert=invert) for bit in range(len(p_port)): @@ -555,7 +592,7 @@ class LatticeECP5Platform(TemplatedPlatform): def get_diff_input_output(self, pin, p_port, n_port, attrs, invert): self._check_feature("differential input/output", pin, attrs, - valid_xdrs=(0, 1, 2), valid_attrs=True) + valid_xdrs=(0, 1, 2, 4), valid_attrs=True) m = Module() i, o, t = self._get_xdr_buffer(m, pin, i_invert=invert, o_invert=invert) for bit in range(len(p_port)):