WIP: non-functional async-wip
authorRaptor Engineering Development Team <support@raptorengineering.com>
Fri, 15 Apr 2022 06:53:24 +0000 (01:53 -0500)
committerRaptor Engineering Development Team <support@raptorengineering.com>
Fri, 15 Apr 2022 06:57:02 +0000 (01:57 -0500)
For comment / early review of overall plan of attack

src/ls2.py

index 50d69e1e5cf337642067fbb82b9a0a22c3c0ec75..d1d7072cb6be6ec52d24ed0dfdbaa8d2c288e91c 100644 (file)
@@ -34,6 +34,7 @@ from soc.bus.tercel import Tercel # SPI XIP master
 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
 
@@ -249,6 +250,7 @@ class DDR3SoC(SoC, Elaboratable):
                  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:
@@ -262,11 +264,13 @@ class DDR3SoC(SoC, Elaboratable):
         #          |
         #      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
@@ -286,10 +290,17 @@ class DDR3SoC(SoC, Elaboratable):
         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")
@@ -344,6 +355,7 @@ class DDR3SoC(SoC, Elaboratable):
         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)
@@ -395,55 +407,103 @@ class DDR3SoC(SoC, Elaboratable):
 
         # 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)
@@ -566,10 +626,29 @@ class DDR3SoC(SoC, Elaboratable):
             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"):
@@ -736,6 +815,7 @@ def build_platform(fpga, firmware):
     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':
@@ -744,6 +824,7 @@ def build_platform(fpga, firmware):
         # 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':
@@ -911,6 +992,7 @@ def build_platform(fpga, firmware):
                   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':