fix partial writes with a functional memory hack

figure out the block size from devices attached to the bus otherwise use a default block size when no devices that care are attached

configs/common/FSConfig.py:
src/mem/bridge.cc:
src/mem/bridge.hh:
src/python/m5/objects/Bridge.py:
    fix partial writes with a functional memory hack
src/mem/bus.cc:
src/mem/bus.hh:
src/python/m5/objects/Bus.py:
    figure out the block size from devices attached to the bus otherwise use a default block size when no devices that care are attached
src/mem/packet.cc:
    fix WriteInvalidateResp to not be a request that needs a response since it isn't
src/mem/port.hh:
    by default return 0 for deviceBlockSize instead of panicing. This makes finding the block size the bus should use easier

--HG--
extra : convert_revision : 3fcfe95f9f392ef76f324ee8bd1d7f6de95c1a64
This commit is contained in:
Ali Saidi 2007-05-07 14:42:03 -04:00
parent b7292a1713
commit 0dfc29a023
9 changed files with 165 additions and 39 deletions

View file

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

View file

@ -43,20 +43,24 @@
Bridge::BridgePort::BridgePort(const std::string &_name, Bridge::BridgePort::BridgePort(const std::string &_name,
Bridge *_bridge, BridgePort *_otherPort, Bridge *_bridge, BridgePort *_otherPort,
int _delay, int _queueLimit) int _delay, int _queueLimit,
bool fix_partial_write)
: Port(_name), bridge(_bridge), otherPort(_otherPort), : Port(_name), bridge(_bridge), otherPort(_otherPort),
delay(_delay), outstandingResponses(0), delay(_delay), fixPartialWrite(fix_partial_write),
queueLimit(_queueLimit), sendEvent(this) outstandingResponses(0), queueLimit(_queueLimit), sendEvent(this)
{ {
} }
Bridge::Bridge(const std::string &n, int qsa, int qsb, Bridge::Bridge(const std::string &n, int qsa, int qsb,
Tick _delay, int write_ack) Tick _delay, int write_ack, bool fix_partial_write_a,
bool fix_partial_write_b)
: MemObject(n), : MemObject(n),
portA(n + "-portA", this, &portB, _delay, qsa), portA(n + "-portA", this, &portB, _delay, qsa, fix_partial_write_a),
portB(n + "-portB", this, &portA, _delay, qsa), portB(n + "-portB", this, &portA, _delay, qsa, fix_partial_write_b),
ackWrites(write_ack) ackWrites(write_ack)
{ {
if (ackWrites)
panic("No support for acknowledging writes\n");
} }
Port * Port *
@ -82,7 +86,10 @@ Bridge::init()
{ {
// Make sure that both sides are connected to. // Make sure that both sides are connected to.
if (portA.getPeer() == NULL || portB.getPeer() == NULL) if (portA.getPeer() == NULL || portB.getPeer() == NULL)
panic("Both ports of bus bridge are not connected to a bus.\n"); fatal("Both ports of bus bridge are not connected to a bus.\n");
if (portA.peerBlockSize() != portB.peerBlockSize())
fatal("Busses don't have the same block size... Not supported.\n");
} }
@ -107,8 +114,10 @@ Bridge::BridgePort::recvTiming(PacketPtr pkt)
bool bool
Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
{ {
if (queueFull()) if (queueFull()) {
DPRINTF(BusBridge, "Queue full, returning false\n");
return false; return false;
}
if (pkt->isResponse()) { if (pkt->isResponse()) {
// This is a response for a request we forwarded earlier. The // This is a response for a request we forwarded earlier. The
@ -149,6 +158,7 @@ Bridge::BridgePort::trySend()
assert(!sendQueue.empty()); assert(!sendQueue.empty());
bool was_full = queueFull(); bool was_full = queueFull();
int pbs = peerBlockSize();
PacketBuffer *buf = sendQueue.front(); PacketBuffer *buf = sendQueue.front();
@ -156,10 +166,18 @@ Bridge::BridgePort::trySend()
PacketPtr pkt = buf->pkt; PacketPtr pkt = buf->pkt;
pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set
if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite &&
pkt->getOffset(pbs) && pkt->getSize() != pbs) {
buf->partialWriteFix(this);
pkt = buf->pkt;
}
DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n",
buf->origSrc, pkt->getDest(), pkt->getAddr()); buf->origSrc, pkt->getDest(), pkt->getAddr());
pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set
if (sendTiming(pkt)) { if (sendTiming(pkt)) {
// send successful // send successful
sendQueue.pop_front(); sendQueue.pop_front();
@ -191,6 +209,7 @@ Bridge::BridgePort::trySend()
} else { } else {
DPRINTF(BusBridge, " unsuccessful\n"); DPRINTF(BusBridge, " unsuccessful\n");
buf->undoPartialWriteFix();
} }
} }
@ -248,6 +267,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge)
Param<int> queue_size_b; Param<int> queue_size_b;
Param<Tick> delay; Param<Tick> delay;
Param<bool> write_ack; Param<bool> write_ack;
Param<bool> fix_partial_write_a;
Param<bool> fix_partial_write_b;
END_DECLARE_SIM_OBJECT_PARAMS(Bridge) END_DECLARE_SIM_OBJECT_PARAMS(Bridge)
@ -256,14 +277,16 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge)
INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"), INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"),
INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"), INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"),
INIT_PARAM(delay, "The miminum delay to cross this bridge"), INIT_PARAM(delay, "The miminum delay to cross this bridge"),
INIT_PARAM(write_ack, "Acknowledge any writes that are received.") INIT_PARAM(write_ack, "Acknowledge any writes that are received."),
INIT_PARAM(fix_partial_write_a, "Fixup any partial block writes that are received"),
INIT_PARAM(fix_partial_write_b, "Fixup any partial block writes that are received")
END_INIT_SIM_OBJECT_PARAMS(Bridge) END_INIT_SIM_OBJECT_PARAMS(Bridge)
CREATE_SIM_OBJECT(Bridge) CREATE_SIM_OBJECT(Bridge)
{ {
return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay, return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay,
write_ack); write_ack, fix_partial_write_a, fix_partial_write_b);
} }
REGISTER_SIM_OBJECT("Bridge", Bridge) REGISTER_SIM_OBJECT("Bridge", Bridge)

View file

@ -66,6 +66,8 @@ class Bridge : public MemObject
/** Minimum delay though this bridge. */ /** Minimum delay though this bridge. */
Tick delay; Tick delay;
bool fixPartialWrite;
class PacketBuffer : public Packet::SenderState { class PacketBuffer : public Packet::SenderState {
public: public:
@ -75,10 +77,13 @@ class Bridge : public MemObject
short origSrc; short origSrc;
bool expectResponse; bool expectResponse;
bool partialWriteFixed;
PacketPtr oldPkt;
PacketBuffer(PacketPtr _pkt, Tick t) PacketBuffer(PacketPtr _pkt, Tick t)
: ready(t), pkt(_pkt), : ready(t), pkt(_pkt),
origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()), origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()),
expectResponse(_pkt->needsResponse()) expectResponse(_pkt->needsResponse()), partialWriteFixed(false)
{ {
if (!pkt->isResponse()) if (!pkt->isResponse())
pkt->senderState = this; pkt->senderState = this;
@ -89,7 +94,46 @@ class Bridge : public MemObject
assert(pkt->senderState == this); assert(pkt->senderState == this);
pkt->setDest(origSrc); pkt->setDest(origSrc);
pkt->senderState = origSenderState; pkt->senderState = origSenderState;
if (partialWriteFixed)
delete oldPkt;
} }
void partialWriteFix(Port *port)
{
assert(!partialWriteFixed);
assert(expectResponse);
int pbs = port->peerBlockSize();
partialWriteFixed = true;
PacketDataPtr data;
data = new uint8_t[pbs];
PacketPtr funcPkt = new Packet(pkt->req, MemCmd::ReadReq,
Packet::Broadcast, pbs);
funcPkt->dataStatic(data);
port->sendFunctional(funcPkt);
assert(funcPkt->result == Packet::Success);
delete funcPkt;
oldPkt = pkt;
memcpy(data + oldPkt->getOffset(pbs), pkt->getPtr<uint8_t>(),
pkt->getSize());
pkt = new Packet(oldPkt->req, MemCmd::WriteInvalidateReq,
Packet::Broadcast, pbs);
pkt->dataDynamicArray(data);
pkt->senderState = oldPkt->senderState;
}
void undoPartialWriteFix()
{
if (!partialWriteFixed)
return;
delete pkt;
pkt = oldPkt;
partialWriteFixed = false;
}
}; };
/** /**
@ -140,7 +184,7 @@ class Bridge : public MemObject
/** Constructor for the BusPort.*/ /** Constructor for the BusPort.*/
BridgePort(const std::string &_name, BridgePort(const std::string &_name,
Bridge *_bridge, BridgePort *_otherPort, Bridge *_bridge, BridgePort *_otherPort,
int _delay, int _queueLimit); int _delay, int _queueLimit, bool fix_partial_write);
protected: protected:
@ -182,7 +226,8 @@ class Bridge : public MemObject
virtual void init(); virtual void init();
Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack); Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack,
bool fix_partial_write_a, bool fix_partial_write_b);
}; };
#endif //__MEM_BUS_HH__ #endif //__MEM_BUS_HH__

View file

@ -48,6 +48,7 @@ Bus::getPort(const std::string &if_name, int idx)
if (defaultPort == NULL) { if (defaultPort == NULL) {
defaultPort = new BusPort(csprintf("%s-default",name()), this, defaultPort = new BusPort(csprintf("%s-default",name()), this,
defaultId); defaultId);
cachedBlockSizeValid = false;
return defaultPort; return defaultPort;
} else } else
fatal("Default port already set\n"); fatal("Default port already set\n");
@ -68,6 +69,7 @@ Bus::getPort(const std::string &if_name, int idx)
assert(maxId < std::numeric_limits<typeof(maxId)>::max()); assert(maxId < std::numeric_limits<typeof(maxId)>::max());
BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
interfaces[id] = bp; interfaces[id] = bp;
cachedBlockSizeValid = false;
return bp; return bp;
} }
@ -182,6 +184,7 @@ Bus::recvTiming(PacketPtr pkt)
if (tickNextIdle > curTick || if (tickNextIdle > curTick ||
(retryList.size() && (!inRetry || pktPort != retryList.front()))) { (retryList.size() && (!inRetry || pktPort != retryList.front()))) {
addToRetryList(pktPort); addToRetryList(pktPort);
DPRINTF(Bus, "recvTiming: Bus is busy, returning false\n");
return false; return false;
} }
@ -207,11 +210,12 @@ Bus::recvTiming(PacketPtr pkt)
inRetry = false; inRetry = false;
} }
occupyBus(pkt); occupyBus(pkt);
DPRINTF(Bus, "recvTiming: Packet sucessfully sent\n");
return true; return true;
} }
} else { } else {
//Snoop didn't succeed //Snoop didn't succeed
DPRINTF(Bus, "Adding a retry to RETRY list %d\n", DPRINTF(Bus, "Adding1 a retry to RETRY list %d\n",
pktPort->getId()); pktPort->getId());
addToRetryList(pktPort); addToRetryList(pktPort);
return false; return false;
@ -239,13 +243,14 @@ Bus::recvTiming(PacketPtr pkt)
} }
// Packet not successfully sent. Leave or put it on the retry list. // Packet not successfully sent. Leave or put it on the retry list.
DPRINTF(Bus, "Adding a retry to RETRY list %d\n", DPRINTF(Bus, "Adding2 a retry to RETRY list %d\n",
pktPort->getId()); pktPort->getId());
addToRetryList(pktPort); addToRetryList(pktPort);
return false; return false;
} }
else { else {
//Forwarding up from responder, just return true; //Forwarding up from responder, just return true;
DPRINTF(Bus, "recvTiming: can we be here?\n");
return true; return true;
} }
} }
@ -253,12 +258,12 @@ Bus::recvTiming(PacketPtr pkt)
void void
Bus::recvRetry(int id) Bus::recvRetry(int id)
{ {
DPRINTF(Bus, "Received a retry\n"); DPRINTF(Bus, "Received a retry from %s\n", id == -1 ? "self" : interfaces[id]->getPeer()->name());
// If there's anything waiting, and the bus isn't busy... // If there's anything waiting, and the bus isn't busy...
if (retryList.size() && curTick >= tickNextIdle) { if (retryList.size() && curTick >= tickNextIdle) {
//retryingPort = retryList.front(); //retryingPort = retryList.front();
inRetry = true; inRetry = true;
DPRINTF(Bus, "Sending a retry\n"); DPRINTF(Bus, "Sending a retry to %s\n", retryList.front()->getPeer()->name());
retryList.front()->sendRetry(); retryList.front()->sendRetry();
// If inRetry is still true, sendTiming wasn't called // If inRetry is still true, sendTiming wasn't called
if (inRetry) if (inRetry)
@ -267,18 +272,20 @@ Bus::recvRetry(int id)
retryList.pop_front(); retryList.pop_front();
inRetry = false; inRetry = false;
//Bring tickNextIdle up to the present if (id != -1) {
while (tickNextIdle < curTick) //Bring tickNextIdle up to the present
while (tickNextIdle < curTick)
tickNextIdle += clock;
//Burn a cycle for the missed grant.
tickNextIdle += clock; tickNextIdle += clock;
//Burn a cycle for the missed grant. if (!busIdle.scheduled()) {
tickNextIdle += clock; busIdle.schedule(tickNextIdle);
} else {
if (!busIdle.scheduled()) { busIdle.reschedule(tickNextIdle);
busIdle.schedule(tickNextIdle); }
} else { } // id != -1
busIdle.reschedule(tickNextIdle);
}
} }
} }
//If we weren't able to drain before, we might be able to now. //If we weren't able to drain before, we might be able to now.
@ -598,6 +605,37 @@ Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
} }
} }
int
Bus::findBlockSize(int id)
{
if (cachedBlockSizeValid)
return cachedBlockSize;
int max_bs = -1, tmp_bs;
range_map<Addr,int>::iterator portIter;
std::vector<DevMap>::iterator snoopIter;
for (portIter = portMap.begin(); portIter != portMap.end(); portIter++) {
tmp_bs = interfaces[portIter->second]->peerBlockSize();
if (tmp_bs > max_bs)
max_bs = tmp_bs;
}
for (snoopIter = portSnoopList.begin();
snoopIter != portSnoopList.end(); snoopIter++) {
tmp_bs = interfaces[snoopIter->portId]->peerBlockSize();
if (tmp_bs > max_bs)
max_bs = tmp_bs;
}
if (max_bs <= 0)
max_bs = defaultBlockSize;
if (max_bs != 64)
warn_once("Blocksize found to not be 64... hmm... probably not.\n");
cachedBlockSize = max_bs;
cachedBlockSizeValid = true;
return max_bs;
}
unsigned int unsigned int
Bus::drain(Event * de) Bus::drain(Event * de)
{ {
@ -618,6 +656,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
Param<int> clock; Param<int> clock;
Param<int> width; Param<int> width;
Param<bool> responder_set; Param<bool> responder_set;
Param<int> block_size;
END_DECLARE_SIM_OBJECT_PARAMS(Bus) END_DECLARE_SIM_OBJECT_PARAMS(Bus)
@ -625,12 +664,14 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
INIT_PARAM(bus_id, "a globally unique bus id"), INIT_PARAM(bus_id, "a globally unique bus id"),
INIT_PARAM(clock, "bus clock speed"), INIT_PARAM(clock, "bus clock speed"),
INIT_PARAM(width, "width of the bus (bits)"), INIT_PARAM(width, "width of the bus (bits)"),
INIT_PARAM(responder_set, "Is a default responder set by the user") INIT_PARAM(responder_set, "Is a default responder set by the user"),
INIT_PARAM(block_size, "Default blocksize if no device has one")
END_INIT_SIM_OBJECT_PARAMS(Bus) END_INIT_SIM_OBJECT_PARAMS(Bus)
CREATE_SIM_OBJECT(Bus) CREATE_SIM_OBJECT(Bus)
{ {
return new Bus(getInstanceName(), bus_id, clock, width, responder_set); return new Bus(getInstanceName(), bus_id, clock, width, responder_set,
block_size);
} }
REGISTER_SIM_OBJECT("Bus", Bus) REGISTER_SIM_OBJECT("Bus", Bus)

View file

@ -133,6 +133,12 @@ class Bus : public MemObject
/** Occupy the bus with transmitting the packet pkt */ /** Occupy the bus with transmitting the packet pkt */
void occupyBus(PacketPtr pkt); void occupyBus(PacketPtr pkt);
/** Ask everyone on the bus what their size is
* @param id id of the busport that made the request
* @return the max of all the sizes
*/
int findBlockSize(int id);
/** Declaration of the buses port type, one will be instantiated for each /** Declaration of the buses port type, one will be instantiated for each
of the interfaces connecting to the bus. */ of the interfaces connecting to the bus. */
class BusPort : public Port class BusPort : public Port
@ -195,8 +201,11 @@ class Bus : public MemObject
AddrRangeList &snoop) AddrRangeList &snoop)
{ bus->addressRanges(resp, snoop, id); } { bus->addressRanges(resp, snoop, id); }
// Hack to make translating port work without changes // Ask the bus to ask everyone on the bus what their block size is and
virtual int deviceBlockSize() { return 32; } // take the max of it. This might need to be changed a bit if we ever
// support multiple block sizes.
virtual int deviceBlockSize()
{ return bus->findBlockSize(id); }
}; };
@ -256,6 +265,10 @@ class Bus : public MemObject
/** Has the user specified their own default responder? */ /** Has the user specified their own default responder? */
bool responderSet; bool responderSet;
int defaultBlockSize;
int cachedBlockSize;
bool cachedBlockSizeValid;
public: public:
/** A function used to return the port associated with this bus object. */ /** A function used to return the port associated with this bus object. */
@ -267,11 +280,12 @@ class Bus : public MemObject
unsigned int drain(Event *de); unsigned int drain(Event *de);
Bus(const std::string &n, int bus_id, int _clock, int _width, Bus(const std::string &n, int bus_id, int _clock, int _width,
bool responder_set) bool responder_set, int dflt_blk_size)
: MemObject(n), busId(bus_id), clock(_clock), width(_width), : MemObject(n), busId(bus_id), clock(_clock), width(_width),
tickNextIdle(0), drainEvent(NULL), busIdle(this), inRetry(false), tickNextIdle(0), drainEvent(NULL), busIdle(this), inRetry(false),
maxId(0), defaultPort(NULL), funcPort(NULL), funcPortId(-4), maxId(0), defaultPort(NULL), funcPort(NULL), funcPortId(-4),
responderSet(responder_set) responderSet(responder_set), defaultBlockSize(dflt_blk_size),
cachedBlockSize(0), cachedBlockSizeValid(false)
{ {
//Both the width and clock period must be positive //Both the width and clock period must be positive
if (width <= 0) if (width <= 0)

View file

@ -85,7 +85,7 @@ MemCmd::commandInfo[] =
{ SET5(IsWrite, IsInvalidate, IsRequest, HasData, NeedsResponse), { SET5(IsWrite, IsInvalidate, IsRequest, HasData, NeedsResponse),
WriteInvalidateResp, "WriteInvalidateReq" }, WriteInvalidateResp, "WriteInvalidateReq" },
/* WriteInvalidateResp */ /* WriteInvalidateResp */
{ SET5(IsWrite, IsInvalidate, IsRequest, NeedsResponse, IsResponse), { SET3(IsWrite, IsInvalidate, IsResponse),
InvalidCmd, "WriteInvalidateResp" }, InvalidCmd, "WriteInvalidateResp" },
/* UpgradeReq */ /* UpgradeReq */
{ SET3(IsInvalidate, IsRequest, IsUpgrade), InvalidCmd, "UpgradeReq" }, { SET3(IsInvalidate, IsRequest, IsUpgrade), InvalidCmd, "UpgradeReq" },

View file

@ -161,10 +161,10 @@ class Port
/** Called by a peer port in order to determine the block size of the /** Called by a peer port in order to determine the block size of the
device connected to this port. It sometimes doesn't make sense for device connected to this port. It sometimes doesn't make sense for
this function to be called, a DMA interface doesn't really have a this function to be called, so it just returns 0. Anytthing that is
block size, so it is defaulted to a panic. concerned with the size should just ignore that.
*/ */
virtual int deviceBlockSize() { panic("??"); M5_DUMMY_RETURN } virtual int deviceBlockSize() { return 0; }
/** The peer port is requesting us to reply with a list of the ranges we /** The peer port is requesting us to reply with a list of the ranges we
are responsible for. are responsible for.

View file

@ -9,3 +9,5 @@ class Bridge(MemObject):
queue_size_b = Param.Int(16, "The number of requests to buffer") queue_size_b = Param.Int(16, "The number of requests to buffer")
delay = Param.Latency('0ns', "The latency of this bridge") delay = Param.Latency('0ns', "The latency of this bridge")
write_ack = Param.Bool(False, "Should this bridge ack writes") 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")

View file

@ -11,6 +11,7 @@ class Bus(MemObject):
clock = Param.Clock("1GHz", "bus clock speed") clock = Param.Clock("1GHz", "bus clock speed")
width = Param.Int(64, "bus width (bytes)") width = Param.Int(64, "bus width (bytes)")
responder_set = Param.Bool(False, "Did the user specify a default responder.") responder_set = Param.Bool(False, "Did the user specify a default responder.")
block_size = Param.Int(64, "The default block size if one isn't set by a device attached to the bus.")
if build_env['FULL_SYSTEM']: if build_env['FULL_SYSTEM']:
responder = BadAddr(pio_addr=0x0, pio_latency="1ps") responder = BadAddr(pio_addr=0x0, pio_latency="1ps")
default = Port(Self.responder.pio, "Default port for requests that aren't handled by a device.") default = Port(Self.responder.pio, "Default port for requests that aren't handled by a device.")