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