MEM: Make the bus bridge unidirectional and fixed address range

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.
This commit is contained in:
Andreas Hansson 2012-01-17 12:55:09 -06:00
parent e731cf4c1d
commit 2208ea049f
23 changed files with 659 additions and 279 deletions

View 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)

View 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:

View 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

View 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")

View 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.
*
@ -28,54 +39,63 @@
*
* 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, "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);
DPRINTF(BusBridge, "Request queue size: %d\n", requestQueue.size());
if (pkt->isRequest() && otherPort->reqQueueFull()) {
DPRINTF(BusBridge, "Remote queue full, nacking\n");
slavePort->queueForSendTiming(pkt);
return true;
}
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,32 +243,9 @@ 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;
}
if (pkt->isRequest()) {
++queuedRequests;
}
Tick readyTime = curTick() + delay;
PacketBuffer *buf = new PacketBuffer(pkt, readyTime);
@ -229,18 +253,50 @@ Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
// 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 (requestQueue.empty()) {
bridge->schedule(sendEvent, readyTime);
}
sendQueue.push_back(buf);
assert(requestQueue.size() != reqQueueLimit);
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;
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 (responseQueue.empty()) {
bridge->schedule(sendEvent, readyTime);
}
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,40 +305,29 @@ 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)
--outstandingResponses;
// If there are more packets to send, schedule event to try again.
if (!sendQueue.empty()) {
buf = sendQueue.front();
if (!requestQueue.empty()) {
buf = requestQueue.front();
DPRINTF(BusBridge, "Scheduling next send\n");
bridge->schedule(sendEvent, std::max(buf->ready, curTick() + 1));
}
@ -292,64 +337,162 @@ Bridge::BridgePort::trySend()
inRetry = true;
}
DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n",
sendQueue.size(), queuedRequests, outstandingResponses);
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 (!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");
inRetry = true;
}
DPRINTF(BusBridge, "trySend: queue size: %d outstanding resp: %d\n",
responseQueue.size(), outstandingResponses);
}
void
Bridge::BridgePort::recvRetry()
Bridge::BridgeMasterPort::recvRetry()
{
inRetry = false;
Tick nextReady = sendQueue.front()->ready;
Tick nextReady = requestQueue.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)
void
Bridge::BridgeSlavePort::recvRetry()
{
return delay + otherPort->sendAtomic(pkt);
inRetry = false;
Tick nextReady = responseQueue.front()->ready;
if (nextReady <= curTick())
trySend();
else
bridge->schedule(sendEvent, nextReady);
}
Tick
Bridge::BridgeMasterPort::recvAtomic(PacketPtr 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()
{
otherPort->sendRangeChange();
// no need to forward as the bridge has a fixed set of ranges
}
void
Bridge::BridgeSlavePort::recvRangeChange()
{
// is a slave port so do nothing
}
AddrRangeList
Bridge::BridgePort::getAddrRanges()
Bridge::BridgeSlavePort::getAddrRanges()
{
AddrRangeList ranges = otherPort->getPeer()->getAddrRanges();
FilterRangeList(filterRanges, ranges);
return ranges;
}

View 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.
*
@ -27,11 +39,13 @@
*
* 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__
@ -49,90 +63,232 @@
#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 request delay though this bridge. */
Tick delay;
/** Min delay to respond with a nack. */
Tick nackDelay;
/** 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;
/** 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:
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:
/**
* 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
*/
BridgeSlavePort(const std::string &_name, Bridge *_bridge,
BridgeMasterPort* _masterPort, int _delay,
int _nack_delay, int _resp_limit,
std::vector<Range<Addr> > _ranges);
/**
* 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);
protected:
/** When receiving a timing request from the peer port,
pass it to the bridge. */
virtual bool recvTiming(PacketPtr pkt);
/** 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);
/**
* When receiving a range change on the slave side do nothing.
*/
virtual void recvRangeChange();
/** When receiving a address range request the peer port,
pass it to the bridge. */
virtual AddrRangeList getAddrRanges();
};
/**
* 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;
/** Min delay to respond to a nack. */
Tick nackDelay;
/** Pass ranges from one side of the bridge to the other? */
std::vector<Range<Addr> > filterRanges;
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;
}
};
/**
* Outbound packet queue. Packets are held in this queue for a
* specified delay to model the processing delay of the
* bridge.
* 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*> sendQueue;
std::list<PacketBuffer*> requestQueue;
int outstandingResponses;
int queuedRequests;
/** If we're waiting for a retry to happen.*/
/** If we're waiting for a retry to happen. */
bool inRetry;
/** Max queue size for outbound packets */
int reqQueueLimit;
/** Max queue size for reserved responses. */
int respQueueLimit;
/**
* Is this side blocked from accepting outbound packets?
*/
bool respQueueFull();
bool reqQueueFull();
void queueForSendTiming(PacketPtr pkt);
void finishSend(PacketBuffer *buf);
void nackRequest(PacketPtr pkt);
/** 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;

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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")