67f87fde2f2adfcf7040226cd5637be8975b6782
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 litedram
.phy
.gensdrphy
import GENSDRPHY
, HalfRateGENSDRPHY
23 from litex
.soc
.cores
.gpio
import GPIOInOut
, GPIOIn
, GPIOOut
24 from litex
.soc
.cores
.spi
import SPIMaster
26 from litex
.tools
.litex_sim
import sdram_module_nphases
, get_sdram_phy_settings
28 from litex
.tools
.litex_sim
import Platform
29 from libresoc
.ls180
import LS180Platform
31 from migen
import Module
32 from litex
.soc
.interconnect
.csr
import AutoCSR
34 from libresoc
import LibreSoC
35 from microwatt
import Microwatt
38 from litex
.soc
.integration
.soc
import SoCCSRHandler
39 SoCCSRHandler
.supported_address_width
.append(12)
42 # LibreSoCSim -----------------------------------------------------------------
44 class LibreSoCSim(SoCCore
):
45 def __init__(self
, cpu
="libresoc", debug
=False, with_sdram
=True,
46 sdram_module
= "AS4C16M16",
47 #sdram_data_width = 16,
48 #sdram_module = "MT48LC16M16",
49 sdram_data_width
= 16,
50 irq_reserved_irqs
= {'uart': 0},
53 assert cpu
in ["libresoc", "microwatt"]
54 sys_clk_freq
= int(50e6
)
59 elif platform
== 'ls180':
60 platform
= LS180Platform()
68 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
69 # "hello_world/hello_world.bin"
70 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
72 #ram_fname = "/tmp/test.bin"
74 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
75 # "micropython/firmware.bin"
76 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
77 # "tests/xics/xics.bin"
78 ram_fname
= "/home/lkcl/src/libresoc/microwatt/" \
79 "tests/decrementer/decrementer.bin"
80 #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
81 # "hello_world/hello_world.bin"
83 # reserve XICS ICP and XICS memory addresses.
84 self
.mem_map
['icp'] = 0xc0010000
85 self
.mem_map
['ics'] = 0xc0011000
86 #self.csr_map["icp"] = 8 # 8 x 0x800 == 0x4000
87 #self.csr_map["ics"] = 10 # 10 x 0x800 == 0x5000
91 #ram_init = get_mem_data({
92 # ram_fname: "0x00000000",
94 ram_init
= get_mem_data(ram_fname
, "little")
96 # remap the main RAM to reset-start-address
97 self
.mem_map
["main_ram"] = 0x00000000
99 # without sram nothing works, therefore move it to higher up
100 self
.mem_map
["sram"] = 0x90000000
102 # put UART at 0xc000200 (w00t! this works!)
103 self
.csr_map
["uart"] = 4
106 # SoCCore -------------------------------------------------------------
107 SoCCore
.__init
__(self
, platform
, clk_freq
=sys_clk_freq
,
108 cpu_type
= "microwatt",
109 cpu_cls
= LibreSoC
if cpu
== "libresoc" \
111 #bus_data_width = 64,
112 csr_address_width
= 14, # limit to 0x8000
113 cpu_variant
= variant
,
116 uart_name
= uart_name
,
117 with_sdram
= with_sdram
,
118 sdram_module
= sdram_module
,
119 sdram_data_width
= sdram_data_width
,
120 integrated_rom_size
= 0 if ram_fname
else 0x10000,
121 integrated_sram_size
= 0x40000,
122 #integrated_main_ram_init = ram_init,
123 integrated_main_ram_size
= 0x00000000 if with_sdram \
124 else 0x10000000 , # 256MB
126 self
.platform
.name
= "ls180"
128 # SDR SDRAM ----------------------------------------------
129 if False: # not self.integrated_main_ram_size:
130 self
.submodules
.sdrphy
= sdrphy_cls(platform
.request("sdram"))
133 if cpu
== "libresoc":
134 # XICS interrupt devices
135 icp_addr
= self
.mem_map
['icp']
136 icp_wb
= self
.cpu
.xics_icp
137 icp_region
= SoCRegion(origin
=icp_addr
, size
=0x20, cached
=False)
138 self
.bus
.add_slave(name
='icp', slave
=icp_wb
, region
=icp_region
)
140 ics_addr
= self
.mem_map
['ics']
141 ics_wb
= self
.cpu
.xics_ics
142 ics_region
= SoCRegion(origin
=ics_addr
, size
=0x1000, cached
=False)
143 self
.bus
.add_slave(name
='ics', slave
=ics_wb
, region
=ics_region
)
145 # CRG -----------------------------------------------------------------
146 self
.submodules
.crg
= CRG(platform
.request("sys_clk"))
150 # SDRAM ----------------------------------------------------
152 sdram_clk_freq
= int(100e6
) # FIXME: use 100MHz timings
153 sdram_module_cls
= getattr(litedram_modules
, sdram_module
)
154 sdram_rate
= "1:{}".format(
155 sdram_module_nphases
[sdram_module_cls
.memtype
])
156 sdram_module
= sdram_module_cls(sdram_clk_freq
, sdram_rate
)
157 phy_settings
= get_sdram_phy_settings(
158 memtype
= sdram_module
.memtype
,
159 data_width
= sdram_data_width
,
160 clk_freq
= sdram_clk_freq
)
161 #sdrphy_cls = HalfRateGENSDRPHY
162 sdrphy_cls
= GENSDRPHY
163 self
.submodules
.sdrphy
= sdrphy_cls(platform
.request("sdram"))
164 #self.submodules.sdrphy = sdrphy_cls(sdram_module,
168 self
.add_sdram("sdram",
170 module
= sdram_module
,
171 origin
= self
.mem_map
["main_ram"],
173 l2_cache_size
= 0, # 8192
174 l2_cache_min_data_width
= 128,
175 l2_cache_reverse
= True
177 # FIXME: skip memtest to avoid corrupting memory
178 self
.add_constant("MEMTEST_BUS_SIZE", 128//16)
179 self
.add_constant("MEMTEST_DATA_SIZE", 128//16)
180 self
.add_constant("MEMTEST_ADDR_SIZE", 128//16)
181 self
.add_constant("MEMTEST_BUS_DEBUG", 1)
182 self
.add_constant("MEMTEST_ADDR_DEBUG", 1)
183 self
.add_constant("MEMTEST_DATA_DEBUG", 1)
186 #platform.add_extension([("gpio_in", 0, Pins(8))])
187 self
.submodules
.gpio_in
= GPIOIn(platform
.request("gpio_in"))
188 self
.add_csr("gpio_in")
189 self
.submodules
.gpio_out
= GPIOIn(platform
.request("gpio_out"))
190 self
.add_csr("gpio_out")
193 self
.submodules
.spi_master
= SPIMaster(
194 pads
= platform
.request("spi_master"),
196 sys_clk_freq
= sys_clk_freq
,
199 self
.add_csr("spi_master")
201 # EINTs - very simple, wire up top 3 bits to ls180 "eint" pins
202 self
.comb
+= self
.cpu
.interrupt
[12:16].eq(platform
.request("eint"))
204 # Debug ---------------------------------------------------------------
208 # setup running of DMI FSM
211 dmi_dout
= Signal(64)
217 dbg_dout
= Signal(64)
220 # capture pc from dmi
222 active_dbg
= Signal()
223 active_dbg_cr
= Signal()
224 active_dbg_xer
= Signal()
233 # increment counter, Stop after 100000 cycles
235 self
.sync
+= uptime
.eq(uptime
+ 1)
236 #self.sync += If(uptime == 1000000000000, Finish())
238 # DMI FSM counter and FSM itself
239 dmicount
= Signal(10)
240 dmirunning
= Signal(1)
241 dmi_monitor
= Signal(1)
243 self
.submodules
+= dmifsm
247 If(dmi_req
& dmi_wen
,
248 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
249 self
.cpu
.dmi_din
.eq(dmi_din
), # DMI in
250 self
.cpu
.dmi_req
.eq(1), # DMI request
251 self
.cpu
.dmi_wr
.eq(1), # DMI write
258 If(dmi_req
& ~dmi_wen
,
259 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
260 self
.cpu
.dmi_req
.eq(1), # DMI request
261 self
.cpu
.dmi_wr
.eq(0), # DMI read
263 # acknowledge received: capture data.
265 NextValue(dbg_addr
, dmi_addr
),
266 NextValue(dbg_dout
, self
.cpu
.dmi_dout
),
267 NextValue(dbg_msg
, 1),
274 # DMI response received: reset the dmi request and check if
278 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
280 NextState("START"), # back to start on next cycle
282 NextValue(dmi_req
, 0),
283 NextValue(dmi_addr
, 0),
284 NextValue(dmi_din
, 0),
285 NextValue(dmi_wen
, 0),
288 # "monitor" mode fires off a STAT request
289 dmifsm
.act("FIRE_MONITOR",
290 (NextValue(dmi_req
, 1),
291 NextValue(dmi_addr
, 1), # DMI STAT address
292 NextValue(dmi_din
, 0),
293 NextValue(dmi_wen
, 0), # read STAT
294 NextState("START"), # back to start on next cycle
298 self
.comb
+= xer_so
.eq((dbg_dout
& 1) == 1)
299 self
.comb
+= xer_ca
.eq((dbg_dout
& 4) == 4)
300 self
.comb
+= xer_ca32
.eq((dbg_dout
& 8) == 8)
301 self
.comb
+= xer_ov
.eq((dbg_dout
& 16) == 16)
302 self
.comb
+= xer_ov32
.eq((dbg_dout
& 32) == 32)
305 self
.sync
+= If(dbg_msg
,
306 (If(active_dbg
& (dbg_addr
== 0b10), # PC
307 Display("pc : %016x", dbg_dout
),
309 If(dbg_addr
== 0b10, # PC
310 pc
.eq(dbg_dout
), # capture PC
312 #If(dbg_addr == 0b11, # MSR
313 # Display(" msr: %016x", dbg_dout),
315 If(dbg_addr
== 0b1000, # CR
316 Display(" cr : %016x", dbg_dout
),
318 If(dbg_addr
== 0b1001, # XER
319 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
320 xer_so
, xer_ca
, xer_ca32
, xer_ov
, xer_ov32
),
322 If(dbg_addr
== 0b101, # GPR
323 Display(" gpr: %016x", dbg_dout
),
325 # also check if this is a "stat"
326 If(dbg_addr
== 1, # requested a STAT
327 #Display(" stat: %x", dbg_dout),
328 If(dbg_dout
& 2, # bit 2 of STAT is "stopped" mode
329 dmirunning
.eq(1), # continue running
330 dmi_monitor
.eq(0), # and stop monitor mode
338 self
.sync
+= If(uptime
== 0,
339 (dmi_addr
.eq(0), # CTRL
340 dmi_din
.eq(1<<0), # STOP
346 self
.sync
+= If(uptime
== 4,
350 self
.sync
+= If(dmirunning
,
351 dmicount
.eq(dmicount
+ 1),
354 # loop every 1<<N cycles
358 self
.sync
+= If(dmicount
== 4,
359 (dmi_addr
.eq(0b10), # NIA
366 self
.sync
+= If(dmicount
== 8,
367 (dmi_addr
.eq(0), # CTRL
368 dmi_din
.eq(1<<3), # STEP
371 dmirunning
.eq(0), # stop counter, need to fire "monitor"
372 dmi_monitor
.eq(1), # start "monitor" instead
376 # limit range of pc for debug reporting
377 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
378 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
379 self
.comb
+= active_dbg
.eq(1)
383 self
.sync
+= If(active_dbg
& (dmicount
== 12),
384 (dmi_addr
.eq(0b11), # MSR
390 if cpu
== "libresoc":
391 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
392 self
.comb
+= active_dbg_cr
.eq(0)
395 self
.sync
+= If(active_dbg_cr
& (dmicount
== 16),
396 (dmi_addr
.eq(0b1000), # CR
402 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
403 self
.comb
+= active_dbg_xer
.eq(active_dbg_cr
)
406 self
.sync
+= If(active_dbg_xer
& (dmicount
== 20),
407 (dmi_addr
.eq(0b1001), # XER
415 self
.sync
+= If(active_dbg
& (dmicount
== 24+(i
*8)),
416 (dmi_addr
.eq(0b100), # GSPR addr
423 self
.sync
+= If(active_dbg
& (dmicount
== 28+(i
*8)),
424 (dmi_addr
.eq(0b101), # GSPR data
430 # monitor bbus read/write
431 self
.sync
+= If(active_dbg
& self
.cpu
.dbus
.stb
& self
.cpu
.dbus
.ack
,
432 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
446 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
448 Display(" [%06x] iadr: %8x, s %01x w %016x",
457 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
459 Display(" [%06x] iadr: %8x, s %01x r %016x",
468 # Build -----------------------------------------------------------------------
471 parser
= argparse
.ArgumentParser(description
="LiteX LibreSoC CPU Sim")
472 parser
.add_argument("--cpu", default
="libresoc",
473 help="CPU to use: libresoc (default) or microwatt")
474 parser
.add_argument("--platform", default
="sim",
475 help="platform (sim or ls180)")
476 parser
.add_argument("--debug", action
="store_true",
477 help="Enable debug traces")
478 parser
.add_argument("--trace", action
="store_true",
479 help="Enable tracing")
480 parser
.add_argument("--trace-start", default
=0,
481 help="Cycle to start FST tracing")
482 parser
.add_argument("--trace-end", default
=-1,
483 help="Cycle to end FST tracing")
484 parser
.add_argument("--build", action
="store_true", help="Build bitstream")
485 args
= parser
.parse_args()
488 if args
.platform
== 'ls180':
489 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
,
490 platform
=args
.platform
)
493 builder
= Builder(soc
, compile_gateware
= True)
494 builder
.build(run
= True)
498 sim_config
= SimConfig(default_clk
="sys_clk")
499 sim_config
.add_module("serial2console", "serial")
502 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
,
503 platform
=args
.platform
)
504 builder
= Builder(soc
, compile_gateware
= i
!=0)
505 builder
.build(sim_config
=sim_config
,
508 trace_start
= int(args
.trace_start
),
509 trace_end
= int(args
.trace_end
),
513 if __name__
== "__main__":