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/" \
63 # "tests/xics/xics.bin"
64 ram_fname
= "/home/lkcl/src/libresoc/microwatt/" \
65 "tests/decrementer/decrementer.bin"
66 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
67 # "hello_world/hello_world.bin"
69 # reserve XICS ICP and XICS memory addresses.
70 self
.mem_map
['icp'] = 0xc0004000
71 self
.mem_map
['ics'] = 0xc0005000
72 self
.mem_map
['gpio'] = 0xc0007000
73 #self.csr_map["icp"] = 8 # 8 x 0x800 == 0x4000
74 #self.csr_map["ics"] = 10 # 10 x 0x800 == 0x5000
78 #ram_init = get_mem_data({
79 # ram_fname: "0x00000000",
81 ram_init
= get_mem_data(ram_fname
, "little")
83 # remap the main RAM to reset-start-address
84 self
.mem_map
["main_ram"] = 0x00000000
86 # without sram nothing works, therefore move it to higher up
87 self
.mem_map
["sram"] = 0x90000000
89 # put UART at 0xc000200 (w00t! this works!)
90 self
.csr_map
["uart"] = 4
93 # SoCCore -------------------------------------------------------------
94 SoCSDRAM
.__init
__(self
, platform
, clk_freq
=sys_clk_freq
,
95 cpu_type
= "microwatt",
96 cpu_cls
= LibreSoC
if cpu
== "libresoc" \
99 csr_address_width
= 12, # limit to 0x4000
100 cpu_variant
= variant
,
104 with_sdram
= with_sdram
,
105 sdram_module
= sdram_module
,
106 sdram_data_width
= sdram_data_width
,
107 integrated_rom_size
= 0 if ram_fname
else 0x10000,
108 integrated_sram_size
= 0x40000,
109 #integrated_main_ram_init = ram_init,
110 integrated_main_ram_size
= 0x00000000 if with_sdram \
111 else 0x10000000 , # 256MB
113 self
.platform
.name
= "sim"
115 if cpu
== "libresoc":
116 # XICS interrupt devices
117 icp_addr
= self
.mem_map
['icp']
118 icp_wb
= self
.cpu
.xics_icp
119 icp_region
= SoCRegion(origin
=icp_addr
, size
=0x20, cached
=False)
120 self
.bus
.add_slave(name
='icp', slave
=icp_wb
, region
=icp_region
)
122 ics_addr
= self
.mem_map
['ics']
123 ics_wb
= self
.cpu
.xics_ics
124 ics_region
= SoCRegion(origin
=ics_addr
, size
=0x1000, cached
=False)
125 self
.bus
.add_slave(name
='ics', slave
=ics_wb
, region
=ics_region
)
127 # Simple GPIO peripheral
128 gpio_addr
= self
.mem_map
['gpio']
129 gpio_wb
= self
.cpu
.simple_gpio
130 gpio_region
= SoCRegion(origin
=gpio_addr
, size
=0x20, cached
=False)
131 self
.bus
.add_slave(name
='gpio', slave
=gpio_wb
, region
=gpio_region
)
134 # CRG -----------------------------------------------------------------
135 self
.submodules
.crg
= CRG(platform
.request("sys_clk"))
139 # SDRAM ----------------------------------------------------
141 sdram_clk_freq
= int(100e6
) # FIXME: use 100MHz timings
142 sdram_module_cls
= getattr(litedram_modules
, sdram_module
)
143 sdram_rate
= "1:{}".format(
144 sdram_module_nphases
[sdram_module_cls
.memtype
])
145 sdram_module
= sdram_module_cls(sdram_clk_freq
, sdram_rate
)
146 phy_settings
= get_sdram_phy_settings(
147 memtype
= sdram_module
.memtype
,
148 data_width
= sdram_data_width
,
149 clk_freq
= sdram_clk_freq
)
150 self
.submodules
.sdrphy
= SDRAMPHYModel(sdram_module
,
156 sdram_module
.geom_settings
,
157 sdram_module
.timing_settings
)
158 # FIXME: skip memtest to avoid corrupting memory
159 self
.add_constant("MEMTEST_BUS_SIZE", 128//16)
160 self
.add_constant("MEMTEST_DATA_SIZE", 128//16)
161 self
.add_constant("MEMTEST_ADDR_SIZE", 128//16)
162 self
.add_constant("MEMTEST_BUS_DEBUG", 1)
163 self
.add_constant("MEMTEST_ADDR_DEBUG", 1)
164 self
.add_constant("MEMTEST_DATA_DEBUG", 1)
167 # Debug ---------------------------------------------------------------
171 # setup running of DMI FSM
174 dmi_dout
= Signal(64)
180 dbg_dout
= Signal(64)
183 # capture pc from dmi
185 active_dbg
= Signal()
186 active_dbg_cr
= Signal()
187 active_dbg_xer
= Signal()
196 # increment counter, Stop after 100000 cycles
198 self
.sync
+= uptime
.eq(uptime
+ 1)
199 #self.sync += If(uptime == 1000000000000, Finish())
201 # DMI FSM counter and FSM itself
202 dmicount
= Signal(10)
203 dmirunning
= Signal(1)
204 dmi_monitor
= Signal(1)
206 self
.submodules
+= dmifsm
210 If(dmi_req
& dmi_wen
,
211 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
212 self
.cpu
.dmi_din
.eq(dmi_din
), # DMI in
213 self
.cpu
.dmi_req
.eq(1), # DMI request
214 self
.cpu
.dmi_wr
.eq(1), # DMI write
221 If(dmi_req
& ~dmi_wen
,
222 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
223 self
.cpu
.dmi_req
.eq(1), # DMI request
224 self
.cpu
.dmi_wr
.eq(0), # DMI read
226 # acknowledge received: capture data.
228 NextValue(dbg_addr
, dmi_addr
),
229 NextValue(dbg_dout
, self
.cpu
.dmi_dout
),
230 NextValue(dbg_msg
, 1),
237 # DMI response received: reset the dmi request and check if
241 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
243 NextState("START"), # back to start on next cycle
245 NextValue(dmi_req
, 0),
246 NextValue(dmi_addr
, 0),
247 NextValue(dmi_din
, 0),
248 NextValue(dmi_wen
, 0),
251 # "monitor" mode fires off a STAT request
252 dmifsm
.act("FIRE_MONITOR",
253 (NextValue(dmi_req
, 1),
254 NextValue(dmi_addr
, 1), # DMI STAT address
255 NextValue(dmi_din
, 0),
256 NextValue(dmi_wen
, 0), # read STAT
257 NextState("START"), # back to start on next cycle
261 self
.comb
+= xer_so
.eq((dbg_dout
& 1) == 1)
262 self
.comb
+= xer_ca
.eq((dbg_dout
& 4) == 4)
263 self
.comb
+= xer_ca32
.eq((dbg_dout
& 8) == 8)
264 self
.comb
+= xer_ov
.eq((dbg_dout
& 16) == 16)
265 self
.comb
+= xer_ov32
.eq((dbg_dout
& 32) == 32)
268 self
.sync
+= If(dbg_msg
,
269 (If(active_dbg
& (dbg_addr
== 0b10), # PC
270 Display("pc : %016x", dbg_dout
),
272 If(dbg_addr
== 0b10, # PC
273 pc
.eq(dbg_dout
), # capture PC
275 #If(dbg_addr == 0b11, # MSR
276 # Display(" msr: %016x", dbg_dout),
278 If(dbg_addr
== 0b1000, # CR
279 Display(" cr : %016x", dbg_dout
),
281 If(dbg_addr
== 0b1001, # XER
282 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
283 xer_so
, xer_ca
, xer_ca32
, xer_ov
, xer_ov32
),
285 If(dbg_addr
== 0b101, # GPR
286 Display(" gpr: %016x", dbg_dout
),
288 # also check if this is a "stat"
289 If(dbg_addr
== 1, # requested a STAT
290 #Display(" stat: %x", dbg_dout),
291 If(dbg_dout
& 2, # bit 2 of STAT is "stopped" mode
292 dmirunning
.eq(1), # continue running
293 dmi_monitor
.eq(0), # and stop monitor mode
301 self
.sync
+= If(uptime
== 0,
302 (dmi_addr
.eq(0), # CTRL
303 dmi_din
.eq(1<<0), # STOP
309 self
.sync
+= If(uptime
== 4,
313 self
.sync
+= If(dmirunning
,
314 dmicount
.eq(dmicount
+ 1),
317 # loop every 1<<N cycles
321 self
.sync
+= If(dmicount
== 4,
322 (dmi_addr
.eq(0b10), # NIA
329 self
.sync
+= If(dmicount
== 8,
330 (dmi_addr
.eq(0), # CTRL
331 dmi_din
.eq(1<<3), # STEP
334 dmirunning
.eq(0), # stop counter, need to fire "monitor"
335 dmi_monitor
.eq(1), # start "monitor" instead
339 # limit range of pc for debug reporting
340 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
341 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
342 self
.comb
+= active_dbg
.eq(1)
346 self
.sync
+= If(active_dbg
& (dmicount
== 12),
347 (dmi_addr
.eq(0b11), # MSR
353 if cpu
== "libresoc":
354 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
355 self
.comb
+= active_dbg_cr
.eq(0)
358 self
.sync
+= If(active_dbg_cr
& (dmicount
== 16),
359 (dmi_addr
.eq(0b1000), # CR
365 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
366 self
.comb
+= active_dbg_xer
.eq(active_dbg_cr
)
369 self
.sync
+= If(active_dbg_xer
& (dmicount
== 20),
370 (dmi_addr
.eq(0b1001), # XER
378 self
.sync
+= If(active_dbg
& (dmicount
== 24+(i
*8)),
379 (dmi_addr
.eq(0b100), # GSPR addr
386 self
.sync
+= If(active_dbg
& (dmicount
== 28+(i
*8)),
387 (dmi_addr
.eq(0b101), # GSPR data
393 # monitor bbus read/write
394 self
.sync
+= If(active_dbg
& self
.cpu
.dbus
.stb
& self
.cpu
.dbus
.ack
,
395 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
409 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
411 Display(" [%06x] iadr: %8x, s %01x w %016x",
420 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
422 Display(" [%06x] iadr: %8x, s %01x r %016x",
431 # Build -----------------------------------------------------------------------
434 parser
= argparse
.ArgumentParser(description
="LiteX LibreSoC CPU Sim")
435 parser
.add_argument("--cpu", default
="libresoc",
436 help="CPU to use: libresoc (default) or microwatt")
437 parser
.add_argument("--debug", action
="store_true",
438 help="Enable debug traces")
439 parser
.add_argument("--trace", action
="store_true",
440 help="Enable tracing")
441 parser
.add_argument("--trace-start", default
=0,
442 help="Cycle to start FST tracing")
443 parser
.add_argument("--trace-end", default
=-1,
444 help="Cycle to end FST tracing")
445 args
= parser
.parse_args()
447 sim_config
= SimConfig(default_clk
="sys_clk")
448 sim_config
.add_module("serial2console", "serial")
451 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
)
452 builder
= Builder(soc
,compile_gateware
= i
!=0)
453 builder
.build(sim_config
=sim_config
,
456 trace_start
= int(args
.trace_start
),
457 trace_end
= int(args
.trace_end
),
461 if __name__
== "__main__":