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