4c33dbb72208669517e6df5c0274b4a2a20aca18
[litex.git] / litex / tools / litex_sim.py
1 #!/usr/bin/env python3
2
3 # This file is Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
4 # This file is Copyright (c) 2020 Antmicro <www.antmicro.com>
5 # This file is Copyright (c) 2017 Pierre-Olivier Vauboin <po@lambdaconcept>
6 # License: BSD
7
8 import argparse
9
10 from migen import *
11
12 from litex.build.generic_platform import *
13 from litex.build.sim import SimPlatform
14 from litex.build.sim.config import SimConfig
15
16 from litex.soc.integration.common import *
17 from litex.soc.integration.soc_core import *
18 from litex.soc.integration.soc_sdram import *
19 from litex.soc.integration.builder import *
20 from litex.soc.integration.soc import *
21 from litex.soc.cores.bitbang import *
22 from litex.soc.cores.cpu import CPUS
23
24 from litedram import modules as litedram_modules
25 from litedram.modules import parse_spd_hexdump
26 from litedram.common import *
27 from litedram.phy.model import SDRAMPHYModel
28
29 from liteeth.phy.model import LiteEthPHYModel
30 from liteeth.mac import LiteEthMAC
31 from liteeth.core.arp import LiteEthARP
32 from liteeth.core.ip import LiteEthIP
33 from liteeth.core.udp import LiteEthUDP
34 from liteeth.core.icmp import LiteEthICMP
35 from liteeth.core import LiteEthUDPIPCore
36 from liteeth.frontend.etherbone import LiteEthEtherbone
37 from liteeth.common import *
38
39 from litescope import LiteScopeAnalyzer
40
41 # IOs ----------------------------------------------------------------------------------------------
42
43 _io = [
44 ("sys_clk", 0, Pins(1)),
45 ("sys_rst", 0, Pins(1)),
46 ("serial", 0,
47 Subsignal("source_valid", Pins(1)),
48 Subsignal("source_ready", Pins(1)),
49 Subsignal("source_data", Pins(8)),
50
51 Subsignal("sink_valid", Pins(1)),
52 Subsignal("sink_ready", Pins(1)),
53 Subsignal("sink_data", Pins(8)),
54 ),
55 ("eth_clocks", 0,
56 Subsignal("tx", Pins(1)),
57 Subsignal("rx", Pins(1)),
58 ),
59 ("eth", 0,
60 Subsignal("source_valid", Pins(1)),
61 Subsignal("source_ready", Pins(1)),
62 Subsignal("source_data", Pins(8)),
63
64 Subsignal("sink_valid", Pins(1)),
65 Subsignal("sink_ready", Pins(1)),
66 Subsignal("sink_data", Pins(8)),
67 ),
68 ("i2c", 0,
69 Subsignal("scl", Pins(1)),
70 Subsignal("sda_out", Pins(1)),
71 Subsignal("sda_in", Pins(1)),
72 ),
73 ]
74
75 # Platform -----------------------------------------------------------------------------------------
76
77 class Platform(SimPlatform):
78 def __init__(self):
79 SimPlatform.__init__(self, "SIM", _io)
80
81 # DFI PHY model settings ---------------------------------------------------------------------------
82
83 sdram_module_nphases = {
84 "SDR": 1,
85 "DDR": 2,
86 "LPDDR": 2,
87 "DDR2": 2,
88 "DDR3": 4,
89 "DDR4": 4,
90 }
91
92 def get_sdram_phy_settings(memtype, data_width, clk_freq):
93 nphases = sdram_module_nphases[memtype]
94
95 if memtype == "SDR":
96 # Settings from gensdrphy
97 rdphase = 0
98 wrphase = 0
99 rdcmdphase = 0
100 wrcmdphase = 0
101 cl = 2
102 cwl = None
103 read_latency = 4
104 write_latency = 0
105 elif memtype in ["DDR", "LPDDR"]:
106 # Settings from s6ddrphy
107 rdphase = 0
108 wrphase = 1
109 rdcmdphase = 1
110 wrcmdphase = 0
111 cl = 3
112 cwl = None
113 read_latency = 5
114 write_latency = 0
115 elif memtype in ["DDR2", "DDR3"]:
116 # Settings from s7ddrphy
117 tck = 2/(2*nphases*clk_freq)
118 cmd_latency = 0
119 cl, cwl = get_cl_cw(memtype, tck)
120 cl_sys_latency = get_sys_latency(nphases, cl)
121 cwl = cwl + cmd_latency
122 cwl_sys_latency = get_sys_latency(nphases, cwl)
123 rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl)
124 wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl)
125 read_latency = 2 + cl_sys_latency + 2 + 3
126 write_latency = cwl_sys_latency
127 elif memtype == "DDR4":
128 # Settings from usddrphy
129 tck = 2/(2*nphases*clk_freq)
130 cmd_latency = 0
131 cl, cwl = get_cl_cw(memtype, tck)
132 cl_sys_latency = get_sys_latency(nphases, cl)
133 cwl = cwl + cmd_latency
134 cwl_sys_latency = get_sys_latency(nphases, cwl)
135 rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl)
136 wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl)
137 read_latency = 2 + cl_sys_latency + 1 + 3
138 write_latency = cwl_sys_latency
139
140 sdram_phy_settings = {
141 "nphases": nphases,
142 "rdphase": rdphase,
143 "wrphase": wrphase,
144 "rdcmdphase": rdcmdphase,
145 "wrcmdphase": wrcmdphase,
146 "cl": cl,
147 "cwl": cwl,
148 "read_latency": read_latency,
149 "write_latency": write_latency,
150 }
151
152 return PhySettings(
153 phytype = "SDRAMPHYModel",
154 memtype = memtype,
155 databits = data_width,
156 dfi_databits = data_width if memtype == "SDR" else 2*data_width,
157 **sdram_phy_settings,
158 )
159
160 # Simulation SoC -----------------------------------------------------------------------------------
161
162 class SimSoC(SoCCore):
163 mem_map = {
164 "ethmac": 0xb0000000,
165 }
166 mem_map.update(SoCCore.mem_map)
167
168 def __init__(self,
169 with_sdram = False,
170 with_ethernet = False,
171 with_etherbone = False,
172 etherbone_mac_address = 0x10e2d5000001,
173 etherbone_ip_address = "192.168.1.51",
174 with_analyzer = False,
175 sdram_module = "MT48LC16M16",
176 sdram_init = [],
177 sdram_data_width = 32,
178 sdram_spd_data = None,
179 sdram_verbosity = 0,
180 with_i2c = False,
181 with_sdcard = False,
182 **kwargs):
183 platform = Platform()
184 sys_clk_freq = int(1e6)
185
186 # SoCCore ----------------------------------------------------------------------------------
187 SoCCore.__init__(self, platform, clk_freq=sys_clk_freq,
188 ident = "LiteX Simulation",
189 ident_version = True,
190 **kwargs)
191
192 # CRG --------------------------------------------------------------------------------------
193 self.submodules.crg = CRG(platform.request("sys_clk"))
194
195 # SDRAM ------------------------------------------------------------------------------------
196 if with_sdram:
197 sdram_clk_freq = int(100e6) # FIXME: use 100MHz timings
198 if sdram_spd_data is None:
199 sdram_module_cls = getattr(litedram_modules, sdram_module)
200 sdram_rate = "1:{}".format(sdram_module_nphases[sdram_module_cls.memtype])
201 sdram_module = sdram_module_cls(sdram_clk_freq, sdram_rate)
202 else:
203 sdram_module = litedram_modules.SDRAMModule.from_spd_data(sdram_spd_data, sdram_clk_freq)
204 phy_settings = get_sdram_phy_settings(
205 memtype = sdram_module.memtype,
206 data_width = sdram_data_width,
207 clk_freq = sdram_clk_freq)
208 self.submodules.sdrphy = SDRAMPHYModel(
209 module = sdram_module,
210 settings = phy_settings,
211 clk_freq = sdram_clk_freq,
212 verbosity = sdram_verbosity,
213 init = sdram_init)
214 self.add_sdram("sdram",
215 phy = self.sdrphy,
216 module = sdram_module,
217 origin = self.mem_map["main_ram"],
218 size = kwargs.get("max_sdram_size", 0x40000000),
219 l2_cache_size = kwargs.get("l2_size", 8192),
220 l2_cache_min_data_width = kwargs.get("min_l2_data_width", 128),
221 l2_cache_reverse = False
222 )
223 # Reduce memtest size for simulation speedup
224 self.add_constant("MEMTEST_DATA_SIZE", 8*1024)
225 self.add_constant("MEMTEST_ADDR_SIZE", 8*1024)
226
227 #assert not (with_ethernet and with_etherbone)
228
229 if with_ethernet and with_etherbone:
230 etherbone_ip_address = convert_ip(etherbone_ip_address)
231 # Ethernet PHY
232 self.submodules.ethphy = LiteEthPHYModel(self.platform.request("eth", 0))
233 self.add_csr("ethphy")
234 # Ethernet MAC
235 self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=8,
236 interface = "hybrid",
237 endianness = self.cpu.endianness,
238 hw_mac = etherbone_mac_address)
239
240 # SoftCPU
241 self.add_memory_region("ethmac", self.mem_map["ethmac"], 0x2000, type="io")
242 self.add_wb_slave(self.mem_regions["ethmac"].origin, self.ethmac.bus, 0x2000)
243 self.add_csr("ethmac")
244 self.add_interrupt("ethmac")
245 # HW ethernet
246 self.submodules.arp = LiteEthARP(self.ethmac, etherbone_mac_address, etherbone_ip_address, sys_clk_freq, dw=8)
247 self.submodules.ip = LiteEthIP(self.ethmac, etherbone_mac_address, etherbone_ip_address, self.arp.table, dw=8)
248 self.submodules.icmp = LiteEthICMP(self.ip, etherbone_ip_address, dw=8)
249 self.submodules.udp = LiteEthUDP(self.ip, etherbone_ip_address, dw=8)
250 # Etherbone
251 self.submodules.etherbone = LiteEthEtherbone(self.udp, 1234, mode="master")
252 self.add_wb_master(self.etherbone.wishbone.bus)
253
254 # Ethernet ---------------------------------------------------------------------------------
255 elif with_ethernet:
256 # Ethernet PHY
257 self.submodules.ethphy = LiteEthPHYModel(self.platform.request("eth", 0))
258 self.add_csr("ethphy")
259 # Ethernet MAC
260 ethmac = LiteEthMAC(phy=self.ethphy, dw=32,
261 interface = "wishbone",
262 endianness = self.cpu.endianness)
263 if with_etherbone:
264 ethmac = ClockDomainsRenamer({"eth_tx": "ethphy_eth_tx", "eth_rx": "ethphy_eth_rx"})(ethmac)
265 self.submodules.ethmac = ethmac
266 self.add_memory_region("ethmac", self.mem_map["ethmac"], 0x2000, type="io")
267 self.add_wb_slave(self.mem_regions["ethmac"].origin, self.ethmac.bus, 0x2000)
268 self.add_csr("ethmac")
269 self.add_interrupt("ethmac")
270
271 # Etherbone --------------------------------------------------------------------------------
272 elif with_etherbone:
273 # Ethernet PHY
274 self.submodules.ethphy = LiteEthPHYModel(self.platform.request("eth", 0)) # FIXME
275 self.add_csr("ethphy")
276 # Ethernet Core
277 ethcore = LiteEthUDPIPCore(self.ethphy,
278 mac_address = etherbone_mac_address,
279 ip_address = etherbone_ip_address,
280 clk_freq = sys_clk_freq)
281 self.submodules.ethcore = ethcore
282 # Etherbone
283 self.submodules.etherbone = LiteEthEtherbone(self.ethcore.udp, 1234, mode="master")
284 self.add_wb_master(self.etherbone.wishbone.bus)
285
286 # Analyzer ---------------------------------------------------------------------------------
287 if with_analyzer:
288 analyzer_signals = [
289 self.cpu.ibus.stb,
290 self.cpu.ibus.cyc,
291 self.cpu.ibus.adr,
292 self.cpu.ibus.we,
293 self.cpu.ibus.ack,
294 self.cpu.ibus.sel,
295 self.cpu.ibus.dat_w,
296 self.cpu.ibus.dat_r,
297 ]
298 self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals,
299 depth = 512,
300 clock_domain = "sys",
301 csr_csv = "analyzer.csv")
302 self.add_csr("analyzer")
303
304 # I2C --------------------------------------------------------------------------------------
305 if with_i2c:
306 pads = platform.request("i2c", 0)
307 self.submodules.i2c = I2CMasterSim(pads)
308 self.add_csr("i2c")
309
310 # SDCard -----------------------------------------------------------------------------------
311 if with_sdcard:
312 self.add_sdcard("sdcard", use_emulator=True)
313
314 # Build --------------------------------------------------------------------------------------------
315
316 def main():
317 parser = argparse.ArgumentParser(description="Generic LiteX SoC Simulation")
318 builder_args(parser)
319 soc_sdram_args(parser)
320 parser.add_argument("--threads", default=1, help="Set number of threads (default=1)")
321 parser.add_argument("--rom-init", default=None, help="rom_init file")
322 parser.add_argument("--ram-init", default=None, help="ram_init file")
323 parser.add_argument("--with-sdram", action="store_true", help="Enable SDRAM support")
324 parser.add_argument("--sdram-module", default="MT48LC16M16", help="Select SDRAM chip")
325 parser.add_argument("--sdram-data-width", default=32, help="Set SDRAM chip data width")
326 parser.add_argument("--sdram-init", default=None, help="SDRAM init file")
327 parser.add_argument("--sdram-from-spd-dump", default=None, help="Generate SDRAM module based on data from SPD EEPROM dump")
328 parser.add_argument("--sdram-verbosity", default=0, help="Set SDRAM checker verbosity")
329 parser.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support")
330 parser.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone support")
331 parser.add_argument("--local-ip", default="192.168.1.50", help="Local IP address of SoC (default=192.168.1.50)")
332 parser.add_argument("--remote-ip", default="192.168.1.100", help="Remote IP address of TFTP server (default=192.168.1.100)")
333 parser.add_argument("--with-analyzer", action="store_true", help="Enable Analyzer support")
334 parser.add_argument("--with-i2c", action="store_true", help="Enable I2C support")
335 parser.add_argument("--with-sdcard", action="store_true", help="Enable SDCard support")
336 parser.add_argument("--trace", action="store_true", help="Enable Tracing")
337 parser.add_argument("--trace-fst", action="store_true", help="Enable FST tracing (default=VCD)")
338 parser.add_argument("--trace-start", default=0, help="Cycle to start tracing")
339 parser.add_argument("--trace-end", default=-1, help="Cycle to end tracing")
340 parser.add_argument("--opt-level", default="O3", help="Compilation optimization level")
341 args = parser.parse_args()
342
343 soc_kwargs = soc_sdram_argdict(args)
344 builder_kwargs = builder_argdict(args)
345
346 sim_config = SimConfig(default_clk="sys_clk")
347
348 # Configuration --------------------------------------------------------------------------------
349
350 cpu = CPUS[soc_kwargs.get("cpu_type", "vexriscv")]
351 if soc_kwargs["uart_name"] == "serial":
352 soc_kwargs["uart_name"] = "sim"
353 sim_config.add_module("serial2console", "serial")
354 if args.rom_init:
355 soc_kwargs["integrated_rom_init"] = get_mem_data(args.rom_init, cpu.endianness)
356 if not args.with_sdram:
357 soc_kwargs["integrated_main_ram_size"] = 0x10000000 # 256 MB
358 if args.ram_init is not None:
359 soc_kwargs["integrated_main_ram_init"] = get_mem_data(args.ram_init, cpu.endianness)
360 else:
361 assert args.ram_init is None
362 soc_kwargs["integrated_main_ram_size"] = 0x0
363 soc_kwargs["sdram_module"] = args.sdram_module
364 soc_kwargs["sdram_data_width"] = int(args.sdram_data_width)
365 soc_kwargs["sdram_verbosity"] = int(args.sdram_verbosity)
366 if args.sdram_from_spd_dump:
367 soc_kwargs["sdram_spd_data"] = parse_spd_hexdump(args.sdram_from_spd_dump)
368
369 if args.with_ethernet or args.with_etherbone:
370 sim_config.add_module("ethernet", "eth", args={"interface": "tap0", "ip": args.remote_ip})
371
372 if args.with_i2c:
373 sim_config.add_module("spdeeprom", "i2c")
374
375 # SoC ------------------------------------------------------------------------------------------
376 soc = SimSoC(
377 with_sdram = args.with_sdram,
378 with_ethernet = args.with_ethernet,
379 with_etherbone = args.with_etherbone,
380 with_analyzer = args.with_analyzer,
381 with_i2c = args.with_i2c,
382 with_sdcard = args.with_sdcard,
383 sdram_init = [] if args.sdram_init is None else get_mem_data(args.sdram_init, cpu.endianness),
384 **soc_kwargs)
385 if args.ram_init is not None:
386 soc.add_constant("ROM_BOOT_ADDRESS", 0x40000000)
387 if args.with_ethernet:
388 for i in range(4):
389 soc.add_constant("LOCALIP{}".format(i+1), int(args.local_ip.split(".")[i]))
390 for i in range(4):
391 soc.add_constant("REMOTEIP{}".format(i+1), int(args.remote_ip.split(".")[i]))
392
393 # Build/Run ------------------------------------------------------------------------------------
394 builder_kwargs["csr_csv"] = "csr.csv"
395 builder = Builder(soc, **builder_kwargs)
396 vns = builder.build(run=False, threads=args.threads, sim_config=sim_config,
397 opt_level = args.opt_level,
398 trace = args.trace,
399 trace_fst = args.trace_fst,
400 trace_start = int(args.trace_start),
401 trace_end = int(args.trace_end))
402 if args.with_analyzer:
403 soc.analyzer.export_csv(vns, "analyzer.csv")
404 builder.build(build=False, threads=args.threads, sim_config=sim_config,
405 opt_level = args.opt_level,
406 trace = args.trace,
407 trace_fst = args.trace,
408 trace_start = int(args.trace_start),
409 trace_end = int(args.trace_end)
410 )
411
412 if __name__ == "__main__":
413 main()