Skip to content

Commit 2da8377

Browse files
committed
Added support for Digilent Genesys 2 target
- ported S7 RGMII from LiteEth - added support for 1x non-IO SPI flash (had problems with x4 IO operation) - added Digilent Genesys 2 target
1 parent f1dc58d commit 2da8377

File tree

3 files changed

+441
-4
lines changed

3 files changed

+441
-4
lines changed
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
#
2+
# This file is part of LiteEth, backported to MiSoC.
3+
#
4+
# Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
5+
# Copyright (c) 2022-2022 Mikolaj Sowinski <msowinski@technosystem.com.pl>
6+
# SPDX-License-Identifier: BSD-2-Clause
7+
8+
# RGMII PHY for 7-Series Xilinx FPGA
9+
10+
from migen import *
11+
from migen.genlib.resetsync import AsyncResetSynchronizer
12+
13+
from misoc.interconnect.csr import *
14+
from misoc.interconnect import stream
15+
from misoc.cores.liteeth_mini.common import *
16+
17+
18+
class LiteEthPHYHWReset(Module):
19+
def __init__(self, cycles=256):
20+
self.reset = Signal()
21+
22+
# # #
23+
24+
counter = Signal(max=cycles + 1)
25+
counter_done = Signal()
26+
counter_ce = Signal()
27+
self.sync += If(counter_ce, counter.eq(counter + 1))
28+
self.comb += [
29+
counter_done.eq(counter == cycles),
30+
counter_ce.eq(~counter_done),
31+
self.reset.eq(~counter_done)
32+
]
33+
34+
35+
class LiteEthPHYRGMIITX(Module):
36+
def __init__(self, pads):
37+
self.sink = sink = stream.Endpoint(eth_phy_layout(8))
38+
39+
# # #
40+
41+
tx_ctl_obuf = Signal()
42+
tx_data_obuf = Signal(4)
43+
44+
self.specials += [
45+
Instance("ODDR",
46+
p_DDR_CLK_EDGE = "SAME_EDGE",
47+
i_C = ClockSignal("eth_tx"),
48+
i_CE = 1,
49+
i_S = 0,
50+
i_R = 0,
51+
i_D1 = sink.stb,
52+
i_D2 = sink.stb,
53+
o_Q = tx_ctl_obuf,
54+
),
55+
Instance("OBUF",
56+
i_I = tx_ctl_obuf,
57+
o_O = pads.tx_ctl,
58+
),
59+
]
60+
for i in range(4):
61+
self.specials += [
62+
Instance("ODDR",
63+
p_DDR_CLK_EDGE = "SAME_EDGE",
64+
i_C = ClockSignal("eth_tx"),
65+
i_CE = 1,
66+
i_S = 0,
67+
i_R = 0,
68+
i_D1 = sink.data[i],
69+
i_D2 = sink.data[4+i],
70+
o_Q = tx_data_obuf[i],
71+
),
72+
Instance("OBUF",
73+
i_I = tx_data_obuf[i],
74+
o_O = pads.tx_data[i],
75+
)
76+
]
77+
self.comb += sink.ack.eq(1)
78+
79+
80+
class LiteEthPHYRGMIIRX(Module):
81+
def __init__(self, pads, rx_delay=2e-9, iodelay_clk_freq=200e6):
82+
self.source = source = stream.Endpoint(eth_phy_layout(8))
83+
84+
# # #
85+
86+
assert iodelay_clk_freq in [200e6, 300e6, 400e6]
87+
iodelay_tap_average = 1 / (2*32 * iodelay_clk_freq)
88+
rx_delay_taps = round(rx_delay / iodelay_tap_average)
89+
assert rx_delay_taps < 32, "Exceeded ODELAYE2 max value: {} >= 32".format(rx_delay_taps)
90+
91+
rx_ctl_ibuf = Signal()
92+
rx_ctl_idelay = Signal()
93+
rx_ctl = Signal()
94+
rx_data_ibuf = Signal(4)
95+
rx_data_idelay = Signal(4)
96+
rx_data = Signal(8)
97+
98+
self.specials += [
99+
Instance("IBUF", i_I=pads.rx_ctl, o_O=rx_ctl_ibuf),
100+
Instance("IDELAYE2",
101+
p_IDELAY_TYPE = "FIXED",
102+
p_IDELAY_VALUE = rx_delay_taps,
103+
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
104+
i_C = 0,
105+
i_LD = 0,
106+
i_CE = 0,
107+
i_LDPIPEEN = 0,
108+
i_INC = 0,
109+
i_IDATAIN = rx_ctl_ibuf,
110+
o_DATAOUT = rx_ctl_idelay,
111+
),
112+
Instance("IDDR",
113+
p_DDR_CLK_EDGE = "SAME_EDGE_PIPELINED",
114+
i_C = ClockSignal("eth_rx"),
115+
i_CE = 1,
116+
i_S = 0,
117+
i_R = 0,
118+
i_D = rx_ctl_idelay,
119+
o_Q1 = rx_ctl,
120+
o_Q2 = Signal(),
121+
)
122+
]
123+
for i in range(4):
124+
self.specials += [
125+
Instance("IBUF",
126+
i_I = pads.rx_data[i],
127+
o_O = rx_data_ibuf[i],
128+
),
129+
Instance("IDELAYE2",
130+
p_IDELAY_TYPE = "FIXED",
131+
p_IDELAY_VALUE = rx_delay_taps,
132+
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
133+
i_C = 0,
134+
i_LD = 0,
135+
i_CE = 0,
136+
i_LDPIPEEN = 0,
137+
i_INC = 0,
138+
i_IDATAIN = rx_data_ibuf[i],
139+
o_DATAOUT = rx_data_idelay[i],
140+
),
141+
Instance("IDDR",
142+
p_DDR_CLK_EDGE = "SAME_EDGE_PIPELINED",
143+
i_C = ClockSignal("eth_rx"),
144+
i_CE = 1,
145+
i_S = 0,
146+
i_R = 0,
147+
i_D = rx_data_idelay[i],
148+
o_Q1 = rx_data[i],
149+
o_Q2 = rx_data[i+4],
150+
)
151+
]
152+
153+
rx_ctl_d = Signal()
154+
self.sync += rx_ctl_d.eq(rx_ctl)
155+
156+
last = Signal()
157+
self.comb += last.eq(~rx_ctl & rx_ctl_d)
158+
self.sync += [
159+
source.stb.eq(rx_ctl),
160+
source.data.eq(rx_data)
161+
]
162+
self.comb += source.eop.eq(last)
163+
164+
165+
class LiteEthPHYRGMIICRG(Module, AutoCSR):
166+
def __init__(self, clock_pads, pads, with_hw_init_reset, tx_delay=2e-9, hw_reset_cycles=256):
167+
self._reset = CSRStorage()
168+
169+
# # #
170+
171+
# RX clock
172+
self.clock_domains.cd_eth_rx = ClockDomain()
173+
eth_rx_clk_ibuf = Signal()
174+
self.specials += [
175+
Instance("IBUF",
176+
i_I = clock_pads.rx,
177+
o_O = eth_rx_clk_ibuf,
178+
),
179+
Instance("BUFG",
180+
i_I = eth_rx_clk_ibuf,
181+
o_O = self.cd_eth_rx.clk,
182+
),
183+
]
184+
185+
# TX clock
186+
self.clock_domains.cd_eth_tx = ClockDomain()
187+
self.clock_domains.cd_eth_tx_delayed = ClockDomain(reset_less=True)
188+
tx_phase = 125e6*tx_delay*360
189+
assert tx_phase < 360
190+
pll_fb = Signal()
191+
eth_tx_clk = Signal()
192+
eth_tx_delayed_clk = Signal()
193+
self.specials += [
194+
Instance("PLLE2_BASE",
195+
p_STARTUP_WAIT="FALSE", o_LOCKED=Signal(),
196+
197+
# VCO @ 1GHz
198+
p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=5.0,
199+
p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1,
200+
i_CLKIN1=ClockSignal("eth_rx"), i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb,
201+
202+
# 125MHz
203+
p_CLKOUT0_DIVIDE=8, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=eth_tx_clk,
204+
205+
# 500MHz
206+
p_CLKOUT1_DIVIDE=8, p_CLKOUT1_PHASE=tx_phase, o_CLKOUT1=eth_tx_delayed_clk,
207+
208+
p_CLKOUT2_DIVIDE=5, p_CLKOUT2_PHASE=0.0, #o_CLKOUT2=,
209+
p_CLKOUT3_DIVIDE=5, p_CLKOUT3_PHASE=0.0, #o_CLKOUT3=,
210+
p_CLKOUT4_DIVIDE=5, p_CLKOUT4_PHASE=0.0, #o_CLKOUT4=
211+
),
212+
Instance("BUFG", i_I=eth_tx_clk, o_O=self.cd_eth_tx.clk),
213+
Instance("BUFG", i_I=eth_tx_delayed_clk, o_O=self.cd_eth_tx_delayed.clk),
214+
]
215+
216+
eth_tx_clk_obuf = Signal()
217+
self.specials += [
218+
Instance("ODDR",
219+
p_DDR_CLK_EDGE = "SAME_EDGE",
220+
i_C = ClockSignal("eth_tx_delayed"),
221+
i_CE = 1,
222+
i_S = 0,
223+
i_R = 0,
224+
i_D1 = 1,
225+
i_D2 = 0,
226+
o_Q = eth_tx_clk_obuf,
227+
),
228+
Instance("OBUF",
229+
i_I = eth_tx_clk_obuf,
230+
o_O = clock_pads.tx,
231+
)
232+
]
233+
234+
# Reset
235+
self.reset = reset = Signal()
236+
if with_hw_init_reset:
237+
self.submodules.hw_reset = LiteEthPHYHWReset(cycles=hw_reset_cycles)
238+
self.comb += reset.eq(self._reset.storage | self.hw_reset.reset)
239+
else:
240+
self.comb += reset.eq(self._reset.storage)
241+
if hasattr(pads, "rst_n"):
242+
self.comb += pads.rst_n.eq(~reset)
243+
self.specials += [
244+
AsyncResetSynchronizer(self.cd_eth_tx, reset),
245+
AsyncResetSynchronizer(self.cd_eth_rx, reset),
246+
]
247+
248+
249+
class LiteEthPHYRGMII(Module, AutoCSR):
250+
dw = 8
251+
tx_clk_freq = 125e6
252+
rx_clk_freq = 125e6
253+
def __init__(self, clock_pads, pads, with_hw_init_reset=True, tx_delay=2e-9, rx_delay=2e-9,
254+
iodelay_clk_freq=200e6, hw_reset_cycles=256):
255+
self.submodules.crg = LiteEthPHYRGMIICRG(clock_pads, pads, with_hw_init_reset, tx_delay, hw_reset_cycles)
256+
self.submodules.tx = ClockDomainsRenamer("eth_tx")(LiteEthPHYRGMIITX(pads))
257+
self.submodules.rx = ClockDomainsRenamer("eth_rx")(LiteEthPHYRGMIIRX(pads, rx_delay, iodelay_clk_freq))
258+
self.sink, self.source = self.tx.sink, self.rx.source

misoc/cores/spi_flash.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ def __init__(self, pads, dummy=15, div=2, with_bitbang=True, endianness="big", d
4040
"""
4141
adr_width = 32-log2_int(dw//8)
4242
self.bus = bus = wishbone.Interface(data_width=dw, adr_width=adr_width)
43-
spi_width = len(pads.dq)
43+
if hasattr(pads, "dq"):
44+
spi_width = len(pads.dq)
45+
else:
46+
spi_width = 1
4447
if with_bitbang:
4548
self.bitbang = CSRStorage(4)
4649
self.miso = CSRStatus()
@@ -62,8 +65,16 @@ def __init__(self, pads, dummy=15, div=2, with_bitbang=True, endianness="big", d
6265

6366
pads.cs_n.reset = 1
6467

65-
dq = TSTriple(spi_width)
66-
self.specials.dq = dq.get_tristate(pads.dq)
68+
if spi_width > 1:
69+
dq = TSTriple(spi_width)
70+
self.specials.dq = dq.get_tristate(pads.dq)
71+
else:
72+
class TripleMock:
73+
def __init__(self):
74+
self.i = pads.miso
75+
self.o = pads.mosi
76+
self.oe = Signal()
77+
dq = TripleMock()
6778

6879
sr = Signal(max(cmd_width, addr_width, dw))
6980
if endianness == "big":
@@ -88,7 +99,8 @@ def __init__(self, pads, dummy=15, div=2, with_bitbang=True, endianness="big", d
8899
dq.oe.eq(1)
89100
),
90101
If(self.bitbang.storage[1],
91-
self.miso.status.eq(dq.i[1])
102+
self.miso.status.eq(dq.i) if spi_width == 1 \
103+
else self.miso.status.eq(dq.i[1])
92104
)
93105
]
94106
if spi_width > 1:

0 commit comments

Comments
 (0)