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", debug
=False, with_sdram
=True,
36 sdram_module
= "AS4C16M16",
37 #sdram_data_width = 16,
38 #sdram_module = "MT48LC16M16",
39 sdram_data_width
= 16,
40 irq_reserved_irqs
= {'uart': 0},
42 assert cpu
in ["libresoc", "microwatt"]
44 sys_clk_freq
= int(100e6
)
49 if cpu_data_width
== 32:
50 variant
= "standard32"
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"
60 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
61 # "micropython/firmware.bin"
62 ram_fname
= "/home/lkcl/src/libresoc/microwatt/" \
64 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
65 # "hello_world/hello_world.bin"
67 # reserve XICS ICP and XICS memory addresses.
68 self
.mem_map
['icp'] = 0xc0004000
69 self
.mem_map
['ics'] = 0xc0005000
70 self
.mem_map
['gpio'] = 0xc0007000
71 #self.csr_map["icp"] = 8 # 8 x 0x800 == 0x4000
72 #self.csr_map["ics"] = 10 # 10 x 0x800 == 0x5000
76 #ram_init = get_mem_data({
77 # ram_fname: "0x00000000",
79 ram_init
= get_mem_data(ram_fname
, "little")
81 # remap the main RAM to reset-start-address
82 self
.mem_map
["main_ram"] = 0x00000000
84 # without sram nothing works, therefore move it to higher up
85 self
.mem_map
["sram"] = 0x90000000
87 # put UART at 0xc000200 (w00t! this works!)
88 self
.csr_map
["uart"] = 4
91 # SoCCore -------------------------------------------------------------
92 SoCSDRAM
.__init
__(self
, platform
, clk_freq
=sys_clk_freq
,
93 cpu_type
= "microwatt",
94 cpu_cls
= LibreSoC
if cpu
== "libresoc" \
97 csr_address_width
= 12, # limit to 0x4000
98 cpu_variant
= variant
,
102 with_sdram
= with_sdram
,
103 sdram_module
= sdram_module
,
104 sdram_data_width
= sdram_data_width
,
105 integrated_rom_size
= 0 if ram_fname
else 0x10000,
106 integrated_sram_size
= 0x40000,
107 #integrated_main_ram_init = ram_init,
108 integrated_main_ram_size
= 0x00000000 if with_sdram \
109 else 0x10000000 , # 256MB
111 self
.platform
.name
= "sim"
113 if cpu
== "libresoc":
114 # XICS interrupt devices
115 icp_addr
= self
.mem_map
['icp']
116 icp_wb
= self
.cpu
.xics_icp
117 icp_region
= SoCRegion(origin
=icp_addr
, size
=0x1000, cached
=False)
118 self
.bus
.add_slave(name
='icp', slave
=icp_wb
, region
=icp_region
)
120 ics_addr
= self
.mem_map
['ics']
121 ics_wb
= self
.cpu
.xics_ics
122 ics_region
= SoCRegion(origin
=ics_addr
, size
=0x20, cached
=False)
123 self
.bus
.add_slave(name
='ics', slave
=ics_wb
, region
=ics_region
)
125 # Simple GPIO peripheral
126 gpio_addr
= self
.mem_map
['gpio']
127 gpio_wb
= self
.cpu
.simple_gpio
128 gpio_region
= SoCRegion(origin
=gpio_addr
, size
=0x20, cached
=False)
129 self
.bus
.add_slave(name
='gpio', slave
=gpio_wb
, region
=gpio_region
)
132 # CRG -----------------------------------------------------------------
133 self
.submodules
.crg
= CRG(platform
.request("sys_clk"))
137 # SDRAM ----------------------------------------------------
139 sdram_clk_freq
= int(100e6
) # FIXME: use 100MHz timings
140 sdram_module_cls
= getattr(litedram_modules
, sdram_module
)
141 sdram_rate
= "1:{}".format(
142 sdram_module_nphases
[sdram_module_cls
.memtype
])
143 sdram_module
= sdram_module_cls(sdram_clk_freq
, sdram_rate
)
144 phy_settings
= get_sdram_phy_settings(
145 memtype
= sdram_module
.memtype
,
146 data_width
= sdram_data_width
,
147 clk_freq
= sdram_clk_freq
)
148 self
.submodules
.sdrphy
= SDRAMPHYModel(sdram_module
,
154 sdram_module
.geom_settings
,
155 sdram_module
.timing_settings
)
156 # FIXME: skip memtest to avoid corrupting memory
157 self
.add_constant("MEMTEST_BUS_SIZE", 128//16)
158 self
.add_constant("MEMTEST_DATA_SIZE", 128//16)
159 self
.add_constant("MEMTEST_ADDR_SIZE", 128//16)
160 self
.add_constant("MEMTEST_BUS_DEBUG", 1)
161 self
.add_constant("MEMTEST_ADDR_DEBUG", 1)
162 self
.add_constant("MEMTEST_DATA_DEBUG", 1)
165 # Debug ---------------------------------------------------------------
169 # setup running of DMI FSM
172 dmi_dout
= Signal(64)
178 dbg_dout
= Signal(64)
181 # capture pc from dmi
183 active_dbg
= Signal()
184 active_dbg_cr
= Signal()
185 active_dbg_xer
= Signal()
194 # increment counter, Stop after 100000 cycles
196 self
.sync
+= uptime
.eq(uptime
+ 1)
197 #self.sync += If(uptime == 1000000000000, Finish())
199 # DMI FSM counter and FSM itself
200 dmicount
= Signal(10)
201 dmirunning
= Signal(1)
202 dmi_monitor
= Signal(1)
204 self
.submodules
+= dmifsm
208 If(dmi_req
& dmi_wen
,
209 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
210 self
.cpu
.dmi_din
.eq(dmi_din
), # DMI in
211 self
.cpu
.dmi_req
.eq(1), # DMI request
212 self
.cpu
.dmi_wr
.eq(1), # DMI write
219 If(dmi_req
& ~dmi_wen
,
220 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
221 self
.cpu
.dmi_req
.eq(1), # DMI request
222 self
.cpu
.dmi_wr
.eq(0), # DMI read
224 # acknowledge received: capture data.
226 NextValue(dbg_addr
, dmi_addr
),
227 NextValue(dbg_dout
, self
.cpu
.dmi_dout
),
228 NextValue(dbg_msg
, 1),
235 # DMI response received: reset the dmi request and check if
239 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
241 NextState("START"), # back to start on next cycle
243 NextValue(dmi_req
, 0),
244 NextValue(dmi_addr
, 0),
245 NextValue(dmi_din
, 0),
246 NextValue(dmi_wen
, 0),
249 # "monitor" mode fires off a STAT request
250 dmifsm
.act("FIRE_MONITOR",
251 (NextValue(dmi_req
, 1),
252 NextValue(dmi_addr
, 1), # DMI STAT address
253 NextValue(dmi_din
, 0),
254 NextValue(dmi_wen
, 0), # read STAT
255 NextState("START"), # back to start on next cycle
259 self
.comb
+= xer_so
.eq((dbg_dout
& 1) == 1)
260 self
.comb
+= xer_ca
.eq((dbg_dout
& 4) == 4)
261 self
.comb
+= xer_ca32
.eq((dbg_dout
& 8) == 8)
262 self
.comb
+= xer_ov
.eq((dbg_dout
& 16) == 16)
263 self
.comb
+= xer_ov32
.eq((dbg_dout
& 32) == 32)
266 self
.sync
+= If(dbg_msg
,
267 (If(active_dbg
& (dbg_addr
== 0b10), # PC
268 Display("pc : %016x", dbg_dout
),
270 If(dbg_addr
== 0b10, # PC
271 pc
.eq(dbg_dout
), # capture PC
273 #If(dbg_addr == 0b11, # MSR
274 # Display(" msr: %016x", dbg_dout),
276 If(dbg_addr
== 0b1000, # CR
277 Display(" cr : %016x", dbg_dout
),
279 If(dbg_addr
== 0b1001, # XER
280 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
281 xer_so
, xer_ca
, xer_ca32
, xer_ov
, xer_ov32
),
283 If(dbg_addr
== 0b101, # GPR
284 Display(" gpr: %016x", dbg_dout
),
286 # also check if this is a "stat"
287 If(dbg_addr
== 1, # requested a STAT
288 #Display(" stat: %x", dbg_dout),
289 If(dbg_dout
& 2, # bit 2 of STAT is "stopped" mode
290 dmirunning
.eq(1), # continue running
291 dmi_monitor
.eq(0), # and stop monitor mode
299 self
.sync
+= If(uptime
== 0,
300 (dmi_addr
.eq(0), # CTRL
301 dmi_din
.eq(1<<0), # STOP
307 self
.sync
+= If(uptime
== 4,
311 self
.sync
+= If(dmirunning
,
312 dmicount
.eq(dmicount
+ 1),
315 # loop every 1<<N cycles
319 self
.sync
+= If(dmicount
== 4,
320 (dmi_addr
.eq(0b10), # NIA
327 self
.sync
+= If(dmicount
== 8,
328 (dmi_addr
.eq(0), # CTRL
329 dmi_din
.eq(1<<3), # STEP
332 dmirunning
.eq(0), # stop counter, need to fire "monitor"
333 dmi_monitor
.eq(1), # start "monitor" instead
337 # limit range of pc for debug reporting
338 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
339 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
340 self
.comb
+= active_dbg
.eq(1)
344 self
.sync
+= If(active_dbg
& (dmicount
== 12),
345 (dmi_addr
.eq(0b11), # MSR
351 if cpu
== "libresoc":
352 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
353 self
.comb
+= active_dbg_cr
.eq(0)
356 self
.sync
+= If(active_dbg_cr
& (dmicount
== 16),
357 (dmi_addr
.eq(0b1000), # CR
363 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
364 self
.comb
+= active_dbg_xer
.eq(active_dbg_cr
)
367 self
.sync
+= If(active_dbg_xer
& (dmicount
== 20),
368 (dmi_addr
.eq(0b1001), # XER
376 self
.sync
+= If(active_dbg
& (dmicount
== 24+(i
*8)),
377 (dmi_addr
.eq(0b100), # GSPR addr
384 self
.sync
+= If(active_dbg
& (dmicount
== 28+(i
*8)),
385 (dmi_addr
.eq(0b101), # GSPR data
391 # monitor bbus read/write
392 self
.sync
+= If(active_dbg
& self
.cpu
.dbus
.stb
& self
.cpu
.dbus
.ack
,
393 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
407 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
409 Display(" [%06x] iadr: %8x, s %01x w %016x",
418 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
420 Display(" [%06x] iadr: %8x, s %01x r %016x",
429 # Build -----------------------------------------------------------------------
432 parser
= argparse
.ArgumentParser(description
="LiteX LibreSoC CPU Sim")
433 parser
.add_argument("--cpu", default
="libresoc",
434 help="CPU to use: libresoc (default) or microwatt")
435 parser
.add_argument("--debug", action
="store_true",
436 help="Enable debug traces")
437 parser
.add_argument("--trace", action
="store_true",
438 help="Enable tracing")
439 parser
.add_argument("--trace-start", default
=0,
440 help="Cycle to start FST tracing")
441 parser
.add_argument("--trace-end", default
=-1,
442 help="Cycle to end FST tracing")
443 args
= parser
.parse_args()
445 sim_config
= SimConfig(default_clk
="sys_clk")
446 sim_config
.add_module("serial2console", "serial")
449 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
)
450 builder
= Builder(soc
,compile_gateware
= i
!=0)
451 builder
.build(sim_config
=sim_config
,
454 trace_start
= int(args
.trace_start
),
455 trace_end
= int(args
.trace_end
),
459 if __name__
== "__main__":