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