Merge zizzer:/bk/newmem

into  zeep.pool:/z/saidi/work/m5.newmem

--HG--
extra : convert_revision : d6f7c4dd146613eeba39249f2d916a77108bc8c1
This commit is contained in:
Ali Saidi 2006-04-28 15:41:22 -04:00
commit ca8a659394
28 changed files with 956 additions and 42 deletions

View file

@ -87,13 +87,15 @@ base_sources = Split('''
cpu/pc_event.cc
cpu/static_inst.cc
cpu/sampler/sampler.cc
mem/request.cc
mem/bridge.cc
mem/bus.cc
mem/connector.cc
mem/mem_object.cc
mem/packet.cc
mem/physical.cc
mem/port.cc
mem/bus.cc
mem/request.cc
python/pyconfig.cc
python/embedded_py.cc

View file

@ -45,7 +45,6 @@ class AlphaSystem : public System
{
std::string console_path;
std::string palcode;
std::string boot_osflags;
uint64_t system_type;
uint64_t system_rev;
};

200
arch/sparc/system.cc Normal file
View file

@ -0,0 +1,200 @@
/*
* Copyright (c) 2002-2006 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.
*/
#include "arch/sparc/system.hh"
#include "arch/vtophys.hh"
#include "base/remote_gdb.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "base/trace.hh"
#include "mem/physical.hh"
#include "sim/byteswap.hh"
#include "sim/builder.hh"
using namespace BigEndianGuest;
SparcSystem::SparcSystem(Params *p)
: System(p)
{
resetSymtab = new SymbolTable;
hypervisorSymtab = new SymbolTable;
openbootSymtab = new SymbolTable;
/**
* Load the boot code, and hypervisor into memory.
*/
// Read the reset binary
reset = createObjectFile(params()->reset_bin);
if (reset == NULL)
fatal("Could not load reset binary %s", params()->reset_bin);
// Read the openboot binary
openboot = createObjectFile(params()->openboot_bin);
if (openboot == NULL)
fatal("Could not load openboot bianry %s", params()->openboot_bin);
// Read the hypervisor binary
hypervisor = createObjectFile(params()->hypervisor_bin);
if (hypervisor == NULL)
fatal("Could not load hypervisor binary %s", params()->hypervisor_bin);
// Load reset binary into memory
reset->loadSections(&functionalPort, SparcISA::LoadAddrMask);
// Load the openboot binary
openboot->loadSections(&functionalPort, SparcISA::LoadAddrMask);
// Load the hypervisor binary
hypervisor->loadSections(&functionalPort, SparcISA::LoadAddrMask);
// load symbols
if (!reset->loadGlobalSymbols(reset))
panic("could not load reset symbols\n");
if (!openboot->loadGlobalSymbols(openbootSymtab))
panic("could not load openboot symbols\n");
if (!hypervisor->loadLocalSymbols(hypervisorSymtab))
panic("could not load hypervisor symbols\n");
// load symbols into debug table
if (!reset->loadGlobalSymbols(debugSymbolTable))
panic("could not load reset symbols\n");
if (!openboot->loadGlobalSymbols(debugSymbolTable))
panic("could not load openboot symbols\n");
if (!hypervisor->loadLocalSymbols(debugSymbolTable))
panic("could not load hypervisor symbols\n");
// @todo any fixup code over writing data in binaries on setting break
// events on functions should happen here.
}
SparcSystem::~SparcSystem()
{
delete resetSymtab;
delete hypervisorSymtab;
delete openbootSymtab;
delete reset;
delete openboot;
delete hypervisor;
}
bool
SparcSystem::breakpoint()
{
panic("Need to implement");
}
void
SparcSystem::serialize(std::ostream &os)
{
System::serialize(os);
resetSymtab->serialize("reset_symtab", os);
hypervisorSymtab->serialize("hypervisor_symtab", os);
openbootSymtab->serialize("openboot_symtab", os);
}
void
SparcSystem::unserialize(Checkpoint *cp, const std::string &section)
{
System::unserialize(cp,section);
resetSymtab->unserialize("reset_symtab", cp, section);
hypervisorSymtab->unserialize("hypervisor_symtab", cp, section);
openbootSymtab->unserialize("openboot_symtab", cp, section);
}
BEGIN_DECLARE_SIM_OBJECT_PARAMS(SparcSystem)
SimObjectParam<PhysicalMemory *> physmem;
Param<std::string> kernel;
Param<std::string> reset_bin;
Param<std::string> hypervisor_bin;
Param<std::string> openboot_bin;
Param<std::string> boot_osflags;
Param<std::string> readfile;
Param<unsigned int> init_param;
Param<bool> bin;
VectorParam<std::string> binned_fns;
Param<bool> bin_int;
END_DECLARE_SIM_OBJECT_PARAMS(SparcSystem)
BEGIN_INIT_SIM_OBJECT_PARAMS(SparcSystem)
INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"),
INIT_PARAM(physmem, "phsyical memory"),
INIT_PARAM(kernel, "file that contains the kernel code"),
INIT_PARAM(reset_bin, "file that contains the reset code"),
INIT_PARAM(hypervisor_bin, "file that contains the hypervisor code"),
INIT_PARAM(openboot_bin, "file that contains the openboot code"),
INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
"a"),
INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34),
INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10),
INIT_PARAM_DFLT(bin, "is this system to be binned", false),
INIT_PARAM(binned_fns, "functions to be broken down and binned"),
INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true)
END_INIT_SIM_OBJECT_PARAMS(SparcSystem)
CREATE_SIM_OBJECT(SparcSystem)
{
SparcSystem::Params *p = new SparcSystem::Params;
p->name = getInstanceName();
p->boot_cpu_frequency = boot_cpu_frequency;
p->physmem = physmem;
p->kernel_path = kernel;
p->reset_bin = reset_bin;
p->hypervisor_bin = hypervisor_bin;
p->openboot_bin = openboot_bin;
p->boot_osflags = boot_osflags;
p->init_param = init_param;
p->readfile = readfile;
p->system_type = system_type;
p->system_rev = system_rev;
p->bin = bin;
p->binned_fns = binned_fns;
p->bin_int = bin_int;
return new SparcSystem(p);
}
REGISTER_SIM_OBJECT("SparcSystem", SparcSystem)

114
arch/sparc/system.hh Normal file
View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2002-2005 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.
*/
#ifndef __ARCH_SPARC_SYSTEM_HH__
#define __ARCH_SPARC_SYSTEM_HH__
#include <string>
#include <vector>
#include "base/loader/symtab.hh"
#include "cpu/pc_event.hh"
#include "kern/system_events.hh"
#include "sim/sim_object.hh"
#include "sim/system.hh"
class SparcSystem : public System
{
public:
struct Params : public System::Params
{
std::string reset_bin;
std::string hypervison_bin;
std::string openboot_bin;
std::string boot_osflags;
uint64_t system_type;
uint64_t system_rev;
};
SparcSystem(Params *p);
~SparcaSystem();
virtual bool breakpoint();
/**
* Serialization stuff
*/
public:
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
/** reset binary symbol table */
SymbolTable *resetSymtab;
/** hypervison binary symbol table */
SymbolTable *hypervisorSymtab;
/** openboot symbol table */
SymbolTable *openbootSymtab;
/** Object pointer for the reset binary */
ObjectFile *reset;
/** Object pointer for the hypervisor code */
ObjectFile *hypervisor;
/** Object pointer for the openboot code */
ObjectFile *openboot;
protected:
const Params *params() const { return (const Params *)_params; }
/** Add a function-based event to reset binary. */
template <class T>
T *SparcSystem::addResetFuncEvent(const char *lbl)
{
return addFuncEvent<T>(resetSymtab, lbl);
}
/** Add a function-based event to the hypervisor. */
template <class T>
T *SparcSystem::addHypervisorFuncEvent(const char *lbl)
{
return addFuncEvent<T>(hypervisorSymtab, lbl);
}
/** Add a function-based event to the openboot. */
template <class T>
T *SparcSystem::addOpenbootFuncEvent(const char *lbl)
{
return addFuncEvent<T>(openbootSymtab, lbl);
}
virtual Addr fixFuncEventAddr(Addr addr);
};
#endif

View file

@ -139,9 +139,13 @@ class LinuxTsunami(BaseTsunami):
pci_func=0, pci_dev=0, pci_bus=0)
class LinuxAlphaSystem(LinuxAlphaSystem):
magicbus = Bus()
magicbus = Bus(bus_id=0)
magicbus2 = Bus(bus_id=1)
bridge = Bridge()
physmem = PhysicalMemory(range = AddrRange('128MB'))
c1 = Connector(side_a=Parent.physmem, side_b=Parent.magicbus)
c0a = Connector(side_a=Parent.magicbus, side_b=Parent.bridge, side_b_name="side_a")
c0b = Connector(side_a=Parent.magicbus2, side_b=Parent.bridge, side_b_name="side_b")
c1 = Connector(side_a=Parent.physmem, side_b=Parent.magicbus2)
tsunami = LinuxTsunami()
c2 = Connector(side_a=Parent.tsunami.cchip, side_a_name='pio', side_b=Parent.magicbus)
c3 = Connector(side_a=Parent.tsunami.pchip, side_a_name='pio', side_b=Parent.magicbus)
@ -177,7 +181,7 @@ class LinuxAlphaSystem(LinuxAlphaSystem):
read_only=True)
simple_disk = SimpleDisk(disk=Parent.raw_image)
intrctrl = IntrControl()
cpu = SimpleCPU(mem=Parent.magicbus)
cpu = SimpleCPU(mem=Parent.magicbus2)
sim_console = SimConsole(listener=ConsoleListener(port=3456))
kernel = '/z/saidi/work/m5.newmem/build/vmlinux'
pal = binary('ts_osfpal')

View file

@ -103,6 +103,10 @@ class SimpleCPU : public BaseCPU
virtual void recvStatusChange(Status status);
virtual Packet *recvRetry();
virtual void getDeviceAddressRanges(AddrRangeList &resp,
AddrRangeList &snoop)
{ resp.clear(); snoop.clear(); }
};
MemObject *mem;

View file

@ -99,7 +99,7 @@ AlphaConsole::read(Packet &pkt)
assert(pkt.result == Unknown);
assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
Addr daddr = pkt.addr - pioAddr;
pkt.allocate();
@ -191,7 +191,7 @@ AlphaConsole::read(Packet &pkt)
Tick
AlphaConsole::write(Packet &pkt)
{
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
assert(pkt.result == Unknown);
assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);

View file

@ -430,7 +430,7 @@ IdeController::read(Packet &pkt)
IdeRegType reg_type;
int disk;
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
pkt.allocate();
if (pkt.size != 1 && pkt.size != 2 && pkt.size !=4)
panic("Bad IDE read size: %d\n", pkt.size);
@ -518,7 +518,7 @@ IdeController::write(Packet &pkt)
int disk;
uint8_t oldVal, newVal;
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
parseAddr(pkt.addr, offset, channel, reg_type);

View file

@ -116,7 +116,13 @@ DmaPort::recvTiming(Packet &pkt)
DmaReqState *state;
state = (DmaReqState*)pkt.senderState;
state->completionEvent->schedule(pkt.time - pkt.req->getTime());
delete pkt.req;
delete &pkt;
} else {
delete pkt.req;
delete &pkt;
}
return Success;
}
@ -203,7 +209,7 @@ DmaPort::sendDma(Packet *pkt)
if (state == Timing) {
if (sendTiming(pkt) == Failure)
transmitList.push_back(&packet);
} else if (state == Atomic) {*/
} else if (state == Atomic) {*/
sendAtomic(*pkt);
if (pkt->senderState) {
DmaReqState *state = (DmaReqState*)pkt->senderState;

View file

@ -167,7 +167,7 @@ class DmaPort : public Port
friend class DmaPort;
};
void sendDma(Packet &pkt);
void sendDma(Packet *pkt);
public:
DmaPort(DmaDevice *dev, Platform *p);

View file

@ -54,7 +54,7 @@ IsaFake::read(Packet &pkt)
assert(pkt.result == Unknown);
assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt.addr, pkt.size);
@ -80,7 +80,7 @@ IsaFake::read(Packet &pkt)
Tick
IsaFake::write(Packet &pkt)
{
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt.addr, pkt.size);
pkt.result = Success;
return pioDelay;

View file

@ -493,7 +493,7 @@ NSGigE::read(Packet &pkt)
{
assert(ioEnable);
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
pkt.allocate();
//The mask is to give you only the offset into the device register file
@ -729,7 +729,7 @@ NSGigE::write(Packet &pkt)
DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
daddr, pkt.addr, pkt.size);
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
if (daddr > LAST && daddr <= RESERVED) {
panic("Accessing reserved register");

View file

@ -99,7 +99,7 @@ PciConfigAll::read(Packet &pkt)
int func = (daddr >> 8) & 0x7;
int reg = daddr & 0xFF;
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
pkt.allocate();
DPRINTF(PciConfigAll, "read va=%#x da=%#x size=%d\n", pkt.addr, daddr,
@ -134,7 +134,7 @@ PciConfigAll::read(Packet &pkt)
Tick
PciConfigAll::write(Packet &pkt)
{
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
assert(pkt.result == Unknown);
assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);

View file

@ -321,7 +321,7 @@ Device::read(Packet &pkt)
Addr index = daddr >> Regs::VirtualShift;
Addr raddr = daddr & Regs::VirtualMask;
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
pkt.allocate();
if (!regValid(raddr))
@ -408,7 +408,7 @@ Device::write(Packet &pkt)
Addr index = daddr >> Regs::VirtualShift;
Addr raddr = daddr & Regs::VirtualMask;
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
if (!regValid(raddr))
panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",

View file

@ -76,7 +76,7 @@ TsunamiCChip::read(Packet &pkt)
assert(pkt.result == Unknown);
assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
Addr regnum = (pkt.addr - pioAddr) >> 6;
Addr daddr = (pkt.addr - pioAddr);
@ -182,7 +182,7 @@ TsunamiCChip::read(Packet &pkt)
Tick
TsunamiCChip::write(Packet &pkt)
{
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);

View file

@ -441,7 +441,7 @@ TsunamiIO::read(Packet &pkt)
assert(pkt.result == Unknown);
assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
Addr daddr = pkt.addr - pioAddr;
DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", pkt.addr,
@ -505,7 +505,7 @@ TsunamiIO::read(Packet &pkt)
Tick
TsunamiIO::write(Packet &pkt)
{
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
assert(pkt.result == Unknown);
assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);

View file

@ -71,7 +71,7 @@ TsunamiPChip::read(Packet &pkt)
assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
pkt.allocate();
Addr daddr = (pkt.addr - pioAddr) >> 6;;
assert(pkt.size == sizeof(uint64_t));
@ -151,7 +151,7 @@ TsunamiPChip::read(Packet &pkt)
Tick
TsunamiPChip::write(Packet &pkt)
{
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
assert(pkt.result == Unknown);
assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);

View file

@ -114,7 +114,7 @@ Uart8250::read(Packet &pkt)
assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);
assert(pkt.size == 1);
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
Addr daddr = pkt.addr - pioAddr;
pkt.allocate();
@ -198,7 +198,7 @@ Uart8250::write(Packet &pkt)
assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);
assert(pkt.size == 1);
pkt.time = curTick + pioDelay;
pkt.time += pioDelay;
Addr daddr = pkt.addr - pioAddr;
DPRINTF(Uart, " write register %#x value %#x\n", daddr, pkt.get<uint8_t>());

263
mem/bridge.cc Normal file
View file

@ -0,0 +1,263 @@
/*
* Copyright (c) 2006 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.
*/
/**
* @file Definition of a simple bus bridge without buffering.
*/
#include "base/trace.hh"
#include "mem/bridge.hh"
#include "sim/builder.hh"
void
Bridge::init()
{
// Make sure that both sides are connected to.
if (sideA == NULL || sideB == NULL)
panic("Both ports of bus bridge are not connected to a bus.\n");
}
/** Function called by the port when the bus is recieving a Timing
* transaction.*/
bool
Bridge::recvTiming(Packet &pkt, Side id)
{
if (blockedA && id == SideA)
return false;
if (blockedB && id == SideB)
return false;
if (delay) {
if (!sendEvent.scheduled())
sendEvent.schedule(curTick + delay);
if (id == SideA) {
inboundA.push_back(std::make_pair<Packet*, Tick>(&pkt, curTick));
blockCheck(SideA);
} else {
inboundB.push_back(std::make_pair<Packet*, Tick>(&pkt, curTick));
blockCheck(SideB);
}
} else {
if (id == SideB) {
sideA->sendPkt(pkt);
blockCheck(SideB);
} else {
sideB->sendPkt(pkt);
blockCheck(SideA);
}
}
return true;
}
void
Bridge::blockCheck(Side id)
{
/* Check that we still have buffer space available. */
if (id == SideB) {
if (sideA->numQueued() + inboundB.size() >= queueSizeA && !blockedB) {
sideB->sendStatusChange(Port::Blocked);
blockedB = true;
} else if (sideA->numQueued() + inboundB.size() < queueSizeA && blockedB) {
sideB->sendStatusChange(Port::Unblocked);
blockedB = false;
}
} else {
if (sideB->numQueued() + inboundA.size() >= queueSizeB && !blockedA) {
sideA->sendStatusChange(Port::Blocked);
blockedA = true;
} else if (sideB->numQueued() + inboundA.size() < queueSizeB && blockedA) {
sideA->sendStatusChange(Port::Unblocked);
blockedA = false;
}
}
}
void Bridge::timerEvent()
{
Tick t = 0;
assert(inboundA.size() || inboundB.size());
if (inboundA.size()) {
while (inboundA.front().second <= curTick + delay){
sideB->sendPkt(inboundA.front());
inboundA.pop_front();
}
if (inboundA.size())
t = inboundA.front().second + delay;
}
if (inboundB.size()) {
while (inboundB.front().second <= curTick + delay){
sideB->sendPkt(inboundA.front());
inboundB.pop_front();
}
if (inboundB.size())
if (t == 0)
t = inboundB.front().second + delay;
else
t = std::min(t,inboundB.front().second + delay);
} else {
panic("timerEvent() called but nothing to do?");
}
if (t != 0)
sendEvent.schedule(t);
}
void
Bridge::BridgePort::sendPkt(Packet &pkt)
{
if (!sendTiming(pkt))
outbound.push_back(std::make_pair<Packet*,Tick>(&pkt, curTick));
}
void
Bridge::BridgePort::sendPkt(std::pair<Packet*, Tick> p)
{
if (!sendTiming(*p.first))
outbound.push_back(p);
}
Packet *
Bridge::BridgePort::recvRetry()
{
Packet *pkt;
assert(outbound.size() > 0);
assert(outbound.front().second >= curTick + bridge->delay);
pkt = outbound.front().first;
outbound.pop_front();
bridge->blockCheck(side);
return pkt;
}
/** Function called by the port when the bus is recieving a Atomic
* transaction.*/
Tick
Bridge::recvAtomic(Packet &pkt, Side id)
{
pkt.time += delay;
if (id == SideA)
return sideB->sendAtomic(pkt);
else
return sideA->sendAtomic(pkt);
}
/** Function called by the port when the bus is recieving a Functional
* transaction.*/
void
Bridge::recvFunctional(Packet &pkt, Side id)
{
pkt.time += delay;
std::list<std::pair<Packet*, Tick> >::iterator i;
bool pktContinue = true;
for(i = inboundA.begin(); i != inboundA.end(); ++i) {
if (pkt.intersect(i->first)) {
pktContinue &= fixPacket(pkt, *i->first);
}
}
for(i = inboundB.begin(); i != inboundB.end(); ++i) {
if (pkt.intersect(i->first)) {
pktContinue &= fixPacket(pkt, *i->first);
}
}
for(i = sideA->outbound.begin(); i != sideA->outbound.end(); ++i) {
if (pkt.intersect(i->first)) {
pktContinue &= fixPacket(pkt, *i->first);
}
}
for(i = sideB->outbound.begin(); i != sideB->outbound.end(); ++i) {
if (pkt.intersect(i->first)) {
pktContinue &= fixPacket(pkt, *i->first);
}
}
if (pktContinue) {
if (id == SideA)
sideB->sendFunctional(pkt);
else
sideA->sendFunctional(pkt);
}
}
/** Function called by the port when the bus is recieving a status change.*/
void
Bridge::recvStatusChange(Port::Status status, Side id)
{
if (status == Port::Blocked || status == Port::Unblocked)
return ;
if (id == SideA)
sideB->sendStatusChange(status);
else
sideA->sendStatusChange(status);
}
void
Bridge::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, Side id)
{
if (id == SideA)
sideB->getPeerAddressRanges(resp, snoop);
else
sideA->getPeerAddressRanges(resp, snoop);
}
BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge)
Param<int> queue_size_a;
Param<int> queue_size_b;
Param<Tick> delay;
Param<bool> write_ack;
END_DECLARE_SIM_OBJECT_PARAMS(Bridge)
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_b, "The size of the queue for data coming into side b"),
INIT_PARAM(delay, "The miminum delay to cross this bridge"),
INIT_PARAM(write_ack, "Acknowledge any writes that are received.")
END_INIT_SIM_OBJECT_PARAMS(Bridge)
CREATE_SIM_OBJECT(Bridge)
{
return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay,
write_ack);
}
REGISTER_SIM_OBJECT("Bridge", Bridge)

214
mem/bridge.hh Normal file
View file

@ -0,0 +1,214 @@
/*
* Copyright (c) 2006 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.
*/
/**
* @file Decleration of a simple bus bridge object with no buffering
*/
#ifndef __MEM_BRIDGE_HH__
#define __MEM_BRIDGE_HH__
#include <string>
#include <list>
#include <inttypes.h>
#include <queue>
#include "mem/mem_object.hh"
#include "mem/packet.hh"
#include "mem/port.hh"
#include "sim/eventq.hh"
class Bridge : public MemObject
{
public:
enum Side
{
SideA,
SideB
};
protected:
/** Function called by the port when the bus is recieving a Timing
transaction.*/
bool recvTiming(Packet &pkt, Side id);
/** Function called by the port when the bus is recieving a Atomic
transaction.*/
Tick recvAtomic(Packet &pkt, Side id);
/** Function called by the port when the bus is recieving a Functional
transaction.*/
void recvFunctional(Packet &pkt, Side id);
/** Function called by the port when the bus is recieving a status change.*/
void recvStatusChange(Port::Status status, Side id);
/** Process address range request.
* @param resp addresses that we can respond to
* @param snoop addresses that we would like to snoop
* @param id ide of the busport that made the request.
*/
void addressRanges(AddrRangeList &resp, AddrRangeList &snoop, Side id);
/** Event that the SendEvent calls when it fires. This code must reschedule
* the send event as required. */
void timerEvent();
/** Decleration of the buses port type, one will be instantiated for each
of the interfaces connecting to the bus. */
class BridgePort : public Port
{
/** A pointer to the bus to which this port belongs. */
Bridge *bridge;
/** A id to keep track of the intercafe ID this port is connected to. */
Bridge::Side side;
public:
/** Constructor for the BusPort.*/
BridgePort(Bridge *_bridge, Side _side)
: bridge(_bridge), side(_side)
{ }
int numQueued() { return outbound.size(); }
protected:
/** Data this is waiting to be transmitted. */
std::list<std::pair<Packet*, Tick> > outbound;
void sendPkt(Packet &pkt);
void sendPkt(std::pair<Packet*, Tick> p);
/** When reciving a timing request from the peer port,
pass it to the bridge. */
virtual bool recvTiming(Packet &pkt)
{ return bridge->recvTiming(pkt, side); }
/** When reciving a retry request from the peer port,
pass it to the bridge. */
virtual Packet* recvRetry();
/** When reciving a Atomic requestfrom the peer port,
pass it to the bridge. */
virtual Tick recvAtomic(Packet &pkt)
{ return bridge->recvAtomic(pkt, side); }
/** When reciving a Functional request from the peer port,
pass it to the bridge. */
virtual void recvFunctional(Packet &pkt)
{ bridge->recvFunctional(pkt, side); }
/** When reciving a status changefrom the peer port,
pass it to the bridge. */
virtual void recvStatusChange(Status status)
{ bridge->recvStatusChange(status, side); }
/** When reciving a address range request the peer port,
pass it to the bridge. */
virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
{ bridge->addressRanges(resp, snoop, side); }
friend class Bridge;
};
class SendEvent : public Event
{
Bridge *bridge;
SendEvent(Bridge *b)
: Event(&mainEventQueue), bridge(b) {}
virtual void process() { bridge->timerEvent(); }
virtual const char *description() { return "bridge delay event"; }
friend class Bridge;
};
SendEvent sendEvent;
/** Sides of the bus bridges. */
BridgePort* sideA;
BridgePort* sideB;
/** inbound queues on both sides. */
std::list<std::pair<Packet*, Tick> > inboundA;
std::list<std::pair<Packet*, Tick> > inboundB;
/** The size of the queue for data coming into side a */
int queueSizeA;
int queueSizeB;
/* if the side is blocked or not. */
bool blockedA;
bool blockedB;
/** Miminum delay though this bridge. */
Tick delay;
/** If this bridge should acknowledge writes. */
bool ackWrites;
public:
/** A function used to return the port associated with this bus object. */
virtual Port *getPort(const std::string &if_name)
{
if (if_name == "side_a") {
if (sideA != NULL)
panic("bridge side a already connected to.");
sideA = new BridgePort(this, SideA);
return sideA;
} else if (if_name == "side_b") {
if (sideB != NULL)
panic("bridge side b already connected to.");
sideB = new BridgePort(this, SideB);
return sideB;
} else
return NULL;
}
virtual void init();
Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack)
: MemObject(n), sendEvent(this), sideA(NULL), sideB(NULL),
queueSizeA(qsa), queueSizeB(qsb), blockedA(false), blockedB(false),
delay(_delay), ackWrites(write_ack)
{}
/** Check if the port should block/unblock after recieving/sending a packet.
* */
void blockCheck(Side id);
friend class Bridge::SendEvent;
};
#endif //__MEM_BUS_HH__

View file

@ -35,13 +35,22 @@
#include "mem/bus.hh"
#include "sim/builder.hh"
/** Get the ranges of anyone that we are connected to. */
void
Bus::init()
{
std::vector<Port*>::iterator intIter;
for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
(*intIter)->sendStatusChange(Port::RangeChange);
}
/** Function called by the port when the bus is recieving a Timing
* transaction.*/
bool
Bus::recvTiming(Packet &pkt, int id)
{
panic("I need to be implemented, but not right now.");
return findPort(pkt.addr, id)->sendTiming(pkt);
}
Port *
@ -90,10 +99,13 @@ Bus::recvFunctional(Packet &pkt, int id)
void
Bus::recvStatusChange(Port::Status status, int id)
{
DPRINTF(Bus, "Bus %d recieved status change from device id %d\n",
busId, id);
assert(status == Port::RangeChange &&
"The other statuses need to be implemented.");
assert(id < interfaces.size() && id >= 0);
int x;
Port *port = interfaces[id];
AddrRangeList ranges;
AddrRangeList snoops;
@ -122,12 +134,31 @@ Bus::recvStatusChange(Port::Status status, int id)
portList.push_back(dm);
}
DPRINTF(MMU, "port list has %d entries\n", portList.size());
// tell all our peers that our address range has changed.
// Don't tell the device that caused this change, it already knows
for (x = 0; x < interfaces.size(); x++)
if (x != id)
interfaces[x]->sendStatusChange(Port::RangeChange);
}
void
Bus::BusPort::addressRanges(AddrRangeList &resp, AddrRangeList &snoop)
Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
{
panic("I'm not implemented.\n");
std::vector<DevMap>::iterator portIter;
resp.clear();
snoop.clear();
DPRINTF(Bus, "Bus id %d recieved address range request returning\n",
busId);
for (portIter = portList.begin(); portIter != portList.end(); portIter++) {
if (portIter->portId != id) {
resp.push_back(portIter->range);
DPRINTF(Bus, "-- %#llX : %#llX\n", portIter->range.start,
portIter->range.end);
}
}
}
BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
@ -137,12 +168,12 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
END_DECLARE_SIM_OBJECT_PARAMS(Bus)
BEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
INIT_PARAM(bus_id, "junk bus id")
END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
INIT_PARAM(bus_id, "a globally unique bus id")
END_INIT_SIM_OBJECT_PARAMS(Bus)
CREATE_SIM_OBJECT(Bus)
{
return new Bus(getInstanceName());
return new Bus(getInstanceName(), bus_id);
}
REGISTER_SIM_OBJECT("Bus", Bus)

View file

@ -45,6 +45,9 @@
class Bus : public MemObject
{
/** a globally unique id for this bus. */
int busId;
struct DevMap {
int portId;
Range<Addr> range;
@ -77,6 +80,14 @@ class Bus : public MemObject
Port *
Bus::findPort(Addr addr, int id);
/** Process address range request.
* @param resp addresses that we can respond to
* @param snoop addresses that we would like to snoop
* @param id ide of the busport that made the request.
*/
void addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id);
/** Decleration of the buses port type, one will be instantiated for each
of the interfaces connecting to the bus. */
class BusPort : public Port
@ -120,7 +131,8 @@ class Bus : public MemObject
// downstream from this bus, yes? That is, the union of all
// the 'owned' address ranges of all the other interfaces on
// this bus...
virtual void addressRanges(AddrRangeList &resp, AddrRangeList &snoop);
virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
{ bus->addressRanges(resp, snoop, id); }
// Hack to make translating port work without changes
virtual int deviceBlockSize() { return 32; }
@ -141,8 +153,11 @@ class Bus : public MemObject
interfaces.push_back(new BusPort(this, id));
return interfaces.back();
}
Bus(const std::string &n)
: MemObject(n) {}
virtual void init();
Bus(const std::string &n, int bus_id)
: MemObject(n), busId(bus_id) {}
};

37
mem/packet.cc Normal file
View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2006 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.
*/
/**
* @file
* Definition of the Packet Class, a packet is a transaction occuring
* between a single level of the memory heirarchy (ie L1->L2).
*/
#include "mem/packet.hh"
bool fixPacket(Packet &func, Packet &timing)
{ panic("Need to implement!"); }

View file

@ -142,7 +142,7 @@ struct Packet
Packet()
: data(NULL), staticData(false), dynamicData(false), arrayData(false),
result(Unknown)
time(curTick), result(Unknown)
{}
~Packet()
@ -156,6 +156,7 @@ struct Packet
deleteData();
dynamicData = false;
arrayData = false;
time = curTick;
}
}
@ -231,6 +232,21 @@ struct Packet
arrayData = true;
data = new uint8_t[size];
}
/** Do the packet modify the same addresses. */
bool intersect(Packet *p) {
Addr s1 = addr;
Addr e1 = addr + size;
Addr s2 = p->addr;
Addr e2 = p->addr + p->size;
if (s1 >= s2 && s1 < e2)
return true;
if (e1 >= s2 && e1 < e2)
return true;
return false;
}
};
bool fixPacket(Packet &func, Packet &timing);
#endif //__MEM_PACKET_HH

View file

@ -181,7 +181,6 @@ PhysicalMemory::getPort(const std::string &if_name)
void
PhysicalMemory::recvStatusChange(Port::Status status)
{
panic("??");
}
PhysicalMemory::MemoryPort::MemoryPort(PhysicalMemory *_memory)

View file

@ -0,0 +1,9 @@
from m5 import *
from MemObject import MemObject
class Bridge(MemObject):
type = 'Bridge'
queue_size_a = 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")
write_ack = Param.Bool(False, "Should this bridge ack writes")

View file

@ -9,6 +9,7 @@ class System(SimObject):
init_param = Param.UInt64(0, "numerical value to pass into simulator")
bin = Param.Bool(False, "is this system binned")
binned_fns = VectorParam.String([], "functions broken down and binned")
boot_osflags = Param.String("a", "boot flags to pass to the kernel")
kernel = Param.String("file that contains the kernel code")
readfile = Param.String("", "file to read startup script from")
@ -16,6 +17,5 @@ class AlphaSystem(System):
type = 'AlphaSystem'
console = Param.String("file that contains the console code")
pal = Param.String("file that contains palcode")
boot_osflags = Param.String("a", "boot flags to pass to the kernel")
system_type = Param.UInt64("Type of system we are emulating")
system_rev = Param.UInt64("Revision of system we are emulating")

View file

@ -155,6 +155,7 @@ class System : public SimObject
#if FULL_SYSTEM
Tick boot_cpu_frequency;
std::string boot_osflags;
uint64_t init_param;
bool bin;
std::vector<std::string> binned_fns;