1 # Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
2 # Copyright (c) 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 from nmigen
import (Module
, Elaboratable
, Instance
, Signal
, ClockDomain
,
5 ClockSignal
, ResetSignal
)
7 __ALL__
= ["ECPIX5CRG"]
10 class PLL(Elaboratable
):
11 def __init__(self
, clkin
, clksel
=Signal(shape
=2, reset
=2),
12 clkout1
=Signal(), clkout2
=Signal(),
13 clkout3
=Signal(), clkout4
=Signal(), lock
=Signal(),
14 CLKI_DIV
=1, CLKFB_DIV
=2, CLK1_DIV
=3, CLK2_DIV
=24):
16 self
.clkout1
= clkout1
17 self
.clkout2
= clkout2
18 self
.clkout3
= clkout3
19 self
.clkout4
= clkout4
22 self
.CLKI_DIV
= CLKI_DIV
23 self
.CLKFB_DIV
= CLKFB_DIV
24 self
.CLKOP_DIV
= CLK1_DIV
25 self
.CLKOS_DIV
= CLK2_DIV
36 def elaborate(self
, platform
):
38 pll
= Instance("EHXPLLL",
39 p_OUTDIVIDER_MUXA
='DIVA',
40 p_OUTDIVIDER_MUXB
='DIVB',
41 p_CLKOP_ENABLE
='ENABLED',
42 p_CLKOS_ENABLE
='ENABLED',
43 p_CLKOS2_ENABLE
='DISABLED',
44 p_CLKOS3_ENABLE
='DISABLED',
45 p_CLKOP_DIV
=self
.CLKOP_DIV
,
46 p_CLKOS_DIV
=self
.CLKOS_DIV
,
47 p_CLKFB_DIV
=self
.CLKFB_DIV
,
48 p_CLKI_DIV
=self
.CLKI_DIV
,
49 p_FEEDBK_PATH
='INT_OP',
50 p_CLKOP_TRIM_POL
="FALLING",
52 p_CLKOS_TRIM_POL
="FALLING",
69 o_CLKOS2
=self
.clkout3
,
70 o_CLKOS3
=self
.clkout4
,
78 class ECPIX5CRG(Elaboratable
):
82 def elaborate(self
, platform
):
85 # Get 100Mhz from oscillator
86 clk100
= platform
.request("clk100")
87 cd_rawclk
= ClockDomain("rawclk", local
=True, reset_less
=True)
88 m
.d
.comb
+= cd_rawclk
.clk
.eq(clk100
)
89 m
.domains
+= cd_rawclk
92 reset
= platform
.request(platform
.default_rst
).i
97 Instance("FD1S3AX", p_GSR
="DISABLED", i_CK
=ClockSignal("rawclk"),
98 i_D
=~reset
, o_Q
=gsr0
),
99 Instance("FD1S3AX", p_GSR
="DISABLED", i_CK
=ClockSignal("rawclk"),
101 Instance("SGSR", i_CLK
=ClockSignal("rawclk"), i_GSR
=gsr1
),
104 # Power-on delay (655us)
105 podcnt
= Signal(16, reset
=2**16-1)
107 with m
.If(podcnt
!= 0):
108 m
.d
.rawclk
+= podcnt
.eq(podcnt
-1)
109 m
.d
.rawclk
+= pod_done
.eq(podcnt
== 0)
111 # Generating sync2x (200Mhz) and init (25Mhz) from clk100
112 cd_sync2x
= ClockDomain("sync2x", local
=False)
113 cd_sync2x_unbuf
= ClockDomain("sync2x_unbuf", local
=False,
115 cd_init
= ClockDomain("init", local
=False)
116 cd_sync
= ClockDomain("sync", local
=False)
117 cd_dramsync
= ClockDomain("dramsync", local
=False)
118 m
.submodules
.pll
= pll
= PLL(ClockSignal("rawclk"),
119 CLKI_DIV
=1, CLKFB_DIV
=2,
120 CLK1_DIV
=3, CLK2_DIV
=24,
121 clkout1
=ClockSignal("sync2x_unbuf"),
122 clkout2
=ClockSignal("init"))
123 m
.submodules
+= Instance("ECLKSYNCB",
124 i_ECLKI
= ClockSignal("sync2x_unbuf"),
126 o_ECLKO
= ClockSignal("sync2x"))
127 m
.domains
+= cd_sync2x_unbuf
128 m
.domains
+= cd_sync2x
131 m
.domains
+= cd_dramsync
132 m
.d
.comb
+= ResetSignal("init").eq(~pll
.lock|~pod_done
)
133 m
.d
.comb
+= ResetSignal("sync").eq(~pll
.lock|~pod_done
)
134 m
.d
.comb
+= ResetSignal("dramsync").eq(~pll
.lock|~pod_done
)
136 # # Generating sync (100Mhz) from sync2x
138 m
.submodules
+= Instance("CLKDIVF",
141 i_CLKI
=ClockSignal("sync2x"),
143 o_CDIVX
=ClockSignal("sync"))
144 m
.d
.comb
+= ClockSignal("dramsync").eq(ClockSignal("sync"))