5 from functools
import reduce
6 from operator
import or_
8 from migen
import (Signal
, FSM
, If
, Display
, Finish
, NextValue
, NextState
,
9 Record
, ClockSignal
, wrap
)
11 from litex
.build
.generic_platform
import Pins
, Subsignal
12 from litex
.build
.sim
import SimPlatform
13 from litex
.build
.io
import CRG
14 from litex
.build
.sim
.config
import SimConfig
16 from litex
.soc
.integration
.soc
import SoCRegion
17 from litex
.soc
.integration
.soc_core
import SoCCore
18 from litex
.soc
.integration
.soc_sdram
import SoCSDRAM
19 from litex
.soc
.integration
.builder
import Builder
20 from litex
.soc
.integration
.common
import get_mem_data
22 from litedram
import modules
as litedram_modules
23 from litedram
.phy
.model
import SDRAMPHYModel
24 from litedram
.phy
.gensdrphy
import GENSDRPHY
, HalfRateGENSDRPHY
26 from litex
.soc
.cores
.spi
import SPIMaster
27 from litex
.soc
.cores
.pwm
import PWM
28 from litex
.soc
.cores
.bitbang
import I2CMaster
30 from litex
.tools
.litex_sim
import sdram_module_nphases
, get_sdram_phy_settings
32 from litex
.tools
.litex_sim
import Platform
33 from libresoc
.ls180
import LS180Platform
35 from migen
import Module
36 from litex
.soc
.interconnect
.csr
import AutoCSR
38 from libresoc
import LibreSoC
39 from microwatt
import Microwatt
42 from litex
.soc
.integration
.soc
import SoCCSRHandler
43 SoCCSRHandler
.supported_address_width
.append(12)
45 # GPIO Tristate -------------------------------------------------------
46 # doesn't work properly.
47 #from litex.soc.cores.gpio import GPIOTristate
48 from litex
.soc
.interconnect
.csr
import CSRStorage
, CSRStatus
49 from migen
.genlib
.cdc
import MultiReg
52 from litex
.soc
.interconnect
import wishbone
53 from litesdcard
.phy
import (SDPHY
, SDPHYClocker
,
54 SDPHYInit
, SDPHYCMDW
, SDPHYCMDR
,
55 SDPHYDATAW
, SDPHYDATAR
,
57 from litesdcard
.core
import SDCore
58 from litesdcard
.frontend
.dma
import SDBlock2MemDMA
, SDMem2BlockDMA
59 from litex
.build
.io
import SDROutput
, SDRInput
62 class GPIOTristateASIC(Module
, AutoCSR
):
63 def __init__(self
, pads
):
64 nbits
= len(pads
.oe
) # hack
65 self
._oe
= CSRStorage(nbits
, description
="GPIO Tristate(s) Control.")
66 self
._in
= CSRStatus(nbits
, description
="GPIO Input(s) Status.")
67 self
._out
= CSRStorage(nbits
, description
="GPIO Ouptut(s) Control.")
71 _pads
= Record( (("i", nbits
),
74 self
.comb
+= _pads
.i
.eq(pads
.i
)
75 self
.comb
+= pads
.o
.eq(_pads
.o
)
76 self
.comb
+= pads
.oe
.eq(_pads
.oe
)
78 self
.comb
+= _pads
.oe
.eq(self
._oe
.storage
)
79 self
.comb
+= _pads
.o
.eq(self
._out
.storage
)
80 for i
in range(nbits
):
81 self
.specials
+= MultiReg(_pads
.i
[i
], self
._in
.status
[i
])
83 # SDCard PHY IO -------------------------------------------------------
86 def __init__(self
, pad
, name
, sdpad
):
88 _o
= getattr(pad
, "%s_o" % name
)
89 _oe
= getattr(pad
, "%s_oe" % name
)
90 _i
= getattr(pad
, "%s_i" % name
)
91 for j
in range(len(_o
)):
92 self
.specials
+= SDROutput(clk
=clk
, i
=sdpad
.o
[j
], o
=_o
[j
])
93 self
.specials
+= SDROutput(clk
=clk
, i
=sdpad
.oe
, o
=_oe
[j
])
94 self
.specials
+= SDRInput(clk
=clk
, i
=_i
[j
], o
=sdpad
.i
[j
])
97 class SDPHYIOGen(Module
):
98 def __init__(self
, clocker
, sdpads
, pads
):
100 if hasattr(pads
, "rst"):
101 self
.comb
+= pads
.rst
.eq(0)
104 self
.specials
+= SDROutput(
106 i
= ~clocker
.clk
& sdpads
.clk
,
111 self
.submodules
.sd_cmd
= SDRPad(pads
, "cmd", sdpads
.cmd
)
114 self
.submodules
.sd_data
= SDRPad(pads
, "data", sdpads
.data
)
117 class SDPHY(Module
, AutoCSR
):
118 def __init__(self
, pads
, device
, sys_clk_freq
,
119 cmd_timeout
=10e-3, data_timeout
=10e-3):
120 self
.card_detect
= CSRStatus() # Assume SDCard is present if no cd pin.
121 self
.comb
+= self
.card_detect
.status
.eq(getattr(pads
, "cd", 0))
123 self
.submodules
.clocker
= clocker
= SDPHYClocker()
124 self
.submodules
.init
= init
= SDPHYInit()
125 self
.submodules
.cmdw
= cmdw
= SDPHYCMDW()
126 self
.submodules
.cmdr
= cmdr
= SDPHYCMDR(sys_clk_freq
,
128 self
.submodules
.dataw
= dataw
= SDPHYDATAW()
129 self
.submodules
.datar
= datar
= SDPHYDATAR(sys_clk_freq
,
134 self
.sdpads
= sdpads
= Record(_sdpads_layout
)
137 sdphy_cls
= SDPHYIOGen
138 self
.submodules
.io
= sdphy_cls(clocker
, sdpads
, pads
)
140 # Connect pads_out of submodules to physical pads --------------
141 pl
= [init
, cmdw
, cmdr
, dataw
, datar
]
143 sdpads
.clk
.eq( reduce(or_
, [m
.pads_out
.clk
for m
in pl
])),
144 sdpads
.cmd
.oe
.eq( reduce(or_
, [m
.pads_out
.cmd
.oe
for m
in pl
])),
145 sdpads
.cmd
.o
.eq( reduce(or_
, [m
.pads_out
.cmd
.o
for m
in pl
])),
146 sdpads
.data
.oe
.eq(reduce(or_
, [m
.pads_out
.data
.oe
for m
in pl
])),
147 sdpads
.data
.o
.eq( reduce(or_
, [m
.pads_out
.data
.o
for m
in pl
])),
150 self
.comb
+= m
.pads_out
.ready
.eq(self
.clocker
.ce
)
152 # Connect physical pads to pads_in of submodules ---------------
154 self
.comb
+= m
.pads_in
.valid
.eq(self
.clocker
.ce
)
155 self
.comb
+= m
.pads_in
.cmd
.i
.eq(sdpads
.cmd
.i
)
156 self
.comb
+= m
.pads_in
.data
.i
.eq(sdpads
.data
.i
)
159 # Speed Throttling -------------------------------------------
160 self
.comb
+= clocker
.stop
.eq(dataw
.stop | datar
.stop
)
162 # LibreSoCSim -----------------------------------------------------------
164 class LibreSoCSim(SoCCore
):
165 def __init__(self
, cpu
="libresoc", debug
=False, with_sdram
=True,
166 sdram_module
= "AS4C16M16",
167 #sdram_data_width = 16,
168 #sdram_module = "MT48LC16M16",
169 sdram_data_width
= 16,
170 irq_reserved_irqs
= {'uart': 0},
173 assert cpu
in ["libresoc", "microwatt"]
174 sys_clk_freq
= int(50e6
)
176 if platform
== 'sim':
177 platform
= Platform()
179 elif platform
== 'ls180':
180 platform
= LS180Platform()
188 # reserve XICS ICP and XICS memory addresses.
189 self
.mem_map
['icp'] = 0xc0010000
190 self
.mem_map
['ics'] = 0xc0011000
191 #self.csr_map["icp"] = 8 # 8 x 0x800 == 0x4000
192 #self.csr_map["ics"] = 10 # 10 x 0x800 == 0x5000
196 #ram_init = get_mem_data({
197 # ram_fname: "0x00000000",
199 ram_init
= get_mem_data(ram_fname
, "little")
201 # remap the main RAM to reset-start-address
203 # without sram nothing works, therefore move it to higher up
204 self
.mem_map
["sram"] = 0x90000000
206 # put UART at 0xc000200 (w00t! this works!)
207 self
.csr_map
["uart"] = 4
209 self
.mem_map
["main_ram"] = 0x90000000
210 self
.mem_map
["sram"] = 0x00000000
212 # SoCCore -------------------------------------------------------------
213 SoCCore
.__init
__(self
, platform
, clk_freq
=sys_clk_freq
,
214 cpu_type
= "microwatt",
215 cpu_cls
= LibreSoC
if cpu
== "libresoc" \
217 #bus_data_width = 64,
218 csr_address_width
= 14, # limit to 0x8000
219 cpu_variant
= variant
,
222 uart_name
= uart_name
,
223 with_sdram
= with_sdram
,
224 sdram_module
= sdram_module
,
225 sdram_data_width
= sdram_data_width
,
226 integrated_rom_size
= 0, # if ram_fname else 0x10000,
227 integrated_sram_size
= 0x200,
228 #integrated_main_ram_init = ram_init,
229 integrated_main_ram_size
= 0x00000000 if with_sdram \
230 else 0x10000000 , # 256MB
232 self
.platform
.name
= "ls180"
234 # SDR SDRAM ----------------------------------------------
235 if False: # not self.integrated_main_ram_size:
236 self
.submodules
.sdrphy
= sdrphy_cls(platform
.request("sdram"))
238 if cpu
== "libresoc":
239 # XICS interrupt devices
240 icp_addr
= self
.mem_map
['icp']
241 icp_wb
= self
.cpu
.xics_icp
242 icp_region
= SoCRegion(origin
=icp_addr
, size
=0x20, cached
=False)
243 self
.bus
.add_slave(name
='icp', slave
=icp_wb
, region
=icp_region
)
245 ics_addr
= self
.mem_map
['ics']
246 ics_wb
= self
.cpu
.xics_ics
247 ics_region
= SoCRegion(origin
=ics_addr
, size
=0x1000, cached
=False)
248 self
.bus
.add_slave(name
='ics', slave
=ics_wb
, region
=ics_region
)
250 # CRG -----------------------------------------------------------------
251 self
.submodules
.crg
= CRG(platform
.request("sys_clk"),
252 platform
.request("sys_rst"))
256 # SDRAM ----------------------------------------------------
258 sdram_clk_freq
= int(100e6
) # FIXME: use 100MHz timings
259 sdram_module_cls
= getattr(litedram_modules
, sdram_module
)
260 sdram_rate
= "1:{}".format(
261 sdram_module_nphases
[sdram_module_cls
.memtype
])
262 sdram_module
= sdram_module_cls(sdram_clk_freq
, sdram_rate
)
263 phy_settings
= get_sdram_phy_settings(
264 memtype
= sdram_module
.memtype
,
265 data_width
= sdram_data_width
,
266 clk_freq
= sdram_clk_freq
)
267 #sdrphy_cls = HalfRateGENSDRPHY
268 sdrphy_cls
= GENSDRPHY
269 self
.submodules
.sdrphy
= sdrphy_cls(platform
.request("sdram"))
270 #self.submodules.sdrphy = sdrphy_cls(sdram_module,
274 self
.add_sdram("sdram",
276 module
= sdram_module
,
277 origin
= self
.mem_map
["main_ram"],
279 l2_cache_size
= 0, # 8192
280 l2_cache_min_data_width
= 128,
281 l2_cache_reverse
= True
283 # FIXME: skip memtest to avoid corrupting memory
284 self
.add_constant("MEMTEST_BUS_SIZE", 128//16)
285 self
.add_constant("MEMTEST_DATA_SIZE", 128//16)
286 self
.add_constant("MEMTEST_ADDR_SIZE", 128//16)
287 self
.add_constant("MEMTEST_BUS_DEBUG", 1)
288 self
.add_constant("MEMTEST_ADDR_DEBUG", 1)
289 self
.add_constant("MEMTEST_DATA_DEBUG", 1)
291 # GPIOs (bi-directional)
292 self
.submodules
.gpio
= GPIOTristateASIC(platform
.request("gpio"))
296 self
.submodules
.spi_master
= SPIMaster(
297 pads
= platform
.request("spi_master"),
299 sys_clk_freq
= sys_clk_freq
,
302 self
.add_csr("spi_master")
304 # EINTs - very simple, wire up top 3 bits to ls180 "eint" pins
305 self
.comb
+= self
.cpu
.interrupt
[12:16].eq(platform
.request("eint"))
308 jtagpads
= platform
.request("jtag")
309 self
.comb
+= self
.cpu
.jtag_tck
.eq(jtagpads
.tck
)
310 self
.comb
+= self
.cpu
.jtag_tms
.eq(jtagpads
.tms
)
311 self
.comb
+= self
.cpu
.jtag_tdi
.eq(jtagpads
.tdi
)
312 self
.comb
+= jtagpads
.tdo
.eq(self
.cpu
.jtag_tdo
)
317 setattr(self
.submodules
, name
, PWM(platform
.request("pwm", i
)))
321 self
.submodules
.i2c
= I2CMaster(platform
.request("i2c"))
324 # SDCard -----------------------------------------------------
327 sdcard_pads
= self
.platform
.request("sdcard")
330 self
.submodules
.sdphy
= SDPHY(sdcard_pads
,
331 self
.platform
.device
, self
.clk_freq
)
332 self
.submodules
.sdcore
= SDCore(self
.sdphy
)
333 self
.add_csr("sdphy")
334 self
.add_csr("sdcore")
337 bus
= wishbone
.Interface(data_width
=self
.bus
.data_width
,
338 adr_width
=self
.bus
.address_width
)
339 self
.submodules
.sdblock2mem
= SDBlock2MemDMA(bus
=bus
,
340 endianness
=self
.cpu
.endianness
)
341 self
.comb
+= self
.sdcore
.source
.connect(self
.sdblock2mem
.sink
)
342 dma_bus
= self
.bus
if not hasattr(self
, "dma_bus") else self
.dma_bus
343 dma_bus
.add_master("sdblock2mem", master
=bus
)
344 self
.add_csr("sdblock2mem")
347 bus
= wishbone
.Interface(data_width
=self
.bus
.data_width
,
348 adr_width
=self
.bus
.address_width
)
349 self
.submodules
.sdmem2block
= SDMem2BlockDMA(bus
=bus
,
350 endianness
=self
.cpu
.endianness
)
351 self
.comb
+= self
.sdmem2block
.source
.connect(self
.sdcore
.sink
)
352 dma_bus
= self
.bus
if not hasattr(self
, "dma_bus") else self
.dma_bus
353 dma_bus
.add_master("sdmem2block", master
=bus
)
354 self
.add_csr("sdmem2block")
356 # Debug ---------------------------------------------------------------
360 # setup running of DMI FSM
363 dmi_dout
= Signal(64)
369 dbg_dout
= Signal(64)
372 # capture pc from dmi
374 active_dbg
= Signal()
375 active_dbg_cr
= Signal()
376 active_dbg_xer
= Signal()
385 # increment counter, Stop after 100000 cycles
387 self
.sync
+= uptime
.eq(uptime
+ 1)
388 #self.sync += If(uptime == 1000000000000, Finish())
390 # DMI FSM counter and FSM itself
391 dmicount
= Signal(10)
392 dmirunning
= Signal(1)
393 dmi_monitor
= Signal(1)
395 self
.submodules
+= dmifsm
399 If(dmi_req
& dmi_wen
,
400 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
401 self
.cpu
.dmi_din
.eq(dmi_din
), # DMI in
402 self
.cpu
.dmi_req
.eq(1), # DMI request
403 self
.cpu
.dmi_wr
.eq(1), # DMI write
410 If(dmi_req
& ~dmi_wen
,
411 (self
.cpu
.dmi_addr
.eq(dmi_addr
), # DMI Addr
412 self
.cpu
.dmi_req
.eq(1), # DMI request
413 self
.cpu
.dmi_wr
.eq(0), # DMI read
415 # acknowledge received: capture data.
417 NextValue(dbg_addr
, dmi_addr
),
418 NextValue(dbg_dout
, self
.cpu
.dmi_dout
),
419 NextValue(dbg_msg
, 1),
426 # DMI response received: reset the dmi request and check if
430 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
432 NextState("START"), # back to start on next cycle
434 NextValue(dmi_req
, 0),
435 NextValue(dmi_addr
, 0),
436 NextValue(dmi_din
, 0),
437 NextValue(dmi_wen
, 0),
440 # "monitor" mode fires off a STAT request
441 dmifsm
.act("FIRE_MONITOR",
442 (NextValue(dmi_req
, 1),
443 NextValue(dmi_addr
, 1), # DMI STAT address
444 NextValue(dmi_din
, 0),
445 NextValue(dmi_wen
, 0), # read STAT
446 NextState("START"), # back to start on next cycle
450 self
.comb
+= xer_so
.eq((dbg_dout
& 1) == 1)
451 self
.comb
+= xer_ca
.eq((dbg_dout
& 4) == 4)
452 self
.comb
+= xer_ca32
.eq((dbg_dout
& 8) == 8)
453 self
.comb
+= xer_ov
.eq((dbg_dout
& 16) == 16)
454 self
.comb
+= xer_ov32
.eq((dbg_dout
& 32) == 32)
457 self
.sync
+= If(dbg_msg
,
458 (If(active_dbg
& (dbg_addr
== 0b10), # PC
459 Display("pc : %016x", dbg_dout
),
461 If(dbg_addr
== 0b10, # PC
462 pc
.eq(dbg_dout
), # capture PC
464 #If(dbg_addr == 0b11, # MSR
465 # Display(" msr: %016x", dbg_dout),
467 If(dbg_addr
== 0b1000, # CR
468 Display(" cr : %016x", dbg_dout
),
470 If(dbg_addr
== 0b1001, # XER
471 Display(" xer: so %d ca %d 32 %d ov %d 32 %d",
472 xer_so
, xer_ca
, xer_ca32
, xer_ov
, xer_ov32
),
474 If(dbg_addr
== 0b101, # GPR
475 Display(" gpr: %016x", dbg_dout
),
477 # also check if this is a "stat"
478 If(dbg_addr
== 1, # requested a STAT
479 #Display(" stat: %x", dbg_dout),
480 If(dbg_dout
& 2, # bit 2 of STAT is "stopped" mode
481 dmirunning
.eq(1), # continue running
482 dmi_monitor
.eq(0), # and stop monitor mode
490 self
.sync
+= If(uptime
== 0,
491 (dmi_addr
.eq(0), # CTRL
492 dmi_din
.eq(1<<0), # STOP
498 self
.sync
+= If(uptime
== 4,
502 self
.sync
+= If(dmirunning
,
503 dmicount
.eq(dmicount
+ 1),
506 # loop every 1<<N cycles
510 self
.sync
+= If(dmicount
== 4,
511 (dmi_addr
.eq(0b10), # NIA
518 self
.sync
+= If(dmicount
== 8,
519 (dmi_addr
.eq(0), # CTRL
520 dmi_din
.eq(1<<3), # STEP
523 dmirunning
.eq(0), # stop counter, need to fire "monitor"
524 dmi_monitor
.eq(1), # start "monitor" instead
528 # limit range of pc for debug reporting
529 #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
530 #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
531 self
.comb
+= active_dbg
.eq(1)
535 self
.sync
+= If(active_dbg
& (dmicount
== 12),
536 (dmi_addr
.eq(0b11), # MSR
542 if cpu
== "libresoc":
543 #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
544 self
.comb
+= active_dbg_cr
.eq(0)
547 self
.sync
+= If(active_dbg_cr
& (dmicount
== 16),
548 (dmi_addr
.eq(0b1000), # CR
554 #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
555 self
.comb
+= active_dbg_xer
.eq(active_dbg_cr
)
558 self
.sync
+= If(active_dbg_xer
& (dmicount
== 20),
559 (dmi_addr
.eq(0b1001), # XER
567 self
.sync
+= If(active_dbg
& (dmicount
== 24+(i
*8)),
568 (dmi_addr
.eq(0b100), # GSPR addr
575 self
.sync
+= If(active_dbg
& (dmicount
== 28+(i
*8)),
576 (dmi_addr
.eq(0b101), # GSPR data
582 # monitor bbus read/write
583 self
.sync
+= If(active_dbg
& self
.cpu
.dbus
.stb
& self
.cpu
.dbus
.ack
,
584 Display(" [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
598 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
600 Display(" [%06x] iadr: %8x, s %01x w %016x",
609 self
.sync
+= If(active_dbg
& self
.cpu
.ibus
.stb
& self
.cpu
.ibus
.ack
&
611 Display(" [%06x] iadr: %8x, s %01x r %016x",
620 # Build -----------------------------------------------------------------------
623 parser
= argparse
.ArgumentParser(description
="LiteX LibreSoC CPU Sim")
624 parser
.add_argument("--cpu", default
="libresoc",
625 help="CPU to use: libresoc (default) or microwatt")
626 parser
.add_argument("--platform", default
="sim",
627 help="platform (sim or ls180)")
628 parser
.add_argument("--debug", action
="store_true",
629 help="Enable debug traces")
630 parser
.add_argument("--trace", action
="store_true",
631 help="Enable tracing")
632 parser
.add_argument("--trace-start", default
=0,
633 help="Cycle to start FST tracing")
634 parser
.add_argument("--trace-end", default
=-1,
635 help="Cycle to end FST tracing")
636 parser
.add_argument("--build", action
="store_true", help="Build bitstream")
637 args
= parser
.parse_args()
640 if args
.platform
== 'ls180':
641 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
,
642 platform
=args
.platform
)
644 builder
= Builder(soc
, compile_gateware
= True)
645 builder
.build(run
= True)
649 sim_config
= SimConfig(default_clk
="sys_clk")
650 sim_config
.add_module("serial2console", "serial")
653 soc
= LibreSoCSim(cpu
=args
.cpu
, debug
=args
.debug
,
654 platform
=args
.platform
)
655 builder
= Builder(soc
, compile_gateware
= i
!=0)
656 builder
.build(sim_config
=sim_config
,
659 trace_start
= int(args
.trace_start
),
660 trace_end
= int(args
.trace_end
),
664 if __name__
== "__main__":