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
#, GPIOTristate
24 from litex
.soc
.cores
.spi
import SPIMaster
25 from litex
.soc
.cores
.pwm
import PWM
27 from litex
.tools
.litex_sim
import sdram_module_nphases
, get_sdram_phy_settings
29 from litex
.tools
.litex_sim
import Platform
30 from libresoc
.ls180
import LS180Platform
32 from migen
import Module
33 from litex
.soc
.interconnect
.csr
import AutoCSR
35 from libresoc
import LibreSoC
36 from microwatt
import Microwatt
39 from litex
.soc
.integration
.soc
import SoCCSRHandler
40 SoCCSRHandler
.supported_address_width
.append(12)
43 # LibreSoCSim -----------------------------------------------------------------
45 class LibreSoCSim(SoCCore
):
46 def __init__(self
, cpu
="libresoc", debug
=False, with_sdram
=True,
47 sdram_module
= "AS4C16M16",
48 #sdram_data_width = 16,
49 #sdram_module = "MT48LC16M16",
50 sdram_data_width
= 16,
51 irq_reserved_irqs
= {'uart': 0},
54 assert cpu
in ["libresoc", "microwatt"]
55 sys_clk_freq
= int(50e6
)
60 elif platform
== 'ls180':
61 platform
= LS180Platform()
69 # reserve XICS ICP and XICS memory addresses.
70 self
.mem_map
['icp'] = 0xc0010000
71 self
.mem_map
['ics'] = 0xc0011000
72 #self.csr_map["icp"] = 8 # 8 x 0x800 == 0x4000
73 #self.csr_map["ics"] = 10 # 10 x 0x800 == 0x5000
77 #ram_init = get_mem_data({
78 # ram_fname: "0x00000000",
80 ram_init
= get_mem_data(ram_fname
, "little")
82 # remap the main RAM to reset-start-address
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
90 self
.mem_map
["main_ram"] = 0x90000000
91 self
.mem_map
["sram"] = 0x00000000
93 # SoCCore -------------------------------------------------------------
94 SoCCore
.__init
__(self
, platform
, clk_freq
=sys_clk_freq
,
95 cpu_type
= "microwatt",
96 cpu_cls
= LibreSoC
if cpu
== "libresoc" \
99 csr_address_width
= 14, # limit to 0x8000
100 cpu_variant
= variant
,
103 uart_name
= uart_name
,
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
= 0x200,
109 #integrated_main_ram_init = ram_init,
110 integrated_main_ram_size
= 0x00000000 if with_sdram \
111 else 0x10000000 , # 256MB
113 self
.platform
.name
= "ls180"
115 # SDR SDRAM ----------------------------------------------
116 if False: # not self.integrated_main_ram_size:
117 self
.submodules
.sdrphy
= sdrphy_cls(platform
.request("sdram"))
119 if cpu
== "libresoc":
120 # XICS interrupt devices
121 icp_addr
= self
.mem_map
['icp']
122 icp_wb
= self
.cpu
.xics_icp
123 icp_region
= SoCRegion(origin
=icp_addr
, size
=0x20, cached
=False)
124 self
.bus
.add_slave(name
='icp', slave
=icp_wb
, region
=icp_region
)
126 ics_addr
= self
.mem_map
['ics']
127 ics_wb
= self
.cpu
.xics_ics
128 ics_region
= SoCRegion(origin
=ics_addr
, size
=0x1000, cached
=False)
129 self
.bus
.add_slave(name
='ics', slave
=ics_wb
, region
=ics_region
)
131 # CRG -----------------------------------------------------------------
132 self
.submodules
.crg
= CRG(platform
.request("sys_clk"),
133 platform
.request("sys_rst"))
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 #sdrphy_cls = HalfRateGENSDRPHY
149 sdrphy_cls
= GENSDRPHY
150 self
.submodules
.sdrphy
= sdrphy_cls(platform
.request("sdram"))
151 #self.submodules.sdrphy = sdrphy_cls(sdram_module,
155 self
.add_sdram("sdram",
157 module
= sdram_module
,
158 origin
= self
.mem_map
["main_ram"],
160 l2_cache_size
= 0, # 8192
161 l2_cache_min_data_width
= 128,
162 l2_cache_reverse
= True
164 # FIXME: skip memtest to avoid corrupting memory
165 self
.add_constant("MEMTEST_BUS_SIZE", 128//16)
166 self
.add_constant("MEMTEST_DATA_SIZE", 128//16)
167 self
.add_constant("MEMTEST_ADDR_SIZE", 128//16)
168 self
.add_constant("MEMTEST_BUS_DEBUG", 1)
169 self
.add_constant("MEMTEST_ADDR_DEBUG", 1)
170 self
.add_constant("MEMTEST_DATA_DEBUG", 1)
173 #platform.add_extension([("gpio_in", 0, Pins(8))])
174 self
.submodules
.gpio_in
= GPIOIn(platform
.request("gpio_in"))
175 self
.add_csr("gpio_in")
176 self
.submodules
.gpio_out
= GPIOIn(platform
.request("gpio_out"))
177 self
.add_csr("gpio_out")
180 self
.submodules
.gpio
= GPIOTristate(platform
.request("gpio"))
184 self
.submodules
.spi_master
= SPIMaster(
185 pads
= platform
.request("spi_master"),
187 sys_clk_freq
= sys_clk_freq
,
190 self
.add_csr("spi_master")
192 # EINTs - very simple, wire up top 3 bits to ls180 "eint" pins
193 self
.comb
+= self
.cpu
.interrupt
[12:16].eq(platform
.request("eint"))
196 jtagpads
= platform
.request("jtag")
197 self
.comb
+= self
.cpu
.jtag_tck
.eq(jtagpads
.tck
)
198 self
.comb
+= self
.cpu
.jtag_tms
.eq(jtagpads
.tms
)
199 self
.comb
+= self
.cpu
.jtag_tdi
.eq(jtagpads
.tdi
)
200 self
.comb
+= jtagpads
.tdo
.eq(self
.cpu
.jtag_tdo
)
205 setattr(self
.submodules
, name
, PWM(platform
.request("pwm", i
)))
209 # Debug ---------------------------------------------------------------
213 # setup running of DMI FSM
216 dmi_dout
= Signal(64)
222 dbg_dout
= Signal(64)
225 # capture pc from dmi
227 active_dbg
= Signal()
228 active_dbg_cr
= Signal()
229 active_dbg_xer
= Signal()
238 # increment counter, Stop after 100000 cycles
240 self
.sync
+= uptime
.eq(uptime
+ 1)
241 #self.sync += If(uptime == 1000000000000, Finish())
243 # DMI FSM counter and FSM itself
244 dmicount
= Signal(10)
245 dmirunning
= Signal(1)
246 dmi_monitor
= Signal(1)
248 self
.submodules
+= dmifsm
252 If(dmi_req
& dmi_wen
,
253 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
254 self
.cpu
.dmi_din
.eq(dmi_din
), # DMI in
255 self
.cpu
.dmi_req
.eq(1), # DMI request
256 self
.cpu
.dmi_wr
.eq(1), # DMI write
263 If(dmi_req
& ~dmi_wen
,
264 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
265 self
.cpu
.dmi_req
.eq(1), # DMI request
266 self
.cpu
.dmi_wr
.eq(0), # DMI read
268 # acknowledge received: capture data.
270 NextValue(dbg_addr
, dmi_addr
),
271 NextValue(dbg_dout
, self
.cpu
.dmi_dout
),
272 NextValue(dbg_msg
, 1),
279 # DMI response received: reset the dmi request and check if
283 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
285 NextState("START"), # back to start on next cycle
287 NextValue(dmi_req
, 0),
288 NextValue(dmi_addr
, 0),
289 NextValue(dmi_din
, 0),
290 NextValue(dmi_wen
, 0),
293 # "monitor" mode fires off a STAT request
294 dmifsm
.act("FIRE_MONITOR",
295 (NextValue(dmi_req
, 1),
296 NextValue(dmi_addr
, 1), # DMI STAT address
297 NextValue(dmi_din
, 0),
298 NextValue(dmi_wen
, 0), # read STAT
299 NextState("START"), # back to start on next cycle
303 self
.comb
+= xer_so
.eq((dbg_dout
& 1) == 1)
304 self
.comb
+= xer_ca
.eq((dbg_dout
& 4) == 4)
305 self
.comb
+= xer_ca32
.eq((dbg_dout
& 8) == 8)
306 self
.comb
+= xer_ov
.eq((dbg_dout
& 16) == 16)
307 self
.comb
+= xer_ov32
.eq((dbg_dout
& 32) == 32)
310 self
.sync
+= If(dbg_msg
,
311 (If(active_dbg
& (dbg_addr
== 0b10), # PC
312 Display("pc : %016x", dbg_dout
),
314 If(dbg_addr
== 0b10, # PC
315 pc
.eq(dbg_dout
), # capture PC
317 #If(dbg_addr == 0b11, # MSR
318 # Display(" msr: %016x", dbg_dout),
320 If(dbg_addr
== 0b1000, # CR
321 Display(" cr : %016x", dbg_dout
),
323 If(dbg_addr
== 0b1001, # XER
324 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
325 xer_so
, xer_ca
, xer_ca32
, xer_ov
, xer_ov32
),
327 If(dbg_addr
== 0b101, # GPR
328 Display(" gpr: %016x", dbg_dout
),
330 # also check if this is a "stat"
331 If(dbg_addr
== 1, # requested a STAT
332 #Display(" stat: %x", dbg_dout),
333 If(dbg_dout
& 2, # bit 2 of STAT is "stopped" mode
334 dmirunning
.eq(1), # continue running
335 dmi_monitor
.eq(0), # and stop monitor mode
343 self
.sync
+= If(uptime
== 0,
344 (dmi_addr
.eq(0), # CTRL
345 dmi_din
.eq(1<<0), # STOP
351 self
.sync
+= If(uptime
== 4,
355 self
.sync
+= If(dmirunning
,
356 dmicount
.eq(dmicount
+ 1),
359 # loop every 1<<N cycles
363 self
.sync
+= If(dmicount
== 4,
364 (dmi_addr
.eq(0b10), # NIA
371 self
.sync
+= If(dmicount
== 8,
372 (dmi_addr
.eq(0), # CTRL
373 dmi_din
.eq(1<<3), # STEP
376 dmirunning
.eq(0), # stop counter, need to fire "monitor"
377 dmi_monitor
.eq(1), # start "monitor" instead
381 # limit range of pc for debug reporting
382 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
383 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
384 self
.comb
+= active_dbg
.eq(1)
388 self
.sync
+= If(active_dbg
& (dmicount
== 12),
389 (dmi_addr
.eq(0b11), # MSR
395 if cpu
== "libresoc":
396 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
397 self
.comb
+= active_dbg_cr
.eq(0)
400 self
.sync
+= If(active_dbg_cr
& (dmicount
== 16),
401 (dmi_addr
.eq(0b1000), # CR
407 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
408 self
.comb
+= active_dbg_xer
.eq(active_dbg_cr
)
411 self
.sync
+= If(active_dbg_xer
& (dmicount
== 20),
412 (dmi_addr
.eq(0b1001), # XER
420 self
.sync
+= If(active_dbg
& (dmicount
== 24+(i
*8)),
421 (dmi_addr
.eq(0b100), # GSPR addr
428 self
.sync
+= If(active_dbg
& (dmicount
== 28+(i
*8)),
429 (dmi_addr
.eq(0b101), # GSPR data
435 # monitor bbus read/write
436 self
.sync
+= If(active_dbg
& self
.cpu
.dbus
.stb
& self
.cpu
.dbus
.ack
,
437 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
451 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
453 Display(" [%06x] iadr: %8x, s %01x w %016x",
462 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
464 Display(" [%06x] iadr: %8x, s %01x r %016x",
473 # Build -----------------------------------------------------------------------
476 parser
= argparse
.ArgumentParser(description
="LiteX LibreSoC CPU Sim")
477 parser
.add_argument("--cpu", default
="libresoc",
478 help="CPU to use: libresoc (default) or microwatt")
479 parser
.add_argument("--platform", default
="sim",
480 help="platform (sim or ls180)")
481 parser
.add_argument("--debug", action
="store_true",
482 help="Enable debug traces")
483 parser
.add_argument("--trace", action
="store_true",
484 help="Enable tracing")
485 parser
.add_argument("--trace-start", default
=0,
486 help="Cycle to start FST tracing")
487 parser
.add_argument("--trace-end", default
=-1,
488 help="Cycle to end FST tracing")
489 parser
.add_argument("--build", action
="store_true", help="Build bitstream")
490 args
= parser
.parse_args()
493 if args
.platform
== 'ls180':
494 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
,
495 platform
=args
.platform
)
498 builder
= Builder(soc
, compile_gateware
= True)
499 builder
.build(run
= True)
503 sim_config
= SimConfig(default_clk
="sys_clk")
504 sim_config
.add_module("serial2console", "serial")
507 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
,
508 platform
=args
.platform
)
509 builder
= Builder(soc
, compile_gateware
= i
!=0)
510 builder
.build(sim_config
=sim_config
,
513 trace_start
= int(args
.trace_start
),
514 trace_end
= int(args
.trace_end
),
518 if __name__
== "__main__":