build/sim: use a real timebase in the simulation
[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 # timebase is half of the period of main simulation clock
347 sys_clk_freq = int(1e6)
348 sim_config = SimConfig(default_clk="sys_clk", timebase_ps=(1/sys_clk_freq / 2) * 1e12)
349
350 # Configuration --------------------------------------------------------------------------------
351
352 cpu = CPUS[soc_kwargs.get("cpu_type", "vexriscv")]
353 if soc_kwargs["uart_name"] == "serial":
354 soc_kwargs["uart_name"] = "sim"
355 sim_config.add_module("serial2console", "serial")
356 if args.rom_init:
357 soc_kwargs["integrated_rom_init"] = get_mem_data(args.rom_init, cpu.endianness)
358 if not args.with_sdram:
359 soc_kwargs["integrated_main_ram_size"] = 0x10000000 # 256 MB
360 if args.ram_init is not None:
361 soc_kwargs["integrated_main_ram_init"] = get_mem_data(args.ram_init, cpu.endianness)
362 else:
363 assert args.ram_init is None
364 soc_kwargs["integrated_main_ram_size"] = 0x0
365 soc_kwargs["sdram_module"] = args.sdram_module
366 soc_kwargs["sdram_data_width"] = int(args.sdram_data_width)
367 soc_kwargs["sdram_verbosity"] = int(args.sdram_verbosity)
368 if args.sdram_from_spd_dump:
369 soc_kwargs["sdram_spd_data"] = parse_spd_hexdump(args.sdram_from_spd_dump)
370
371 if args.with_ethernet or args.with_etherbone:
372 sim_config.add_module("ethernet", "eth", args={"interface": "tap0", "ip": args.remote_ip})
373
374 if args.with_i2c:
375 sim_config.add_module("spdeeprom", "i2c")
376
377 # SoC ------------------------------------------------------------------------------------------
378 soc = SimSoC(
379 with_sdram = args.with_sdram,
380 with_ethernet = args.with_ethernet,
381 with_etherbone = args.with_etherbone,
382 with_analyzer = args.with_analyzer,
383 with_i2c = args.with_i2c,
384 with_sdcard = args.with_sdcard,
385 sdram_init = [] if args.sdram_init is None else get_mem_data(args.sdram_init, cpu.endianness),
386 **soc_kwargs)
387 if args.ram_init is not None:
388 soc.add_constant("ROM_BOOT_ADDRESS", 0x40000000)
389 if args.with_ethernet:
390 for i in range(4):
391 soc.add_constant("LOCALIP{}".format(i+1), int(args.local_ip.split(".")[i]))
392 for i in range(4):
393 soc.add_constant("REMOTEIP{}".format(i+1), int(args.remote_ip.split(".")[i]))
394
395 # Build/Run ------------------------------------------------------------------------------------
396 builder_kwargs["csr_csv"] = "csr.csv"
397 builder = Builder(soc, **builder_kwargs)
398 vns = builder.build(run=False, threads=args.threads, sim_config=sim_config,
399 opt_level = args.opt_level,
400 trace = args.trace,
401 trace_fst = args.trace_fst,
402 trace_start = int(args.trace_start),
403 trace_end = int(args.trace_end))
404 if args.with_analyzer:
405 soc.analyzer.export_csv(vns, "analyzer.csv")
406 builder.build(build=False, threads=args.threads, sim_config=sim_config,
407 opt_level = args.opt_level,
408 trace = args.trace,
409 trace_fst = args.trace,
410 trace_start = int(args.trace_start),
411 trace_end = int(args.trace_end)
412 )
413
414 if __name__ == "__main__":
415 main()