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