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