1 # This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
4 from nmigen
.lib
.cdc
import ResetSynchronizer
5 from nmigen_soc
import wishbone
, memory
7 from lambdasoc
.cpu
.minerva
import MinervaCPU
8 from lambdasoc
.periph
.intc
import GenericInterruptController
9 from lambdasoc
.periph
.serial
import AsyncSerialPeripheral
10 from lambdasoc
.periph
.sram
import SRAMPeripheral
11 from lambdasoc
.periph
.timer
import TimerPeripheral
12 from lambdasoc
.periph
import Peripheral
13 from lambdasoc
.soc
.base
import SoC
15 from gram
.core
import gramCore
16 from gram
.phy
.ecp5ddrphy
import ECP5DDRPHY
17 from gram
.modules
import MT41K256M16
18 from gram
.frontend
.wishbone
import gramWishbone
20 from icarusecpix5platform
import IcarusECPIX5Platform
21 from uartbridge
import UARTBridge
23 class PLL(Elaboratable
):
24 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):
26 self
.clkout1
= clkout1
27 self
.clkout2
= clkout2
28 self
.clkout3
= clkout3
29 self
.clkout4
= clkout4
32 self
.CLKI_DIV
= CLKI_DIV
33 self
.CLKFB_DIV
= CLKFB_DIV
34 self
.CLKOP_DIV
= CLK1_DIV
35 self
.CLKOS_DIV
= CLK2_DIV
36 self
.CLKOS2_DIV
= CLK3_DIV
37 self
.CLKOS3_DIV
= CLK4_DIV
48 def elaborate(self
, platform
):
50 pll
= Instance("EHXPLLL",
53 p_OUTDIVIDER_MUXA
='DIVA',
54 p_CLKOP_ENABLE
='ENABLED',
55 p_CLKOP_DIV
=self
.CLKOP_DIV
,
56 p_CLKOS_DIV
=self
.CLKOS_DIV
,
57 p_CLKOS2_DIV
=self
.CLKOS2_DIV
,
58 p_CLKOS3_DIV
=self
.CLKOS3_DIV
,
59 p_CLKFB_DIV
=self
.CLKFB_DIV
,
60 p_CLKI_DIV
=self
.CLKI_DIV
,
61 p_FEEDBK_PATH
='INT_OP',
62 #p_FREQUENCY_PIN_CLKOP='200',
78 o_CLKOS2
=self
.clkout3
,
79 o_CLKOS3
=self
.clkout4
,
84 with m
.If(self
.clksel
== 0):
85 m
.d
.comb
+= clkfb
.eq(self
.clkout1
)
86 with m
.Elif(self
.clksel
== 1):
87 m
.d
.comb
+= clkfb
.eq(self
.clkout2
)
88 with m
.Elif(self
.clksel
== 2):
89 m
.d
.comb
+= clkfb
.eq(self
.clkout3
)
91 m
.d
.comb
+= clkfb
.eq(self
.clkout4
)
95 class ECPIX5CRG(Elaboratable
):
99 def elaborate(self
, platform
):
102 # Get 100Mhz from oscillator
103 clk100
= platform
.request("clk100")
104 cd_rawclk
= ClockDomain("rawclk", local
=True, reset_less
=True)
105 m
.d
.comb
+= cd_rawclk
.clk
.eq(clk100
)
106 m
.domains
+= cd_rawclk
109 reset
= platform
.request(platform
.default_rst
).i
114 Instance("FD1S3AX", p_GSR
="DISABLED", i_CK
=ClockSignal("rawclk"), i_D
=~reset
, o_Q
=gsr0
),
115 Instance("FD1S3AX", p_GSR
="DISABLED", i_CK
=ClockSignal("rawclk"), i_D
=gsr0
, o_Q
=gsr1
),
116 Instance("SGSR", i_CLK
=ClockSignal("rawclk"), i_GSR
=gsr1
),
119 # Power-on delay (655us)
120 podcnt
= Signal(16, reset
=2**16-1)
122 with m
.If(podcnt
!= 0):
123 m
.d
.rawclk
+= podcnt
.eq(podcnt
-1)
124 m
.d
.comb
+= pod_done
.eq(podcnt
== 0)
126 # Generating sync2x (200Mhz) and init (25Mhz) from clk100
127 cd_sync2x
= ClockDomain("sync2x", local
=False)
128 cd_sync2x_unbuf
= ClockDomain("sync2x_unbuf", local
=True, reset_less
=True)
129 cd_init
= ClockDomain("init", local
=False)
130 cd_sync
= ClockDomain("sync", local
=False)
131 cd_dramsync
= ClockDomain("dramsync", local
=False)
132 m
.submodules
.pll
= pll
= PLL(ClockSignal("rawclk"), CLKI_DIV
=1, CLKFB_DIV
=2, CLK1_DIV
=2, CLK2_DIV
=16, CLK3_DIV
=4,
133 clkout1
=ClockSignal("sync2x_unbuf"), clkout2
=ClockSignal("init"))
134 m
.submodules
+= Instance("ECLKSYNCB",
135 i_ECLKI
= ClockSignal("sync2x_unbuf"),
137 o_ECLKO
= ClockSignal("sync2x"))
138 m
.domains
+= cd_sync2x_unbuf
139 m
.domains
+= cd_sync2x
142 m
.domains
+= cd_dramsync
143 m
.d
.comb
+= ResetSignal("init").eq(~pll
.lock|~pod_done
)
144 m
.d
.comb
+= ResetSignal("sync").eq(~pll
.lock|~pod_done
)
145 m
.d
.comb
+= ResetSignal("dramsync").eq(~pll
.lock|~pod_done
)
147 rgb_led
= platform
.request("rgb_led", 2)
149 m
.d
.sync
+= cnt
.eq(cnt
+1)
150 m
.d
.comb
+= rgb_led
.r
.eq(cnt
[24])
151 m
.d
.comb
+= rgb_led
.g
.eq(~pod_done
)
152 m
.d
.comb
+= rgb_led
.b
.eq(~pll
.lock
)
154 # Generating sync (100Mhz) from sync2x
156 m
.submodules
+= Instance("CLKDIVF",
159 i_CLKI
=ClockSignal("sync2x"),
161 o_CDIVX
=ClockSignal("sync"))
162 m
.d
.comb
+= ClockSignal("dramsync").eq(ClockSignal("sync"))
166 class OldCRG(Elaboratable
):
167 def elaborate(self
, platform
):
170 m
.submodules
.pll
= pll
= PLL(ClockSignal(
171 "sync"), CLKI_DIV
=1, CLKFB_DIV
=2, CLK1_DIV
=2, CLK2_DIV
=16)
172 cd_sync2x
= ClockDomain("sync2x", local
=False)
173 m
.d
.comb
+= cd_sync2x
.clk
.eq(pll
.clkout1
)
174 m
.domains
+= cd_sync2x
176 cd_init
= ClockDomain("init", local
=False)
177 m
.d
.comb
+= cd_init
.clk
.eq(pll
.clkout2
)
182 class ThinCRG(Elaboratable
):
184 Sync (clk100, resetless) => PLL => sync2x_unbuf (200Mhz) => ECLKSYNC => sync2x => CLKDIVF => dramsync
190 def elaborate(self
, platform
):
193 # Power-on delay (655us)
194 podcnt
= Signal(16, reset
=2**16-1)
196 with m
.If(podcnt
!= 0):
197 m
.d
.sync
+= podcnt
.eq(podcnt
-1)
198 m
.d
.comb
+= pod_done
.eq(podcnt
== 0)
200 # Generating sync2x (200Mhz) and init (25Mhz) from clk100
201 cd_sync2x
= ClockDomain("sync2x", local
=False)
202 cd_sync2x_unbuf
= ClockDomain("sync2x_unbuf", local
=True, reset_less
=True)
203 cd_init
= ClockDomain("init", local
=False)
204 cd_dramsync
= ClockDomain("dramsync", local
=False)
205 m
.submodules
.pll
= pll
= PLL(ClockSignal("sync"), CLKI_DIV
=1, CLKFB_DIV
=2, CLK1_DIV
=2, CLK2_DIV
=16, CLK3_DIV
=4,
206 clkout1
=ClockSignal("sync2x_unbuf"), clkout2
=ClockSignal("init"))
207 m
.submodules
+= Instance("ECLKSYNCB",
208 i_ECLKI
= ClockSignal("sync2x_unbuf"),
210 o_ECLKO
= ClockSignal("sync2x"))
211 m
.domains
+= cd_sync2x_unbuf
212 m
.domains
+= cd_sync2x
214 m
.domains
+= cd_dramsync
215 m
.d
.comb
+= ResetSignal("init").eq(~pll
.lock|~pod_done
)
216 m
.d
.comb
+= ResetSignal("dramsync").eq(~pll
.lock|~pod_done
)
218 # Generating sync (100Mhz) from sync2x
219 m
.submodules
+= Instance("CLKDIVF",
222 i_CLKI
=ClockSignal("sync2x"),
224 o_CDIVX
=ClockSignal("dramsync"))
229 class DDR3SoC(SoC
, Elaboratable
):
230 def __init__(self
, *, clk_freq
,
231 ddrphy_addr
, dramcore_addr
,
233 self
._arbiter
= wishbone
.Arbiter(addr_width
=30, data_width
=32, granularity
=8,
234 features
={"cti", "bte"})
235 self
._decoder
= wishbone
.Decoder(addr_width
=30, data_width
=32, granularity
=8,
236 features
={"cti", "bte"})
238 self
.crg
= ECPIX5CRG()
240 self
.ub
= UARTBridge(divisor
=868, pins
=platform
.request("uart", 0))
241 self
._arbiter
.add(self
.ub
.bus
)
243 self
.ddrphy
= DomainRenamer("dramsync")(ECP5DDRPHY(platform
.request("ddr3", 0, dir={"dq":"-", "dqs":"-"})))
244 self
._decoder
.add(self
.ddrphy
.bus
, addr
=ddrphy_addr
)
246 ddrmodule
= MT41K256M16(clk_freq
, "1:4")
248 self
.dramcore
= DomainRenamer("dramsync")(gramCore(
250 geom_settings
=ddrmodule
.geom_settings
,
251 timing_settings
=ddrmodule
.timing_settings
,
253 self
._decoder
.add(self
.dramcore
.bus
, addr
=dramcore_addr
)
255 self
.drambone
= DomainRenamer("dramsync")(gramWishbone(self
.dramcore
))
256 self
._decoder
.add(self
.drambone
.bus
, addr
=ddr_addr
)
258 self
.memory_map
= self
._decoder
.bus
.memory_map
260 self
.clk_freq
= clk_freq
262 def elaborate(self
, platform
):
265 m
.submodules
.sysclk
= self
.crg
267 m
.submodules
.arbiter
= self
._arbiter
268 m
.submodules
.ub
= self
.ub
270 m
.submodules
.decoder
= self
._decoder
271 m
.submodules
.ddrphy
= self
.ddrphy
272 m
.submodules
.dramcore
= self
.dramcore
273 m
.submodules
.drambone
= self
.drambone
276 self
._arbiter
.bus
.connect(self
._decoder
.bus
),
282 if __name__
== "__main__":
283 platform
= IcarusECPIX5Platform()
285 soc
= DDR3SoC(clk_freq
=int(platform
.default_clk_frequency
),
286 ddrphy_addr
=0x00008000, dramcore_addr
=0x00009000,
289 soc
.build(do_build
=True)