from soc.bus.opencores_ethmac import EthMAC # OpenCores 10/100 Ethernet MAC
from soc.bus.external_core import ExternalCore # external libresoc/microwatt
from soc.bus.wb_downconvert import WishboneDownConvert
+from soc.bus.wb_async import WBAsyncBridge
from soc.bus.syscon import MicrowattSYSCON
from soc.interrupts.xics import XICS_ICP, XICS_ICS
hyperram_pins=None,
xics_icp_addr=None, xics_ics_addr=None,
clk_freq=50e6,
+ dram_clk_freq=None,
add_cpu=True):
# wishbone routing is as follows:
# |
# 64to32DownCvt
# |
- # arbiter------------------------------------------+
- # | |
- # +---decoder----+--------+---------+-------+--------+ |
- # | | | | | | | |
- # uart XICS CSRs DRAM XIP SPI HyperRAM EthMAC
+ # arbiter--------------------------------------------------------+
+ # | |
+ # +---decoder----+--------+-----------------+-------------+--------+ |
+ # | | | | | | | |
+ # | | | WBAsyncBridge | | | |
+ # | | | | | | | |
+ # uart XICS CSRs DRAM XIP SPI HyperRAM EthMAC
# set up wishbone bus arbiter and decoder. arbiter routes,
# decoder maps local-relative addressed satellites to global addresses
if fpga in ['versa_ecp5', 'versa_ecp5_85', 'isim', 'ulx3s']:
if fpga in ['isim']:
pod_bits = 6
- self.crg = ECP5CRG(clk_freq, dram_clk_freq=None, pod_bits=pod_bits)
+ if fpga in ['versa_ecp5_85']:
+ self.crg = ECP5CRG(clk_freq, dram_clk_freq=dram_clk_freq, pod_bits=pod_bits)
+ else:
+ self.crg = ECP5CRG(clk_freq, dram_clk_freq=None, pod_bits=pod_bits)
if fpga in ['arty_a7']:
self.crg = ArtyA7CRG(clk_freq)
+ self.dram_clk_freq = dram_clk_freq
+ if self.dram_clk_freq is None:
+ self.dram_clk_freq = clk_freq
+
# set up CPU, with 64-to-32-bit downconverters
if add_cpu:
self.cpu = ExternalCore(name="ext_core")
spi_offset = 2<<20 if (spi_0_pins is not None) else None
dram_offset = ddr_addr if (ddr_pins is not None) else None
self.syscon = MicrowattSYSCON(sys_clk_freq=clk_freq,
+ mem_clk_freq=self.dram_clk_freq,
has_uart=(uart_pins is not None),
spi_offset=spi_offset,
dram_addr=dram_offset)
# DRAM Module
if ddr_pins is not None: # or fpga == 'sim':
- ddrmodule = dram_cls(clk_freq, "1:2") # match DDR3 ASIC P/N
+ ddrmodule = dram_cls(self.dram_clk_freq, "1:2") # match DDR3 ASIC P/N
# remap both the sync domain (wherever it occurs) and
- # the sync2x domain. technically this should NOT be done.
- # it's a bit of a mess. ok: this should be done only
- # when dramsync===sync (and dramsync2x===sync2x)
- drs = DomainRenamer({"sync": "dramsync",
+ # the sync2x domain, if dram frequency is specified and
+ # not equal to the core clock
+ drs = None
+ if (dram_clk_freq is not None) and (self.dram_clk_freq != clk_freq):
+ drs = lambda x: x
+ else:
+ drs = DomainRenamer({"sync": "dramsync",
"sync2x": "dramsync2x"})
- # HOWEVER, when the ASyncBridge is deployed, the two domains
- # must NOT be renamed, instead this used:
- #drs = lambda x: x
- # and then the ASyncBridge takes care of the two.
- # but, back in ecp5_crg.py, when ASyncBridge is added,
- # dram_clk_freq must be passed to ECP5CRG, which will call
- # ECP5CRG.phase2_domain on your behalf, setting up the
- # necessary dramsync2x which is needed for the xdr=4 IOpads
-
if fpga == 'sim':
self.ddrphy = FakePHY(module=ddrmodule,
- settings=sim_ddr3_settings(clk_freq),
+ settings=sim_ddr3_settings(self.dram_clk_freq),
verbosity=SDRAM_VERBOSE_DBG,
- clk_freq=clk_freq)
+ clk_freq=self.dram_clk_freq)
else:
- self.ddrphy = drs(ECP5DDRPHY(ddr_pins, sys_clk_freq=clk_freq))
- self._decoder.add(self.ddrphy.bus, addr=ddrphy_addr)
+ self.ddrphy = drs(ECP5DDRPHY(ddr_pins, sys_clk_freq=self.dram_clk_freq))
+
+ # Set up Wishbone asynchronous bridge
+ self.ddrphy_async_bus = wishbone.Interface(
+ addr_width=self.ddrphy.bus.addr_width,
+ data_width=self.ddrphy.bus.data_width,
+ granularity=self.ddrphy.bus.granularity,
+ features={'stall'})
+ self.ddrphy_async_bus.memory_map = self.ddrphy.bus.memory_map
+
+ self.ddrphy_async_br = WBAsyncBridge(
+ master_bus=self.ddrphy_async_bus,
+ slave_bus=self.ddrphy.bus,
+ master_clock_domain=None,
+ slave_clock_domain="dramsync",
+ address_width=self.ddrphy.bus.addr_width,
+ data_width=self.ddrphy.bus.data_width,
+ granularity=self.ddrphy.bus.granularity,
+ master_features={'stall'})
+
+ # Add wishbone decoder
+ self._decoder.add(self.ddrphy_async_bus, addr=ddrphy_addr)
dramcore = gramCore(phy=self.ddrphy,
geom_settings=ddrmodule.geom_settings,
timing_settings=ddrmodule.timing_settings,
- clk_freq=clk_freq)
+ clk_freq=self.dram_clk_freq)
if fpga == 'sim':
self.dramcore = dramcore
else:
self.dramcore = drs(dramcore)
- self._decoder.add(self.dramcore.bus, addr=dramcore_addr)
- # map the DRAM onto Wishbone, XXX use stall but set classic below
- # XXX WHEN ADDING ASYNCBRIDGE IT IS THE **BRIDGE** THAT MUST
- # XXX HAVE THE STALL SIGNAL, AND THE **BRIDGE** THAT MUST HAVE
- # XXX stall=stb&~ack APPLIED
- drambone = gramWishbone(dramcore, features={'stall'})
+ # Set up Wishbone asynchronous bridge
+ self.dramcore_async_bus = wishbone.Interface(
+ addr_width=self.dramcore.bus.addr_width,
+ data_width=self.dramcore.bus.data_width,
+ granularity=self.dramcore.bus.granularity,
+ features={'stall'})
+ self.dramcore_async_bus.memory_map = self.dramcore.bus.memory_map
+
+ self.dramcore_async_br = WBAsyncBridge(
+ master_bus=self.dramcore_async_bus,
+ slave_bus=self.dramcore.bus,
+ master_clock_domain=None,
+ slave_clock_domain="dramsync",
+ address_width=self.dramcore.bus.addr_width,
+ data_width=self.dramcore.bus.data_width,
+ granularity=self.dramcore.bus.granularity,
+ master_features={'stall'})
+
+ # Add wishbone decoder
+ self._decoder.add(self.dramcore_async_bus, addr=dramcore_addr)
+
+ drambone = gramWishbone(dramcore)
if fpga == 'sim':
self.drambone = drambone
else:
self.drambone = drs(drambone)
- # XXX ADD THE ASYNCBRIDGE NOT THE DRAMBONE.BUS, THEN
- # XXX ADD DRAMBONE.BUS TO ASYNCBRIDGE
- self._decoder.add(self.drambone.bus, addr=ddr_addr)
+
+ # Set up Wishbone asynchronous bridge
+ self.drambone_async_bus = wishbone.Interface(
+ addr_width=self.drambone.bus.addr_width,
+ data_width=self.drambone.bus.data_width,
+ granularity=self.drambone.bus.granularity,
+ features={'stall'})
+ self.drambone_async_bus.memory_map = self.drambone.bus.memory_map
+
+ self.drambone_async_br = WBAsyncBridge(
+ master_bus=self.drambone_async_bus,
+ slave_bus=self.drambone.bus,
+ master_clock_domain=None,
+ slave_clock_domain="dramsync",
+ address_width=self.drambone.bus.addr_width,
+ data_width=self.drambone.bus.data_width,
+ granularity=self.drambone.bus.granularity,
+ master_features={'stall'})
+
+ # Add wishbone decoder
+ self._decoder.add(self.drambone_async_bus, addr=ddr_addr)
# additional SRAM at address if DRAM is not also at 0x0
# (TODO, check Flash, and HyperRAM as well)
m.submodules.ddrphy = self.ddrphy
m.submodules.dramcore = self.dramcore
m.submodules.drambone = drambone = self.drambone
- # grrr, same problem with drambone: not WB4-pipe compliant
- # XXX TAKE THIS OUT, REPLACE WITH ASYNCBRIDGE HAVING
- # XXX asyncbridge.bus.stall.eq(asyncbridge.bus.cyc & ...)
- comb += drambone.bus.stall.eq(drambone.bus.cyc & ~drambone.bus.ack)
+
+ # add async wishbone bridges
+ m.submodules.ddrphy_async_br = self.ddrphy_async_br
+ m.submodules.dramcore_async_br = self.dramcore_async_br
+ m.submodules.drambone_async_br = self.drambone_async_br
+
+ # grrr, same problem with WB async bridge: not WB4-pipe compliant
+ comb += self.ddrphy_async_bus.stall.eq(self.ddrphy_async_bus.cyc & ~self.ddrphy_async_bus.ack)
+ comb += self.dramcore_async_bus.stall.eq(self.dramcore_async_bus.cyc & ~self.dramcore_async_bus.ack)
+ comb += self.drambone_async_bus.stall.eq(self.drambone_async_bus.cyc & ~self.drambone_async_bus.ack)
+
+ # add wb async bridge verilog source. assumes a directory structure where
+ # microwatt has been checked out in a common subdirectory with:
+ # git clone https://github.com/alexforencich/verilog-wishbone.git
+ # git checkout d1fa24a0
+ verilog_wishbone = "../../verilog-wishbone/rtl"
+ pth = os.path.split(__file__)[0]
+ pth = os.path.join(pth, verilog_wishbone)
+ fname = os.path.abspath(pth)
+ print (fname)
+ self.ddrphy_async_br.add_verilog_source(fname, platform)
+ self.dramcore_async_br.add_verilog_source(fname, platform)
+ self.drambone_async_br.add_verilog_source(fname, platform)
# add hyperram module
if hasattr(self, "hyperram"):
clk_freq = 70e6
if fpga == 'sim':
clk_freq = 100e6
+ dram_clk_freq = clk_freq
if fpga == 'isim':
clk_freq = 55e6 # below 50 mhz, stops DRAM being enabled
if fpga == 'versa_ecp5':
# 50MHz works. 100MHz works. 55MHz does NOT work.
# Stick with multiples of 50MHz...
clk_freq = 50e6
+ dram_clk_freq = 100e6
if fpga == 'arty_a7':
clk_freq = 50e6
if fpga == 'ulx3s':
xics_icp_addr=0xc000_4000, # XICS_ICP_BASE
xics_ics_addr=0xc000_5000, # XICS_ICS_BASE
clk_freq=clk_freq,
+ dram_clk_freq=dram_clk_freq,
add_cpu=True)
if toolchain == 'Trellis':