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 # TODO: not have these conflict with csr locations
69 self
.mem_map
['icp'] = 0xc0004000
70 self
.mem_map
['ics'] = 0xc0005000
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 # XICS interrupt devices
114 icp_addr
= self
.mem_map
['icp']
115 icp_wb
= self
.cpu
.xics_icp
116 icp_region
= SoCRegion(origin
=icp_addr
, size
=0x1000, cached
=False)
117 self
.bus
.add_slave(name
='icp', slave
=icp_wb
, region
=icp_region
)
119 ics_addr
= self
.mem_map
['ics']
120 ics_wb
= self
.cpu
.xics_ics
121 ics_region
= SoCRegion(origin
=ics_addr
, size
=0x20, cached
=False)
122 self
.bus
.add_slave(name
='ics', slave
=ics_wb
, region
=ics_region
)
124 # CRG -----------------------------------------------------------------
125 self
.submodules
.crg
= CRG(platform
.request("sys_clk"))
129 # SDRAM ----------------------------------------------------
131 sdram_clk_freq
= int(100e6
) # FIXME: use 100MHz timings
132 sdram_module_cls
= getattr(litedram_modules
, sdram_module
)
133 sdram_rate
= "1:{}".format(
134 sdram_module_nphases
[sdram_module_cls
.memtype
])
135 sdram_module
= sdram_module_cls(sdram_clk_freq
, sdram_rate
)
136 phy_settings
= get_sdram_phy_settings(
137 memtype
= sdram_module
.memtype
,
138 data_width
= sdram_data_width
,
139 clk_freq
= sdram_clk_freq
)
140 self
.submodules
.sdrphy
= SDRAMPHYModel(sdram_module
,
146 sdram_module
.geom_settings
,
147 sdram_module
.timing_settings
)
148 # FIXME: skip memtest to avoid corrupting memory
149 self
.add_constant("MEMTEST_BUS_SIZE", 128//16)
150 self
.add_constant("MEMTEST_DATA_SIZE", 128//16)
151 self
.add_constant("MEMTEST_ADDR_SIZE", 128//16)
152 self
.add_constant("MEMTEST_BUS_DEBUG", 1)
153 self
.add_constant("MEMTEST_ADDR_DEBUG", 1)
154 self
.add_constant("MEMTEST_DATA_DEBUG", 1)
157 # Debug ---------------------------------------------------------------
161 # setup running of DMI FSM
164 dmi_dout
= Signal(64)
170 dbg_dout
= Signal(64)
173 # capture pc from dmi
175 active_dbg
= Signal()
176 active_dbg_cr
= Signal()
177 active_dbg_xer
= Signal()
186 # increment counter, Stop after 100000 cycles
188 self
.sync
+= uptime
.eq(uptime
+ 1)
189 #self.sync += If(uptime == 1000000000000, Finish())
191 # DMI FSM counter and FSM itself
192 dmicount
= Signal(10)
193 dmirunning
= Signal(1)
194 dmi_monitor
= Signal(1)
196 self
.submodules
+= dmifsm
200 If(dmi_req
& dmi_wen
,
201 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
202 self
.cpu
.dmi_din
.eq(dmi_din
), # DMI in
203 self
.cpu
.dmi_req
.eq(1), # DMI request
204 self
.cpu
.dmi_wr
.eq(1), # DMI write
211 If(dmi_req
& ~dmi_wen
,
212 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
213 self
.cpu
.dmi_req
.eq(1), # DMI request
214 self
.cpu
.dmi_wr
.eq(0), # DMI read
216 # acknowledge received: capture data.
218 NextValue(dbg_addr
, dmi_addr
),
219 NextValue(dbg_dout
, self
.cpu
.dmi_dout
),
220 NextValue(dbg_msg
, 1),
227 # DMI response received: reset the dmi request and check if
231 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
233 NextState("START"), # back to start on next cycle
235 NextValue(dmi_req
, 0),
236 NextValue(dmi_addr
, 0),
237 NextValue(dmi_din
, 0),
238 NextValue(dmi_wen
, 0),
241 # "monitor" mode fires off a STAT request
242 dmifsm
.act("FIRE_MONITOR",
243 (NextValue(dmi_req
, 1),
244 NextValue(dmi_addr
, 1), # DMI STAT address
245 NextValue(dmi_din
, 0),
246 NextValue(dmi_wen
, 0), # read STAT
247 NextState("START"), # back to start on next cycle
251 self
.comb
+= xer_so
.eq((dbg_dout
& 1) == 1)
252 self
.comb
+= xer_ca
.eq((dbg_dout
& 4) == 4)
253 self
.comb
+= xer_ca32
.eq((dbg_dout
& 8) == 8)
254 self
.comb
+= xer_ov
.eq((dbg_dout
& 16) == 16)
255 self
.comb
+= xer_ov32
.eq((dbg_dout
& 32) == 32)
258 self
.sync
+= If(dbg_msg
,
259 (If(active_dbg
& (dbg_addr
== 0b10), # PC
260 Display("pc : %016x", dbg_dout
),
262 If(dbg_addr
== 0b10, # PC
263 pc
.eq(dbg_dout
), # capture PC
265 #If(dbg_addr == 0b11, # MSR
266 # Display(" msr: %016x", dbg_dout),
268 If(dbg_addr
== 0b1000, # CR
269 Display(" cr : %016x", dbg_dout
),
271 If(dbg_addr
== 0b1001, # XER
272 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
273 xer_so
, xer_ca
, xer_ca32
, xer_ov
, xer_ov32
),
275 If(dbg_addr
== 0b101, # GPR
276 Display(" gpr: %016x", dbg_dout
),
278 # also check if this is a "stat"
279 If(dbg_addr
== 1, # requested a STAT
280 #Display(" stat: %x", dbg_dout),
281 If(dbg_dout
& 2, # bit 2 of STAT is "stopped" mode
282 dmirunning
.eq(1), # continue running
283 dmi_monitor
.eq(0), # and stop monitor mode
291 self
.sync
+= If(uptime
== 0,
292 (dmi_addr
.eq(0), # CTRL
293 dmi_din
.eq(1<<0), # STOP
299 self
.sync
+= If(uptime
== 4,
303 self
.sync
+= If(dmirunning
,
304 dmicount
.eq(dmicount
+ 1),
307 # loop every 1<<N cycles
311 self
.sync
+= If(dmicount
== 4,
312 (dmi_addr
.eq(0b10), # NIA
319 self
.sync
+= If(dmicount
== 8,
320 (dmi_addr
.eq(0), # CTRL
321 dmi_din
.eq(1<<3), # STEP
324 dmirunning
.eq(0), # stop counter, need to fire "monitor"
325 dmi_monitor
.eq(1), # start "monitor" instead
329 # limit range of pc for debug reporting
330 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
331 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
332 self
.comb
+= active_dbg
.eq(1)
336 self
.sync
+= If(active_dbg
& (dmicount
== 12),
337 (dmi_addr
.eq(0b11), # MSR
343 if cpu
== "libresoc":
344 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
345 self
.comb
+= active_dbg_cr
.eq(0)
348 self
.sync
+= If(active_dbg_cr
& (dmicount
== 16),
349 (dmi_addr
.eq(0b1000), # CR
355 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
356 self
.comb
+= active_dbg_xer
.eq(active_dbg_cr
)
359 self
.sync
+= If(active_dbg_xer
& (dmicount
== 20),
360 (dmi_addr
.eq(0b1001), # XER
368 self
.sync
+= If(active_dbg
& (dmicount
== 24+(i
*8)),
369 (dmi_addr
.eq(0b100), # GSPR addr
376 self
.sync
+= If(active_dbg
& (dmicount
== 28+(i
*8)),
377 (dmi_addr
.eq(0b101), # GSPR data
383 # monitor bbus read/write
384 self
.sync
+= If(active_dbg
& self
.cpu
.dbus
.stb
& self
.cpu
.dbus
.ack
,
385 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
399 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
401 Display(" [%06x] iadr: %8x, s %01x w %016x",
410 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
412 Display(" [%06x] iadr: %8x, s %01x r %016x",
421 # Build -----------------------------------------------------------------------
424 parser
= argparse
.ArgumentParser(description
="LiteX LibreSoC CPU Sim")
425 parser
.add_argument("--cpu", default
="libresoc",
426 help="CPU to use: libresoc (default) or microwatt")
427 parser
.add_argument("--debug", action
="store_true",
428 help="Enable debug traces")
429 parser
.add_argument("--trace", action
="store_true",
430 help="Enable tracing")
431 parser
.add_argument("--trace-start", default
=0,
432 help="Cycle to start FST tracing")
433 parser
.add_argument("--trace-end", default
=-1,
434 help="Cycle to end FST tracing")
435 args
= parser
.parse_args()
437 sim_config
= SimConfig(default_clk
="sys_clk")
438 sim_config
.add_module("serial2console", "serial")
441 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
)
442 builder
= Builder(soc
,compile_gateware
= i
!=0)
443 builder
.build(sim_config
=sim_config
,
446 trace_start
= int(args
.trace_start
),
447 trace_end
= int(args
.trace_end
),
451 if __name__
== "__main__":