Add DDRSoC simulation
[gram.git] / gram / simulation / simsoc.py
1 # This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
2
3 from nmigen import *
4 from nmigen.lib.cdc import ResetSynchronizer
5 from nmigen_soc import wishbone, memory
6
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
14
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
19
20 from icarusecpix5platform import IcarusECPIX5Platform
21 from uartbridge import UARTBridge
22
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):
25 self.clkin = clkin
26 self.clkout1 = clkout1
27 self.clkout2 = clkout2
28 self.clkout3 = clkout3
29 self.clkout4 = clkout4
30 self.clksel = clksel
31 self.lock = lock
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
38 self.ports = [
39 self.clkin,
40 self.clkout1,
41 self.clkout2,
42 self.clkout3,
43 self.clkout4,
44 self.clksel,
45 self.lock,
46 ]
47
48 def elaborate(self, platform):
49 clkfb = Signal()
50 pll = Instance("EHXPLLL",
51 p_PLLRST_ENA='DISABLED',
52 p_INTFB_WAKE='DISABLED',
53 p_STDBY_ENABLE='DISABLED',
54 p_CLKOP_FPHASE=0,
55 p_CLKOP_CPHASE=1,
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',
66 i_CLKI=self.clkin,
67 i_CLKFB=clkfb,
68 i_RST=0,
69 i_STDBY=0,
70 i_PHASESEL0=0,
71 i_PHASESEL1=0,
72 i_PHASEDIR=0,
73 i_PHASESTEP=0,
74 i_PLLWAKESYNC=0,
75 i_ENCLKOP=0,
76 i_ENCLKOS=0,
77 i_ENCLKOS2=0,
78 i_ENCLKOS3=0,
79 o_CLKOP=self.clkout1,
80 o_CLKOS=self.clkout2,
81 o_CLKOS2=self.clkout3,
82 o_CLKOS3=self.clkout4,
83 o_LOCK=self.lock,
84 )
85 m = Module()
86 m.submodules += pll
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)
93 with m.Else():
94 m.d.comb += clkfb.eq(self.clkout4)
95 return m
96
97
98 class ECPIX5CRG(Elaboratable):
99 def __init__(self):
100 ...
101
102 def elaborate(self, platform):
103 m = Module()
104
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
110
111 # Reset
112 reset = platform.request(platform.default_rst).i
113 gsr0 = Signal()
114 gsr1 = Signal()
115
116 m.submodules += [
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),
120 ]
121
122 # Power-on delay (655us)
123 podcnt = Signal(16, reset=2**16-1)
124 pod_done = Signal()
125 with m.If(podcnt != 0):
126 m.d.rawclk += podcnt.eq(podcnt-1)
127 m.d.comb += pod_done.eq(podcnt == 0)
128
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"),
139 i_STOP = 0,
140 o_ECLKO = ClockSignal("sync2x"))
141 m.domains += cd_sync2x_unbuf
142 m.domains += cd_sync2x
143 m.domains += cd_init
144 m.domains += cd_sync
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)
148
149 rgb_led = platform.request("rgb_led", 2)
150 cnt = Signal(25)
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)
155
156 # Generating sync (100Mhz) from sync2x
157
158 m.submodules += Instance("CLKDIVF",
159 p_DIV="2.0",
160 i_ALIGNWD=0,
161 i_CLKI=ClockSignal("sync2x"),
162 i_RST=0,
163 o_CDIVX=ClockSignal("sync"))
164 m.d.comb += ClockSignal("dramsync").eq(ClockSignal("sync"))
165
166 return m
167
168 class OldCRG(Elaboratable):
169 def elaborate(self, platform):
170 m = Module()
171
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
177
178 cd_init = ClockDomain("init", local=False)
179 m.d.comb += cd_init.clk.eq(pll.clkout2)
180 m.domains += cd_init
181
182 return m
183
184 class ThinCRG(Elaboratable):
185 """
186 Sync (clk100, resetless) => PLL => sync2x_unbuf (200Mhz) => ECLKSYNC => sync2x => CLKDIVF => dramsync
187 """
188
189 def __init__(self):
190 ...
191
192 def elaborate(self, platform):
193 m = Module()
194
195 # Power-on delay (655us)
196 podcnt = Signal(16, reset=2**16-1)
197 pod_done = Signal()
198 with m.If(podcnt != 0):
199 m.d.sync += podcnt.eq(podcnt-1)
200 m.d.comb += pod_done.eq(podcnt == 0)
201
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"),
211 i_STOP = 0,
212 o_ECLKO = ClockSignal("sync2x"))
213 m.domains += cd_sync2x_unbuf
214 m.domains += cd_sync2x
215 m.domains += cd_init
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)
219
220 # Generating sync (100Mhz) from sync2x
221 m.submodules += Instance("CLKDIVF",
222 p_DIV="2.0",
223 i_ALIGNWD=0,
224 i_CLKI=ClockSignal("sync2x"),
225 i_RST=0,
226 o_CDIVX=ClockSignal("dramsync"))
227
228 return m
229
230
231 class DDR3SoC(SoC, Elaboratable):
232 def __init__(self, *, clk_freq,
233 ddrphy_addr, dramcore_addr,
234 ddr_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"})
239
240 self.crg = ECPIX5CRG()
241
242 self.ub = UARTBridge(divisor=868, pins=platform.request("uart", 0))
243 self._arbiter.add(self.ub.bus)
244
245 self.ddrphy = ECP5DDRPHY(platform.request("ddr3", 0, dir={"dq":"-", "dqs":"-"}))
246 self._decoder.add(self.ddrphy.bus, addr=ddrphy_addr)
247
248 ddrmodule = MT41K256M16(clk_freq, "1:4")
249
250 self.dramcore = gramCore(
251 phy=self.ddrphy,
252 geom_settings=ddrmodule.geom_settings,
253 timing_settings=ddrmodule.timing_settings,
254 clk_freq=clk_freq)
255 self._decoder.add(self.dramcore.bus, addr=dramcore_addr)
256
257 self.drambone = gramWishbone(self.dramcore)
258 self._decoder.add(self.drambone.bus, addr=ddr_addr)
259
260 self.memory_map = self._decoder.bus.memory_map
261
262 self.clk_freq = clk_freq
263
264 def elaborate(self, platform):
265 m = Module()
266
267 m.submodules.sysclk = self.crg
268
269 m.submodules.arbiter = self._arbiter
270 m.submodules.ub = self.ub
271
272 m.submodules.decoder = self._decoder
273 m.submodules.ddrphy = self.ddrphy
274 m.submodules.dramcore = self.dramcore
275 m.submodules.drambone = self.drambone
276
277 m.d.comb += [
278 self._arbiter.bus.connect(self._decoder.bus),
279 ]
280
281 return m
282
283
284 if __name__ == "__main__":
285 platform = IcarusECPIX5Platform()
286
287 soc = DDR3SoC(clk_freq=int(platform.default_clk_frequency),
288 ddrphy_addr=0x00008000, dramcore_addr=0x00009000,
289 ddr_addr=0x10000000)
290
291 soc.build(do_build=True)
292 platform.build(soc)