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
28 # LibreSoCSim -----------------------------------------------------------------
30 class LibreSoCSim(SoCSDRAM
):
31 def __init__(self
, cpu
="libresoc", debug
=False, with_sdram
=True,
32 sdram_module
= "AS4C16M16",
33 #sdram_data_width = 16,
34 #sdram_module = "MT48LC16M16",
35 sdram_data_width
= 16,
37 assert cpu
in ["libresoc", "microwatt"]
39 sys_clk_freq
= int(100e6
)
44 if cpu_data_width
== 32:
45 variant
= "standard32"
49 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
50 # "hello_world/hello_world.bin"
51 ram_fname
= "/home/lkcl/src/libresoc/microwatt/" \
53 #ram_fname = "/tmp/test.bin"
55 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
56 # "micropython/firmware.bin"
57 ram_fname
= "/home/lkcl/src/libresoc/microwatt/" \
58 "hello_world/hello_world.bin"
62 #ram_init = get_mem_data({
63 # ram_fname: "0x00000000",
65 ram_init
= get_mem_data(ram_fname
, "little")
67 # remap the main RAM to reset-start-address
68 self
.mem_map
["main_ram"] = 0x00000000
70 # without sram nothing works, therefore move it to higher up
71 self
.mem_map
["sram"] = 0x90000000
73 # put UART at 0xc000200 (w00t! this works!)
74 self
.csr_map
["uart"] = 4
77 # SoCCore -------------------------------------------------------------
78 SoCSDRAM
.__init
__(self
, platform
, clk_freq
=sys_clk_freq
,
79 cpu_type
= "microwatt",
80 cpu_cls
= LibreSoC
if cpu
== "libresoc" \
83 cpu_variant
= variant
,
87 with_sdram
= with_sdram
,
88 sdram_module
= sdram_module
,
89 sdram_data_width
= sdram_data_width
,
90 integrated_rom_size
= 0 if ram_fname
else 0x10000,
91 integrated_sram_size
= 0x40000,
92 #integrated_main_ram_init = ram_init,
93 integrated_main_ram_size
= 0x00000000 if with_sdram \
94 else 0x10000000 , # 256MB
96 self
.platform
.name
= "sim"
98 # CRG -----------------------------------------------------------------
99 self
.submodules
.crg
= CRG(platform
.request("sys_clk"))
103 # SDRAM ----------------------------------------------------
105 sdram_clk_freq
= int(100e6
) # FIXME: use 100MHz timings
106 sdram_module_cls
= getattr(litedram_modules
, sdram_module
)
107 sdram_rate
= "1:{}".format(
108 sdram_module_nphases
[sdram_module_cls
.memtype
])
109 sdram_module
= sdram_module_cls(sdram_clk_freq
, sdram_rate
)
110 phy_settings
= get_sdram_phy_settings(
111 memtype
= sdram_module
.memtype
,
112 data_width
= sdram_data_width
,
113 clk_freq
= sdram_clk_freq
)
114 self
.submodules
.sdrphy
= SDRAMPHYModel(sdram_module
,
120 sdram_module
.geom_settings
,
121 sdram_module
.timing_settings
)
122 # FIXME: skip memtest to avoid corrupting memory
123 self
.add_constant("MEMTEST_BUS_SIZE", 128//16)
124 self
.add_constant("MEMTEST_DATA_SIZE", 128//16)
125 self
.add_constant("MEMTEST_ADDR_SIZE", 128//16)
126 self
.add_constant("MEMTEST_BUS_DEBUG", 1)
127 self
.add_constant("MEMTEST_ADDR_DEBUG", 1)
128 self
.add_constant("MEMTEST_DATA_DEBUG", 1)
131 # Debug ---------------------------------------------------------------
135 # setup running of DMI FSM
138 dmi_dout
= Signal(64)
144 dbg_dout
= Signal(64)
147 # capture pc from dmi
149 active_dbg
= Signal()
150 active_dbg_cr
= Signal()
151 active_dbg_xer
= Signal()
160 # increment counter, Stop after 100000 cycles
162 self
.sync
+= uptime
.eq(uptime
+ 1)
163 #self.sync += If(uptime == 1000000000000, Finish())
165 # DMI FSM counter and FSM itself
166 dmicount
= Signal(10)
167 dmirunning
= Signal(1)
168 dmi_monitor
= Signal(1)
170 self
.submodules
+= dmifsm
174 If(dmi_req
& dmi_wen
,
175 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
176 self
.cpu
.dmi_din
.eq(dmi_din
), # DMI in
177 self
.cpu
.dmi_req
.eq(1), # DMI request
178 self
.cpu
.dmi_wr
.eq(1), # DMI write
185 If(dmi_req
& ~dmi_wen
,
186 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
187 self
.cpu
.dmi_req
.eq(1), # DMI request
188 self
.cpu
.dmi_wr
.eq(0), # DMI read
190 # acknowledge received: capture data.
192 NextValue(dbg_addr
, dmi_addr
),
193 NextValue(dbg_dout
, self
.cpu
.dmi_dout
),
194 NextValue(dbg_msg
, 1),
201 # DMI response received: reset the dmi request and check if
205 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
207 NextState("START"), # back to start on next cycle
209 NextValue(dmi_req
, 0),
210 NextValue(dmi_addr
, 0),
211 NextValue(dmi_din
, 0),
212 NextValue(dmi_wen
, 0),
215 # "monitor" mode fires off a STAT request
216 dmifsm
.act("FIRE_MONITOR",
217 (NextValue(dmi_req
, 1),
218 NextValue(dmi_addr
, 1), # DMI STAT address
219 NextValue(dmi_din
, 0),
220 NextValue(dmi_wen
, 0), # read STAT
221 NextState("START"), # back to start on next cycle
225 self
.comb
+= xer_so
.eq((dbg_dout
& 1) == 1)
226 self
.comb
+= xer_ca
.eq((dbg_dout
& 4) == 4)
227 self
.comb
+= xer_ca32
.eq((dbg_dout
& 8) == 8)
228 self
.comb
+= xer_ov
.eq((dbg_dout
& 16) == 16)
229 self
.comb
+= xer_ov32
.eq((dbg_dout
& 32) == 32)
232 self
.sync
+= If(dbg_msg
,
233 (If(active_dbg
& (dbg_addr
== 0b10), # PC
234 Display("pc : %016x", dbg_dout
),
236 If(dbg_addr
== 0b10, # PC
237 pc
.eq(dbg_dout
), # capture PC
239 #If(dbg_addr == 0b11, # MSR
240 # Display(" msr: %016x", dbg_dout),
242 If(dbg_addr
== 0b1000, # CR
243 Display(" cr : %016x", dbg_dout
),
245 If(dbg_addr
== 0b1001, # XER
246 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
247 xer_so
, xer_ca
, xer_ca32
, xer_ov
, xer_ov32
),
249 If(dbg_addr
== 0b101, # GPR
250 Display(" gpr: %016x", dbg_dout
),
252 # also check if this is a "stat"
253 If(dbg_addr
== 1, # requested a STAT
254 #Display(" stat: %x", dbg_dout),
255 If(dbg_dout
& 2, # bit 2 of STAT is "stopped" mode
256 dmirunning
.eq(1), # continue running
257 dmi_monitor
.eq(0), # and stop monitor mode
265 self
.sync
+= If(uptime
== 0,
266 (dmi_addr
.eq(0), # CTRL
267 dmi_din
.eq(1<<0), # STOP
273 self
.sync
+= If(uptime
== 4,
277 self
.sync
+= If(dmirunning
,
278 dmicount
.eq(dmicount
+ 1),
281 # loop every 1<<N cycles
285 self
.sync
+= If(dmicount
== 4,
286 (dmi_addr
.eq(0b10), # NIA
293 self
.sync
+= If(dmicount
== 8,
294 (dmi_addr
.eq(0), # CTRL
295 dmi_din
.eq(1<<3), # STEP
298 dmirunning
.eq(0), # stop counter, need to fire "monitor"
299 dmi_monitor
.eq(1), # start "monitor" instead
303 # limit range of pc for debug reporting
304 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
305 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
306 self
.comb
+= active_dbg
.eq(1)
310 self
.sync
+= If(active_dbg
& (dmicount
== 12),
311 (dmi_addr
.eq(0b11), # MSR
317 if cpu
== "libresoc":
318 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
319 self
.comb
+= active_dbg_cr
.eq(0)
322 self
.sync
+= If(active_dbg_cr
& (dmicount
== 16),
323 (dmi_addr
.eq(0b1000), # CR
329 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
330 self
.comb
+= active_dbg_xer
.eq(active_dbg_cr
)
333 self
.sync
+= If(active_dbg_xer
& (dmicount
== 20),
334 (dmi_addr
.eq(0b1001), # XER
342 self
.sync
+= If(active_dbg
& (dmicount
== 24+(i
*8)),
343 (dmi_addr
.eq(0b100), # GSPR addr
350 self
.sync
+= If(active_dbg
& (dmicount
== 28+(i
*8)),
351 (dmi_addr
.eq(0b101), # GSPR data
357 # monitor bbus read/write
358 self
.sync
+= If(active_dbg
& self
.cpu
.dbus
.stb
& self
.cpu
.dbus
.ack
,
359 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
373 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
375 Display(" [%06x] iadr: %8x, s %01x w %016x",
384 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
386 Display(" [%06x] iadr: %8x, s %01x r %016x",
395 # Build -----------------------------------------------------------------------
398 parser
= argparse
.ArgumentParser(description
="LiteX LibreSoC CPU Sim")
399 parser
.add_argument("--cpu", default
="libresoc",
400 help="CPU to use: libresoc (default) or microwatt")
401 parser
.add_argument("--debug", action
="store_true",
402 help="Enable debug traces")
403 parser
.add_argument("--trace", action
="store_true",
404 help="Enable tracing")
405 parser
.add_argument("--trace-start", default
=0,
406 help="Cycle to start FST tracing")
407 parser
.add_argument("--trace-end", default
=-1,
408 help="Cycle to end FST tracing")
409 args
= parser
.parse_args()
411 sim_config
= SimConfig(default_clk
="sys_clk")
412 sim_config
.add_module("serial2console", "serial")
415 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
)
416 builder
= Builder(soc
,compile_gateware
= i
!=0)
417 builder
.build(sim_config
=sim_config
,
420 trace_start
= int(args
.trace_start
),
421 trace_end
= int(args
.trace_end
),
425 if __name__
== "__main__":