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>
12 from litex
.build
.generic_platform
import *
13 from litex
.build
.sim
import SimPlatform
14 from litex
.build
.sim
.config
import SimConfig
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
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
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 *
39 from litescope
import LiteScopeAnalyzer
41 # IOs ----------------------------------------------------------------------------------------------
44 ("sys_clk", 0, Pins(1)),
45 ("sys_rst", 0, Pins(1)),
47 Subsignal("source_valid", Pins(1)),
48 Subsignal("source_ready", Pins(1)),
49 Subsignal("source_data", Pins(8)),
51 Subsignal("sink_valid", Pins(1)),
52 Subsignal("sink_ready", Pins(1)),
53 Subsignal("sink_data", Pins(8)),
56 Subsignal("tx", Pins(1)),
57 Subsignal("rx", Pins(1)),
60 Subsignal("source_valid", Pins(1)),
61 Subsignal("source_ready", Pins(1)),
62 Subsignal("source_data", Pins(8)),
64 Subsignal("sink_valid", Pins(1)),
65 Subsignal("sink_ready", Pins(1)),
66 Subsignal("sink_data", Pins(8)),
69 Subsignal("scl", Pins(1)),
70 Subsignal("sda_out", Pins(1)),
71 Subsignal("sda_in", Pins(1)),
75 # Platform -----------------------------------------------------------------------------------------
77 class Platform(SimPlatform
):
79 SimPlatform
.__init
__(self
, "SIM", _io
)
81 # DFI PHY model settings ---------------------------------------------------------------------------
83 sdram_module_nphases
= {
92 def get_sdram_phy_settings(memtype
, data_width
, clk_freq
):
93 nphases
= sdram_module_nphases
[memtype
]
96 # Settings from gensdrphy
105 elif memtype
in ["DDR", "LPDDR"]:
106 # Settings from s6ddrphy
115 elif memtype
in ["DDR2", "DDR3"]:
116 # Settings from s7ddrphy
117 tck
= 2/(2*nphases
*clk_freq
)
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
)
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
140 sdram_phy_settings
= {
144 "rdcmdphase": rdcmdphase
,
145 "wrcmdphase": wrcmdphase
,
148 "read_latency": read_latency
,
149 "write_latency": write_latency
,
153 phytype
= "SDRAMPHYModel",
155 databits
= data_width
,
156 dfi_databits
= data_width
if memtype
== "SDR" else 2*data_width
,
157 **sdram_phy_settings
,
160 # Simulation SoC -----------------------------------------------------------------------------------
162 class SimSoC(SoCCore
):
164 "ethmac": 0xb0000000,
166 mem_map
.update(SoCCore
.mem_map
)
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",
177 sdram_data_width
= 32,
178 sdram_spd_data
= None,
183 platform
= Platform()
184 sys_clk_freq
= int(1e6
)
186 # SoCCore ----------------------------------------------------------------------------------
187 SoCCore
.__init
__(self
, platform
, clk_freq
=sys_clk_freq
,
188 ident
= "LiteX Simulation",
189 ident_version
= True,
192 # CRG --------------------------------------------------------------------------------------
193 self
.submodules
.crg
= CRG(platform
.request("sys_clk"))
195 # 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
)
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
,
214 self
.add_sdram("sdram",
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
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)
227 #assert not (with_ethernet and with_etherbone)
229 if with_ethernet
and with_etherbone
:
230 etherbone_ip_address
= convert_ip(etherbone_ip_address
)
232 self
.submodules
.ethphy
= LiteEthPHYModel(self
.platform
.request("eth", 0))
233 self
.add_csr("ethphy")
235 self
.submodules
.ethmac
= LiteEthMAC(phy
=self
.ethphy
, dw
=8,
236 interface
= "hybrid",
237 endianness
= self
.cpu
.endianness
,
238 hw_mac
= etherbone_mac_address
)
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")
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)
251 self
.submodules
.etherbone
= LiteEthEtherbone(self
.udp
, 1234, mode
="master")
252 self
.add_wb_master(self
.etherbone
.wishbone
.bus
)
254 # Ethernet ---------------------------------------------------------------------------------
257 self
.submodules
.ethphy
= LiteEthPHYModel(self
.platform
.request("eth", 0))
258 self
.add_csr("ethphy")
260 ethmac
= LiteEthMAC(phy
=self
.ethphy
, dw
=32,
261 interface
= "wishbone",
262 endianness
= self
.cpu
.endianness
)
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")
271 # Etherbone --------------------------------------------------------------------------------
274 self
.submodules
.ethphy
= LiteEthPHYModel(self
.platform
.request("eth", 0)) # FIXME
275 self
.add_csr("ethphy")
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
283 self
.submodules
.etherbone
= LiteEthEtherbone(self
.ethcore
.udp
, 1234, mode
="master")
284 self
.add_wb_master(self
.etherbone
.wishbone
.bus
)
286 # Analyzer ---------------------------------------------------------------------------------
298 self
.submodules
.analyzer
= LiteScopeAnalyzer(analyzer_signals
,
300 clock_domain
= "sys",
301 csr_csv
= "analyzer.csv")
302 self
.add_csr("analyzer")
304 # I2C --------------------------------------------------------------------------------------
306 pads
= platform
.request("i2c", 0)
307 self
.submodules
.i2c
= I2CMasterSim(pads
)
310 # SDCard -----------------------------------------------------------------------------------
312 self
.add_sdcard("sdcard", use_emulator
=True)
314 # Build --------------------------------------------------------------------------------------------
317 parser
= argparse
.ArgumentParser(description
="Generic LiteX SoC Simulation")
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()
343 soc_kwargs
= soc_sdram_argdict(args
)
344 builder_kwargs
= builder_argdict(args
)
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
)
350 # Configuration --------------------------------------------------------------------------------
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")
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
)
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
)
371 if args
.with_ethernet
or args
.with_etherbone
:
372 sim_config
.add_module("ethernet", "eth", args
={"interface": "tap0", "ip": args
.remote_ip
})
375 sim_config
.add_module("spdeeprom", "i2c")
377 # SoC ------------------------------------------------------------------------------------------
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
),
387 if args
.ram_init
is not None:
388 soc
.add_constant("ROM_BOOT_ADDRESS", 0x40000000)
389 if args
.with_ethernet
:
391 soc
.add_constant("LOCALIP{}".format(i
+1), int(args
.local_ip
.split(".")[i
]))
393 soc
.add_constant("REMOTEIP{}".format(i
+1), int(args
.remote_ip
.split(".")[i
]))
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
,
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
,
409 trace_fst
= args
.trace
,
410 trace_start
= int(args
.trace_start
),
411 trace_end
= int(args
.trace_end
)
414 if __name__
== "__main__":