c4d1b9d257fae4ce3bbf70e827816132e6a567d5
3 # Notes for "Debug" mode:
4 # both microwatt and Libre-SOC implement (pretty much) the same DMI
5 # interface. TBD: really, there should be an OPF Debug SIG which
6 # defines this properly. still, these two are interoperable.
7 # https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/debug/dmi.py
8 # https://github.com/antonblanchard/microwatt/blob/master/core_debug.vhdl
13 from migen
import (Signal
, FSM
, If
, Display
, Finish
, NextValue
, NextState
)
15 from litex
.build
.generic_platform
import Pins
, Subsignal
16 from litex
.build
.sim
import SimPlatform
17 from litex
.build
.io
import CRG
18 from litex
.build
.sim
.config
import SimConfig
20 from litex
.soc
.integration
.soc
import SoCRegion
21 from litex
.soc
.integration
.soc_core
import SoCCore
22 from litex
.soc
.integration
.soc_sdram
import SoCSDRAM
23 from litex
.soc
.integration
.builder
import Builder
24 from litex
.soc
.integration
.common
import get_mem_data
26 from litedram
import modules
as litedram_modules
27 from litedram
.phy
.model
import SDRAMPHYModel
28 from litex
.tools
.litex_sim
import sdram_module_nphases
, get_sdram_phy_settings
30 from litex
.tools
.litex_sim
import Platform
32 from libresoc
import LibreSoC
33 from microwatt
import Microwatt
36 from litex
.soc
.integration
.soc
import SoCCSRHandler
37 SoCCSRHandler
.supported_address_width
.append(12)
39 # LibreSoCSim -----------------------------------------------------------------
41 class LibreSoCSim(SoCSDRAM
):
42 def __init__(self
, cpu
="libresoc", variant
="standardjtag", debug
=False,
44 sdram_module
= "AS4C16M16",
45 #sdram_data_width = 16,
46 #sdram_module = "MT48LC16M16",
47 sdram_data_width
= 16,
48 irq_reserved_irqs
= {'uart': 0},
50 assert cpu
in ["libresoc", "microwatt"]
52 sys_clk_freq
= int(100e6
)
54 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
55 # "hello_world/hello_world.bin"
56 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
58 #ram_fname = "/tmp/test.bin"
59 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
60 # "micropython/firmware.bin"
61 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
62 # "tests/xics/xics.bin"
63 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
64 # "tests/decrementer/decrementer.bin"
65 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
66 # "hello_world/hello_world.bin"
67 ram_fname
= "/home/lkcl/src/libresoc/microwatt/" \
71 # reserve XICS ICP and XICS memory addresses.
72 self
.mem_map
['xicsicp'] = 0xc0004000
73 self
.mem_map
['xicsics'] = 0xc0005000
74 self
.mem_map
['gpio'] = 0xc0007000
75 #self.csr_map["xicsicp"] = 8 # 8 x 0x800 == 0x4000
76 #self.csr_map["xicsics"] = 10 # 10 x 0x800 == 0x5000
80 #ram_init = get_mem_data({
81 # ram_fname: "0x00000000",
83 ram_init
= get_mem_data(ram_fname
, "little")
85 # remap the main RAM to reset-start-address
86 self
.mem_map
["main_ram"] = 0x00000000
88 # without sram nothing works, therefore move it to higher up
89 self
.mem_map
["sram"] = 0x90000000
91 # put UART at 0xc000200 (w00t! this works!)
92 self
.csr_map
["uart"] = 4
95 # SoCCore -------------------------------------------------------------
96 SoCSDRAM
.__init
__(self
, platform
, clk_freq
=sys_clk_freq
,
97 cpu_type
= "microwatt",
98 cpu_cls
= LibreSoC
if cpu
== "libresoc" \
100 #bus_data_width = 64,
101 csr_address_width
= 12, # limit to 0x4000
102 cpu_variant
= variant
,
106 with_sdram
= with_sdram
,
107 sdram_module
= sdram_module
,
108 sdram_data_width
= sdram_data_width
,
109 integrated_rom_size
= 0 if ram_fname
else 0x10000,
110 integrated_sram_size
= 0x40000,
111 #integrated_main_ram_init = ram_init,
112 integrated_main_ram_size
= 0x00000000 if with_sdram \
113 else 0x10000000 , # 256MB
115 self
.platform
.name
= "sim"
117 if cpu
== "libresoc":
118 # XICS interrupt devices
119 icp_addr
= self
.mem_map
['xicsicp']
120 icp_wb
= self
.cpu
.xics_icp
121 icp_region
= SoCRegion(origin
=icp_addr
, size
=0x20, cached
=False)
122 self
.bus
.add_slave(name
='xicsicp', slave
=icp_wb
, region
=icp_region
)
124 ics_addr
= self
.mem_map
['xicsics']
125 ics_wb
= self
.cpu
.xics_ics
126 ics_region
= SoCRegion(origin
=ics_addr
, size
=0x1000, cached
=False)
127 self
.bus
.add_slave(name
='xicsics', slave
=ics_wb
, region
=ics_region
)
129 if "gpio" in variant
:
130 # Simple GPIO peripheral
131 gpio_addr
= self
.mem_map
['gpio']
132 gpio_wb
= self
.cpu
.simple_gpio
133 gpio_region
= SoCRegion(origin
=gpio_addr
, size
=0x20, cached
=False)
134 self
.bus
.add_slave(name
='gpio', slave
=gpio_wb
, region
=gpio_region
)
137 # CRG -----------------------------------------------------------------
138 self
.submodules
.crg
= CRG(platform
.request("sys_clk"))
142 # SDRAM ----------------------------------------------------
144 sdram_clk_freq
= int(100e6
) # FIXME: use 100MHz timings
145 sdram_module_cls
= getattr(litedram_modules
, sdram_module
)
146 sdram_rate
= "1:{}".format(
147 sdram_module_nphases
[sdram_module_cls
.memtype
])
148 sdram_module
= sdram_module_cls(sdram_clk_freq
, sdram_rate
)
149 phy_settings
= get_sdram_phy_settings(
150 memtype
= sdram_module
.memtype
,
151 data_width
= sdram_data_width
,
152 clk_freq
= sdram_clk_freq
)
153 self
.submodules
.sdrphy
= SDRAMPHYModel(sdram_module
,
159 sdram_module
.geom_settings
,
160 sdram_module
.timing_settings
)
161 # FIXME: skip memtest to avoid corrupting memory
162 self
.add_constant("MEMTEST_BUS_SIZE", 128//16)
163 self
.add_constant("MEMTEST_DATA_SIZE", 128//16)
164 self
.add_constant("MEMTEST_ADDR_SIZE", 128//16)
165 self
.add_constant("MEMTEST_BUS_DEBUG", 1)
166 self
.add_constant("MEMTEST_ADDR_DEBUG", 1)
167 self
.add_constant("MEMTEST_DATA_DEBUG", 1)
170 if "jtag" in variant
:
171 # add JTAG platform pins
172 platform
.add_extension([
174 Subsignal("tck", Pins(1)),
175 Subsignal("tms", Pins(1)),
176 Subsignal("tdi", Pins(1)),
177 Subsignal("tdo", Pins(1)),
181 jtagpads
= platform
.request("jtag")
182 self
.comb
+= self
.cpu
.jtag_tck
.eq(jtagpads
.tck
)
183 self
.comb
+= self
.cpu
.jtag_tms
.eq(jtagpads
.tms
)
184 self
.comb
+= self
.cpu
.jtag_tdi
.eq(jtagpads
.tdi
)
185 self
.comb
+= jtagpads
.tdo
.eq(self
.cpu
.jtag_tdo
)
188 # Debug ---------------------------------------------------------------
189 # (enable with ./sim.py --debug --variant=standard)
193 # In debug mode, the DMI interface is used to perform single-step
194 # and dump of the full register set (MSR, r0-r31, CR, XER, PC).
195 # by running the exact same program with microwatt and libre-soc
196 # a straight "diff -u" of the complete progress dumps can be done
197 # and therefore computation instruction discrepancies found immediately
198 # and easily, running at "verilator" speed.
200 # the FSM is a bit of a dog's dinner, it relies on the way that DMI
201 # works, sending requests at periodic intervals. needs work. DoesTheJob.
203 # setup running of DMI FSM
206 dmi_dout
= Signal(64)
212 dbg_dout
= Signal(64)
215 # capture pc from dmi
217 active_dbg
= Signal()
218 active_dbg_cr
= Signal()
219 active_dbg_xer
= Signal()
228 # increment counter, Stop after 100000 cycles
230 self
.sync
+= uptime
.eq(uptime
+ 1)
231 #self.sync += If(uptime == 1000000000000, Finish())
233 # DMI FSM counter and FSM itself
234 dmicount
= Signal(10)
235 dmirunning
= Signal(1)
236 dmi_monitor
= Signal(1)
238 self
.submodules
+= dmifsm
242 If(dmi_req
& dmi_wen
,
243 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
244 self
.cpu
.dmi_din
.eq(dmi_din
), # DMI in
245 self
.cpu
.dmi_req
.eq(1), # DMI request
246 self
.cpu
.dmi_wr
.eq(1), # DMI write
253 If(dmi_req
& ~dmi_wen
,
254 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
255 self
.cpu
.dmi_req
.eq(1), # DMI request
256 self
.cpu
.dmi_wr
.eq(0), # DMI read
258 # acknowledge received: capture data.
260 NextValue(dbg_addr
, dmi_addr
),
261 NextValue(dbg_dout
, self
.cpu
.dmi_dout
),
262 NextValue(dbg_msg
, 1),
269 # DMI response received: reset the dmi request and check if
273 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
275 NextState("START"), # back to start on next cycle
277 NextValue(dmi_req
, 0),
278 NextValue(dmi_addr
, 0),
279 NextValue(dmi_din
, 0),
280 NextValue(dmi_wen
, 0),
283 # "monitor" mode fires off a STAT request
284 dmifsm
.act("FIRE_MONITOR",
285 (NextValue(dmi_req
, 1),
286 NextValue(dmi_addr
, 1), # DMI STAT address
287 NextValue(dmi_din
, 0),
288 NextValue(dmi_wen
, 0), # read STAT
289 NextState("START"), # back to start on next cycle
293 self
.comb
+= xer_so
.eq((dbg_dout
& 1) == 1)
294 self
.comb
+= xer_ca
.eq((dbg_dout
& 4) == 4)
295 self
.comb
+= xer_ca32
.eq((dbg_dout
& 8) == 8)
296 self
.comb
+= xer_ov
.eq((dbg_dout
& 16) == 16)
297 self
.comb
+= xer_ov32
.eq((dbg_dout
& 32) == 32)
300 self
.sync
+= If(dbg_msg
,
301 (If(active_dbg
& (dbg_addr
== 0b10), # PC
302 Display("pc : %016x", dbg_dout
),
304 If(dbg_addr
== 0b10, # PC
305 pc
.eq(dbg_dout
), # capture PC
307 If(dbg_addr
== 0b11, # MSR
308 Display(" msr: %016x", dbg_dout
),
310 If(dbg_addr
== 0b1000, # CR
311 Display(" cr : %016x", dbg_dout
),
313 If(dbg_addr
== 0b1001, # XER
314 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
315 xer_so
, xer_ca
, xer_ca32
, xer_ov
, xer_ov32
),
317 If(dbg_addr
== 0b101, # GPR
318 Display(" gpr: %016x", dbg_dout
),
320 # also check if this is a "stat"
321 If(dbg_addr
== 1, # requested a STAT
322 #Display(" stat: %x", dbg_dout),
323 If(dbg_dout
& 2, # bit 2 of STAT is "stopped" mode
324 dmirunning
.eq(1), # continue running
325 dmi_monitor
.eq(0), # and stop monitor mode
333 self
.sync
+= If(uptime
== 0,
334 (dmi_addr
.eq(0), # CTRL
335 dmi_din
.eq(1<<0), # STOP
341 self
.sync
+= If(uptime
== 4,
345 self
.sync
+= If(dmirunning
,
346 dmicount
.eq(dmicount
+ 1),
349 # loop every 1<<N cycles
353 self
.sync
+= If(dmicount
== 4,
354 (dmi_addr
.eq(0b10), # NIA
361 self
.sync
+= If(dmicount
== 8,
362 (dmi_addr
.eq(0), # CTRL
363 dmi_din
.eq(1<<3), # STEP
366 dmirunning
.eq(0), # stop counter, need to fire "monitor"
367 dmi_monitor
.eq(1), # start "monitor" instead
371 # limit range of pc for debug reporting
372 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
373 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
374 self
.comb
+= active_dbg
.eq(1)
378 self
.sync
+= If(active_dbg
& (dmicount
== 12),
379 (dmi_addr
.eq(0b11), # MSR
385 if cpu
== "libresoc": # XXX TODO: waiting on microwatt upstream patch
386 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
387 self
.comb
+= active_dbg_cr
.eq(0)
390 self
.sync
+= If(active_dbg_cr
& (dmicount
== 16),
391 (dmi_addr
.eq(0b1000), # CR
397 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
398 self
.comb
+= active_dbg_xer
.eq(active_dbg_cr
)
401 self
.sync
+= If(active_dbg_xer
& (dmicount
== 20),
402 (dmi_addr
.eq(0b1001), # XER
410 self
.sync
+= If(active_dbg
& (dmicount
== 24+(i
*8)),
411 (dmi_addr
.eq(0b100), # GSPR addr
418 self
.sync
+= If(active_dbg
& (dmicount
== 28+(i
*8)),
419 (dmi_addr
.eq(0b101), # GSPR data
425 # monitor bbus read/write
426 self
.sync
+= If(active_dbg
& self
.cpu
.dbus
.stb
& self
.cpu
.dbus
.ack
,
427 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
441 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
443 Display(" [%06x] iadr: %8x, s %01x w %016x",
452 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
454 Display(" [%06x] iadr: %8x, s %01x r %016x",
463 # Build -----------------------------------------------------------------------
466 parser
= argparse
.ArgumentParser(description
="LiteX LibreSoC CPU Sim")
467 parser
.add_argument("--cpu", default
="libresoc",
468 help="CPU to use: libresoc (default) or microwatt")
469 parser
.add_argument("--variant", default
="standardjtag",
470 help="Specify variant with different features")
471 parser
.add_argument("--debug", action
="store_true",
472 help="Enable debug traces")
473 parser
.add_argument("--trace", action
="store_true",
474 help="Enable tracing")
475 parser
.add_argument("--trace-start", default
=0,
476 help="Cycle to start FST tracing")
477 parser
.add_argument("--trace-end", default
=-1,
478 help="Cycle to end FST tracing")
479 args
= parser
.parse_args()
481 sim_config
= SimConfig(default_clk
="sys_clk")
482 sim_config
.add_module("serial2console", "serial")
483 sim_config
.add_module("jtagremote", "jtag", args
={'port': 44853})
486 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
, variant
=args
.variant
)
487 builder
= Builder(soc
,compile_gateware
= i
!=0)
488 builder
.build(sim_config
=sim_config
,
491 trace_start
= int(args
.trace_start
),
492 trace_end
= int(args
.trace_end
),
496 if __name__
== "__main__":