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