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