MEM: Make the bus bridge unidirectional and fixed address range
authorAndreas Hansson <andreas.hansson@arm.com>
Tue, 17 Jan 2012 18:55:09 +0000 (12:55 -0600)
committerAndreas Hansson <andreas.hansson@arm.com>
Tue, 17 Jan 2012 18:55:09 +0000 (12:55 -0600)
This patch makes the bus bridge uni-directional and specialises the
bus ports to be a master port and a slave port. This greatly
simplifies the assumptions on both sides as either port only has to
deal with requests or responses. The following patches introduce the
notion of master and slave ports, and would not be possible without
this split of responsibilities.

In making the bridge unidirectional, the address range mechanism of
the bridge is also changed. For the cases where communication is
taking place both ways, an additional bridge is needed. This causes
issues with the existing mechanism, as the busses cannot determine
when to stop iterating the address updates from the two bridges. To
avoid this issue, and also greatly simplify the specification, the
bridge now has a fixed set of address ranges, specified at creation
time.

23 files changed:
configs/common/FSConfig.py
configs/example/fs.py
src/dev/arm/RealView.py
src/mem/Bridge.py
src/mem/bridge.cc
src/mem/bridge.hh
tests/configs/pc-o3-timing.py
tests/configs/pc-simple-atomic.py
tests/configs/pc-simple-timing.py
tests/configs/realview-o3-dual.py
tests/configs/realview-o3.py
tests/configs/realview-simple-atomic-dual.py
tests/configs/realview-simple-atomic.py
tests/configs/realview-simple-timing-dual.py
tests/configs/realview-simple-timing.py
tests/configs/tsunami-inorder.py
tests/configs/tsunami-o3-dual.py
tests/configs/tsunami-o3.py
tests/configs/tsunami-simple-atomic-dual.py
tests/configs/tsunami-simple-atomic.py
tests/configs/tsunami-simple-timing-dual.py
tests/configs/tsunami-simple-timing.py
tests/configs/twosys-tsunami-simple-atomic.py

index 3c506c21510d3973eb64624e700fa899d787e210..8407db86952f8dad199636fde2e4160701450088 100644 (file)
@@ -56,6 +56,7 @@ class MemBus(Bus):
 
 
 def makeLinuxAlphaSystem(mem_mode, mdesc = None):
+    IO_address_space_base = 0x80000000000
     class BaseTsunami(Tsunami):
         ethernet = NSGigE(pci_bus=0, pci_dev=1, pci_func=0)
         ide = IdeController(disks=[Parent.disk0, Parent.disk2],
@@ -68,10 +69,13 @@ def makeLinuxAlphaSystem(mem_mode, mdesc = None):
     self.readfile = mdesc.script()
     self.iobus = Bus(bus_id=0)
     self.membus = MemBus(bus_id=1)
-    self.bridge = Bridge(delay='50ns', nack_delay='4ns')
+    # By default the bridge responds to all addresses above the I/O
+    # base address (including the PCI config space)
+    self.bridge = Bridge(delay='50ns', nack_delay='4ns',
+                         ranges = [AddrRange(IO_address_space_base, Addr.max)])
     self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem()))
-    self.bridge.side_a = self.iobus.port
-    self.bridge.side_b = self.membus.port
+    self.bridge.master = self.iobus.port
+    self.bridge.slave = self.membus.port
     self.physmem.port = self.membus.port
     self.disk0 = CowIdeDisk(driveID='master')
     self.disk2 = CowIdeDisk(driveID='master')
@@ -146,6 +150,10 @@ def makeLinuxAlphaRubySystem(mem_mode, mdesc = None):
     return self
 
 def makeSparcSystem(mem_mode, mdesc = None):
+    # Constants from iob.cc and uart8250.cc
+    iob_man_addr = 0x9800000000
+    uart_pio_size = 8
+
     class CowMmDisk(MmDisk):
         image = CowDiskImage(child=RawDiskImage(read_only=True),
                              read_only=False)
@@ -166,8 +174,8 @@ def makeSparcSystem(mem_mode, mdesc = None):
     self.t1000.attachIO(self.iobus)
     self.physmem = PhysicalMemory(range = AddrRange(Addr('1MB'), size = '64MB'), zero = True)
     self.physmem2 = PhysicalMemory(range = AddrRange(Addr('2GB'), size ='256MB'), zero = True)
-    self.bridge.side_a = self.iobus.port
-    self.bridge.side_b = self.membus.port
+    self.bridge.master = self.iobus.port
+    self.bridge.slave = self.membus.port
     self.physmem.port = self.membus.port
     self.physmem2.port = self.membus.port
     self.rom.port = self.membus.port
@@ -178,6 +186,25 @@ def makeSparcSystem(mem_mode, mdesc = None):
     self.disk0 = CowMmDisk()
     self.disk0.childImage(disk('disk.s10hw2'))
     self.disk0.pio = self.iobus.port
+
+    # The puart0 and hvuart are placed on the IO bus, so create ranges
+    # for them. The remaining IO range is rather fragmented, so poke
+    # holes for the iob and partition descriptors etc.
+    self.bridge.ranges = \
+        [
+        AddrRange(self.t1000.puart0.pio_addr,
+                  self.t1000.puart0.pio_addr + uart_pio_size - 1),
+        AddrRange(self.disk0.pio_addr,
+                  self.t1000.fake_jbi.pio_addr +
+                  self.t1000.fake_jbi.pio_size - 1),
+        AddrRange(self.t1000.fake_clk.pio_addr,
+                  iob_man_addr - 1),
+        AddrRange(self.t1000.fake_l2_1.pio_addr,
+                  self.t1000.fake_ssi.pio_addr +
+                  self.t1000.fake_ssi.pio_size - 1),
+        AddrRange(self.t1000.hvuart.pio_addr,
+                  self.t1000.hvuart.pio_addr + uart_pio_size - 1)
+        ]
     self.reset_bin = binary('reset_new.bin')
     self.hypervisor_bin = binary('q_new.bin')
     self.openboot_bin = binary('openboot_new.bin')
@@ -206,8 +233,8 @@ def makeArmSystem(mem_mode, machine_type, mdesc = None, bare_metal=False):
     self.membus = MemBus(bus_id=1)
     self.membus.badaddr_responder.warn_access = "warn"
     self.bridge = Bridge(delay='50ns', nack_delay='4ns')
-    self.bridge.side_a = self.iobus.port
-    self.bridge.side_b = self.membus.port
+    self.bridge.master = self.iobus.port
+    self.bridge.slave = self.membus.port
 
     self.mem_mode = mem_mode
 
@@ -261,7 +288,7 @@ def makeArmSystem(mem_mode, machine_type, mdesc = None, bare_metal=False):
         self.boot_osflags = boot_flags
 
     self.physmem.port = self.membus.port
-    self.realview.attachOnChipIO(self.membus)
+    self.realview.attachOnChipIO(self.membus, self.bridge)
     self.realview.attachIO(self.iobus)
     self.intrctrl = IntrControl()
     self.terminal = Terminal()
@@ -287,8 +314,8 @@ def makeLinuxMipsSystem(mem_mode, mdesc = None):
     self.membus = MemBus(bus_id=1)
     self.bridge = Bridge(delay='50ns', nack_delay='4ns')
     self.physmem = PhysicalMemory(range = AddrRange('1GB'))
-    self.bridge.side_a = self.iobus.port
-    self.bridge.side_b = self.membus.port
+    self.bridge.master = self.iobus.port
+    self.bridge.slave = self.membus.port
     self.physmem.port = self.membus.port
     self.disk0 = CowIdeDisk(driveID='master')
     self.disk2 = CowIdeDisk(driveID='master')
@@ -316,14 +343,42 @@ def x86IOAddress(port):
     return IO_address_space_base + port
 
 def connectX86ClassicSystem(x86_sys):
+    # Constants similar to x86_traits.hh
+    IO_address_space_base = 0x8000000000000000
+    pci_config_address_space_base = 0xc000000000000000
+    interrupts_address_space_base = 0xa000000000000000
+    APIC_range_size = 1 << 12;
+
     x86_sys.membus = MemBus(bus_id=1)
     x86_sys.physmem.port = x86_sys.membus.port
 
     # North Bridge
     x86_sys.iobus = Bus(bus_id=0)
     x86_sys.bridge = Bridge(delay='50ns', nack_delay='4ns')
-    x86_sys.bridge.side_a = x86_sys.iobus.port
-    x86_sys.bridge.side_b = x86_sys.membus.port
+    x86_sys.bridge.master = x86_sys.iobus.port
+    x86_sys.bridge.slave = x86_sys.membus.port
+    # Allow the bridge to pass through the IO APIC (two pages),
+    # everything in the IO address range up to the local APIC, and
+    # then the entire PCI address space and beyond
+    x86_sys.bridge.ranges = \
+        [
+        AddrRange(x86_sys.pc.south_bridge.io_apic.pio_addr,
+                  x86_sys.pc.south_bridge.io_apic.pio_addr +
+                  APIC_range_size - 1),
+        AddrRange(IO_address_space_base,
+                  interrupts_address_space_base - 1),
+        AddrRange(pci_config_address_space_base,
+                  Addr.max)
+        ]
+
+    # Create a bridge from the IO bus to the memory bus to allow access to
+    # the local APIC (two pages)
+    x86_sys.iobridge = Bridge(delay='50ns', nack_delay='4ns')
+    x86_sys.iobridge.slave = x86_sys.iobus.port
+    x86_sys.iobridge.master = x86_sys.membus.port
+    x86_sys.iobridge.ranges = [AddrRange(interrupts_address_space_base,
+                                         interrupts_address_space_base +
+                                         APIC_range_size - 1)]
 
     # connect the io bus
     x86_sys.pc.attachIO(x86_sys.iobus)
index 05e35c4ba933c07ea93ad8208c3d92a828e331d8..11d7d43f0fefbe8911ce831166c02b0f91d0033b 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2010 ARM Limited
+# Copyright (c) 2010-2011 ARM Limited
 # All rights reserved.
 #
 # The license below extends only to copyright in the software and shall
@@ -157,23 +157,19 @@ test_sys.cpu = [TestCPUClass(cpu_id=i) for i in xrange(np)]
 
 CacheConfig.config_cache(options, test_sys)
 
+if bm[0]:
+    mem_size = bm[0].mem()
+else:
+    mem_size = SysConfig().mem()
 if options.caches or options.l2cache:
-    if bm[0]:
-        mem_size = bm[0].mem()
-    else:
-        mem_size = SysConfig().mem()
-    # For x86, we need to poke a hole for interrupt messages to get back to the
-    # CPU. These use a portion of the physical address space which has a
-    # non-zero prefix in the top nibble. Normal memory accesses have a 0
-    # prefix.
-    if buildEnv['TARGET_ISA'] == 'x86':
-        test_sys.bridge.filter_ranges_a=[AddrRange(0, Addr.max >> 4)]
-    else:
-        test_sys.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-    test_sys.bridge.filter_ranges_b=[AddrRange(mem_size)]
     test_sys.iocache = IOCache(addr_range=mem_size)
     test_sys.iocache.cpu_side = test_sys.iobus.port
     test_sys.iocache.mem_side = test_sys.membus.port
+else:
+    test_sys.iobridge = Bridge(delay='50ns', nack_delay='4ns',
+                               ranges = [AddrRange(0, mem_size)])
+    test_sys.iobridge.slave = test_sys.iobus.port
+    test_sys.iobridge.master = test_sys.membus.port
 
 for i in xrange(np):
     if options.fastmem:
index 96f3c8a6172e34867ce99c0aa188451d1830e70f..cd7744362b981024b626f7dd904d924b1c9d37c5 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2009 ARM Limited
+# Copyright (c) 2009-2011 ARM Limited
 # All rights reserved.
 #
 # The license below extends only to copyright in the software and shall
@@ -177,12 +177,18 @@ class RealViewPBX(RealView):
     rtc_fake      = AmbaFake(pio_addr=0x10017000, amba_id=0x41031)
 
 
-    # Attach I/O devices that are on chip
-    def attachOnChipIO(self, bus):
+    # Attach I/O devices that are on chip and also set the appropriate
+    # ranges for the bridge
+    def attachOnChipIO(self, bus, bridge):
        self.gic.pio = bus.port
        self.l2x0_fake.pio = bus.port
        self.a9scu.pio = bus.port
        self.local_cpu_timer.pio = bus.port
+       # Bridge ranges based on excluding what is part of on-chip I/O
+       # (gic, l2x0, a9scu, local_cpu_timer)
+       bridge.ranges = [AddrRange(self.realview_io.pio_addr,
+                                  self.a9scu.pio_addr - 1),
+                        AddrRange(self.flash_fake.pio_addr, Addr.max)]
 
     # Attach I/O devices to specified bus object.  Can't do this
     # earlier, since the bus object itself is typically defined at the
@@ -248,10 +254,16 @@ class RealViewEB(RealView):
 
 
 
-    # Attach I/O devices that are on chip
-    def attachOnChipIO(self, bus):
+    # Attach I/O devices that are on chip and also set the appropriate
+    # ranges for the bridge
+    def attachOnChipIO(self, bus, bridge):
        self.gic.pio = bus.port
        self.l2x0_fake.pio = bus.port
+       # Bridge ranges based on excluding what is part of on-chip I/O
+       # (gic, l2x0)
+       bridge.ranges = [AddrRange(self.realview_io.pio_addr,
+                                  self.gic.cpu_addr - 1),
+                        AddrRange(self.flash_fake.pio_addr, Addr.max)]
 
     # Attach I/O devices to specified bus object.  Can't do this
     # earlier, since the bus object itself is typically defined at the
@@ -329,10 +341,15 @@ class VExpress_ELT(RealView):
     usb_fake       = IsaFake(pio_addr=0xFB000000, pio_size=0x1ffff)
 
 
-    # Attach I/O devices that are on chip
-    def attachOnChipIO(self, bus):
+    # Attach I/O devices that are on chip and also set the appropriate
+    # ranges for the bridge
+    def attachOnChipIO(self, bus, bridge):
        self.gic.pio = bus.port
        self.a9scu.pio = bus.port
+       # Bridge ranges based on excluding what is part of on-chip I/O
+       # (gic, a9scu)
+       bridge.ranges = [AddrRange(self.pci_cfg_base, self.a9scu.pio_addr - 1),
+                        AddrRange(self.local_cpu_timer.pio_addr, Addr.max)]
 
     # Attach I/O devices to specified bus object.  Can't do this
     # earlier, since the bus object itself is typically defined at the
index b48e1684d7db257965b449525855a2525cc2bd89..38b344613b68a962d04cb62d1c18b699087ff29d 100644 (file)
@@ -31,16 +31,12 @@ from MemObject import MemObject
 
 class Bridge(MemObject):
     type = 'Bridge'
-    side_a = Port('Side A port')
-    side_b = Port('Side B port')
-    req_size_a = Param.Int(16, "The number of requests to buffer")
-    req_size_b = Param.Int(16, "The number of requests to buffer")
-    resp_size_a = Param.Int(16, "The number of requests to buffer")
-    resp_size_b = Param.Int(16, "The number of requests to buffer")
+    slave = Port('Slave port')
+    master = Port('Master port')
+    req_size = Param.Int(16, "The number of requests to buffer")
+    resp_size = Param.Int(16, "The number of requests to buffer")
     delay = Param.Latency('0ns', "The latency of this bridge")
     nack_delay = Param.Latency('0ns', "The latency of this bridge")
     write_ack = Param.Bool(False, "Should this bridge ack writes")
-    filter_ranges_a = VectorParam.AddrRange([],
-            "What addresses shouldn't be passed through the side of the bridge")
-    filter_ranges_b = VectorParam.AddrRange([],
-            "What addresses shouldn't be passed through the side of the bridge")
+    ranges = VectorParam.AddrRange([AllMemory],
+                                   "Address ranges to pass through the bridge")
index 71cbcb76c40d8710e3a66a4243e26cd9d4df6c68..b486621185652b0f8cbdb20e6f7d40b8b3300702 100644 (file)
@@ -1,5 +1,16 @@
-
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2006 The Regents of The University of Michigan
  * All rights reserved.
  *
  *
  * Authors: Ali Saidi
  *          Steve Reinhardt
+ *          Andreas Hansson
  */
 
 /**
  * @file
- * Definition of a simple bus bridge without buffering.
+ * Implementation of a memory-mapped bus bridge that connects a master
+ * and a slave through a request and response queue.
  */
 
-#include <algorithm>
-
-#include "base/range_ops.hh"
 #include "base/trace.hh"
 #include "debug/BusBridge.hh"
 #include "mem/bridge.hh"
 #include "params/Bridge.hh"
 
-Bridge::BridgePort::BridgePort(const std::string &_name,
-                               Bridge *_bridge, BridgePort *_otherPort,
-                               int _delay, int _nack_delay, int _req_limit,
-                               int _resp_limit,
-                               std::vector<Range<Addr> > filter_ranges)
-    : Port(_name, _bridge), bridge(_bridge), otherPort(_otherPort),
-      delay(_delay), nackDelay(_nack_delay), filterRanges(filter_ranges),
-      outstandingResponses(0), queuedRequests(0), inRetry(false),
-      reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this)
+Bridge::BridgeSlavePort::BridgeSlavePort(const std::string &_name,
+                                         Bridge* _bridge,
+                                         BridgeMasterPort* _masterPort,
+                                         int _delay, int _nack_delay,
+                                         int _resp_limit,
+                                         std::vector<Range<Addr> > _ranges)
+    : Port(_name, _bridge), bridge(_bridge), masterPort(_masterPort),
+      delay(_delay), nackDelay(_nack_delay),
+      ranges(_ranges.begin(), _ranges.end()),
+      outstandingResponses(0), inRetry(false),
+      respQueueLimit(_resp_limit), sendEvent(this)
+{
+}
+
+Bridge::BridgeMasterPort::BridgeMasterPort(const std::string &_name,
+                                           Bridge* _bridge,
+                                           BridgeSlavePort* _slavePort,
+                                           int _delay, int _req_limit)
+    : Port(_name, _bridge), bridge(_bridge), slavePort(_slavePort),
+      delay(_delay), inRetry(false), reqQueueLimit(_req_limit), sendEvent(this)
 {
 }
 
 Bridge::Bridge(Params *p)
     : MemObject(p),
-      portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay,
-              p->req_size_a, p->resp_size_a, p->filter_ranges_a),
-      portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay,
-              p->req_size_b, p->resp_size_b, p->filter_ranges_b),
+      slavePort(p->name + "-slave", this, &masterPort, p->delay,
+                p->nack_delay, p->resp_size, p->ranges),
+      masterPort(p->name + "-master", this, &slavePort, p->delay, p->req_size),
       ackWrites(p->write_ack), _params(p)
 {
     if (ackWrites)
         panic("No support for acknowledging writes\n");
 }
 
-Port *
+Port*
 Bridge::getPort(const std::string &if_name, int idx)
 {
-    BridgePort *port;
+    Port* port;
 
-    if (if_name == "side_a")
-        port = &portA;
-    else if (if_name == "side_b")
-        port = &portB;
+    if (if_name == "slave")
+        port = &slavePort;
+    else if (if_name == "master")
+        port = &masterPort;
     else
         return NULL;
 
@@ -89,106 +109,133 @@ Bridge::getPort(const std::string &if_name, int idx)
 void
 Bridge::init()
 {
-    // Make sure that both sides are connected to.
-    if (!portA.isConnected() || !portB.isConnected())
+    // make sure both sides are connected and have the same block size
+    if (!slavePort.isConnected() || !masterPort.isConnected())
         fatal("Both ports of bus bridge are not connected to a bus.\n");
 
-    if (portA.peerBlockSize() != portB.peerBlockSize())
-        fatal("port A size %d, port B size %d \n " \
+    if (slavePort.peerBlockSize() != masterPort.peerBlockSize())
+        fatal("Slave port size %d, master port size %d \n " \
               "Busses don't have the same block size... Not supported.\n",
-              portA.peerBlockSize(), portB.peerBlockSize());
+              slavePort.peerBlockSize(), masterPort.peerBlockSize());
+
+    // notify the master side  of our address ranges
+    slavePort.sendRangeChange();
 }
 
 bool
-Bridge::BridgePort::respQueueFull()
+Bridge::BridgeSlavePort::respQueueFull()
 {
-    assert(outstandingResponses >= 0 && outstandingResponses <= respQueueLimit);
-    return outstandingResponses >= respQueueLimit;
+    return outstandingResponses == respQueueLimit;
 }
 
 bool
-Bridge::BridgePort::reqQueueFull()
+Bridge::BridgeMasterPort::reqQueueFull()
 {
-    assert(queuedRequests >= 0 && queuedRequests <= reqQueueLimit);
-    return queuedRequests >= reqQueueLimit;
+    return requestQueue.size() == reqQueueLimit;
 }
 
-/** Function called by the port when the bus is receiving a Timing
- * transaction.*/
 bool
-Bridge::BridgePort::recvTiming(PacketPtr pkt)
+Bridge::BridgeMasterPort::recvTiming(PacketPtr pkt)
 {
+    // should only see responses on the master side
+    assert(pkt->isResponse());
+
+    // all checks are done when the request is accepted on the slave
+    // side, so we are guaranteed to have space for the response
+
     DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
-                pkt->getSrc(), pkt->getDest(), pkt->getAddr());
+            pkt->getSrc(), pkt->getDest(), pkt->getAddr());
+
+    DPRINTF(BusBridge, "Request queue size: %d\n", requestQueue.size());
 
-    DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n",
-                    sendQueue.size(), queuedRequests, outstandingResponses);
-    DPRINTF(BusBridge, "Remote queue size: %d outreq: %d outresp: %d\n",
-                    otherPort->sendQueue.size(), otherPort->queuedRequests,
-                    otherPort->outstandingResponses);
+    slavePort->queueForSendTiming(pkt);
+
+    return true;
+}
 
-    if (pkt->isRequest() && otherPort->reqQueueFull()) {
-        DPRINTF(BusBridge, "Remote queue full, nacking\n");
+bool
+Bridge::BridgeSlavePort::recvTiming(PacketPtr pkt)
+{
+    // should only see requests on the slave side
+    assert(pkt->isRequest());
+
+    DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
+            pkt->getSrc(), pkt->getDest(), pkt->getAddr());
+
+    DPRINTF(BusBridge, "Response queue size: %d outresp: %d\n",
+            responseQueue.size(), outstandingResponses);
+
+    if (masterPort->reqQueueFull()) {
+        DPRINTF(BusBridge, "Request queue full, nacking\n");
         nackRequest(pkt);
         return true;
     }
 
     if (pkt->needsResponse()) {
         if (respQueueFull()) {
-            DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n");
-            DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n",
-                    sendQueue.size(), queuedRequests, outstandingResponses);
+            DPRINTF(BusBridge,
+                    "Response queue full, no space for response, nacking\n");
+            DPRINTF(BusBridge,
+                    "queue size: %d outstanding resp: %d\n",
+                    responseQueue.size(), outstandingResponses);
             nackRequest(pkt);
             return true;
         } else {
             DPRINTF(BusBridge, "Request Needs response, reserving space\n");
+            assert(outstandingResponses != respQueueLimit);
             ++outstandingResponses;
         }
     }
 
-    otherPort->queueForSendTiming(pkt);
+    masterPort->queueForSendTiming(pkt);
 
     return true;
 }
 
 void
-Bridge::BridgePort::nackRequest(PacketPtr pkt)
+Bridge::BridgeSlavePort::nackRequest(PacketPtr pkt)
 {
     // Nack the packet
     pkt->makeTimingResponse();
     pkt->setNacked();
 
-    //put it on the list to send
+    // The Nack packets are stored in the response queue just like any
+    // other response, but they do not occupy any space as this is
+    // tracked by the outstandingResponses, this guarantees space for
+    // the Nack packets, but implicitly means we have an (unrealistic)
+    // unbounded Nack queue.
+
+    // put it on the list to send
     Tick readyTime = curTick() + nackDelay;
     PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true);
 
     // nothing on the list, add it and we're done
-    if (sendQueue.empty()) {
+    if (responseQueue.empty()) {
         assert(!sendEvent.scheduled());
         bridge->schedule(sendEvent, readyTime);
-        sendQueue.push_back(buf);
+        responseQueue.push_back(buf);
         return;
     }
 
     assert(sendEvent.scheduled() || inRetry);
 
     // does it go at the end?
-    if (readyTime >= sendQueue.back()->ready) {
-        sendQueue.push_back(buf);
+    if (readyTime >= responseQueue.back()->ready) {
+        responseQueue.push_back(buf);
         return;
     }
 
     // ok, somewhere in the middle, fun
-    std::list<PacketBuffer*>::iterator i = sendQueue.begin();
-    std::list<PacketBuffer*>::iterator end = sendQueue.end();
-    std::list<PacketBuffer*>::iterator begin = sendQueue.begin();
+    std::list<PacketBuffer*>::iterator i = responseQueue.begin();
+    std::list<PacketBuffer*>::iterator end = responseQueue.end();
+    std::list<PacketBuffer*>::iterator begin = responseQueue.begin();
     bool done = false;
 
     while (i != end && !done) {
         if (readyTime < (*i)->ready) {
             if (i == begin)
                 bridge->reschedule(sendEvent, readyTime);
-            sendQueue.insert(i,buf);
+            responseQueue.insert(i,buf);
             done = true;
         }
         i++;
@@ -196,51 +243,60 @@ Bridge::BridgePort::nackRequest(PacketPtr pkt)
     assert(done);
 }
 
-
 void
-Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
+Bridge::BridgeMasterPort::queueForSendTiming(PacketPtr pkt)
 {
-    if (pkt->isResponse()) {
-        // This is a response for a request we forwarded earlier.  The
-        // corresponding PacketBuffer should be stored in the packet's
-        // senderState field.
-
-        PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState);
-        assert(buf != NULL);
-        // set up new packet dest & senderState based on values saved
-        // from original request
-        buf->fixResponse(pkt);
-
-        DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest());
-        delete buf;
+    Tick readyTime = curTick() + delay;
+    PacketBuffer *buf = new PacketBuffer(pkt, readyTime);
+
+    // If we're about to put this packet at the head of the queue, we
+    // need to schedule an event to do the transmit.  Otherwise there
+    // should already be an event scheduled for sending the head
+    // packet.
+    if (requestQueue.empty()) {
+        bridge->schedule(sendEvent, readyTime);
     }
 
+    assert(requestQueue.size() != reqQueueLimit);
 
-    if (pkt->isRequest()) {
-        ++queuedRequests;
-    }
+    requestQueue.push_back(buf);
+}
 
 
+void
+Bridge::BridgeSlavePort::queueForSendTiming(PacketPtr pkt)
+{
+    // This is a response for a request we forwarded earlier.  The
+    // corresponding PacketBuffer should be stored in the packet's
+    // senderState field.
+    PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState);
+    assert(buf != NULL);
+    // set up new packet dest & senderState based on values saved
+    // from original request
+    buf->fixResponse(pkt);
+
+    DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest());
+    delete buf;
 
     Tick readyTime = curTick() + delay;
-    PacketBuffer *buf = new PacketBuffer(pkt, readyTime);
+    buf = new PacketBuffer(pkt, readyTime);
 
     // If we're about to put this packet at the head of the queue, we
     // need to schedule an event to do the transmit.  Otherwise there
     // should already be an event scheduled for sending the head
     // packet.
-    if (sendQueue.empty()) {
+    if (responseQueue.empty()) {
         bridge->schedule(sendEvent, readyTime);
     }
-    sendQueue.push_back(buf);
+    responseQueue.push_back(buf);
 }
 
 void
-Bridge::BridgePort::trySend()
+Bridge::BridgeMasterPort::trySend()
 {
-    assert(!sendQueue.empty());
+    assert(!requestQueue.empty());
 
-    PacketBuffer *buf = sendQueue.front();
+    PacketBuffer *buf = requestQueue.front();
 
     assert(buf->ready <= curTick());
 
@@ -249,107 +305,194 @@ Bridge::BridgePort::trySend()
     DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n",
             buf->origSrc, pkt->getDest(), pkt->getAddr());
 
-    bool wasReq = pkt->isRequest();
-    bool was_nacked_here = buf->nackedHere;
-
     // If the send was successful, make sure sender state was set to NULL
     // otherwise we could get a NACK back of a packet that didn't expect a
     // response and we would try to use freed memory.
 
     Packet::SenderState *old_sender_state = pkt->senderState;
-    if (pkt->isRequest() && !buf->expectResponse)
+    if (!buf->expectResponse)
         pkt->senderState = NULL;
 
     if (sendTiming(pkt)) {
         // send successful
-        sendQueue.pop_front();
-        buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it
+        requestQueue.pop_front();
+        // we no longer own packet, so it's not safe to look at it
+        buf->pkt = NULL;
 
-        if (buf->expectResponse) {
-            // Must wait for response
-            DPRINTF(BusBridge, "  successful: awaiting response (%d)\n",
-                    outstandingResponses);
-        } else {
+        if (!buf->expectResponse) {
             // no response expected... deallocate packet buffer now.
             DPRINTF(BusBridge, "  successful: no response expected\n");
             delete buf;
         }
 
-        if (wasReq)
-            --queuedRequests;
-        else if (!was_nacked_here)
+        // If there are more packets to send, schedule event to try again.
+        if (!requestQueue.empty()) {
+            buf = requestQueue.front();
+            DPRINTF(BusBridge, "Scheduling next send\n");
+            bridge->schedule(sendEvent, std::max(buf->ready, curTick() + 1));
+        }
+    } else {
+        DPRINTF(BusBridge, "  unsuccessful\n");
+        pkt->senderState = old_sender_state;
+        inRetry = true;
+    }
+
+    DPRINTF(BusBridge, "trySend: request queue size: %d\n",
+            requestQueue.size());
+}
+
+void
+Bridge::BridgeSlavePort::trySend()
+{
+    assert(!responseQueue.empty());
+
+    PacketBuffer *buf = responseQueue.front();
+
+    assert(buf->ready <= curTick());
+
+    PacketPtr pkt = buf->pkt;
+
+    DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n",
+            buf->origSrc, pkt->getDest(), pkt->getAddr());
+
+    bool was_nacked_here = buf->nackedHere;
+
+    // no need to worry about the sender state since we are not
+    // modifying it
+
+    if (sendTiming(pkt)) {
+        DPRINTF(BusBridge, "  successful\n");
+        // send successful
+        responseQueue.pop_front();
+        // this is a response... deallocate packet buffer now.
+        delete buf;
+
+        if (!was_nacked_here) {
+            assert(outstandingResponses != 0);
             --outstandingResponses;
+        }
 
         // If there are more packets to send, schedule event to try again.
-        if (!sendQueue.empty()) {
-            buf = sendQueue.front();
+        if (!responseQueue.empty()) {
+            buf = responseQueue.front();
             DPRINTF(BusBridge, "Scheduling next send\n");
             bridge->schedule(sendEvent, std::max(buf->ready, curTick() + 1));
         }
     } else {
         DPRINTF(BusBridge, "  unsuccessful\n");
-        pkt->senderState = old_sender_state;
         inRetry = true;
     }
 
-    DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n",
-                    sendQueue.size(), queuedRequests, outstandingResponses);
+    DPRINTF(BusBridge, "trySend: queue size: %d outstanding resp: %d\n",
+            responseQueue.size(), outstandingResponses);
 }
 
+void
+Bridge::BridgeMasterPort::recvRetry()
+{
+    inRetry = false;
+    Tick nextReady = requestQueue.front()->ready;
+    if (nextReady <= curTick())
+        trySend();
+    else
+        bridge->schedule(sendEvent, nextReady);
+}
 
 void
-Bridge::BridgePort::recvRetry()
+Bridge::BridgeSlavePort::recvRetry()
 {
     inRetry = false;
-    Tick nextReady = sendQueue.front()->ready;
+    Tick nextReady = responseQueue.front()->ready;
     if (nextReady <= curTick())
         trySend();
     else
         bridge->schedule(sendEvent, nextReady);
 }
 
-/** Function called by the port when the bus is receiving a Atomic
- * transaction.*/
 Tick
-Bridge::BridgePort::recvAtomic(PacketPtr pkt)
+Bridge::BridgeMasterPort::recvAtomic(PacketPtr pkt)
 {
-    return delay + otherPort->sendAtomic(pkt);
+    // master port should never receive any atomic access (panic only
+    // works once the other side, i.e. the busses, respects this)
+    //
+    //panic("Master port on %s got a recvAtomic\n", bridge->name());
+    return 0;
+}
+
+Tick
+Bridge::BridgeSlavePort::recvAtomic(PacketPtr pkt)
+{
+    return delay + masterPort->sendAtomic(pkt);
 }
 
-/** Function called by the port when the bus is receiving a Functional
- * transaction.*/
 void
-Bridge::BridgePort::recvFunctional(PacketPtr pkt)
+Bridge::BridgeMasterPort::recvFunctional(PacketPtr pkt)
+{
+    // master port should never receive any functional access (panic
+    // only works once the other side, i.e. the busses, respect this)
+
+    // panic("Master port on %s got a recvFunctional\n", bridge->name());
+}
+
+void
+Bridge::BridgeSlavePort::recvFunctional(PacketPtr pkt)
 {
     std::list<PacketBuffer*>::iterator i;
 
     pkt->pushLabel(name());
 
-    for (i = sendQueue.begin();  i != sendQueue.end(); ++i) {
+    // check the response queue
+    for (i = responseQueue.begin();  i != responseQueue.end(); ++i) {
         if (pkt->checkFunctional((*i)->pkt)) {
             pkt->makeResponse();
             return;
         }
     }
 
+    // also check the master port's request queue
+    if (masterPort->checkFunctional(pkt)) {
+        return;
+    }
+
     pkt->popLabel();
 
     // fall through if pkt still not satisfied
-    otherPort->sendFunctional(pkt);
+    masterPort->sendFunctional(pkt);
+}
+
+bool
+Bridge::BridgeMasterPort::checkFunctional(PacketPtr pkt)
+{
+    bool found = false;
+    std::list<PacketBuffer*>::iterator i = requestQueue.begin();
+
+    while(i != requestQueue.end() && !found) {
+        if (pkt->checkFunctional((*i)->pkt)) {
+            pkt->makeResponse();
+            found = true;
+        }
+        ++i;
+    }
+
+    return found;
 }
 
 /** Function called by the port when the bridge is receiving a range change.*/
 void
-Bridge::BridgePort::recvRangeChange()
+Bridge::BridgeMasterPort::recvRangeChange()
+{
+    // no need to forward as the bridge has a fixed set of ranges
+}
+
+void
+Bridge::BridgeSlavePort::recvRangeChange()
 {
-    otherPort->sendRangeChange();
+    // is a slave port so do nothing
 }
 
 AddrRangeList
-Bridge::BridgePort::getAddrRanges()
+Bridge::BridgeSlavePort::getAddrRanges()
 {
-    AddrRangeList ranges = otherPort->getPeer()->getAddrRanges();
-    FilterRangeList(filterRanges, ranges);
     return ranges;
 }
 
index a3fa1f8f6068611b73a31029bb0e873942de3e14..d389c0a5e30087fbb2b20360a1900c0dd0530e2e 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2006 The Regents of The University of Michigan
  * All rights reserved.
  *
  *
  * Authors: Ali Saidi
  *          Steve Reinhardt
+ *          Andreas Hansson
  */
 
 /**
  * @file
- * Declaration of a simple bus bridge object with no buffering
+ * Declaration of a memory-mapped bus bridge that connects a master
+ * and a slave through a request and response queue.
  */
 
 #ifndef __MEM_BRIDGE_HH__
 #include "params/Bridge.hh"
 #include "sim/eventq.hh"
 
+/**
+ * A bridge is used to interface two different busses (or in general a
+ * memory-mapped master and slave), with buffering for requests and
+ * responses. The bridge has a fixed delay for packets passing through
+ * it and responds to a fixed set of address ranges.
+ *
+ * The bridge comprises a slave port and a master port, that buffer
+ * outgoing responses and requests respectively. Buffer space is
+ * reserved when a request arrives, also reserving response space
+ * before forwarding the request. An incoming request is always
+ * accepted (recvTiming returns true), but is potentially NACKed if
+ * there is no request space or response space.
+ */
 class Bridge : public MemObject
 {
   protected:
-    /** Declaration of the buses port type, one will be instantiated for each
-        of the interfaces connecting to the bus. */
-    class BridgePort : public Port
+
+    /**
+     * A packet buffer stores packets along with their sender state
+     * and scheduled time for transmission.
+     */
+    class PacketBuffer : public Packet::SenderState, public FastAlloc {
+
+      public:
+        Tick ready;
+        PacketPtr pkt;
+        bool nackedHere;
+        Packet::SenderState *origSenderState;
+        short origSrc;
+        bool expectResponse;
+
+        PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false)
+            : ready(t), pkt(_pkt), nackedHere(nack),
+              origSenderState(_pkt->senderState),
+              origSrc(nack ? _pkt->getDest() : _pkt->getSrc() ),
+              expectResponse(_pkt->needsResponse() && !nack)
+
+        {
+            if (!pkt->isResponse() && !nack)
+                pkt->senderState = this;
+        }
+
+        void fixResponse(PacketPtr pkt)
+        {
+            assert(pkt->senderState == this);
+            pkt->setDest(origSrc);
+            pkt->senderState = origSenderState;
+        }
+    };
+
+    // Forward declaration to allow the slave port to have a pointer
+    class BridgeMasterPort;
+
+    /**
+     * The port on the side that receives requests and sends
+     * responses. The slave port has a set of address ranges that it
+     * is responsible for. The slave port also has a buffer for the
+     * responses not yet sent.
+     */
+    class BridgeSlavePort : public Port
     {
+
+      private:
+
         /** A pointer to the bridge to which this port belongs. */
         Bridge *bridge;
 
         /**
-         * Pointer to the port on the other side of the bridge
+         * Pointer to the master port on the other side of the bridge
          * (connected to the other bus).
          */
-        BridgePort *otherPort;
+        BridgeMasterPort* masterPort;
 
-        /** Minimum delay though this bridge. */
+        /** Minimum request delay though this bridge. */
         Tick delay;
 
-        /** Min delay to respond to a nack. */
+        /** Min delay to respond with a nack. */
         Tick nackDelay;
 
-        /** Pass ranges from one side of the bridge to the other? */
-        std::vector<Range<Addr> > filterRanges;
+        /** Address ranges to pass through the bridge */
+        AddrRangeList ranges;
+
+        /**
+         * Response packet queue. Response packets are held in this
+         * queue for a specified delay to model the processing delay
+         * of the bridge.
+         */
+        std::list<PacketBuffer*> responseQueue;
 
-        class PacketBuffer : public Packet::SenderState, public FastAlloc {
+        /** Counter to track the outstanding responses. */
+        unsigned int outstandingResponses;
+
+        /** If we're waiting for a retry to happen. */
+        bool inRetry;
+
+        /** Max queue size for reserved responses. */
+        unsigned int respQueueLimit;
+
+        /**
+         * Is this side blocked from accepting new response packets.
+         *
+         * @return true if the reserved space has reached the set limit
+         */
+        bool respQueueFull();
+
+        /**
+         * Turn the request packet into a NACK response and put it in
+         * the response queue and schedule its transmission.
+         *
+         * @param pkt the request packet to NACK
+         */
+        void nackRequest(PacketPtr pkt);
+
+        /**
+         * Handle send event, scheduled when the packet at the head of
+         * the response queue is ready to transmit (for timing
+         * accesses only).
+         */
+        void trySend();
+
+        /**
+         * Private class for scheduling sending of responses from the
+         * response queue.
+         */
+        class SendEvent : public Event
+        {
+            BridgeSlavePort *port;
 
           public:
-            Tick ready;
-            PacketPtr pkt;
-            bool nackedHere;
-            Packet::SenderState *origSenderState;
-            short origSrc;
-            bool expectResponse;
-
-            PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false)
-                : ready(t), pkt(_pkt), nackedHere(nack),
-                  origSenderState(_pkt->senderState),
-                  origSrc(nack ? _pkt->getDest() : _pkt->getSrc() ),
-                  expectResponse(_pkt->needsResponse() && !nack)
-
-            {
-                if (!pkt->isResponse() && !nack)
-                    pkt->senderState = this;
-            }
-
-            void fixResponse(PacketPtr pkt)
-            {
-                assert(pkt->senderState == this);
-                pkt->setDest(origSrc);
-                pkt->senderState = origSenderState;
-            }
+            SendEvent(BridgeSlavePort *p) : port(p) {}
+            virtual void process() { port->trySend(); }
+            virtual const char *description() const { return "bridge send"; }
         };
 
+        /** Send event for the response queue. */
+        SendEvent sendEvent;
+
+      public:
+
         /**
-         * Outbound packet queue.  Packets are held in this queue for a
-         * specified delay to model the processing delay of the
-         * bridge.
+         * Constructor for the BridgeSlavePort.
+         *
+         * @param _name the port name including the owner
+         * @param _bridge the structural owner
+         * @param _masterPort the master port on the other side of the bridge
+         * @param _delay the delay from seeing a response to sending it
+         * @param _nack_delay the delay from a NACK to sending the response
+         * @param _resp_limit the size of the response queue
+         * @param _ranges a number of address ranges to forward
          */
-        std::list<PacketBuffer*> sendQueue;
+        BridgeSlavePort(const std::string &_name, Bridge *_bridge,
+                        BridgeMasterPort* _masterPort, int _delay,
+                        int _nack_delay, int _resp_limit,
+                        std::vector<Range<Addr> > _ranges);
 
-        int outstandingResponses;
-        int queuedRequests;
+        /**
+         * Queue a response packet to be sent out later and also schedule
+         * a send if necessary.
+         *
+         * @param pkt a response to send out after a delay
+         */
+        void queueForSendTiming(PacketPtr pkt);
 
-        /** If we're waiting for a retry to happen.*/
-        bool inRetry;
+      protected:
 
-        /** Max queue size for outbound packets */
-        int reqQueueLimit;
+        /** When receiving a timing request from the peer port,
+            pass it to the bridge. */
+        virtual bool recvTiming(PacketPtr pkt);
 
-        /** Max queue size for reserved responses. */
-        int respQueueLimit;
+        /** When receiving a retry request from the peer port,
+            pass it to the bridge. */
+        virtual void recvRetry();
+
+        /** When receiving a Atomic requestfrom the peer port,
+            pass it to the bridge. */
+        virtual Tick recvAtomic(PacketPtr pkt);
+
+        /** When receiving a Functional request from the peer port,
+            pass it to the bridge. */
+        virtual void recvFunctional(PacketPtr pkt);
 
         /**
-         * Is this side blocked from accepting outbound packets?
+         * When receiving a range change on the slave side do nothing.
          */
-        bool respQueueFull();
-        bool reqQueueFull();
+        virtual void recvRangeChange();
 
-        void queueForSendTiming(PacketPtr pkt);
+        /** When receiving a address range request the peer port,
+            pass it to the bridge. */
+        virtual AddrRangeList getAddrRanges();
+    };
 
-        void finishSend(PacketBuffer *buf);
 
-        void nackRequest(PacketPtr pkt);
+    /**
+     * Port on the side that forwards requests and receives
+     * responses. The master port has a buffer for the requests not
+     * yet sent.
+     */
+    class BridgeMasterPort : public Port
+    {
+
+      private:
+
+        /** A pointer to the bridge to which this port belongs. */
+        Bridge* bridge;
+
+        /**
+         * Pointer to the slave port on the other side of the bridge
+         * (connected to the other bus).
+         */
+        BridgeSlavePort* slavePort;
+
+        /** Minimum delay though this bridge. */
+        Tick delay;
+
+        /**
+         * Request packet queue. Request packets are held in this
+         * queue for a specified delay to model the processing delay
+         * of the bridge.
+         */
+        std::list<PacketBuffer*> requestQueue;
+
+        /** If we're waiting for a retry to happen. */
+        bool inRetry;
+
+        /** Max queue size for request packets */
+        unsigned int reqQueueLimit;
 
         /**
          * Handle send event, scheduled when the packet at the head of
@@ -141,24 +297,62 @@ class Bridge : public MemObject
          */
         void trySend();
 
+        /**
+         * Private class for scheduling sending of requests from the
+         * request queue.
+         */
         class SendEvent : public Event
         {
-            BridgePort *port;
+            BridgeMasterPort *port;
 
           public:
-            SendEvent(BridgePort *p) : port(p) {}
+            SendEvent(BridgeMasterPort *p) : port(p) {}
             virtual void process() { port->trySend(); }
             virtual const char *description() const { return "bridge send"; }
         };
 
+        /** Send event for the request queue. */
         SendEvent sendEvent;
 
       public:
-        /** Constructor for the BusPort.*/
-        BridgePort(const std::string &_name, Bridge *_bridge,
-                BridgePort *_otherPort, int _delay, int _nack_delay,
-                int _req_limit, int _resp_limit,
-                std::vector<Range<Addr> > filter_ranges);
+
+        /**
+         * Constructor for the BridgeMasterPort.
+         *
+         * @param _name the port name including the owner
+         * @param _bridge the structural owner
+         * @param _slavePort the slave port on the other side of the bridge
+         * @param _delay the delay from seeing a request to sending it
+         * @param _req_limit the size of the request queue
+         */
+        BridgeMasterPort(const std::string &_name, Bridge *_bridge,
+                         BridgeSlavePort* _slavePort, int _delay,
+                         int _req_limit);
+
+        /**
+         * Is this side blocked from accepting new request packets.
+         *
+         * @return true if the occupied space has reached the set limit
+         */
+        bool reqQueueFull();
+
+        /**
+         * Queue a request packet to be sent out later and also schedule
+         * a send if necessary.
+         *
+         * @param pkt a request to send out after a delay
+         */
+        void queueForSendTiming(PacketPtr pkt);
+
+        /**
+         * Check a functional request against the packets in our
+         * request queue.
+         *
+         * @param pkt packet to check against
+         *
+         * @return true if we find a match
+         */
+        bool checkFunctional(PacketPtr pkt);
 
       protected:
 
@@ -182,13 +376,13 @@ class Bridge : public MemObject
          * When receiving a range change, pass it through the bridge.
          */
         virtual void recvRangeChange();
-
-        /** When receiving a address range request the peer port,
-            pass it to the bridge. */
-        virtual AddrRangeList getAddrRanges();
     };
 
-    BridgePort portA, portB;
+    /** Slave port of the bridge. */
+    BridgeSlavePort slavePort;
+
+    /** Master port of the bridge. */
+    BridgeMasterPort masterPort;
 
     /** If this bridge should acknowledge writes. */
     bool ackWrites;
index c697e97a9e0e56af0cce57d9b8aa3507f2f5a422..0fe23d1ee8c37585c0ece06a224116526014625e 100644 (file)
@@ -86,8 +86,6 @@ cpu = DerivO3CPU(cpu_id=0)
 mdesc = SysConfig(disk = 'linux-x86.img')
 system = FSConfig.makeLinuxX86System('timing', mdesc=mdesc)
 system.kernel = FSConfig.binary('x86_64-vmlinux-2.6.22.9')
-system.bridge.filter_ranges_a = [AddrRange(0, Addr.max >> 4)]
-system.bridge.filter_ranges_b = [AddrRange(0, size=mem_size)]
 system.iocache = IOCache(addr_range=mem_size)
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 1c35ff2d9ae7c45dc2fd0268d2d899cb519dce18..eeff170694688c688085e41f997bd28a6f0704c7 100644 (file)
@@ -88,8 +88,6 @@ cpu = AtomicSimpleCPU(cpu_id=0)
 mdesc = SysConfig(disk = 'linux-x86.img')
 system = FSConfig.makeLinuxX86System('atomic', mdesc=mdesc)
 system.kernel = FSConfig.binary('x86_64-vmlinux-2.6.22.9')
-system.bridge.filter_ranges_a = [AddrRange(0, Addr.max >> 4)]
-system.bridge.filter_ranges_b = [AddrRange(0, size=mem_size)]
 system.iocache = IOCache(addr_range=mem_size)
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 9c9f4aeca425a27bf0ecfdfd669bc3a0b9f4df03..a1b2f46765485528dcab1848decf51f4008d02c6 100644 (file)
@@ -91,8 +91,6 @@ system.kernel = FSConfig.binary('x86_64-vmlinux-2.6.22.9')
 system.cpu = cpu
 #create the l1/l2 bus
 system.toL2Bus = Bus()
-system.bridge.filter_ranges_a = [AddrRange(0, Addr.max >> 4)]
-system.bridge.filter_ranges_b = [AddrRange(0, size=mem_size)]
 system.iocache = IOCache(addr_range=mem_size)
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 489b5c5b64fd25fdda73d8784c5ce947d0d7776d..69c583abdcaaba95b5160cf501bef899192f865e 100644 (file)
@@ -71,8 +71,6 @@ class IOCache(BaseCache):
 cpus = [DerivO3CPU(cpu_id=i) for i in xrange(2) ]
 #the system
 system = FSConfig.makeArmSystem('timing', "RealView_PBX", None, False)
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='256MB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 61e7591e6261b6778097aaec4bf0ae0e06deabab..bab5a193d6e340ecd3aa9ccc30e02bdbf2d01df7 100644 (file)
@@ -75,8 +75,6 @@ system = FSConfig.makeArmSystem('timing', "RealView_PBX", None, False)
 system.cpu = cpu
 #create the l1/l2 bus
 system.toL2Bus = Bus()
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='256MB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index b301eac14cf39b4ac722159db981d8f9ed6e8d7f..edfd940adaf9ad659a843a4faa014aad31425c68 100644 (file)
@@ -71,8 +71,6 @@ class IOCache(BaseCache):
 cpus = [AtomicSimpleCPU(cpu_id=i) for i in xrange(2) ]
 #the system
 system = FSConfig.makeArmSystem('atomic', "RealView_PBX", None, False)
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='256MB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index b74e5607377c0edb005cf7db589a87b1a6a505d3..83f85641a4224b6a8958780da5968a9dc2b7ee1c 100644 (file)
@@ -70,8 +70,6 @@ class IOCache(BaseCache):
 cpu = AtomicSimpleCPU(cpu_id=0)
 #the system
 system = FSConfig.makeArmSystem('atomic', "RealView_PBX", None, False)
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='256MB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 1f1402dfcc0897d8078da0dc9a91a414be7713da..7fe0d409bbbcbc08b3eb4dfa69d98990ea430157 100644 (file)
@@ -71,8 +71,6 @@ class IOCache(BaseCache):
 cpus = [TimingSimpleCPU(cpu_id=i) for i in xrange(2) ]
 #the system
 system = FSConfig.makeArmSystem('timing', "RealView_PBX", None, False)
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='256MB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 74fc617f34a47f238075ff1db9f10e0d0550945e..90f2539e6ece4941b5a52c28cab0666ccad47d16 100644 (file)
@@ -75,8 +75,6 @@ system = FSConfig.makeArmSystem('timing', "RealView_PBX", None, False)
 system.cpu = cpu
 #create the l1/l2 bus
 system.toL2Bus = Bus()
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='256MB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index fd62e252a514c94f2cb475ffa70be3280d597986..a082615337b13e24684d7601b9d28b8e3e7aa667 100644 (file)
@@ -79,8 +79,6 @@ system = FSConfig.makeLinuxAlphaSystem('timing')
 system.cpu = cpu
 #create the l1/l2 bus
 system.toL2Bus = Bus()
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='8GB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 786452a0905e6c2bcead967f17859c96aea1f0fd..c63637f73cd3e6b78bdbcdfe5e2f96b7ad620eea 100644 (file)
@@ -76,8 +76,6 @@ system = FSConfig.makeLinuxAlphaSystem('timing')
 system.cpu = cpus
 #create the l1/l2 bus
 system.toL2Bus = Bus()
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='8GB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 8a003dad8787b9cd04ef4a0ccabe729f384e2952..a6bb4b12210427233865785a6401601e9f581c1f 100644 (file)
@@ -76,8 +76,6 @@ system = FSConfig.makeLinuxAlphaSystem('timing')
 system.cpu = cpu
 #create the l1/l2 bus
 system.toL2Bus = Bus()
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='8GB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 2e56ce8510ea737cad1a8c7a605f6eabcf548919..758dbef098f9b79871e0f587bc1030555d1f3e44 100644 (file)
@@ -71,8 +71,6 @@ class IOCache(BaseCache):
 cpus = [ AtomicSimpleCPU(cpu_id=i) for i in xrange(2) ]
 #the system
 system = FSConfig.makeLinuxAlphaSystem('atomic')
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='8GB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 3c1981464e59a19e1ae1f14a50e6768783efb35d..a2335d7636505615a7a511af641820b51a064455 100644 (file)
@@ -71,8 +71,6 @@ class IOCache(BaseCache):
 cpu = AtomicSimpleCPU(cpu_id=0)
 #the system
 system = FSConfig.makeLinuxAlphaSystem('atomic')
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='8GB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 747cdac180ddbadfc79b99b1711e0a1b6169f776..ad466a5c086f528699afc8c387a2da51d97472c1 100644 (file)
@@ -71,8 +71,6 @@ class IOCache(BaseCache):
 cpus = [ TimingSimpleCPU(cpu_id=i) for i in xrange(2) ]
 #the system
 system = FSConfig.makeLinuxAlphaSystem('timing')
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='8GB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 110e6ee74cbe8a1481de4e5b65c47208c6450465..7dc0ded5c01f3e60da0e2ed2f870abb9c5f1a303 100644 (file)
@@ -76,8 +76,6 @@ system = FSConfig.makeLinuxAlphaSystem('timing')
 system.cpu = cpu
 #create the l1/l2 bus
 system.toL2Bus = Bus()
-system.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
-system.bridge.filter_ranges_b=[AddrRange(0, size='8GB')]
 system.iocache = IOCache()
 system.iocache.cpu_side = system.iobus.port
 system.iocache.mem_side = system.membus.port
index 7c6fde7c329abbe0a72e13bdacb9dd15be329f3f..658508fa033f4c6d6502690e729bd687db606a7f 100644 (file)
@@ -36,11 +36,22 @@ test_sys = makeLinuxAlphaSystem('atomic',
                                  SysConfig('netperf-stream-client.rcS'))
 test_sys.cpu = AtomicSimpleCPU(cpu_id=0)
 test_sys.cpu.connectAllPorts(test_sys.membus)
+# In contrast to the other (one-system) Tsunami configurations we do
+# not have an IO cache but instead rely on an IO bridge for accesses
+# from masters on the IO bus to the memory bus
+test_sys.iobridge = Bridge(delay='50ns', nack_delay='4ns',
+                           ranges = [AddrRange(0, '8GB')])
+test_sys.iobridge.slave = test_sys.iobus.port
+test_sys.iobridge.master = test_sys.membus.port
 
 drive_sys = makeLinuxAlphaSystem('atomic',
                                  SysConfig('netperf-server.rcS'))
 drive_sys.cpu = AtomicSimpleCPU(cpu_id=0)
 drive_sys.cpu.connectAllPorts(drive_sys.membus)
+drive_sys.iobridge = Bridge(delay='50ns', nack_delay='4ns',
+                            ranges = [AddrRange(0, '8GB')])
+drive_sys.iobridge.slave = drive_sys.iobus.port
+drive_sys.iobridge.master = drive_sys.membus.port
 
 root = makeDualRoot(test_sys, drive_sys, "ethertrace")