argh got fed up trying to shoe-horn into sim.py
[soc.git] / src / soc / litex / florent / ls180soc.py
1 #!/usr/bin/env python3
2
3 import os
4 import argparse
5
6 from migen import (Signal, FSM, If, Display, Finish, NextValue, NextState)
7
8 from litex.build.generic_platform import Pins, Subsignal
9 from litex.build.sim import SimPlatform
10 from litex.build.io import CRG
11 from litex.build.sim.config import SimConfig
12
13 from litex.soc.integration.soc import SoCRegion
14 from litex.soc.integration.soc_core import SoCCore
15 from litex.soc.integration.soc_sdram import SoCSDRAM
16 from litex.soc.integration.builder import Builder
17 from litex.soc.integration.common import get_mem_data
18
19 from litedram import modules as litedram_modules
20 from litedram.phy.model import SDRAMPHYModel
21 from litedram.phy.gensdrphy import GENSDRPHY, HalfRateGENSDRPHY
22
23 from litex.tools.litex_sim import sdram_module_nphases, get_sdram_phy_settings
24
25 from litex.tools.litex_sim import Platform
26 from libresoc.ls180 import LS180Platform
27
28 from libresoc import LibreSoC
29 from microwatt import Microwatt
30
31 # HACK!
32 from litex.soc.integration.soc import SoCCSRHandler
33 SoCCSRHandler.supported_address_width.append(12)
34
35 # LibreSoCSim -----------------------------------------------------------------
36
37 class LibreSoCSim(SoCCore):
38 def __init__(self, cpu="libresoc", debug=False, with_sdram=True,
39 sdram_module = "AS4C16M16",
40 #sdram_data_width = 16,
41 #sdram_module = "MT48LC16M16",
42 sdram_data_width = 16,
43 irq_reserved_irqs = {'uart': 0},
44 platform='sim',
45 ):
46 assert cpu in ["libresoc", "microwatt"]
47 sys_clk_freq = int(100e6)
48
49 if platform == 'sim':
50 platform = Platform()
51 uart_name = "sim"
52 elif platform == 'ls180':
53 platform = LS180Platform()
54 uart_name = "serial"
55
56 #cpu_data_width = 32
57 cpu_data_width = 64
58
59 if cpu_data_width == 32:
60 variant = "standard32"
61 else:
62 variant = "standard"
63
64 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
65 # "hello_world/hello_world.bin"
66 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
67 # "tests/1.bin"
68 #ram_fname = "/tmp/test.bin"
69 #ram_fname = None
70 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
71 # "micropython/firmware.bin"
72 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
73 # "tests/xics/xics.bin"
74 ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
75 "tests/decrementer/decrementer.bin"
76 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
77 # "hello_world/hello_world.bin"
78
79 # reserve XICS ICP and XICS memory addresses.
80 self.mem_map['icp'] = 0xc0004000
81 self.mem_map['ics'] = 0xc0005000
82 self.mem_map['gpio'] = 0xc0007000
83 #self.csr_map["icp"] = 8 # 8 x 0x800 == 0x4000
84 #self.csr_map["ics"] = 10 # 10 x 0x800 == 0x5000
85
86 ram_init = []
87 if ram_fname:
88 #ram_init = get_mem_data({
89 # ram_fname: "0x00000000",
90 # }, "little")
91 ram_init = get_mem_data(ram_fname, "little")
92
93 # remap the main RAM to reset-start-address
94 self.mem_map["main_ram"] = 0x00000000
95
96 # without sram nothing works, therefore move it to higher up
97 self.mem_map["sram"] = 0x90000000
98
99 # put UART at 0xc000200 (w00t! this works!)
100 self.csr_map["uart"] = 4
101
102
103 # SoCCore -------------------------------------------------------------
104 SoCCore.__init__(self, platform, clk_freq=sys_clk_freq,
105 cpu_type = "microwatt",
106 cpu_cls = LibreSoC if cpu == "libresoc" \
107 else Microwatt,
108 #bus_data_width = 64,
109 csr_address_width = 12, # limit to 0x4000
110 cpu_variant = variant,
111 csr_data_width = 8,
112 l2_size = 0,
113 uart_name = uart_name,
114 with_sdram = with_sdram,
115 sdram_module = sdram_module,
116 sdram_data_width = sdram_data_width,
117 integrated_rom_size = 0 if ram_fname else 0x10000,
118 integrated_sram_size = 0x40000,
119 #integrated_main_ram_init = ram_init,
120 integrated_main_ram_size = 0x00000000 if with_sdram \
121 else 0x10000000 , # 256MB
122 )
123 self.platform.name = "sim"
124
125 # SDR SDRAM ----------------------------------------------
126 if False: # not self.integrated_main_ram_size:
127 self.submodules.sdrphy = sdrphy_cls(platform.request("sdram"))
128
129
130 if cpu == "libresoc":
131 # XICS interrupt devices
132 icp_addr = self.mem_map['icp']
133 icp_wb = self.cpu.xics_icp
134 icp_region = SoCRegion(origin=icp_addr, size=0x20, cached=False)
135 self.bus.add_slave(name='icp', slave=icp_wb, region=icp_region)
136
137 ics_addr = self.mem_map['ics']
138 ics_wb = self.cpu.xics_ics
139 ics_region = SoCRegion(origin=ics_addr, size=0x1000, cached=False)
140 self.bus.add_slave(name='ics', slave=ics_wb, region=ics_region)
141
142 # Simple GPIO peripheral
143 gpio_addr = self.mem_map['gpio']
144 gpio_wb = self.cpu.simple_gpio
145 gpio_region = SoCRegion(origin=gpio_addr, size=0x20, cached=False)
146 self.bus.add_slave(name='gpio', slave=gpio_wb, region=gpio_region)
147
148
149 # CRG -----------------------------------------------------------------
150 self.submodules.crg = CRG(platform.request("sys_clk"))
151
152 #ram_init = []
153
154 # SDRAM ----------------------------------------------------
155 if with_sdram:
156 sdram_clk_freq = int(100e6) # FIXME: use 100MHz timings
157 sdram_module_cls = getattr(litedram_modules, sdram_module)
158 sdram_rate = "1:{}".format(
159 sdram_module_nphases[sdram_module_cls.memtype])
160 sdram_module = sdram_module_cls(sdram_clk_freq, sdram_rate)
161 phy_settings = get_sdram_phy_settings(
162 memtype = sdram_module.memtype,
163 data_width = sdram_data_width,
164 clk_freq = sdram_clk_freq)
165 #sdrphy_cls = HalfRateGENSDRPHY
166 sdrphy_cls = GENSDRPHY
167 self.submodules.sdrphy = sdrphy_cls(platform.request("sdram"))
168 #self.submodules.sdrphy = sdrphy_cls(sdram_module,
169 # phy_settings,
170 # init=ram_init
171 # )
172 self.add_sdram("sdram",
173 phy = self.sdrphy,
174 module = sdram_module,
175 origin = self.mem_map["main_ram"],
176 size = 0x40000000,
177 l2_cache_size = 0, # 8192
178 l2_cache_min_data_width = 128,
179 l2_cache_reverse = True
180 )
181 # FIXME: skip memtest to avoid corrupting memory
182 self.add_constant("MEMTEST_BUS_SIZE", 128//16)
183 self.add_constant("MEMTEST_DATA_SIZE", 128//16)
184 self.add_constant("MEMTEST_ADDR_SIZE", 128//16)
185 self.add_constant("MEMTEST_BUS_DEBUG", 1)
186 self.add_constant("MEMTEST_ADDR_DEBUG", 1)
187 self.add_constant("MEMTEST_DATA_DEBUG", 1)
188
189
190 # Debug ---------------------------------------------------------------
191 if not debug:
192 return
193
194 # setup running of DMI FSM
195 dmi_addr = Signal(4)
196 dmi_din = Signal(64)
197 dmi_dout = Signal(64)
198 dmi_wen = Signal(1)
199 dmi_req = Signal(1)
200
201 # debug log out
202 dbg_addr = Signal(4)
203 dbg_dout = Signal(64)
204 dbg_msg = Signal(1)
205
206 # capture pc from dmi
207 pc = Signal(64)
208 active_dbg = Signal()
209 active_dbg_cr = Signal()
210 active_dbg_xer = Signal()
211
212 # xer flags
213 xer_so = Signal()
214 xer_ca = Signal()
215 xer_ca32 = Signal()
216 xer_ov = Signal()
217 xer_ov32 = Signal()
218
219 # increment counter, Stop after 100000 cycles
220 uptime = Signal(64)
221 self.sync += uptime.eq(uptime + 1)
222 #self.sync += If(uptime == 1000000000000, Finish())
223
224 # DMI FSM counter and FSM itself
225 dmicount = Signal(10)
226 dmirunning = Signal(1)
227 dmi_monitor = Signal(1)
228 dmifsm = FSM()
229 self.submodules += dmifsm
230
231 # DMI FSM
232 dmifsm.act("START",
233 If(dmi_req & dmi_wen,
234 (self.cpu.dmi_addr.eq(dmi_addr), # DMI Addr
235 self.cpu.dmi_din.eq(dmi_din), # DMI in
236 self.cpu.dmi_req.eq(1), # DMI request
237 self.cpu.dmi_wr.eq(1), # DMI write
238 If(self.cpu.dmi_ack,
239 (NextState("IDLE"),
240 )
241 ),
242 ),
243 ),
244 If(dmi_req & ~dmi_wen,
245 (self.cpu.dmi_addr.eq(dmi_addr), # DMI Addr
246 self.cpu.dmi_req.eq(1), # DMI request
247 self.cpu.dmi_wr.eq(0), # DMI read
248 If(self.cpu.dmi_ack,
249 # acknowledge received: capture data.
250 (NextState("IDLE"),
251 NextValue(dbg_addr, dmi_addr),
252 NextValue(dbg_dout, self.cpu.dmi_dout),
253 NextValue(dbg_msg, 1),
254 ),
255 ),
256 ),
257 )
258 )
259
260 # DMI response received: reset the dmi request and check if
261 # in "monitor" mode
262 dmifsm.act("IDLE",
263 If(dmi_monitor,
264 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
265 ).Else(
266 NextState("START"), # back to start on next cycle
267 ),
268 NextValue(dmi_req, 0),
269 NextValue(dmi_addr, 0),
270 NextValue(dmi_din, 0),
271 NextValue(dmi_wen, 0),
272 )
273
274 # "monitor" mode fires off a STAT request
275 dmifsm.act("FIRE_MONITOR",
276 (NextValue(dmi_req, 1),
277 NextValue(dmi_addr, 1), # DMI STAT address
278 NextValue(dmi_din, 0),
279 NextValue(dmi_wen, 0), # read STAT
280 NextState("START"), # back to start on next cycle
281 )
282 )
283
284 self.comb += xer_so.eq((dbg_dout & 1) == 1)
285 self.comb += xer_ca.eq((dbg_dout & 4) == 4)
286 self.comb += xer_ca32.eq((dbg_dout & 8) == 8)
287 self.comb += xer_ov.eq((dbg_dout & 16) == 16)
288 self.comb += xer_ov32.eq((dbg_dout & 32) == 32)
289
290 # debug messages out
291 self.sync += If(dbg_msg,
292 (If(active_dbg & (dbg_addr == 0b10), # PC
293 Display("pc : %016x", dbg_dout),
294 ),
295 If(dbg_addr == 0b10, # PC
296 pc.eq(dbg_dout), # capture PC
297 ),
298 #If(dbg_addr == 0b11, # MSR
299 # Display(" msr: %016x", dbg_dout),
300 #),
301 If(dbg_addr == 0b1000, # CR
302 Display(" cr : %016x", dbg_dout),
303 ),
304 If(dbg_addr == 0b1001, # XER
305 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
306 xer_so, xer_ca, xer_ca32, xer_ov, xer_ov32),
307 ),
308 If(dbg_addr == 0b101, # GPR
309 Display(" gpr: %016x", dbg_dout),
310 ),
311 # also check if this is a "stat"
312 If(dbg_addr == 1, # requested a STAT
313 #Display(" stat: %x", dbg_dout),
314 If(dbg_dout & 2, # bit 2 of STAT is "stopped" mode
315 dmirunning.eq(1), # continue running
316 dmi_monitor.eq(0), # and stop monitor mode
317 ),
318 ),
319 dbg_msg.eq(0)
320 )
321 )
322
323 # kick off a "stop"
324 self.sync += If(uptime == 0,
325 (dmi_addr.eq(0), # CTRL
326 dmi_din.eq(1<<0), # STOP
327 dmi_req.eq(1),
328 dmi_wen.eq(1),
329 )
330 )
331
332 self.sync += If(uptime == 4,
333 dmirunning.eq(1),
334 )
335
336 self.sync += If(dmirunning,
337 dmicount.eq(dmicount + 1),
338 )
339
340 # loop every 1<<N cycles
341 cyclewid = 9
342
343 # get the PC
344 self.sync += If(dmicount == 4,
345 (dmi_addr.eq(0b10), # NIA
346 dmi_req.eq(1),
347 dmi_wen.eq(0),
348 )
349 )
350
351 # kick off a "step"
352 self.sync += If(dmicount == 8,
353 (dmi_addr.eq(0), # CTRL
354 dmi_din.eq(1<<3), # STEP
355 dmi_req.eq(1),
356 dmi_wen.eq(1),
357 dmirunning.eq(0), # stop counter, need to fire "monitor"
358 dmi_monitor.eq(1), # start "monitor" instead
359 )
360 )
361
362 # limit range of pc for debug reporting
363 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
364 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
365 self.comb += active_dbg.eq(1)
366
367
368 # get the MSR
369 self.sync += If(active_dbg & (dmicount == 12),
370 (dmi_addr.eq(0b11), # MSR
371 dmi_req.eq(1),
372 dmi_wen.eq(0),
373 )
374 )
375
376 if cpu == "libresoc":
377 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
378 self.comb += active_dbg_cr.eq(0)
379
380 # get the CR
381 self.sync += If(active_dbg_cr & (dmicount == 16),
382 (dmi_addr.eq(0b1000), # CR
383 dmi_req.eq(1),
384 dmi_wen.eq(0),
385 )
386 )
387
388 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
389 self.comb += active_dbg_xer.eq(active_dbg_cr)
390
391 # get the CR
392 self.sync += If(active_dbg_xer & (dmicount == 20),
393 (dmi_addr.eq(0b1001), # XER
394 dmi_req.eq(1),
395 dmi_wen.eq(0),
396 )
397 )
398
399 # read all 32 GPRs
400 for i in range(32):
401 self.sync += If(active_dbg & (dmicount == 24+(i*8)),
402 (dmi_addr.eq(0b100), # GSPR addr
403 dmi_din.eq(i), # r1
404 dmi_req.eq(1),
405 dmi_wen.eq(1),
406 )
407 )
408
409 self.sync += If(active_dbg & (dmicount == 28+(i*8)),
410 (dmi_addr.eq(0b101), # GSPR data
411 dmi_req.eq(1),
412 dmi_wen.eq(0),
413 )
414 )
415
416 # monitor bbus read/write
417 self.sync += If(active_dbg & self.cpu.dbus.stb & self.cpu.dbus.ack,
418 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
419 #uptime,
420 0,
421 self.cpu.dbus.adr,
422 self.cpu.dbus.we,
423 self.cpu.dbus.sel,
424 self.cpu.dbus.dat_w,
425 self.cpu.dbus.dat_r
426 )
427 )
428
429 return
430
431 # monitor ibus write
432 self.sync += If(active_dbg & self.cpu.ibus.stb & self.cpu.ibus.ack &
433 self.cpu.ibus.we,
434 Display(" [%06x] iadr: %8x, s %01x w %016x",
435 #uptime,
436 0,
437 self.cpu.ibus.adr,
438 self.cpu.ibus.sel,
439 self.cpu.ibus.dat_w,
440 )
441 )
442 # monitor ibus read
443 self.sync += If(active_dbg & self.cpu.ibus.stb & self.cpu.ibus.ack &
444 ~self.cpu.ibus.we,
445 Display(" [%06x] iadr: %8x, s %01x r %016x",
446 #uptime,
447 0,
448 self.cpu.ibus.adr,
449 self.cpu.ibus.sel,
450 self.cpu.ibus.dat_r
451 )
452 )
453
454 # Build -----------------------------------------------------------------------
455
456 def main():
457 parser = argparse.ArgumentParser(description="LiteX LibreSoC CPU Sim")
458 parser.add_argument("--cpu", default="libresoc",
459 help="CPU to use: libresoc (default) or microwatt")
460 parser.add_argument("--platform", default="sim",
461 help="platform (sim or ls180)")
462 parser.add_argument("--debug", action="store_true",
463 help="Enable debug traces")
464 parser.add_argument("--trace", action="store_true",
465 help="Enable tracing")
466 parser.add_argument("--trace-start", default=0,
467 help="Cycle to start FST tracing")
468 parser.add_argument("--trace-end", default=-1,
469 help="Cycle to end FST tracing")
470 parser.add_argument("--build", action="store_true", help="Build bitstream")
471 args = parser.parse_args()
472
473
474 if args.platform == 'ls180':
475 soc = LibreSoCSim(cpu=args.cpu, debug=args.debug,
476 platform=args.platform)
477 #soc.add_sdcard()
478 builder = Builder(soc, compile_gateware = True)
479 builder.build(run = True)
480 os.chdir("../")
481 else:
482
483 sim_config = SimConfig(default_clk="sys_clk")
484 sim_config.add_module("serial2console", "serial")
485
486 for i in range(2):
487 soc = LibreSoCSim(cpu=args.cpu, debug=args.debug,
488 platform=args.platform)
489 builder = Builder(soc, compile_gateware = i!=0)
490 builder.build(sim_config=sim_config,
491 run = i!=0,
492 trace = args.trace,
493 trace_start = int(args.trace_start),
494 trace_end = int(args.trace_end),
495 trace_fst = 0)
496 os.chdir("../")
497
498 if __name__ == "__main__":
499 main()