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:
parent
5c38668ed6
commit
06a9f58c68
16 changed files with 134 additions and 49 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
55
src/base/range_ops.hh
Normal 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__
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
4
src/mem/cache/BaseCache.py
vendored
4
src/mem/cache/BaseCache.py
vendored
|
@ -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")
|
||||
|
|
5
src/mem/cache/base_cache.cc
vendored
5
src/mem/cache/base_cache.cc
vendored
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
16
src/mem/cache/base_cache.hh
vendored
16
src/mem/cache/base_cache.hh
vendored
|
@ -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)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
6
src/mem/cache/cache.hh
vendored
6
src/mem/cache/cache.hh
vendored
|
@ -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
|
||||
|
|
3
src/mem/cache/cache_builder.cc
vendored
3
src/mem/cache/cache_builder.cc
vendored
|
@ -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) {
|
||||
|
|
23
src/mem/cache/cache_impl.hh
vendored
23
src/mem/cache/cache_impl.hh
vendored
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue