1 # This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
4 from nmigen
.cli
import main
5 from nmigen
.lib
.cdc
import ResetSynchronizer
7 class PLL(Elaboratable
):
8 def __init__(self
, clkin
, clksel
=Signal(shape
=2, reset
=2), clkout1
=Signal(), clkout2
=Signal(), clkout3
=Signal(), clkout4
=Signal(), lock
=Signal(), CLKI_DIV
=1, CLKFB_DIV
=1, CLK1_DIV
=3, CLK2_DIV
=4, CLK3_DIV
=5, CLK4_DIV
=6):
10 self
.clkout1
= clkout1
11 self
.clkout2
= clkout2
12 self
.clkout3
= clkout3
13 self
.clkout4
= clkout4
16 self
.CLKI_DIV
= CLKI_DIV
17 self
.CLKFB_DIV
= CLKFB_DIV
18 self
.CLKOP_DIV
= CLK1_DIV
19 self
.CLKOS_DIV
= CLK2_DIV
20 self
.CLKOS2_DIV
= CLK3_DIV
21 self
.CLKOS3_DIV
= CLK4_DIV
32 def elaborate(self
, platform
):
34 pll
= Instance("EHXPLLL",
37 p_OUTDIVIDER_MUXA
='DIVA',
38 p_CLKOP_ENABLE
='ENABLED',
39 p_CLKOP_DIV
=self
.CLKOP_DIV
,
40 p_CLKOS_DIV
=self
.CLKOS_DIV
,
41 p_CLKOS2_DIV
=self
.CLKOS2_DIV
,
42 p_CLKOS3_DIV
=self
.CLKOS3_DIV
,
43 p_CLKFB_DIV
=self
.CLKFB_DIV
,
44 p_CLKI_DIV
=self
.CLKI_DIV
,
45 p_FEEDBK_PATH
='INT_OP',
46 #p_FREQUENCY_PIN_CLKOP='200',
62 o_CLKOS2
=self
.clkout3
,
63 o_CLKOS3
=self
.clkout4
,
68 with m
.If(self
.clksel
== 0):
69 m
.d
.comb
+= clkfb
.eq(self
.clkout1
)
70 with m
.Elif(self
.clksel
== 1):
71 m
.d
.comb
+= clkfb
.eq(self
.clkout2
)
72 with m
.Elif(self
.clksel
== 2):
73 m
.d
.comb
+= clkfb
.eq(self
.clkout3
)
75 m
.d
.comb
+= clkfb
.eq(self
.clkout4
)
79 class ECPIX5CRG(Elaboratable
):
83 def elaborate(self
, platform
):
86 # Get 100Mhz from oscillator
87 cd_rawclk
= ClockDomain("rawclk", local
=True, reset_less
=True)
88 m
.d
.comb
+= cd_rawclk
.clk
.eq(self
.clkin
)
89 m
.domains
+= cd_rawclk
91 # Power-on delay (655us)
92 podcnt
= Signal(16, reset
=2**16-1)
94 with m
.If(podcnt
!= 0):
95 m
.d
.rawclk
+= podcnt
.eq(podcnt
-1)
96 m
.d
.comb
+= pod_done
.eq(podcnt
== 0)
98 # Generating sync2x (200Mhz) and init (25Mhz) from clk100
99 cd_sync2x
= ClockDomain("sync2x", local
=False)
100 cd_sync2x_unbuf
= ClockDomain("sync2x_unbuf", local
=True, reset_less
=True)
101 cd_init
= ClockDomain("init", local
=False)
102 cd_sync
= ClockDomain("sync", local
=False, reset_less
=True)
103 cd_dramsync
= ClockDomain("dramsync", local
=False)
104 m
.submodules
.pll
= pll
= PLL(ClockSignal("rawclk"), CLKI_DIV
=1, CLKFB_DIV
=2, CLK1_DIV
=2, CLK2_DIV
=16, CLK3_DIV
=4,
105 clkout1
=ClockSignal("sync2x_unbuf"), clkout2
=ClockSignal("init"))
106 m
.submodules
+= Instance("ECLKSYNCB",
107 i_ECLKI
= ClockSignal("sync2x_unbuf"),
109 o_ECLKO
= ClockSignal("sync2x"))
110 m
.domains
+= cd_sync2x_unbuf
111 m
.domains
+= cd_sync2x
114 m
.domains
+= cd_dramsync
115 m
.d
.comb
+= ResetSignal("init").eq(~pll
.lock|~pod_done
)
116 m
.d
.comb
+= ResetSignal("dramsync").eq(~pll
.lock|~pod_done
)
118 # Generating sync (100Mhz) from sync2x
120 m
.submodules
+= Instance("CLKDIVF",
123 i_CLKI
=ClockSignal("sync2x"),
125 o_CDIVX
=ClockSignal("sync"))
126 m
.d
.comb
+= ClockSignal("dramsync").eq(ClockSignal("sync"))
130 class SimCRGTop(Elaboratable
):
132 self
.clkin
= Signal()
134 self
.sync2x
= Signal()
136 self
.dramsync
= Signal()
139 def elaborate(self
, platform
):
142 m
.submodules
.crg
= crg
= ECPIX5CRG()
144 crg
.clkin
.eq(self
.clkin
),
145 self
.sync2x
.eq(ClockSignal("sync2x")),
146 self
.sync
.eq(ClockSignal("sync")),
147 self
.dramsync
.eq(ClockSignal("dramsync")),
148 self
.init
.eq(ClockSignal("init")),
154 if __name__
== "__main__":
156 main(top
, name
="simcrgtop", ports
=[top
.clkin
, top
.sync
, top
.sync2x
, top
.dramsync
, top
.init
])