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