-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathcrg.py
More file actions
136 lines (102 loc) · 5.08 KB
/
Copy pathcrg.py
File metadata and controls
136 lines (102 loc) · 5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
"""Clock-Reset Generators (CRG) for each target.
All three CRGs consume their clocks directly from external pads. The top-level
FPGA design instantiates one PLL and feeds the SoC the required clock(s):
- cyclone10: clk_sys (sys_clk_freq, typ. 75 MHz)
- cyc1000: clk_sys + clk_sys_ps (sys_clk_freq, 90deg shifted, for SDRAM)
- gowin: clk_sys + clk_sys2x (sys_clk_freq and 2x, for DDR3)
This keeps the SoC portable: no target-specific PLL primitives are baked into
the generated SoC HDL, and a single top-level PLL can drive everything
(including non-SoC FPGA logic on the same clock).
MAC clock domains (mac_rx/mac_tx) are bound ONLY where the eth packet buffer
(eth_buf) is built — i.e. the aes67_bridge target. CPU and spibone targets do
not instantiate eth_buf, so binding them there would just create unused clock
domains and dangling clk_mac_rx/clk_mac_tx top-level ports.
"""
from migen import *
from litex.gen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
def _bind_mac_clocks(crg, platform):
"""Wire mac_rx/mac_tx clock domains directly from the Ethernet MAC pads."""
crg.cd_mac_rx = ClockDomain(reset_less=True)
crg.cd_mac_tx = ClockDomain(reset_less=True)
crg.comb += [
crg.cd_mac_rx.clk.eq(platform.request("clk_mac_rx")),
crg.cd_mac_tx.clk.eq(platform.request("clk_mac_tx")),
]
# -- CRG (Clock Reset Generator) — Cyclone 10LP --------------------------------
class _CRG_Cyclone10(LiteXModule):
def __init__(self, platform, sys_clk_freq):
self.rst = Signal()
self.cd_sys = ClockDomain()
# System clock fed from external (top-level) PLL.
self.comb += self.cd_sys.clk.eq(platform.request("clk_sys"))
self.specials += AsyncResetSynchronizer(self.cd_sys, self.rst)
# -- CRG (Clock Reset Generator) — spibone / aes67_bridge (no main RAM) -------
class _CRG_Spibone(LiteXModule):
"""CRG for the CPU-less bridges (spibone / aes67_bridge): sys clock only,
no main-RAM clocks.
The aes67_bridge instantiates eth_buf, which needs the mac_rx/mac_tx
domains, so they are bound there (``with_mac_clocks=True``). spibone has no
eth_buf and leaves them unbound.
"""
def __init__(self, platform, sys_clk_freq, with_mac_clocks=False):
self.rst = Signal()
self.cd_sys = ClockDomain()
# System clock fed from external (top-level) PLL.
self.comb += self.cd_sys.clk.eq(platform.request("clk_sys"))
self.specials += AsyncResetSynchronizer(self.cd_sys, self.rst)
if with_mac_clocks:
_bind_mac_clocks(self, platform)
# -- CRG (Clock Reset Generator) — Cyclone 10LP CYC1000 (SDRAM) ---------------
class _CRG_Cyc1000(LiteXModule):
def __init__(self, platform, sys_clk_freq):
self.rst = Signal()
self.cd_sys = ClockDomain()
self.cd_sys_ps = ClockDomain() # 90deg phase-shifted for SDRAM
# Both clocks fed from external (top-level) PLL.
self.comb += self.cd_sys.clk.eq(platform.request("clk_sys"))
self.comb += self.cd_sys_ps.clk.eq(platform.request("clk_sys_ps"))
self.specials += AsyncResetSynchronizer(self.cd_sys, self.rst)
# SDRAM clock output pad (phase-shifted)
self.comb += platform.request("sdram_clock").eq(self.cd_sys_ps.clk)
# -- CRG (Clock Reset Generator) — Gowin GW2A (Tang Primer 20k) ---------------
class _CRG_Gowin(LiteXModule):
def __init__(self, platform, sys_clk_freq):
self.rst = Signal()
self.cd_sys = ClockDomain()
self.cd_por = ClockDomain()
# DDR3 requires 2:1 clock ratio
self.cd_init = ClockDomain()
self.cd_sys2x = ClockDomain()
self.cd_sys2x_i = ClockDomain()
# # #
self.stop = Signal()
self.reset = Signal()
# Both clocks fed from external (top-level) PLL.
clk_sys = platform.request("clk_sys")
clk_sys2x = platform.request("clk_sys2x")
# Power on reset (driven from sys clock — onboard POR is not aware
# of reprogramming).
por_count = Signal(16, reset=2**16-1)
por_done = Signal()
self.comb += self.cd_por.clk.eq(clk_sys)
self.comb += por_done.eq(por_count == 0)
self.sync.por += If(~por_done, por_count.eq(por_count - 1))
# 2:1 clock for DDR3: clk_sys2x → DHCEN (gated) → sys2x → CLKDIV/2 → sys
self.comb += self.cd_sys2x_i.clk.eq(clk_sys2x)
self.specials += [
Instance("DHCEN",
i_CLKIN = self.cd_sys2x_i.clk,
i_CE = self.stop,
o_CLKOUT = self.cd_sys2x.clk),
Instance("CLKDIV",
p_DIV_MODE = "2",
i_CALIB = 0,
i_HCLKIN = self.cd_sys2x.clk,
i_RESETN = ~self.reset,
o_CLKOUT = self.cd_sys.clk),
]
# Init clock domain (raw sys clock, used by DDR3 init FSM)
self.comb += self.cd_init.clk.eq(clk_sys)
self.comb += self.cd_init.rst.eq(~por_done)
self.specials += AsyncResetSynchronizer(self.cd_sys, ~por_done | self.rst | self.reset)