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
.soc
.cores
.gpio
import GPIOInOut
, GPIOIn
, GPIOOut
, GPIOTristate
24 from litex
.soc
.cores
.spi
import SPIMaster
26 from litex
.tools
.litex_sim
import sdram_module_nphases
, get_sdram_phy_settings
28 from litex
.tools
.litex_sim
import Platform
29 from libresoc
.ls180
import LS180Platform
31 from migen
import Module
32 from litex
.soc
.interconnect
.csr
import AutoCSR
34 from libresoc
import LibreSoC
35 from microwatt
import Microwatt
38 from litex
.soc
.integration
.soc
import SoCCSRHandler
39 SoCCSRHandler
.supported_address_width
.append(12)
42 # LibreSoCSim -----------------------------------------------------------------
44 class LibreSoCSim(SoCCore
):
45 def __init__(self
, cpu
="libresoc", debug
=False, with_sdram
=True,
46 sdram_module
= "AS4C16M16",
47 #sdram_data_width = 16,
48 #sdram_module = "MT48LC16M16",
49 sdram_data_width
= 16,
50 irq_reserved_irqs
= {'uart': 0},
53 assert cpu
in ["libresoc", "microwatt"]
54 sys_clk_freq
= int(50e6
)
59 elif platform
== 'ls180':
60 platform
= LS180Platform()
68 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
69 # "hello_world/hello_world.bin"
70 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
72 #ram_fname = "/tmp/test.bin"
74 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
75 # "micropython/firmware.bin"
76 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
77 # "tests/xics/xics.bin"
78 ram_fname
= "/home/lkcl/src/libresoc/microwatt/" \
79 "tests/decrementer/decrementer.bin"
80 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
81 # "hello_world/hello_world.bin"
83 # reserve XICS ICP and XICS memory addresses.
84 self
.mem_map
['icp'] = 0xc0010000
85 self
.mem_map
['ics'] = 0xc0011000
86 #self.csr_map["icp"] = 8 # 8 x 0x800 == 0x4000
87 #self.csr_map["ics"] = 10 # 10 x 0x800 == 0x5000
91 #ram_init = get_mem_data({
92 # ram_fname: "0x00000000",
94 ram_init
= get_mem_data(ram_fname
, "little")
96 # remap the main RAM to reset-start-address
97 self
.mem_map
["main_ram"] = 0x00000000
99 # without sram nothing works, therefore move it to higher up
100 self
.mem_map
["sram"] = 0x90000000
102 # put UART at 0xc000200 (w00t! this works!)
103 self
.csr_map
["uart"] = 4
106 # SoCCore -------------------------------------------------------------
107 SoCCore
.__init
__(self
, platform
, clk_freq
=sys_clk_freq
,
108 cpu_type
= "microwatt",
109 cpu_cls
= LibreSoC
if cpu
== "libresoc" \
111 #bus_data_width = 64,
112 csr_address_width
= 14, # limit to 0x8000
113 cpu_variant
= variant
,
116 uart_name
= uart_name
,
117 with_sdram
= with_sdram
,
118 sdram_module
= sdram_module
,
119 sdram_data_width
= sdram_data_width
,
120 integrated_rom_size
= 0 if ram_fname
else 0x10000,
121 integrated_sram_size
= 0x40000,
122 #integrated_main_ram_init = ram_init,
123 integrated_main_ram_size
= 0x00000000 if with_sdram \
124 else 0x10000000 , # 256MB
126 self
.platform
.name
= "ls180"
128 # SDR SDRAM ----------------------------------------------
129 if False: # not self.integrated_main_ram_size:
130 self
.submodules
.sdrphy
= sdrphy_cls(platform
.request("sdram"))
133 if cpu
== "libresoc":
134 # XICS interrupt devices
135 icp_addr
= self
.mem_map
['icp']
136 icp_wb
= self
.cpu
.xics_icp
137 icp_region
= SoCRegion(origin
=icp_addr
, size
=0x20, cached
=False)
138 self
.bus
.add_slave(name
='icp', slave
=icp_wb
, region
=icp_region
)
140 ics_addr
= self
.mem_map
['ics']
141 ics_wb
= self
.cpu
.xics_ics
142 ics_region
= SoCRegion(origin
=ics_addr
, size
=0x1000, cached
=False)
143 self
.bus
.add_slave(name
='ics', slave
=ics_wb
, region
=ics_region
)
145 # CRG -----------------------------------------------------------------
146 self
.submodules
.crg
= CRG(platform
.request("sys_clk"))
150 # SDRAM ----------------------------------------------------
152 sdram_clk_freq
= int(100e6
) # FIXME: use 100MHz timings
153 sdram_module_cls
= getattr(litedram_modules
, sdram_module
)
154 sdram_rate
= "1:{}".format(
155 sdram_module_nphases
[sdram_module_cls
.memtype
])
156 sdram_module
= sdram_module_cls(sdram_clk_freq
, sdram_rate
)
157 phy_settings
= get_sdram_phy_settings(
158 memtype
= sdram_module
.memtype
,
159 data_width
= sdram_data_width
,
160 clk_freq
= sdram_clk_freq
)
161 #sdrphy_cls = HalfRateGENSDRPHY
162 sdrphy_cls
= GENSDRPHY
163 self
.submodules
.sdrphy
= sdrphy_cls(platform
.request("sdram"))
164 #self.submodules.sdrphy = sdrphy_cls(sdram_module,
168 self
.add_sdram("sdram",
170 module
= sdram_module
,
171 origin
= self
.mem_map
["main_ram"],
173 l2_cache_size
= 0, # 8192
174 l2_cache_min_data_width
= 128,
175 l2_cache_reverse
= True
177 # FIXME: skip memtest to avoid corrupting memory
178 self
.add_constant("MEMTEST_BUS_SIZE", 128//16)
179 self
.add_constant("MEMTEST_DATA_SIZE", 128//16)
180 self
.add_constant("MEMTEST_ADDR_SIZE", 128//16)
181 self
.add_constant("MEMTEST_BUS_DEBUG", 1)
182 self
.add_constant("MEMTEST_ADDR_DEBUG", 1)
183 self
.add_constant("MEMTEST_DATA_DEBUG", 1)
186 #platform.add_extension([("gpio_in", 0, Pins(8))])
187 self
.submodules
.gpio_in
= GPIOIn(platform
.request("gpio_in"))
188 self
.add_csr("gpio_in")
189 self
.submodules
.gpio_out
= GPIOIn(platform
.request("gpio_out"))
190 self
.add_csr("gpio_out")
193 self
.submodules
.gpio
= GPIOTristate(platform
.request("gpio"))
197 self
.submodules
.spi_master
= SPIMaster(
198 pads
= platform
.request("spi_master"),
200 sys_clk_freq
= sys_clk_freq
,
203 self
.add_csr("spi_master")
205 # EINTs - very simple, wire up top 3 bits to ls180 "eint" pins
206 self
.comb
+= self
.cpu
.interrupt
[12:16].eq(platform
.request("eint"))
208 # Debug ---------------------------------------------------------------
212 # setup running of DMI FSM
215 dmi_dout
= Signal(64)
221 dbg_dout
= Signal(64)
224 # capture pc from dmi
226 active_dbg
= Signal()
227 active_dbg_cr
= Signal()
228 active_dbg_xer
= Signal()
237 # increment counter, Stop after 100000 cycles
239 self
.sync
+= uptime
.eq(uptime
+ 1)
240 #self.sync += If(uptime == 1000000000000, Finish())
242 # DMI FSM counter and FSM itself
243 dmicount
= Signal(10)
244 dmirunning
= Signal(1)
245 dmi_monitor
= Signal(1)
247 self
.submodules
+= dmifsm
251 If(dmi_req
& dmi_wen
,
252 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
253 self
.cpu
.dmi_din
.eq(dmi_din
), # DMI in
254 self
.cpu
.dmi_req
.eq(1), # DMI request
255 self
.cpu
.dmi_wr
.eq(1), # DMI write
262 If(dmi_req
& ~dmi_wen
,
263 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
264 self
.cpu
.dmi_req
.eq(1), # DMI request
265 self
.cpu
.dmi_wr
.eq(0), # DMI read
267 # acknowledge received: capture data.
269 NextValue(dbg_addr
, dmi_addr
),
270 NextValue(dbg_dout
, self
.cpu
.dmi_dout
),
271 NextValue(dbg_msg
, 1),
278 # DMI response received: reset the dmi request and check if
282 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
284 NextState("START"), # back to start on next cycle
286 NextValue(dmi_req
, 0),
287 NextValue(dmi_addr
, 0),
288 NextValue(dmi_din
, 0),
289 NextValue(dmi_wen
, 0),
292 # "monitor" mode fires off a STAT request
293 dmifsm
.act("FIRE_MONITOR",
294 (NextValue(dmi_req
, 1),
295 NextValue(dmi_addr
, 1), # DMI STAT address
296 NextValue(dmi_din
, 0),
297 NextValue(dmi_wen
, 0), # read STAT
298 NextState("START"), # back to start on next cycle
302 self
.comb
+= xer_so
.eq((dbg_dout
& 1) == 1)
303 self
.comb
+= xer_ca
.eq((dbg_dout
& 4) == 4)
304 self
.comb
+= xer_ca32
.eq((dbg_dout
& 8) == 8)
305 self
.comb
+= xer_ov
.eq((dbg_dout
& 16) == 16)
306 self
.comb
+= xer_ov32
.eq((dbg_dout
& 32) == 32)
309 self
.sync
+= If(dbg_msg
,
310 (If(active_dbg
& (dbg_addr
== 0b10), # PC
311 Display("pc : %016x", dbg_dout
),
313 If(dbg_addr
== 0b10, # PC
314 pc
.eq(dbg_dout
), # capture PC
316 #If(dbg_addr == 0b11, # MSR
317 # Display(" msr: %016x", dbg_dout),
319 If(dbg_addr
== 0b1000, # CR
320 Display(" cr : %016x", dbg_dout
),
322 If(dbg_addr
== 0b1001, # XER
323 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
324 xer_so
, xer_ca
, xer_ca32
, xer_ov
, xer_ov32
),
326 If(dbg_addr
== 0b101, # GPR
327 Display(" gpr: %016x", dbg_dout
),
329 # also check if this is a "stat"
330 If(dbg_addr
== 1, # requested a STAT
331 #Display(" stat: %x", dbg_dout),
332 If(dbg_dout
& 2, # bit 2 of STAT is "stopped" mode
333 dmirunning
.eq(1), # continue running
334 dmi_monitor
.eq(0), # and stop monitor mode
342 self
.sync
+= If(uptime
== 0,
343 (dmi_addr
.eq(0), # CTRL
344 dmi_din
.eq(1<<0), # STOP
350 self
.sync
+= If(uptime
== 4,
354 self
.sync
+= If(dmirunning
,
355 dmicount
.eq(dmicount
+ 1),
358 # loop every 1<<N cycles
362 self
.sync
+= If(dmicount
== 4,
363 (dmi_addr
.eq(0b10), # NIA
370 self
.sync
+= If(dmicount
== 8,
371 (dmi_addr
.eq(0), # CTRL
372 dmi_din
.eq(1<<3), # STEP
375 dmirunning
.eq(0), # stop counter, need to fire "monitor"
376 dmi_monitor
.eq(1), # start "monitor" instead
380 # limit range of pc for debug reporting
381 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
382 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
383 self
.comb
+= active_dbg
.eq(1)
387 self
.sync
+= If(active_dbg
& (dmicount
== 12),
388 (dmi_addr
.eq(0b11), # MSR
394 if cpu
== "libresoc":
395 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
396 self
.comb
+= active_dbg_cr
.eq(0)
399 self
.sync
+= If(active_dbg_cr
& (dmicount
== 16),
400 (dmi_addr
.eq(0b1000), # CR
406 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
407 self
.comb
+= active_dbg_xer
.eq(active_dbg_cr
)
410 self
.sync
+= If(active_dbg_xer
& (dmicount
== 20),
411 (dmi_addr
.eq(0b1001), # XER
419 self
.sync
+= If(active_dbg
& (dmicount
== 24+(i
*8)),
420 (dmi_addr
.eq(0b100), # GSPR addr
427 self
.sync
+= If(active_dbg
& (dmicount
== 28+(i
*8)),
428 (dmi_addr
.eq(0b101), # GSPR data
434 # monitor bbus read/write
435 self
.sync
+= If(active_dbg
& self
.cpu
.dbus
.stb
& self
.cpu
.dbus
.ack
,
436 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
450 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
452 Display(" [%06x] iadr: %8x, s %01x w %016x",
461 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
463 Display(" [%06x] iadr: %8x, s %01x r %016x",
472 # Build -----------------------------------------------------------------------
475 parser
= argparse
.ArgumentParser(description
="LiteX LibreSoC CPU Sim")
476 parser
.add_argument("--cpu", default
="libresoc",
477 help="CPU to use: libresoc (default) or microwatt")
478 parser
.add_argument("--platform", default
="sim",
479 help="platform (sim or ls180)")
480 parser
.add_argument("--debug", action
="store_true",
481 help="Enable debug traces")
482 parser
.add_argument("--trace", action
="store_true",
483 help="Enable tracing")
484 parser
.add_argument("--trace-start", default
=0,
485 help="Cycle to start FST tracing")
486 parser
.add_argument("--trace-end", default
=-1,
487 help="Cycle to end FST tracing")
488 parser
.add_argument("--build", action
="store_true", help="Build bitstream")
489 args
= parser
.parse_args()
492 if args
.platform
== 'ls180':
493 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
,
494 platform
=args
.platform
)
497 builder
= Builder(soc
, compile_gateware
= True)
498 builder
.build(run
= True)
502 sim_config
= SimConfig(default_clk
="sys_clk")
503 sim_config
.add_module("serial2console", "serial")
506 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
,
507 platform
=args
.platform
)
508 builder
= Builder(soc
, compile_gateware
= i
!=0)
509 builder
.build(sim_config
=sim_config
,
512 trace_start
= int(args
.trace_start
),
513 trace_end
= int(args
.trace_end
),
517 if __name__
== "__main__":