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",
51 p_PLLRST_ENA
='DISABLED',
52 p_INTFB_WAKE
='DISABLED',
53 p_STDBY_ENABLE
='DISABLED',
56 p_OUTDIVIDER_MUXA
='DIVA',
57 p_CLKOP_ENABLE
='ENABLED',
58 p_CLKOP_DIV
=self
.CLKOP_DIV
,
59 p_CLKOS_DIV
=self
.CLKOS_DIV
,
60 p_CLKOS2_DIV
=self
.CLKOS2_DIV
,
61 p_CLKOS3_DIV
=self
.CLKOS3_DIV
,
62 p_CLKFB_DIV
=self
.CLKFB_DIV
,
63 p_CLKI_DIV
=self
.CLKI_DIV
,
64 p_FEEDBK_PATH
='CLKOP',
65 #p_FREQUENCY_PIN_CLKOP='200',
81 o_CLKOS2
=self
.clkout3
,
82 o_CLKOS3
=self
.clkout4
,
87 with m
.If(self
.clksel
== 0):
88 m
.d
.comb
+= clkfb
.eq(self
.clkout1
)
89 with m
.Elif(self
.clksel
== 1):
90 m
.d
.comb
+= clkfb
.eq(self
.clkout2
)
91 with m
.Elif(self
.clksel
== 2):
92 m
.d
.comb
+= clkfb
.eq(self
.clkout3
)
94 m
.d
.comb
+= clkfb
.eq(self
.clkout4
)
98 class ECPIX5CRG(Elaboratable
):
102 def elaborate(self
, platform
):
105 # Get 100Mhz from oscillator
106 clk100
= platform
.request("clk100")
107 cd_rawclk
= ClockDomain("rawclk", local
=True, reset_less
=True)
108 m
.d
.comb
+= cd_rawclk
.clk
.eq(clk100
)
109 m
.domains
+= cd_rawclk
112 reset
= platform
.request(platform
.default_rst
).i
117 Instance("FD1S3AX", p_GSR
="DISABLED", i_CK
=ClockSignal("rawclk"), i_D
=~reset
, o_Q
=gsr0
),
118 Instance("FD1S3AX", p_GSR
="DISABLED", i_CK
=ClockSignal("rawclk"), i_D
=gsr0
, o_Q
=gsr1
),
119 Instance("SGSR", i_CLK
=ClockSignal("rawclk"), i_GSR
=gsr1
),
122 # Power-on delay (655us)
123 podcnt
= Signal(16, reset
=2**16-1)
125 with m
.If(podcnt
!= 0):
126 m
.d
.rawclk
+= podcnt
.eq(podcnt
-1)
127 m
.d
.comb
+= pod_done
.eq(podcnt
== 0)
129 # Generating sync2x (200Mhz) and init (25Mhz) from clk100
130 cd_sync2x
= ClockDomain("sync2x", local
=False)
131 cd_sync2x_unbuf
= ClockDomain("sync2x_unbuf", local
=True, reset_less
=True)
132 cd_init
= ClockDomain("init", local
=False)
133 cd_sync
= ClockDomain("sync", local
=False, reset_less
=True)
134 cd_dramsync
= ClockDomain("dramsync", local
=False)
135 m
.submodules
.pll
= pll
= PLL(ClockSignal("rawclk"), CLKI_DIV
=1, CLKFB_DIV
=2, CLK1_DIV
=2, CLK2_DIV
=16, CLK3_DIV
=4,
136 clkout1
=ClockSignal("sync2x_unbuf"), clkout2
=ClockSignal("init"))
137 m
.submodules
+= Instance("ECLKSYNCB",
138 i_ECLKI
= ClockSignal("sync2x_unbuf"),
140 o_ECLKO
= ClockSignal("sync2x"))
141 m
.domains
+= cd_sync2x_unbuf
142 m
.domains
+= cd_sync2x
145 m
.domains
+= cd_dramsync
146 m
.d
.comb
+= ResetSignal("init").eq(~pll
.lock|~pod_done
)
147 m
.d
.comb
+= ResetSignal("dramsync").eq(~pll
.lock|~pod_done
)
149 rgb_led
= platform
.request("rgb_led", 2)
151 m
.d
.sync
+= cnt
.eq(cnt
+1)
152 m
.d
.comb
+= rgb_led
.r
.eq(cnt
[24])
153 m
.d
.comb
+= rgb_led
.g
.eq(~pod_done
)
154 m
.d
.comb
+= rgb_led
.b
.eq(~pll
.lock
)
156 # Generating sync (100Mhz) from sync2x
158 m
.submodules
+= Instance("CLKDIVF",
161 i_CLKI
=ClockSignal("sync2x"),
163 o_CDIVX
=ClockSignal("sync"))
164 m
.d
.comb
+= ClockSignal("dramsync").eq(ClockSignal("sync"))
168 class OldCRG(Elaboratable
):
169 def elaborate(self
, platform
):
172 m
.submodules
.pll
= pll
= PLL(ClockSignal(
173 "sync"), CLKI_DIV
=1, CLKFB_DIV
=2, CLK1_DIV
=2, CLK2_DIV
=16)
174 cd_sync2x
= ClockDomain("sync2x", local
=False)
175 m
.d
.comb
+= cd_sync2x
.clk
.eq(pll
.clkout1
)
176 m
.domains
+= cd_sync2x
178 cd_init
= ClockDomain("init", local
=False)
179 m
.d
.comb
+= cd_init
.clk
.eq(pll
.clkout2
)
184 class ThinCRG(Elaboratable
):
186 Sync (clk100, resetless) => PLL => sync2x_unbuf (200Mhz) => ECLKSYNC => sync2x => CLKDIVF => dramsync
192 def elaborate(self
, platform
):
195 # Power-on delay (655us)
196 podcnt
= Signal(16, reset
=2**16-1)
198 with m
.If(podcnt
!= 0):
199 m
.d
.sync
+= podcnt
.eq(podcnt
-1)
200 m
.d
.comb
+= pod_done
.eq(podcnt
== 0)
202 # Generating sync2x (200Mhz) and init (25Mhz) from clk100
203 cd_sync2x
= ClockDomain("sync2x", local
=False)
204 cd_sync2x_unbuf
= ClockDomain("sync2x_unbuf", local
=True, reset_less
=True)
205 cd_init
= ClockDomain("init", local
=False)
206 cd_dramsync
= ClockDomain("dramsync", local
=False)
207 m
.submodules
.pll
= pll
= PLL(ClockSignal("sync"), CLKI_DIV
=1, CLKFB_DIV
=2, CLK1_DIV
=2, CLK2_DIV
=16, CLK3_DIV
=4,
208 clkout1
=ClockSignal("sync2x_unbuf"), clkout2
=ClockSignal("init"))
209 m
.submodules
+= Instance("ECLKSYNCB",
210 i_ECLKI
= ClockSignal("sync2x_unbuf"),
212 o_ECLKO
= ClockSignal("sync2x"))
213 m
.domains
+= cd_sync2x_unbuf
214 m
.domains
+= cd_sync2x
216 m
.domains
+= cd_dramsync
217 m
.d
.comb
+= ResetSignal("init").eq(~pll
.lock|~pod_done
)
218 m
.d
.comb
+= ResetSignal("dramsync").eq(~pll
.lock|~pod_done
)
220 # Generating sync (100Mhz) from sync2x
221 m
.submodules
+= Instance("CLKDIVF",
224 i_CLKI
=ClockSignal("sync2x"),
226 o_CDIVX
=ClockSignal("dramsync"))
231 class DDR3SoC(SoC
, Elaboratable
):
232 def __init__(self
, *, clk_freq
,
233 ddrphy_addr
, dramcore_addr
,
235 self
._arbiter
= wishbone
.Arbiter(addr_width
=30, data_width
=32, granularity
=8,
236 features
={"cti", "bte"})
237 self
._decoder
= wishbone
.Decoder(addr_width
=30, data_width
=32, granularity
=8,
238 features
={"cti", "bte"})
240 self
.crg
= ECPIX5CRG()
242 self
.ub
= UARTBridge(divisor
=868, pins
=platform
.request("uart", 0))
243 self
._arbiter
.add(self
.ub
.bus
)
245 self
.ddrphy
= ECP5DDRPHY(platform
.request("ddr3", 0, dir={"dq":"-", "dqs":"-"}))
246 self
._decoder
.add(self
.ddrphy
.bus
, addr
=ddrphy_addr
)
248 ddrmodule
= MT41K256M16(clk_freq
, "1:4")
250 self
.dramcore
= gramCore(
252 geom_settings
=ddrmodule
.geom_settings
,
253 timing_settings
=ddrmodule
.timing_settings
,
255 self
._decoder
.add(self
.dramcore
.bus
, addr
=dramcore_addr
)
257 self
.drambone
= gramWishbone(self
.dramcore
)
258 self
._decoder
.add(self
.drambone
.bus
, addr
=ddr_addr
)
260 self
.memory_map
= self
._decoder
.bus
.memory_map
262 self
.clk_freq
= clk_freq
264 def elaborate(self
, platform
):
267 m
.submodules
.sysclk
= self
.crg
269 m
.submodules
.arbiter
= self
._arbiter
270 m
.submodules
.ub
= self
.ub
272 m
.submodules
.decoder
= self
._decoder
273 m
.submodules
.ddrphy
= self
.ddrphy
274 m
.submodules
.dramcore
= self
.dramcore
275 m
.submodules
.drambone
= self
.drambone
278 self
._arbiter
.bus
.connect(self
._decoder
.bus
),
284 if __name__
== "__main__":
285 platform
= IcarusECPIX5Platform()
287 soc
= DDR3SoC(clk_freq
=int(platform
.default_clk_frequency
),
288 ddrphy_addr
=0x00008000, dramcore_addr
=0x00009000,
291 soc
.build(do_build
=True)