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
['icp'] = 0xc0004000
64 self
.mem_map
['ics'] = 0xc0005000
65 self
.mem_map
['gpio'] = 0xc0007000
66 #self.csr_map["icp"] = 8 # 8 x 0x800 == 0x4000
67 #self.csr_map["ics"] = 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
['icp']
111 icp_wb
= self
.cpu
.xics_icp
112 icp_region
= SoCRegion(origin
=icp_addr
, size
=0x20, cached
=False)
113 self
.bus
.add_slave(name
='icp', slave
=icp_wb
, region
=icp_region
)
115 ics_addr
= self
.mem_map
['ics']
116 ics_wb
= self
.cpu
.xics_ics
117 ics_region
= SoCRegion(origin
=ics_addr
, size
=0x1000, cached
=False)
118 self
.bus
.add_slave(name
='ics', 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 ---------------------------------------------------------------
182 # setup running of DMI FSM
185 dmi_dout
= Signal(64)
191 dbg_dout
= Signal(64)
194 # capture pc from dmi
196 active_dbg
= Signal()
197 active_dbg_cr
= Signal()
198 active_dbg_xer
= Signal()
207 # increment counter, Stop after 100000 cycles
209 self
.sync
+= uptime
.eq(uptime
+ 1)
210 #self.sync += If(uptime == 1000000000000, Finish())
212 # DMI FSM counter and FSM itself
213 dmicount
= Signal(10)
214 dmirunning
= Signal(1)
215 dmi_monitor
= Signal(1)
217 self
.submodules
+= dmifsm
221 If(dmi_req
& dmi_wen
,
222 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
223 self
.cpu
.dmi_din
.eq(dmi_din
), # DMI in
224 self
.cpu
.dmi_req
.eq(1), # DMI request
225 self
.cpu
.dmi_wr
.eq(1), # DMI write
232 If(dmi_req
& ~dmi_wen
,
233 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
234 self
.cpu
.dmi_req
.eq(1), # DMI request
235 self
.cpu
.dmi_wr
.eq(0), # DMI read
237 # acknowledge received: capture data.
239 NextValue(dbg_addr
, dmi_addr
),
240 NextValue(dbg_dout
, self
.cpu
.dmi_dout
),
241 NextValue(dbg_msg
, 1),
248 # DMI response received: reset the dmi request and check if
252 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
254 NextState("START"), # back to start on next cycle
256 NextValue(dmi_req
, 0),
257 NextValue(dmi_addr
, 0),
258 NextValue(dmi_din
, 0),
259 NextValue(dmi_wen
, 0),
262 # "monitor" mode fires off a STAT request
263 dmifsm
.act("FIRE_MONITOR",
264 (NextValue(dmi_req
, 1),
265 NextValue(dmi_addr
, 1), # DMI STAT address
266 NextValue(dmi_din
, 0),
267 NextValue(dmi_wen
, 0), # read STAT
268 NextState("START"), # back to start on next cycle
272 self
.comb
+= xer_so
.eq((dbg_dout
& 1) == 1)
273 self
.comb
+= xer_ca
.eq((dbg_dout
& 4) == 4)
274 self
.comb
+= xer_ca32
.eq((dbg_dout
& 8) == 8)
275 self
.comb
+= xer_ov
.eq((dbg_dout
& 16) == 16)
276 self
.comb
+= xer_ov32
.eq((dbg_dout
& 32) == 32)
279 self
.sync
+= If(dbg_msg
,
280 (If(active_dbg
& (dbg_addr
== 0b10), # PC
281 Display("pc : %016x", dbg_dout
),
283 If(dbg_addr
== 0b10, # PC
284 pc
.eq(dbg_dout
), # capture PC
286 #If(dbg_addr == 0b11, # MSR
287 # Display(" msr: %016x", dbg_dout),
289 If(dbg_addr
== 0b1000, # CR
290 Display(" cr : %016x", dbg_dout
),
292 If(dbg_addr
== 0b1001, # XER
293 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
294 xer_so
, xer_ca
, xer_ca32
, xer_ov
, xer_ov32
),
296 If(dbg_addr
== 0b101, # GPR
297 Display(" gpr: %016x", dbg_dout
),
299 # also check if this is a "stat"
300 If(dbg_addr
== 1, # requested a STAT
301 #Display(" stat: %x", dbg_dout),
302 If(dbg_dout
& 2, # bit 2 of STAT is "stopped" mode
303 dmirunning
.eq(1), # continue running
304 dmi_monitor
.eq(0), # and stop monitor mode
312 self
.sync
+= If(uptime
== 0,
313 (dmi_addr
.eq(0), # CTRL
314 dmi_din
.eq(1<<0), # STOP
320 self
.sync
+= If(uptime
== 4,
324 self
.sync
+= If(dmirunning
,
325 dmicount
.eq(dmicount
+ 1),
328 # loop every 1<<N cycles
332 self
.sync
+= If(dmicount
== 4,
333 (dmi_addr
.eq(0b10), # NIA
340 self
.sync
+= If(dmicount
== 8,
341 (dmi_addr
.eq(0), # CTRL
342 dmi_din
.eq(1<<3), # STEP
345 dmirunning
.eq(0), # stop counter, need to fire "monitor"
346 dmi_monitor
.eq(1), # start "monitor" instead
350 # limit range of pc for debug reporting
351 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
352 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
353 self
.comb
+= active_dbg
.eq(1)
357 self
.sync
+= If(active_dbg
& (dmicount
== 12),
358 (dmi_addr
.eq(0b11), # MSR
364 if cpu
== "libresoc":
365 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
366 self
.comb
+= active_dbg_cr
.eq(0)
369 self
.sync
+= If(active_dbg_cr
& (dmicount
== 16),
370 (dmi_addr
.eq(0b1000), # CR
376 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
377 self
.comb
+= active_dbg_xer
.eq(active_dbg_cr
)
380 self
.sync
+= If(active_dbg_xer
& (dmicount
== 20),
381 (dmi_addr
.eq(0b1001), # XER
389 self
.sync
+= If(active_dbg
& (dmicount
== 24+(i
*8)),
390 (dmi_addr
.eq(0b100), # GSPR addr
397 self
.sync
+= If(active_dbg
& (dmicount
== 28+(i
*8)),
398 (dmi_addr
.eq(0b101), # GSPR data
404 # monitor bbus read/write
405 self
.sync
+= If(active_dbg
& self
.cpu
.dbus
.stb
& self
.cpu
.dbus
.ack
,
406 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
420 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
422 Display(" [%06x] iadr: %8x, s %01x w %016x",
431 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
433 Display(" [%06x] iadr: %8x, s %01x r %016x",
442 # Build -----------------------------------------------------------------------
445 parser
= argparse
.ArgumentParser(description
="LiteX LibreSoC CPU Sim")
446 parser
.add_argument("--cpu", default
="libresoc",
447 help="CPU to use: libresoc (default) or microwatt")
448 parser
.add_argument("--variant", default
="standardjtag",
449 help="Specify variant with different features")
450 parser
.add_argument("--debug", action
="store_true",
451 help="Enable debug traces")
452 parser
.add_argument("--trace", action
="store_true",
453 help="Enable tracing")
454 parser
.add_argument("--trace-start", default
=0,
455 help="Cycle to start FST tracing")
456 parser
.add_argument("--trace-end", default
=-1,
457 help="Cycle to end FST tracing")
458 args
= parser
.parse_args()
460 sim_config
= SimConfig(default_clk
="sys_clk")
461 sim_config
.add_module("serial2console", "serial")
462 sim_config
.add_module("jtagremote", "jtag", args
={'port': 44853})
465 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
, variant
=args
.variant
)
466 builder
= Builder(soc
,compile_gateware
= i
!=0)
467 builder
.build(sim_config
=sim_config
,
470 trace_start
= int(args
.trace_start
),
471 trace_end
= int(args
.trace_end
),
475 if __name__
== "__main__":