DMA: Add IOCache and fix bus bridge to optionally only send requests one

way so a cache can handle partial block requests for i/o devices.

--HG--
extra : convert_revision : a68b5ae826731bc87ed93eb7ef326a2393053964
This commit is contained in:
Ali Saidi 2007-08-10 16:14:01 -04:00
parent 5c38668ed6
commit 06a9f58c68
16 changed files with 134 additions and 49 deletions

View file

@ -43,3 +43,10 @@ class L2Cache(BaseCache):
mshrs = 20
tgts_per_mshr = 12
class IOCache(BaseCache):
assoc = 8
block_size = 64
latency = '10ns'
mshrs = 20
size = '1kB'
tgts_per_mshr = 12

View file

@ -53,7 +53,7 @@ def makeLinuxAlphaSystem(mem_mode, mdesc = None):
self.readfile = mdesc.script()
self.iobus = Bus(bus_id=0)
self.membus = Bus(bus_id=1)
self.bridge = Bridge(fix_partial_write_b=True, delay='50ns', nack_delay='4ns')
self.bridge = Bridge(delay='50ns', nack_delay='4ns')
self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem()))
self.bridge.side_a = self.iobus.port
self.bridge.side_b = self.membus.port

View file

@ -121,7 +121,12 @@ for i in xrange(np):
if options.caches:
test_sys.cpu[i].addPrivateSplitL1Caches(L1Cache(size = '32kB'),
L1Cache(size = '64kB'))
test_sys.bridge.filter_ranges_a=[AddrRange(0, Addr.max)]
test_sys.bridge.filter_ranges_b=[AddrRange(0, size='8GB')]
test_sys.iocache = IOCache(mem_side_filter_ranges=[AddrRange(0, Addr.max)],
cpu_side_filter_ranges=[AddrRange(0x8000000000, Addr.max)])
test_sys.iocache.cpu_side = test_sys.iobus.port
test_sys.iocache.mem_side = test_sys.membus.port
if options.l2cache:
test_sys.cpu[i].connectMemPorts(test_sys.tol2bus)
else:

55
src/base/range_ops.hh Normal file
View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2007 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
*/
#ifndef __BASE_RANGE_OPS_HH__
#define __BASE_RANGE_OPS_HH__
#include <list>
#include <vector>
#include "base/range.hh"
template <class T>
inline void
FilterRangeList(std::vector<Range<T> > filter_list, std::list<Range<T> >
&range_list) {
typename std::list<Range<T> >::iterator i;
for (int x = 0; x < filter_list.size(); x++) {
for (i = range_list.begin(); i != range_list.end(); ) {
// Is the range within one of our filter ranges?
if (filter_list[x] == i->start || filter_list[x] == i->end)
range_list.erase(i++);
else
i++;
}
}
}
#endif //__BASE_RANGE_OPS_HH__

View file

@ -266,8 +266,7 @@ class DmaDevice : public PioDevice
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data)
{
dmaPort->dmaAction(MemCmd::WriteInvalidateReq,
addr, size, event, data);
dmaPort->dmaAction(MemCmd::WriteReq, addr, size, event, data);
}
void dmaRead(Addr addr, int size, Event *event, uint8_t *data)

View file

@ -40,5 +40,7 @@ class Bridge(MemObject):
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")
fix_partial_write_a = Param.Bool(False, "Should this bridge fixup partial block writes")
fix_partial_write_b = Param.Bool(False, "Should this bridge fixup partial block 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")

View file

@ -37,6 +37,7 @@
#include <algorithm>
#include "base/range_ops.hh"
#include "base/trace.hh"
#include "mem/bridge.hh"
#include "params/Bridge.hh"
@ -44,9 +45,10 @@
Bridge::BridgePort::BridgePort(const std::string &_name,
Bridge *_bridge, BridgePort *_otherPort,
int _delay, int _nack_delay, int _req_limit,
int _resp_limit, bool fix_partial_write)
int _resp_limit,
std::vector<Range<Addr> > filter_ranges)
: Port(_name), bridge(_bridge), otherPort(_otherPort),
delay(_delay), nackDelay(_nack_delay), fixPartialWrite(fix_partial_write),
delay(_delay), nackDelay(_nack_delay), filterRanges(filter_ranges),
outstandingResponses(0), queuedRequests(0), inRetry(false),
reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this)
{
@ -55,9 +57,9 @@ Bridge::BridgePort::BridgePort(const std::string &_name,
Bridge::Bridge(Params *p)
: MemObject(p->name),
portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay,
p->req_size_a, p->resp_size_a, p->fix_partial_write_a),
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->fix_partial_write_b),
p->req_size_b, p->resp_size_b, p->filter_ranges_b),
ackWrites(p->write_ack), _params(p)
{
if (ackWrites)
@ -243,17 +245,6 @@ Bridge::BridgePort::trySend()
PacketPtr pkt = buf->pkt;
// Ugly! @todo When multilevel coherence works this will be removed
if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite &&
!pkt->wasNacked()) {
PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq,
Packet::Broadcast);
funcPkt->dataStatic(pkt->getPtr<uint8_t>());
sendFunctional(funcPkt);
pkt->cmd = MemCmd::WriteReq;
delete funcPkt;
}
DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n",
buf->origSrc, pkt->getDest(), pkt->getAddr());
@ -313,17 +304,6 @@ Bridge::BridgePort::recvRetry()
Tick
Bridge::BridgePort::recvAtomic(PacketPtr pkt)
{
// fix partial atomic writes... similar to the timing code that does the
// same... will be removed once our code gets this right
if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite) {
PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq,
Packet::Broadcast);
funcPkt->dataStatic(pkt->getPtr<uint8_t>());
otherPort->sendFunctional(funcPkt);
delete funcPkt;
pkt->cmd = MemCmd::WriteReq;
}
return delay + otherPort->sendAtomic(pkt);
}
@ -355,6 +335,7 @@ Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp,
bool &snoop)
{
otherPort->getPeerAddressRanges(resp, snoop);
FilterRangeList(filterRanges, resp);
// we don't allow snooping across bridges
snoop = false;
}

View file

@ -70,7 +70,8 @@ class Bridge : public MemObject
/** Min delay to respond to a nack. */
Tick nackDelay;
bool fixPartialWrite;
/** Pass ranges from one side of the bridge to the other? */
std::vector<Range<Addr> > filterRanges;
class PacketBuffer : public Packet::SenderState {
@ -156,7 +157,8 @@ class Bridge : public MemObject
/** Constructor for the BusPort.*/
BridgePort(const std::string &_name, Bridge *_bridge,
BridgePort *_otherPort, int _delay, int _nack_delay,
int _req_limit, int _resp_limit, bool fix_partial_write);
int _req_limit, int _resp_limit,
std::vector<Range<Addr> > filter_ranges);
protected:

View file

@ -457,6 +457,10 @@ Bus::recvStatusChange(Port::Status status, int id)
bool snoops;
AddrRangeIter iter;
if (inRecvStatusChange.count(id))
return;
inRecvStatusChange.insert(id);
assert(status == Port::RangeChange &&
"The other statuses need to be implemented.");
@ -524,6 +528,7 @@ Bus::recvStatusChange(Port::Status status, int id)
if (id != defaultId && defaultPort)
defaultPort->sendStatusChange(Port::RangeChange);
inRecvStatusChange.erase(id);
}
void

View file

@ -38,6 +38,7 @@
#define __MEM_BUS_HH__
#include <string>
#include <set>
#include <list>
#include <inttypes.h>
@ -253,6 +254,7 @@ class Bus : public MemObject
BusFreeEvent busIdle;
bool inRetry;
std::set<int> inRecvStatusChange;
/** max number of bus ids we've handed out so far */
short maxId;

View file

@ -81,4 +81,8 @@ class BaseCache(MemObject):
"Only prefetch on data not on instruction accesses")
cpu_side = Port("Port on side closer to CPU")
mem_side = Port("Port on side closer to MEM")
cpu_side_filter_ranges = VectorParam.AddrRange([],
"What addresses shouldn't be passed through the side of the bridge")
mem_side_filter_ranges = VectorParam.AddrRange([],
"What addresses shouldn't be passed through the side of the bridge")
addr_range = VectorParam.AddrRange(AllMemory, "The address range in bytes")

View file

@ -40,9 +40,10 @@
using namespace std;
BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache)
BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache,
std::vector<Range<Addr> > filter_ranges)
: SimpleTimingPort(_name, _cache), cache(_cache), otherPort(NULL),
blocked(false), mustSendRetry(false)
blocked(false), mustSendRetry(false), filterRanges(filter_ranges)
{
}

View file

@ -98,7 +98,8 @@ class BaseCache : public MemObject
BaseCache *cache;
protected:
CachePort(const std::string &_name, BaseCache *_cache);
CachePort(const std::string &_name, BaseCache *_cache,
std::vector<Range<Addr> > filter_ranges);
virtual void recvStatusChange(Status status);
@ -124,6 +125,9 @@ class BaseCache : public MemObject
bool mustSendRetry;
/** filter ranges */
std::vector<Range<Addr> > filterRanges;
void requestBus(RequestCause cause, Tick time)
{
DPRINTF(CachePort, "Asserting bus request for cause %d\n", cause);
@ -367,15 +371,21 @@ class BaseCache : public MemObject
*/
Counter maxMisses;
std::vector<Range<Addr> > cpuSideFilterRanges;
std::vector<Range<Addr> > memSideFilterRanges;
/**
* Construct an instance of this parameter class.
*/
Params(int _hitLatency, int _blkSize,
int _numMSHRs, int _numTargets, int _numWriteBuffers,
Counter _maxMisses)
Counter _maxMisses,
std::vector<Range<Addr> > cpu_side_filter_ranges,
std::vector<Range<Addr> > mem_side_filter_ranges)
: hitLatency(_hitLatency), blkSize(_blkSize),
numMSHRs(_numMSHRs), numTargets(_numTargets),
numWriteBuffers(_numWriteBuffers), maxMisses(_maxMisses)
numWriteBuffers(_numWriteBuffers), maxMisses(_maxMisses),
cpuSideFilterRanges(cpu_side_filter_ranges),
memSideFilterRanges(mem_side_filter_ranges)
{
}
};

View file

@ -72,7 +72,8 @@ class Cache : public BaseCache
{
public:
CpuSidePort(const std::string &_name,
Cache<TagStore> *_cache);
Cache<TagStore> *_cache,
std::vector<Range<Addr> > filterRanges);
// BaseCache::CachePort just has a BaseCache *; this function
// lets us get back the type info we lost when we stored the
@ -95,7 +96,8 @@ class Cache : public BaseCache
{
public:
MemSidePort(const std::string &_name,
Cache<TagStore> *_cache);
Cache<TagStore> *_cache,
std::vector<Range<Addr> > filterRanges);
// BaseCache::CachePort just has a BaseCache *; this function
// lets us get back the type info we lost when we stored the

View file

@ -241,7 +241,8 @@ BaseCacheParams::create()
// Build BaseCache param object
BaseCache::Params base_params(latency, block_size,
mshrs, tgts_per_mshr, write_buffers,
max_miss_count);
max_miss_count, cpu_side_filter_ranges,
mem_side_filter_ranges);
//Warnings about prefetcher policy
if (prefetch_policy == Enums::none) {

View file

@ -39,6 +39,7 @@
#include "sim/host.hh"
#include "base/misc.hh"
#include "base/range_ops.hh"
#include "mem/cache/cache.hh"
#include "mem/cache/cache_blk.hh"
@ -61,8 +62,10 @@ Cache<TagStore>::Cache(const std::string &_name,
tempBlock = new BlkType();
tempBlock->data = new uint8_t[blkSize];
cpuSidePort = new CpuSidePort(_name + "-cpu_side_port", this);
memSidePort = new MemSidePort(_name + "-mem_side_port", this);
cpuSidePort = new CpuSidePort(_name + "-cpu_side_port", this,
params.baseParams.cpuSideFilterRanges);
memSidePort = new MemSidePort(_name + "-mem_side_port", this,
params.baseParams.memSideFilterRanges);
cpuSidePort->setOtherPort(memSidePort);
memSidePort->setOtherPort(cpuSidePort);
@ -88,7 +91,8 @@ Cache<TagStore>::getPort(const std::string &if_name, int idx)
} else if (if_name == "mem_side") {
return memSidePort;
} else if (if_name == "functional") {
return new CpuSidePort(name() + "-cpu_side_funcport", this);
return new CpuSidePort(name() + "-cpu_side_funcport", this,
std::vector<Range<Addr> >());
} else {
panic("Port name %s unrecognized\n", if_name);
}
@ -1221,6 +1225,7 @@ getDeviceAddressRanges(AddrRangeList &resp, bool &snoop)
// CPU side port doesn't snoop; it's a target only.
bool dummy;
otherPort->getPeerAddressRanges(resp, dummy);
FilterRangeList(filterRanges, resp);
snoop = false;
}
@ -1262,8 +1267,9 @@ Cache<TagStore>::CpuSidePort::recvFunctional(PacketPtr pkt)
template<class TagStore>
Cache<TagStore>::
CpuSidePort::CpuSidePort(const std::string &_name,
Cache<TagStore> *_cache)
: BaseCache::CachePort(_name, _cache)
Cache<TagStore> *_cache, std::vector<Range<Addr> >
filterRanges)
: BaseCache::CachePort(_name, _cache, filterRanges)
{
}
@ -1279,6 +1285,8 @@ Cache<TagStore>::MemSidePort::
getDeviceAddressRanges(AddrRangeList &resp, bool &snoop)
{
otherPort->getPeerAddressRanges(resp, snoop);
FilterRangeList(filterRanges, resp);
// Memory-side port always snoops, so unconditionally set flag for
// caller.
snoop = true;
@ -1416,8 +1424,9 @@ Cache<TagStore>::MemSidePort::processSendEvent()
template<class TagStore>
Cache<TagStore>::
MemSidePort::MemSidePort(const std::string &_name, Cache<TagStore> *_cache)
: BaseCache::CachePort(_name, _cache)
MemSidePort::MemSidePort(const std::string &_name, Cache<TagStore> *_cache,
std::vector<Range<Addr> > filterRanges)
: BaseCache::CachePort(_name, _cache, filterRanges)
{
// override default send event from SimpleTimingPort
delete sendEvent;