6 from migen
import (Signal
, FSM
, If
, Display
, Finish
, NextValue
, NextState
)
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
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
19 from litedram
import modules
as litedram_modules
20 from litedram
.phy
.model
import SDRAMPHYModel
21 from litedram
.phy
.gensdrphy
import GENSDRPHY
, HalfRateGENSDRPHY
23 from litex
.tools
.litex_sim
import sdram_module_nphases
, get_sdram_phy_settings
25 from litex
.tools
.litex_sim
import Platform
26 from libresoc
.ls180
import LS180Platform
28 from libresoc
import LibreSoC
29 from microwatt
import Microwatt
32 from litex
.soc
.integration
.soc
import SoCCSRHandler
33 SoCCSRHandler
.supported_address_width
.append(12)
35 # LibreSoCSim -----------------------------------------------------------------
37 class LibreSoCSim(SoCCore
):
38 def __init__(self
, cpu
="libresoc", debug
=False, with_sdram
=True,
39 sdram_module
= "AS4C16M16",
40 #sdram_data_width = 16,
41 #sdram_module = "MT48LC16M16",
42 sdram_data_width
= 16,
43 irq_reserved_irqs
= {'uart': 0},
46 assert cpu
in ["libresoc", "microwatt"]
47 sys_clk_freq
= int(100e6
)
52 elif platform
== 'ls180':
53 platform
= LS180Platform()
59 if cpu_data_width
== 32:
60 variant
= "standard32"
64 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
65 # "hello_world/hello_world.bin"
66 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
68 #ram_fname = "/tmp/test.bin"
70 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
71 # "micropython/firmware.bin"
72 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
73 # "tests/xics/xics.bin"
74 ram_fname
= "/home/lkcl/src/libresoc/microwatt/" \
75 "tests/decrementer/decrementer.bin"
76 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
77 # "hello_world/hello_world.bin"
79 # reserve XICS ICP and XICS memory addresses.
80 self
.mem_map
['icp'] = 0xc0004000
81 self
.mem_map
['ics'] = 0xc0005000
82 self
.mem_map
['gpio'] = 0xc0007000
83 #self.csr_map["icp"] = 8 # 8 x 0x800 == 0x4000
84 #self.csr_map["ics"] = 10 # 10 x 0x800 == 0x5000
88 #ram_init = get_mem_data({
89 # ram_fname: "0x00000000",
91 ram_init
= get_mem_data(ram_fname
, "little")
93 # remap the main RAM to reset-start-address
94 self
.mem_map
["main_ram"] = 0x00000000
96 # without sram nothing works, therefore move it to higher up
97 self
.mem_map
["sram"] = 0x90000000
99 # put UART at 0xc000200 (w00t! this works!)
100 self
.csr_map
["uart"] = 4
103 # SoCCore -------------------------------------------------------------
104 SoCCore
.__init
__(self
, platform
, clk_freq
=sys_clk_freq
,
105 cpu_type
= "microwatt",
106 cpu_cls
= LibreSoC
if cpu
== "libresoc" \
108 #bus_data_width = 64,
109 csr_address_width
= 12, # limit to 0x4000
110 cpu_variant
= variant
,
113 uart_name
= uart_name
,
114 with_sdram
= with_sdram
,
115 sdram_module
= sdram_module
,
116 sdram_data_width
= sdram_data_width
,
117 integrated_rom_size
= 0 if ram_fname
else 0x10000,
118 integrated_sram_size
= 0x40000,
119 #integrated_main_ram_init = ram_init,
120 integrated_main_ram_size
= 0x00000000 if with_sdram \
121 else 0x10000000 , # 256MB
123 self
.platform
.name
= "sim"
125 # SDR SDRAM ----------------------------------------------
126 if False: # not self.integrated_main_ram_size:
127 self
.submodules
.sdrphy
= sdrphy_cls(platform
.request("sdram"))
130 if cpu
== "libresoc":
131 # XICS interrupt devices
132 icp_addr
= self
.mem_map
['icp']
133 icp_wb
= self
.cpu
.xics_icp
134 icp_region
= SoCRegion(origin
=icp_addr
, size
=0x20, cached
=False)
135 self
.bus
.add_slave(name
='icp', slave
=icp_wb
, region
=icp_region
)
137 ics_addr
= self
.mem_map
['ics']
138 ics_wb
= self
.cpu
.xics_ics
139 ics_region
= SoCRegion(origin
=ics_addr
, size
=0x1000, cached
=False)
140 self
.bus
.add_slave(name
='ics', slave
=ics_wb
, region
=ics_region
)
142 # Simple GPIO peripheral
143 gpio_addr
= self
.mem_map
['gpio']
144 gpio_wb
= self
.cpu
.simple_gpio
145 gpio_region
= SoCRegion(origin
=gpio_addr
, size
=0x20, cached
=False)
146 self
.bus
.add_slave(name
='gpio', slave
=gpio_wb
, region
=gpio_region
)
149 # CRG -----------------------------------------------------------------
150 self
.submodules
.crg
= CRG(platform
.request("sys_clk"))
154 # SDRAM ----------------------------------------------------
156 sdram_clk_freq
= int(100e6
) # FIXME: use 100MHz timings
157 sdram_module_cls
= getattr(litedram_modules
, sdram_module
)
158 sdram_rate
= "1:{}".format(
159 sdram_module_nphases
[sdram_module_cls
.memtype
])
160 sdram_module
= sdram_module_cls(sdram_clk_freq
, sdram_rate
)
161 phy_settings
= get_sdram_phy_settings(
162 memtype
= sdram_module
.memtype
,
163 data_width
= sdram_data_width
,
164 clk_freq
= sdram_clk_freq
)
165 #sdrphy_cls = HalfRateGENSDRPHY
166 sdrphy_cls
= GENSDRPHY
167 self
.submodules
.sdrphy
= sdrphy_cls(platform
.request("sdram"))
168 #self.submodules.sdrphy = sdrphy_cls(sdram_module,
172 self
.add_sdram("sdram",
174 module
= sdram_module
,
175 origin
= self
.mem_map
["main_ram"],
177 l2_cache_size
= 0, # 8192
178 l2_cache_min_data_width
= 128,
179 l2_cache_reverse
= True
181 # FIXME: skip memtest to avoid corrupting memory
182 self
.add_constant("MEMTEST_BUS_SIZE", 128//16)
183 self
.add_constant("MEMTEST_DATA_SIZE", 128//16)
184 self
.add_constant("MEMTEST_ADDR_SIZE", 128//16)
185 self
.add_constant("MEMTEST_BUS_DEBUG", 1)
186 self
.add_constant("MEMTEST_ADDR_DEBUG", 1)
187 self
.add_constant("MEMTEST_DATA_DEBUG", 1)
190 # Debug ---------------------------------------------------------------
194 # setup running of DMI FSM
197 dmi_dout
= Signal(64)
203 dbg_dout
= Signal(64)
206 # capture pc from dmi
208 active_dbg
= Signal()
209 active_dbg_cr
= Signal()
210 active_dbg_xer
= Signal()
219 # increment counter, Stop after 100000 cycles
221 self
.sync
+= uptime
.eq(uptime
+ 1)
222 #self.sync += If(uptime == 1000000000000, Finish())
224 # DMI FSM counter and FSM itself
225 dmicount
= Signal(10)
226 dmirunning
= Signal(1)
227 dmi_monitor
= Signal(1)
229 self
.submodules
+= dmifsm
233 If(dmi_req
& dmi_wen
,
234 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
235 self
.cpu
.dmi_din
.eq(dmi_din
), # DMI in
236 self
.cpu
.dmi_req
.eq(1), # DMI request
237 self
.cpu
.dmi_wr
.eq(1), # DMI write
244 If(dmi_req
& ~dmi_wen
,
245 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
246 self
.cpu
.dmi_req
.eq(1), # DMI request
247 self
.cpu
.dmi_wr
.eq(0), # DMI read
249 # acknowledge received: capture data.
251 NextValue(dbg_addr
, dmi_addr
),
252 NextValue(dbg_dout
, self
.cpu
.dmi_dout
),
253 NextValue(dbg_msg
, 1),
260 # DMI response received: reset the dmi request and check if
264 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
266 NextState("START"), # back to start on next cycle
268 NextValue(dmi_req
, 0),
269 NextValue(dmi_addr
, 0),
270 NextValue(dmi_din
, 0),
271 NextValue(dmi_wen
, 0),
274 # "monitor" mode fires off a STAT request
275 dmifsm
.act("FIRE_MONITOR",
276 (NextValue(dmi_req
, 1),
277 NextValue(dmi_addr
, 1), # DMI STAT address
278 NextValue(dmi_din
, 0),
279 NextValue(dmi_wen
, 0), # read STAT
280 NextState("START"), # back to start on next cycle
284 self
.comb
+= xer_so
.eq((dbg_dout
& 1) == 1)
285 self
.comb
+= xer_ca
.eq((dbg_dout
& 4) == 4)
286 self
.comb
+= xer_ca32
.eq((dbg_dout
& 8) == 8)
287 self
.comb
+= xer_ov
.eq((dbg_dout
& 16) == 16)
288 self
.comb
+= xer_ov32
.eq((dbg_dout
& 32) == 32)
291 self
.sync
+= If(dbg_msg
,
292 (If(active_dbg
& (dbg_addr
== 0b10), # PC
293 Display("pc : %016x", dbg_dout
),
295 If(dbg_addr
== 0b10, # PC
296 pc
.eq(dbg_dout
), # capture PC
298 #If(dbg_addr == 0b11, # MSR
299 # Display(" msr: %016x", dbg_dout),
301 If(dbg_addr
== 0b1000, # CR
302 Display(" cr : %016x", dbg_dout
),
304 If(dbg_addr
== 0b1001, # XER
305 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
306 xer_so
, xer_ca
, xer_ca32
, xer_ov
, xer_ov32
),
308 If(dbg_addr
== 0b101, # GPR
309 Display(" gpr: %016x", dbg_dout
),
311 # also check if this is a "stat"
312 If(dbg_addr
== 1, # requested a STAT
313 #Display(" stat: %x", dbg_dout),
314 If(dbg_dout
& 2, # bit 2 of STAT is "stopped" mode
315 dmirunning
.eq(1), # continue running
316 dmi_monitor
.eq(0), # and stop monitor mode
324 self
.sync
+= If(uptime
== 0,
325 (dmi_addr
.eq(0), # CTRL
326 dmi_din
.eq(1<<0), # STOP
332 self
.sync
+= If(uptime
== 4,
336 self
.sync
+= If(dmirunning
,
337 dmicount
.eq(dmicount
+ 1),
340 # loop every 1<<N cycles
344 self
.sync
+= If(dmicount
== 4,
345 (dmi_addr
.eq(0b10), # NIA
352 self
.sync
+= If(dmicount
== 8,
353 (dmi_addr
.eq(0), # CTRL
354 dmi_din
.eq(1<<3), # STEP
357 dmirunning
.eq(0), # stop counter, need to fire "monitor"
358 dmi_monitor
.eq(1), # start "monitor" instead
362 # limit range of pc for debug reporting
363 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
364 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
365 self
.comb
+= active_dbg
.eq(1)
369 self
.sync
+= If(active_dbg
& (dmicount
== 12),
370 (dmi_addr
.eq(0b11), # MSR
376 if cpu
== "libresoc":
377 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
378 self
.comb
+= active_dbg_cr
.eq(0)
381 self
.sync
+= If(active_dbg_cr
& (dmicount
== 16),
382 (dmi_addr
.eq(0b1000), # CR
388 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
389 self
.comb
+= active_dbg_xer
.eq(active_dbg_cr
)
392 self
.sync
+= If(active_dbg_xer
& (dmicount
== 20),
393 (dmi_addr
.eq(0b1001), # XER
401 self
.sync
+= If(active_dbg
& (dmicount
== 24+(i
*8)),
402 (dmi_addr
.eq(0b100), # GSPR addr
409 self
.sync
+= If(active_dbg
& (dmicount
== 28+(i
*8)),
410 (dmi_addr
.eq(0b101), # GSPR data
416 # monitor bbus read/write
417 self
.sync
+= If(active_dbg
& self
.cpu
.dbus
.stb
& self
.cpu
.dbus
.ack
,
418 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
432 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
434 Display(" [%06x] iadr: %8x, s %01x w %016x",
443 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
445 Display(" [%06x] iadr: %8x, s %01x r %016x",
454 # Build -----------------------------------------------------------------------
457 parser
= argparse
.ArgumentParser(description
="LiteX LibreSoC CPU Sim")
458 parser
.add_argument("--cpu", default
="libresoc",
459 help="CPU to use: libresoc (default) or microwatt")
460 parser
.add_argument("--platform", default
="sim",
461 help="platform (sim or ls180)")
462 parser
.add_argument("--debug", action
="store_true",
463 help="Enable debug traces")
464 parser
.add_argument("--trace", action
="store_true",
465 help="Enable tracing")
466 parser
.add_argument("--trace-start", default
=0,
467 help="Cycle to start FST tracing")
468 parser
.add_argument("--trace-end", default
=-1,
469 help="Cycle to end FST tracing")
470 parser
.add_argument("--build", action
="store_true", help="Build bitstream")
471 args
= parser
.parse_args()
474 if args
.platform
== 'ls180':
475 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
,
476 platform
=args
.platform
)
478 builder
= Builder(soc
, compile_gateware
= True)
479 builder
.build(run
= True)
483 sim_config
= SimConfig(default_clk
="sys_clk")
484 sim_config
.add_module("serial2console", "serial")
487 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
,
488 platform
=args
.platform
)
489 builder
= Builder(soc
, compile_gateware
= i
!=0)
490 builder
.build(sim_config
=sim_config
,
493 trace_start
= int(args
.trace_start
),
494 trace_end
= int(args
.trace_end
),
498 if __name__
== "__main__":