From: Luke Kenneth Casson Leighton Date: Fri, 15 Apr 2022 09:40:44 +0000 (+0100) Subject: add input and output reset signals to Pin X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3d2a9a18c53aeeada3a94d363010145f71e02adb;p=nmigen.git add input and output reset signals to Pin https://gitlab.com/nmigen/nmigen/-/issues/2 the issue being encountered is that ECP5 2x, 4x and 7x phase-tapped IO pads will come up 50% of the time in an incorrect phase setting the RST line of IDDR71B and other IOpad instances to Const(0) is the likely root cause. unfortunately, to fix this, an actual Signal has to be passed in, to the LatticeECP5Platform, for it to be able to pass it to the IOpad. that in turn means that the Pin Record has to have a reset signal added. current experiments with GRAM show that setting the reset signal equal to the domain reset signal is not quite sufficient, but greatly improves the number of times that the DQS and other DDR IOpads get a successful lock. this most likely because the 2x PLL has not been given enough time to stabilise. at least with the addition of reset signals i_prst and o_prst to Pin, experimentation and investigation can proceed --- diff --git a/nmigen/lib/io.py b/nmigen/lib/io.py index 9776eff..acff790 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 xdf >= 2: + fields.append(("i_prst", 1)) if xdr > 2: fields.append(("i_fclk", 1)) if xdr in (0, 1): @@ -36,6 +38,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_prst", 1)) if xdr > 2: fields.append(("o_fclk", 1)) if xdr in (0, 1): @@ -85,6 +89,10 @@ class Pin(Record): i_fclk: I/O buffer input fast clock. Synchronizes `i*` on higer gearbox ratios. Present if ``xdr`` is greater than 2. + i_prst: + I/O buffer pad reset. Some FPGAs (ECP5) have a built-in PLL that will + lock 180 out of phase 50% of the time without a proper reset. + Present if ``xdr`` is greater or equal to 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. @@ -96,6 +104,10 @@ class Pin(Record): o_fclk: I/O buffer output fast clock. Synchronizes `o*` on higher gearbox ratios. Present if ``xdr`` is greater than 2. + o_prst: + I/O buffer pad reset. Some FPGAs (ECP5) have a built-in PLL that will + lock 180 out of phase 50% of the time without a proper reset. + Present if ``xdr`` is greater or equal to 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 0972d01..73f17b8 100644 --- a/nmigen/vendor/lattice_ecp5.py +++ b/nmigen/vendor/lattice_ecp5.py @@ -396,61 +396,61 @@ class LatticeECP5Platform(TemplatedPlatform): o_Q=q[bit] ) - def get_iddr(sclk, d, q0, q1): + def get_iddr(sclk, prst, d, q0, q1): for bit in range(len(d)): m.submodules += Instance("IDDRX1F", i_SCLK=sclk, - i_RST=Const(0), + i_RST=prst, i_D=d[bit], o_Q0=q0[bit], o_Q1=q1[bit] ) - def get_iddrx2(sclk, eclk, d, q0, q1, q2, q3): + def get_iddrx2(sclk, eclk, prst, 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_RST=prst, i_D=d[bit], o_Q0=q0[bit], o_Q1=q1[bit], o_Q2=q2[bit], o_Q3=q3[bit] ) - def get_iddr71b(sclk, eclk, d, q0, q1, q2, q3, q4, q5, q6): + def get_iddr71b(sclk, eclk, prst, d, q0, q1, q2, q3, q4, q5, q6): for bit in range(len(d)): m.submodules += Instance("IDDR71B", i_SCLK=sclk, i_ECLK=eclk, - i_RST=Const(0), + i_RST=prst, i_D=d[bit], o_Q0=q0[bit], o_Q1=q1[bit], o_Q2=q2[bit], o_Q3=q3[bit], o_Q4=q4[bit], o_Q5=q5[bit], o_Q6=q6[bit], ) - def get_oddr(sclk, d0, d1, q): + def get_oddr(sclk, prst, d0, d1, q): for bit in range(len(q)): m.submodules += Instance("ODDRX1F", i_SCLK=sclk, - i_RST=Const(0), + i_RST=prst, i_D0=d0[bit], i_D1=d1[bit], o_Q=q[bit] ) - def get_oddrx2(sclk, eclk, d0, d1, d2, d3, q): + def get_oddrx2(sclk, eclk, prst, 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_RST=prst, i_D0=d0[bit], i_D1=d1[bit], i_D2=d2[bit], i_D3=d3[bit], o_Q=q[bit] ) - def get_oddr71b(sclk, eclk, d0, d1, d2, d3, d4, d5, d6, q): + def get_oddr71b(sclk, eclk, prst, d0, d1, d2, d3, d4, d5, d6, q): for bit in range(len(q)): m.submodules += Instance("ODDR71B", i_SCLK=sclk, i_ECLK=eclk, - i_RST=Const(0), + i_RST=prst, i_D0=d0[bit], i_D1=d1[bit], i_D2=d2[bit], i_D3=d3[bit], i_D4=d4[bit], i_D5=d5[bit], i_D6=d6[bit], o_Q=q[bit] @@ -535,23 +535,29 @@ class LatticeECP5Platform(TemplatedPlatform): get_oereg(pin.o_clk, ~pin.oe, t) elif pin.xdr == 2: if "i" in pin.dir: - get_iddr(pin.i_clk, i, pin_i0, pin_i1) + get_iddr(pin.i_clk, pin.i_prst, i, pin_i0, pin_i1) if "o" in pin.dir: - get_oddr(pin.o_clk, pin_o0, pin_o1, o) + get_oddr(pin.o_clk, pin.o_prst, pin_o0, pin_o1, o) if pin.dir in ("oe", "io"): get_oereg(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) + get_iddrx2(pin.i_clk, pin.i_fclk, pin.i_prst, 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) + get_oddrx2(pin.o_clk, pin.o_fclk, pin.o_prst, + pin_o0, pin_o1, pin_o2, pin_o3, o) if pin.dir in ("oe", "io"): get_oereg(pin.o_clk, ~pin.oe, t) elif pin.xdr == 7: if "i" in pin.dir: - get_iddr71b(pin.i_clk, pin.i_fclk, i, pin_i0, pin_i1, pin_i2, pin_i3, pin_i4, pin_i5, pin_i6) + get_iddr71b(pin.i_clk, pin.i_fclk, pin.o_prst, i, + pin_i0, pin_i1, pin_i2, pin_i3, + pin_i4, pin_i5, pin_i6) if "o" in pin.dir: - get_oddr71b(pin.o_clk, pin.o_fclk, pin_o0, pin_o1, pin_o2, pin_o3, pin_o4, pin_o5, pin_o6, o) + get_oddr71b(pin.o_clk, pin.o_fclk, pin.o_prst, + pin_o0, pin_o1, pin_o2, pin_o3, + pin_o4, pin_o5, pin_o6, o) if pin.dir in ("oe", "io"): get_oereg(pin.o_clk, ~pin.oe, t) else: