2dd1874d74aa5f5653778e2fef54262508bff2b2
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 litex
.tools
.litex_sim
import sdram_module_nphases
, get_sdram_phy_settings
23 from litex
.tools
.litex_sim
import Platform
25 from libresoc
import LibreSoC
26 from microwatt
import Microwatt
29 from litex
.soc
.integration
.soc
import SoCCSRHandler
30 SoCCSRHandler
.supported_address_width
.append(12)
32 # LibreSoCSim -----------------------------------------------------------------
34 class LibreSoCSim(SoCSDRAM
):
35 def __init__(self
, cpu
="libresoc", variant
="standardjtag", debug
=False,
37 sdram_module
= "AS4C16M16",
38 #sdram_data_width = 16,
39 #sdram_module = "MT48LC16M16",
40 sdram_data_width
= 16,
41 irq_reserved_irqs
= {'uart': 0},
43 assert cpu
in ["libresoc", "microwatt"]
45 sys_clk_freq
= int(100e6
)
47 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
48 # "hello_world/hello_world.bin"
49 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
51 #ram_fname = "/tmp/test.bin"
52 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
53 # "micropython/firmware.bin"
54 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
55 # "tests/xics/xics.bin"
56 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
57 # "tests/decrementer/decrementer.bin"
58 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
59 # "hello_world/hello_world.bin"
62 # reserve XICS ICP and XICS memory addresses.
63 self
.mem_map
['xicsicp'] = 0xc0004000
64 self
.mem_map
['xicsics'] = 0xc0005000
65 self
.mem_map
['gpio'] = 0xc0007000
66 #self.csr_map["xicsicp"] = 8 # 8 x 0x800 == 0x4000
67 #self.csr_map["xicsics"] = 10 # 10 x 0x800 == 0x5000
71 #ram_init = get_mem_data({
72 # ram_fname: "0x00000000",
74 ram_init
= get_mem_data(ram_fname
, "little")
76 # remap the main RAM to reset-start-address
77 self
.mem_map
["main_ram"] = 0x00000000
79 # without sram nothing works, therefore move it to higher up
80 self
.mem_map
["sram"] = 0x90000000
82 # put UART at 0xc000200 (w00t! this works!)
83 self
.csr_map
["uart"] = 4
86 # SoCCore -------------------------------------------------------------
87 SoCSDRAM
.__init
__(self
, platform
, clk_freq
=sys_clk_freq
,
88 cpu_type
= "microwatt",
89 cpu_cls
= LibreSoC
if cpu
== "libresoc" \
92 csr_address_width
= 12, # limit to 0x4000
93 cpu_variant
= variant
,
97 with_sdram
= with_sdram
,
98 sdram_module
= sdram_module
,
99 sdram_data_width
= sdram_data_width
,
100 integrated_rom_size
= 0 if ram_fname
else 0x10000,
101 integrated_sram_size
= 0x40000,
102 #integrated_main_ram_init = ram_init,
103 integrated_main_ram_size
= 0x00000000 if with_sdram \
104 else 0x10000000 , # 256MB
106 self
.platform
.name
= "sim"
108 if cpu
== "libresoc":
109 # XICS interrupt devices
110 icp_addr
= self
.mem_map
['xicsicp']
111 icp_wb
= self
.cpu
.xics_icp
112 icp_region
= SoCRegion(origin
=icp_addr
, size
=0x20, cached
=False)
113 self
.bus
.add_slave(name
='xicsicp', slave
=icp_wb
, region
=icp_region
)
115 ics_addr
= self
.mem_map
['xicsics']
116 ics_wb
= self
.cpu
.xics_ics
117 ics_region
= SoCRegion(origin
=ics_addr
, size
=0x1000, cached
=False)
118 self
.bus
.add_slave(name
='xicsics', slave
=ics_wb
, region
=ics_region
)
120 if "gpio" in variant
:
121 # Simple GPIO peripheral
122 gpio_addr
= self
.mem_map
['gpio']
123 gpio_wb
= self
.cpu
.simple_gpio
124 gpio_region
= SoCRegion(origin
=gpio_addr
, size
=0x20, cached
=False)
125 self
.bus
.add_slave(name
='gpio', slave
=gpio_wb
, region
=gpio_region
)
128 # CRG -----------------------------------------------------------------
129 self
.submodules
.crg
= CRG(platform
.request("sys_clk"))
133 # SDRAM ----------------------------------------------------
135 sdram_clk_freq
= int(100e6
) # FIXME: use 100MHz timings
136 sdram_module_cls
= getattr(litedram_modules
, sdram_module
)
137 sdram_rate
= "1:{}".format(
138 sdram_module_nphases
[sdram_module_cls
.memtype
])
139 sdram_module
= sdram_module_cls(sdram_clk_freq
, sdram_rate
)
140 phy_settings
= get_sdram_phy_settings(
141 memtype
= sdram_module
.memtype
,
142 data_width
= sdram_data_width
,
143 clk_freq
= sdram_clk_freq
)
144 self
.submodules
.sdrphy
= SDRAMPHYModel(sdram_module
,
150 sdram_module
.geom_settings
,
151 sdram_module
.timing_settings
)
152 # FIXME: skip memtest to avoid corrupting memory
153 self
.add_constant("MEMTEST_BUS_SIZE", 128//16)
154 self
.add_constant("MEMTEST_DATA_SIZE", 128//16)
155 self
.add_constant("MEMTEST_ADDR_SIZE", 128//16)
156 self
.add_constant("MEMTEST_BUS_DEBUG", 1)
157 self
.add_constant("MEMTEST_ADDR_DEBUG", 1)
158 self
.add_constant("MEMTEST_DATA_DEBUG", 1)
161 # add JTAG platform pins
162 platform
.add_extension([
164 Subsignal("tck", Pins(1)),
165 Subsignal("tms", Pins(1)),
166 Subsignal("tdi", Pins(1)),
167 Subsignal("tdo", Pins(1)),
171 jtagpads
= platform
.request("jtag")
172 self
.comb
+= self
.cpu
.jtag_tck
.eq(jtagpads
.tck
)
173 self
.comb
+= self
.cpu
.jtag_tms
.eq(jtagpads
.tms
)
174 self
.comb
+= self
.cpu
.jtag_tdi
.eq(jtagpads
.tdi
)
175 self
.comb
+= jtagpads
.tdo
.eq(self
.cpu
.jtag_tdo
)
178 # Debug ---------------------------------------------------------------
179 # (enable with ./sim.py --debug)
183 # In debug mode, the DMI interface is used to perform single-step
184 # and dump of the full register set (MSR, r0-r31, CR, XER, PC).
185 # by running the exact same program with microwatt and libre-soc
186 # a straight "diff -u" of the complete progress dumps can be done
187 # and therefore computation instruction discrepancies found immediately
188 # and easily, running at "verilator" speed.
190 # the FSM is a bit of a dog's dinner, it relies on the way that DMI
191 # works, sending requests at periodic intervals. needs work. DoesTheJob.
193 # setup running of DMI FSM
196 dmi_dout
= Signal(64)
202 dbg_dout
= Signal(64)
205 # capture pc from dmi
207 active_dbg
= Signal()
208 active_dbg_cr
= Signal()
209 active_dbg_xer
= Signal()
218 # increment counter, Stop after 100000 cycles
220 self
.sync
+= uptime
.eq(uptime
+ 1)
221 #self.sync += If(uptime == 1000000000000, Finish())
223 # DMI FSM counter and FSM itself
224 dmicount
= Signal(10)
225 dmirunning
= Signal(1)
226 dmi_monitor
= Signal(1)
228 self
.submodules
+= dmifsm
232 If(dmi_req
& dmi_wen
,
233 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
234 self
.cpu
.dmi_din
.eq(dmi_din
), # DMI in
235 self
.cpu
.dmi_req
.eq(1), # DMI request
236 self
.cpu
.dmi_wr
.eq(1), # DMI write
243 If(dmi_req
& ~dmi_wen
,
244 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
245 self
.cpu
.dmi_req
.eq(1), # DMI request
246 self
.cpu
.dmi_wr
.eq(0), # DMI read
248 # acknowledge received: capture data.
250 NextValue(dbg_addr
, dmi_addr
),
251 NextValue(dbg_dout
, self
.cpu
.dmi_dout
),
252 NextValue(dbg_msg
, 1),
259 # DMI response received: reset the dmi request and check if
263 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
265 NextState("START"), # back to start on next cycle
267 NextValue(dmi_req
, 0),
268 NextValue(dmi_addr
, 0),
269 NextValue(dmi_din
, 0),
270 NextValue(dmi_wen
, 0),
273 # "monitor" mode fires off a STAT request
274 dmifsm
.act("FIRE_MONITOR",
275 (NextValue(dmi_req
, 1),
276 NextValue(dmi_addr
, 1), # DMI STAT address
277 NextValue(dmi_din
, 0),
278 NextValue(dmi_wen
, 0), # read STAT
279 NextState("START"), # back to start on next cycle
283 self
.comb
+= xer_so
.eq((dbg_dout
& 1) == 1)
284 self
.comb
+= xer_ca
.eq((dbg_dout
& 4) == 4)
285 self
.comb
+= xer_ca32
.eq((dbg_dout
& 8) == 8)
286 self
.comb
+= xer_ov
.eq((dbg_dout
& 16) == 16)
287 self
.comb
+= xer_ov32
.eq((dbg_dout
& 32) == 32)
290 self
.sync
+= If(dbg_msg
,
291 (If(active_dbg
& (dbg_addr
== 0b10), # PC
292 Display("pc : %016x", dbg_dout
),
294 If(dbg_addr
== 0b10, # PC
295 pc
.eq(dbg_dout
), # capture PC
297 #If(dbg_addr == 0b11, # MSR
298 # Display(" msr: %016x", dbg_dout),
300 If(dbg_addr
== 0b1000, # CR
301 Display(" cr : %016x", dbg_dout
),
303 If(dbg_addr
== 0b1001, # XER
304 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
305 xer_so
, xer_ca
, xer_ca32
, xer_ov
, xer_ov32
),
307 If(dbg_addr
== 0b101, # GPR
308 Display(" gpr: %016x", dbg_dout
),
310 # also check if this is a "stat"
311 If(dbg_addr
== 1, # requested a STAT
312 #Display(" stat: %x", dbg_dout),
313 If(dbg_dout
& 2, # bit 2 of STAT is "stopped" mode
314 dmirunning
.eq(1), # continue running
315 dmi_monitor
.eq(0), # and stop monitor mode
323 self
.sync
+= If(uptime
== 0,
324 (dmi_addr
.eq(0), # CTRL
325 dmi_din
.eq(1<<0), # STOP
331 self
.sync
+= If(uptime
== 4,
335 self
.sync
+= If(dmirunning
,
336 dmicount
.eq(dmicount
+ 1),
339 # loop every 1<<N cycles
343 self
.sync
+= If(dmicount
== 4,
344 (dmi_addr
.eq(0b10), # NIA
351 self
.sync
+= If(dmicount
== 8,
352 (dmi_addr
.eq(0), # CTRL
353 dmi_din
.eq(1<<3), # STEP
356 dmirunning
.eq(0), # stop counter, need to fire "monitor"
357 dmi_monitor
.eq(1), # start "monitor" instead
361 # limit range of pc for debug reporting
362 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
363 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
364 self
.comb
+= active_dbg
.eq(1)
368 self
.sync
+= If(active_dbg
& (dmicount
== 12),
369 (dmi_addr
.eq(0b11), # MSR
375 if cpu
== "libresoc": # XXX TODO: waiting on microwatt upstream patch
376 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
377 self
.comb
+= active_dbg_cr
.eq(0)
380 self
.sync
+= If(active_dbg_cr
& (dmicount
== 16),
381 (dmi_addr
.eq(0b1000), # CR
387 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
388 self
.comb
+= active_dbg_xer
.eq(active_dbg_cr
)
391 self
.sync
+= If(active_dbg_xer
& (dmicount
== 20),
392 (dmi_addr
.eq(0b1001), # XER
400 self
.sync
+= If(active_dbg
& (dmicount
== 24+(i
*8)),
401 (dmi_addr
.eq(0b100), # GSPR addr
408 self
.sync
+= If(active_dbg
& (dmicount
== 28+(i
*8)),
409 (dmi_addr
.eq(0b101), # GSPR data
415 # monitor bbus read/write
416 self
.sync
+= If(active_dbg
& self
.cpu
.dbus
.stb
& self
.cpu
.dbus
.ack
,
417 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
431 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
433 Display(" [%06x] iadr: %8x, s %01x w %016x",
442 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
444 Display(" [%06x] iadr: %8x, s %01x r %016x",
453 # Build -----------------------------------------------------------------------
456 parser
= argparse
.ArgumentParser(description
="LiteX LibreSoC CPU Sim")
457 parser
.add_argument("--cpu", default
="libresoc",
458 help="CPU to use: libresoc (default) or microwatt")
459 parser
.add_argument("--variant", default
="standardjtag",
460 help="Specify variant with different features")
461 parser
.add_argument("--debug", action
="store_true",
462 help="Enable debug traces")
463 parser
.add_argument("--trace", action
="store_true",
464 help="Enable tracing")
465 parser
.add_argument("--trace-start", default
=0,
466 help="Cycle to start FST tracing")
467 parser
.add_argument("--trace-end", default
=-1,
468 help="Cycle to end FST tracing")
469 args
= parser
.parse_args()
471 sim_config
= SimConfig(default_clk
="sys_clk")
472 sim_config
.add_module("serial2console", "serial")
473 sim_config
.add_module("jtagremote", "jtag", args
={'port': 44853})
476 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
, variant
=args
.variant
)
477 builder
= Builder(soc
,compile_gateware
= i
!=0)
478 builder
.build(sim_config
=sim_config
,
481 trace_start
= int(args
.trace_start
),
482 trace_end
= int(args
.trace_end
),
486 if __name__
== "__main__":