ruby: route all packets through ruby port
Currently, the interrupt controller in x86 is connected to the io bus directly. Therefore the packets between the io devices and the interrupt controller do not go through ruby. This patch changes ruby port so that these packets arrive at the ruby port first, which then routes them to their destination. Note that the patch does not make these packets go through the ruby network. That would happen in a subsequent patch.
This commit is contained in:
parent
5755fff998
commit
7e27860ef4
6 changed files with 216 additions and 90 deletions
|
@ -122,14 +122,17 @@ for (i, cpu) in enumerate(system.cpu):
|
||||||
cpu.clk_domain = system.cpu_clk_domain
|
cpu.clk_domain = system.cpu_clk_domain
|
||||||
cpu.createThreads()
|
cpu.createThreads()
|
||||||
cpu.createInterruptController()
|
cpu.createInterruptController()
|
||||||
|
|
||||||
cpu.icache_port = system.ruby._cpu_ruby_ports[i].slave
|
cpu.icache_port = system.ruby._cpu_ruby_ports[i].slave
|
||||||
cpu.dcache_port = system.ruby._cpu_ruby_ports[i].slave
|
cpu.dcache_port = system.ruby._cpu_ruby_ports[i].slave
|
||||||
|
|
||||||
if buildEnv['TARGET_ISA'] == "x86":
|
if buildEnv['TARGET_ISA'] == "x86":
|
||||||
cpu.itb.walker.port = system.ruby._cpu_ruby_ports[i].slave
|
cpu.itb.walker.port = system.ruby._cpu_ruby_ports[i].slave
|
||||||
cpu.dtb.walker.port = system.ruby._cpu_ruby_ports[i].slave
|
cpu.dtb.walker.port = system.ruby._cpu_ruby_ports[i].slave
|
||||||
cpu.interrupts.pio = system.piobus.master
|
|
||||||
cpu.interrupts.int_master = system.piobus.slave
|
cpu.interrupts.pio = system.ruby._cpu_ruby_ports[i].master
|
||||||
cpu.interrupts.int_slave = system.piobus.master
|
cpu.interrupts.int_master = system.ruby._cpu_ruby_ports[i].slave
|
||||||
|
cpu.interrupts.int_slave = system.ruby._cpu_ruby_ports[i].master
|
||||||
|
|
||||||
system.ruby._cpu_ruby_ports[i].access_phys_mem = True
|
system.ruby._cpu_ruby_ports[i].access_phys_mem = True
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,9 @@ def create_system(options, system, piobus, dma_ports, ruby_system):
|
||||||
l1_cntrl.sequencer = cpu_seq
|
l1_cntrl.sequencer = cpu_seq
|
||||||
|
|
||||||
if piobus != None:
|
if piobus != None:
|
||||||
cpu_seq.pio_port = piobus.slave
|
cpu_seq.pio_master_port = piobus.slave
|
||||||
|
cpu_seq.mem_master_port = piobus.slave
|
||||||
|
cpu_seq.pio_slave_port = piobus.master
|
||||||
|
|
||||||
exec("ruby_system.l1_cntrl%d = l1_cntrl" % i)
|
exec("ruby_system.l1_cntrl%d = l1_cntrl" % i)
|
||||||
|
|
||||||
|
|
|
@ -50,25 +50,28 @@
|
||||||
|
|
||||||
RubyPort::RubyPort(const Params *p)
|
RubyPort::RubyPort(const Params *p)
|
||||||
: MemObject(p), m_version(p->version), m_controller(NULL),
|
: MemObject(p), m_version(p->version), m_controller(NULL),
|
||||||
m_mandatory_q_ptr(NULL),
|
m_mandatory_q_ptr(NULL), m_usingRubyTester(p->using_ruby_tester),
|
||||||
pio_port(csprintf("%s-pio-port", name()), this),
|
pioMasterPort(csprintf("%s.pio-master-port", name()), this),
|
||||||
m_usingRubyTester(p->using_ruby_tester),
|
pioSlavePort(csprintf("%s.pio-slave-port", name()), this),
|
||||||
drainManager(NULL), ruby_system(p->ruby_system), system(p->system),
|
memMasterPort(csprintf("%s.mem-master-port", name()), this),
|
||||||
|
memSlavePort(csprintf("%s-mem-slave-port", name()), this,
|
||||||
|
p->ruby_system, p->access_phys_mem, -1),
|
||||||
|
gotAddrRanges(p->port_master_connection_count), drainManager(NULL),
|
||||||
|
ruby_system(p->ruby_system), system(p->system),
|
||||||
access_phys_mem(p->access_phys_mem)
|
access_phys_mem(p->access_phys_mem)
|
||||||
{
|
{
|
||||||
assert(m_version != -1);
|
assert(m_version != -1);
|
||||||
|
|
||||||
// create the slave ports based on the number of connected ports
|
// create the slave ports based on the number of connected ports
|
||||||
for (size_t i = 0; i < p->port_slave_connection_count; ++i) {
|
for (size_t i = 0; i < p->port_slave_connection_count; ++i) {
|
||||||
slave_ports.push_back(new M5Port(csprintf("%s-slave%d", name(), i),
|
slave_ports.push_back(new MemSlavePort(csprintf("%s.slave%d", name(),
|
||||||
this, ruby_system,
|
i), this, ruby_system, access_phys_mem, i));
|
||||||
access_phys_mem, i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the master ports based on the number of connected ports
|
// create the master ports based on the number of connected ports
|
||||||
for (size_t i = 0; i < p->port_master_connection_count; ++i) {
|
for (size_t i = 0; i < p->port_master_connection_count; ++i) {
|
||||||
master_ports.push_back(new PioPort(csprintf("%s-master%d", name(), i),
|
master_ports.push_back(new PioMasterPort(csprintf("%s.master%d",
|
||||||
this));
|
name(), i), this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,8 +86,12 @@ RubyPort::init()
|
||||||
BaseMasterPort &
|
BaseMasterPort &
|
||||||
RubyPort::getMasterPort(const std::string &if_name, PortID idx)
|
RubyPort::getMasterPort(const std::string &if_name, PortID idx)
|
||||||
{
|
{
|
||||||
if (if_name == "pio_port") {
|
if (if_name == "mem_master_port") {
|
||||||
return pio_port;
|
return memMasterPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (if_name == "pio_master_port") {
|
||||||
|
return pioMasterPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
// used by the x86 CPUs to connect the interrupt PIO and interrupt slave
|
// used by the x86 CPUs to connect the interrupt PIO and interrupt slave
|
||||||
|
@ -104,6 +111,13 @@ RubyPort::getMasterPort(const std::string &if_name, PortID idx)
|
||||||
BaseSlavePort &
|
BaseSlavePort &
|
||||||
RubyPort::getSlavePort(const std::string &if_name, PortID idx)
|
RubyPort::getSlavePort(const std::string &if_name, PortID idx)
|
||||||
{
|
{
|
||||||
|
if (if_name == "mem_slave_port") {
|
||||||
|
return memSlavePort;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (if_name == "pio_slave_port")
|
||||||
|
return pioSlavePort;
|
||||||
|
|
||||||
// used by the CPUs to connect the caches to the interconnect, and
|
// used by the CPUs to connect the caches to the interconnect, and
|
||||||
// for the x86 case also the interrupt master
|
// for the x86 case also the interrupt master
|
||||||
if (if_name != "slave") {
|
if (if_name != "slave") {
|
||||||
|
@ -118,32 +132,48 @@ RubyPort::getSlavePort(const std::string &if_name, PortID idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RubyPort::PioPort::PioPort(const std::string &_name,
|
RubyPort::PioMasterPort::PioMasterPort(const std::string &_name,
|
||||||
RubyPort *_port)
|
RubyPort *_port)
|
||||||
: QueuedMasterPort(_name, _port, queue), queue(*_port, *this),
|
: QueuedMasterPort(_name, _port, queue), queue(*_port, *this)
|
||||||
ruby_port(_port)
|
|
||||||
{
|
{
|
||||||
DPRINTF(RubyPort, "creating master port on ruby sequencer %s\n", _name);
|
DPRINTF(RubyPort, "Created master pioport on sequencer %s\n", _name);
|
||||||
}
|
}
|
||||||
|
|
||||||
RubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port,
|
RubyPort::PioSlavePort::PioSlavePort(const std::string &_name,
|
||||||
|
RubyPort *_port)
|
||||||
|
: QueuedSlavePort(_name, _port, queue), queue(*_port, *this)
|
||||||
|
{
|
||||||
|
DPRINTF(RubyPort, "Created slave pioport on sequencer %s\n", _name);
|
||||||
|
}
|
||||||
|
|
||||||
|
RubyPort::MemMasterPort::MemMasterPort(const std::string &_name,
|
||||||
|
RubyPort *_port)
|
||||||
|
: QueuedMasterPort(_name, _port, queue), queue(*_port, *this)
|
||||||
|
{
|
||||||
|
DPRINTF(RubyPort, "Created master memport on ruby sequencer %s\n", _name);
|
||||||
|
}
|
||||||
|
|
||||||
|
RubyPort::MemSlavePort::MemSlavePort(const std::string &_name, RubyPort *_port,
|
||||||
RubySystem *_system, bool _access_phys_mem, PortID id)
|
RubySystem *_system, bool _access_phys_mem, PortID id)
|
||||||
: QueuedSlavePort(_name, _port, queue, id), queue(*_port, *this),
|
: QueuedSlavePort(_name, _port, queue, id), queue(*_port, *this),
|
||||||
ruby_port(_port), ruby_system(_system),
|
ruby_system(_system), access_phys_mem(_access_phys_mem)
|
||||||
access_phys_mem(_access_phys_mem)
|
|
||||||
{
|
{
|
||||||
DPRINTF(RubyPort, "creating slave port on ruby sequencer %s\n", _name);
|
DPRINTF(RubyPort, "Created slave memport on ruby sequencer %s\n", _name);
|
||||||
}
|
|
||||||
|
|
||||||
Tick
|
|
||||||
RubyPort::M5Port::recvAtomic(PacketPtr pkt)
|
|
||||||
{
|
|
||||||
panic("RubyPort::M5Port::recvAtomic() not implemented!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RubyPort::recvTimingResp(PacketPtr pkt, PortID master_port_id)
|
RubyPort::PioMasterPort::recvTimingResp(PacketPtr pkt)
|
||||||
|
{
|
||||||
|
RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
|
||||||
|
DPRINTF(RubyPort, "Response for address: 0x%#x\n", pkt->getAddr());
|
||||||
|
|
||||||
|
// send next cycle
|
||||||
|
ruby_port->pioSlavePort.schedTimingResp(
|
||||||
|
pkt, curTick() + g_system_ptr->clockPeriod());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RubyPort::MemMasterPort::recvTimingResp(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
// got a response from a device
|
// got a response from a device
|
||||||
assert(pkt->isResponse());
|
assert(pkt->isResponse());
|
||||||
|
@ -153,43 +183,66 @@ RubyPort::recvTimingResp(PacketPtr pkt, PortID master_port_id)
|
||||||
DPRINTF(RubyPort, "Pio response for address %#x, going to %d\n",
|
DPRINTF(RubyPort, "Pio response for address %#x, going to %d\n",
|
||||||
pkt->getAddr(), pkt->getDest());
|
pkt->getAddr(), pkt->getDest());
|
||||||
|
|
||||||
// Retrieve the port from the destination field
|
// First we must retrieve the request port from the sender State
|
||||||
assert(pkt->getDest() < slave_ports.size());
|
RubyPort::SenderState *senderState =
|
||||||
|
safe_cast<RubyPort::SenderState *>(pkt->popSenderState());
|
||||||
|
MemSlavePort *port = senderState->port;
|
||||||
|
assert(port != NULL);
|
||||||
|
delete senderState;
|
||||||
|
|
||||||
// attempt to send the response in the next cycle
|
// attempt to send the response in the next cycle
|
||||||
slave_ports[pkt->getDest()]->schedTimingResp(pkt, curTick() +
|
port->schedTimingResp(pkt, curTick() + g_system_ptr->clockPeriod());
|
||||||
g_system_ptr->clockPeriod());
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RubyPort::M5Port::recvTimingReq(PacketPtr pkt)
|
RubyPort::PioSlavePort::recvTimingReq(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
DPRINTF(RubyPort,
|
RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
|
||||||
"Timing access for address %#x on port %d\n", pkt->getAddr(),
|
|
||||||
id);
|
for (size_t i = 0; i < ruby_port->master_ports.size(); ++i) {
|
||||||
|
AddrRangeList l = ruby_port->master_ports[i]->getAddrRanges();
|
||||||
|
for (auto it = l.begin(); it != l.end(); ++it) {
|
||||||
|
if (it->contains(pkt->getAddr())) {
|
||||||
|
ruby_port->master_ports[i]->sendTimingReq(pkt);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("Should never reach here!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RubyPort::MemSlavePort::recvTimingReq(PacketPtr pkt)
|
||||||
|
{
|
||||||
|
DPRINTF(RubyPort, "Timing request for address %#x on port %d\n",
|
||||||
|
pkt->getAddr(), id);
|
||||||
|
RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
|
||||||
|
|
||||||
if (pkt->memInhibitAsserted())
|
if (pkt->memInhibitAsserted())
|
||||||
panic("RubyPort should never see an inhibited request\n");
|
panic("RubyPort should never see an inhibited request\n");
|
||||||
|
|
||||||
// Save the port id to be used later to route the response
|
|
||||||
pkt->setSrc(id);
|
|
||||||
|
|
||||||
// Check for pio requests and directly send them to the dedicated
|
// Check for pio requests and directly send them to the dedicated
|
||||||
// pio port.
|
// pio port.
|
||||||
if (!isPhysMemAddress(pkt->getAddr())) {
|
if (!isPhysMemAddress(pkt->getAddr())) {
|
||||||
assert(ruby_port->pio_port.isConnected());
|
assert(ruby_port->memMasterPort.isConnected());
|
||||||
DPRINTF(RubyPort,
|
DPRINTF(RubyPort, "Request address %#x assumed to be a pio address\n",
|
||||||
"Request for address 0x%#x is assumed to be a pio request\n",
|
|
||||||
pkt->getAddr());
|
pkt->getAddr());
|
||||||
|
|
||||||
|
// Save the port in the sender state object to be used later to
|
||||||
|
// route the response
|
||||||
|
pkt->pushSenderState(new SenderState(this));
|
||||||
|
|
||||||
// send next cycle
|
// send next cycle
|
||||||
ruby_port->pio_port.schedTimingReq(pkt,
|
ruby_port->memMasterPort.schedTimingReq(pkt,
|
||||||
curTick() + g_system_ptr->clockPeriod());
|
curTick() + g_system_ptr->clockPeriod());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save the port id to be used later to route the response
|
||||||
|
pkt->setSrc(id);
|
||||||
|
|
||||||
assert(Address(pkt->getAddr()).getOffset() + pkt->getSize() <=
|
assert(Address(pkt->getAddr()).getOffset() + pkt->getSize() <=
|
||||||
RubySystem::getBlockSizeBytes());
|
RubySystem::getBlockSizeBytes());
|
||||||
|
|
||||||
|
@ -213,26 +266,24 @@ RubyPort::M5Port::recvTimingReq(PacketPtr pkt)
|
||||||
ruby_port->addToRetryList(this);
|
ruby_port->addToRetryList(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(RubyPort,
|
DPRINTF(RubyPort, "Request for address %#x did not issued because %s\n",
|
||||||
"Request for address %#x did not issue because %s\n",
|
|
||||||
pkt->getAddr(), RequestStatus_to_string(requestStatus));
|
pkt->getAddr(), RequestStatus_to_string(requestStatus));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RubyPort::M5Port::recvFunctional(PacketPtr pkt)
|
RubyPort::MemSlavePort::recvFunctional(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
DPRINTF(RubyPort, "Functional access caught for address %#x\n",
|
DPRINTF(RubyPort, "Functional access for address: %#x\n", pkt->getAddr());
|
||||||
pkt->getAddr());
|
RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
|
||||||
|
|
||||||
// Check for pio requests and directly send them to the dedicated
|
// Check for pio requests and directly send them to the dedicated
|
||||||
// pio port.
|
// pio port.
|
||||||
if (!isPhysMemAddress(pkt->getAddr())) {
|
if (!isPhysMemAddress(pkt->getAddr())) {
|
||||||
assert(ruby_port->pio_port.isConnected());
|
assert(ruby_port->memMasterPort.isConnected());
|
||||||
DPRINTF(RubyPort, "Request for address 0x%#x is a pio request\n",
|
DPRINTF(RubyPort, "Pio Request for address: 0x%#x\n", pkt->getAddr());
|
||||||
pkt->getAddr());
|
panic("RubyPort::PioMasterPort::recvFunctional() not implemented!\n");
|
||||||
panic("RubyPort::PioPort::recvFunctional() not implemented!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(pkt->getAddr() + pkt->getSize() <=
|
assert(pkt->getAddr() + pkt->getSize() <=
|
||||||
|
@ -248,8 +299,7 @@ RubyPort::M5Port::recvFunctional(PacketPtr pkt)
|
||||||
} else if (pkt->isWrite()) {
|
} else if (pkt->isWrite()) {
|
||||||
accessSucceeded = ruby_system->functionalWrite(pkt);
|
accessSucceeded = ruby_system->functionalWrite(pkt);
|
||||||
} else {
|
} else {
|
||||||
panic("RubyPort: unsupported functional command %s\n",
|
panic("Unsupported functional command %s\n", pkt->cmdString());
|
||||||
pkt->cmdString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unless the requester explicitly said otherwise, generate an error if
|
// Unless the requester explicitly said otherwise, generate an error if
|
||||||
|
@ -298,7 +348,7 @@ RubyPort::ruby_hit_callback(PacketPtr pkt)
|
||||||
slave_ports[pkt->getSrc()]->hitCallback(pkt);
|
slave_ports[pkt->getSrc()]->hitCallback(pkt);
|
||||||
|
|
||||||
//
|
//
|
||||||
// If we had to stall the M5Ports, wake them up because the sequencer
|
// If we had to stall the MemSlavePorts, wake them up because the sequencer
|
||||||
// likely has free resources now.
|
// likely has free resources now.
|
||||||
//
|
//
|
||||||
if (!retryList.empty()) {
|
if (!retryList.empty()) {
|
||||||
|
@ -309,7 +359,7 @@ RubyPort::ruby_hit_callback(PacketPtr pkt)
|
||||||
// list. Therefore we want to clear the retryList before calling
|
// list. Therefore we want to clear the retryList before calling
|
||||||
// sendRetry.
|
// sendRetry.
|
||||||
//
|
//
|
||||||
std::vector<M5Port*> curRetryList(retryList);
|
std::vector<MemSlavePort *> curRetryList(retryList);
|
||||||
|
|
||||||
retryList.clear();
|
retryList.clear();
|
||||||
|
|
||||||
|
@ -345,8 +395,8 @@ RubyPort::getChildDrainCount(DrainManager *dm)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
if (pio_port.isConnected()) {
|
if (memMasterPort.isConnected()) {
|
||||||
count += pio_port.drain(dm);
|
count += memMasterPort.drain(dm);
|
||||||
DPRINTF(Config, "count after pio check %d\n", count);
|
DPRINTF(Config, "count after pio check %d\n", count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,14 +405,13 @@ RubyPort::getChildDrainCount(DrainManager *dm)
|
||||||
DPRINTF(Config, "count after slave port check %d\n", count);
|
DPRINTF(Config, "count after slave port check %d\n", count);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<PioPort*>::iterator p = master_ports.begin();
|
for (std::vector<PioMasterPort *>::iterator p = master_ports.begin();
|
||||||
p != master_ports.end(); ++p) {
|
p != master_ports.end(); ++p) {
|
||||||
count += (*p)->drain(dm);
|
count += (*p)->drain(dm);
|
||||||
DPRINTF(Config, "count after master port check %d\n", count);
|
DPRINTF(Config, "count after master port check %d\n", count);
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(Config, "final count %d\n", count);
|
DPRINTF(Config, "final count %d\n", count);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +450,7 @@ RubyPort::drain(DrainManager *dm)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RubyPort::M5Port::hitCallback(PacketPtr pkt)
|
RubyPort::MemSlavePort::hitCallback(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
bool needsResponse = pkt->needsResponse();
|
bool needsResponse = pkt->needsResponse();
|
||||||
|
|
||||||
|
@ -444,6 +493,7 @@ RubyPort::M5Port::hitCallback(PacketPtr pkt)
|
||||||
DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse);
|
DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse);
|
||||||
|
|
||||||
if (accessPhysMem) {
|
if (accessPhysMem) {
|
||||||
|
RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
|
||||||
ruby_port->system->getPhysMem().access(pkt);
|
ruby_port->system->getPhysMem().access(pkt);
|
||||||
} else if (needsResponse) {
|
} else if (needsResponse) {
|
||||||
pkt->makeResponse();
|
pkt->makeResponse();
|
||||||
|
@ -461,16 +511,25 @@ RubyPort::M5Port::hitCallback(PacketPtr pkt)
|
||||||
}
|
}
|
||||||
|
|
||||||
AddrRangeList
|
AddrRangeList
|
||||||
RubyPort::M5Port::getAddrRanges() const
|
RubyPort::PioSlavePort::getAddrRanges() const
|
||||||
{
|
{
|
||||||
// at the moment the assumption is that the master does not care
|
// at the moment the assumption is that the master does not care
|
||||||
AddrRangeList ranges;
|
AddrRangeList ranges;
|
||||||
|
RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ruby_port->master_ports.size(); ++i) {
|
||||||
|
ranges.splice(ranges.begin(),
|
||||||
|
ruby_port->master_ports[i]->getAddrRanges());
|
||||||
|
}
|
||||||
|
for (AddrRangeConstIter r = ranges.begin(); r != ranges.end(); ++r)
|
||||||
|
DPRINTF(RubyPort, "%s\n", r->to_string());
|
||||||
return ranges;
|
return ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RubyPort::M5Port::isPhysMemAddress(Addr addr) const
|
RubyPort::MemSlavePort::isPhysMemAddress(Addr addr) const
|
||||||
{
|
{
|
||||||
|
RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
|
||||||
return ruby_port->system->isMemAddr(addr);
|
return ruby_port->system->isMemAddr(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,3 +553,13 @@ RubyPort::ruby_eviction_callback(const Address& address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RubyPort::PioMasterPort::recvRangeChange()
|
||||||
|
{
|
||||||
|
RubyPort &r = static_cast<RubyPort &>(owner);
|
||||||
|
r.gotAddrRanges--;
|
||||||
|
if (r.gotAddrRanges == 0) {
|
||||||
|
r.pioSlavePort.sendRangeChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -58,44 +58,86 @@ class AbstractController;
|
||||||
class RubyPort : public MemObject
|
class RubyPort : public MemObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class M5Port : public QueuedSlavePort
|
class MemMasterPort : public QueuedMasterPort
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
MasterPacketQueue queue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MemMasterPort(const std::string &_name, RubyPort *_port);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool recvTimingResp(PacketPtr pkt);
|
||||||
|
void recvRangeChange() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MemSlavePort : public QueuedSlavePort
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
SlavePacketQueue queue;
|
SlavePacketQueue queue;
|
||||||
RubyPort *ruby_port;
|
|
||||||
RubySystem* ruby_system;
|
RubySystem* ruby_system;
|
||||||
bool access_phys_mem;
|
bool access_phys_mem;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
M5Port(const std::string &_name, RubyPort *_port,
|
MemSlavePort(const std::string &_name, RubyPort *_port,
|
||||||
RubySystem*_system, bool _access_phys_mem, PortID id);
|
RubySystem*_system, bool _access_phys_mem, PortID id);
|
||||||
void hitCallback(PacketPtr pkt);
|
void hitCallback(PacketPtr pkt);
|
||||||
void evictionCallback(const Address& address);
|
void evictionCallback(const Address& address);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool recvTimingReq(PacketPtr pkt);
|
bool recvTimingReq(PacketPtr pkt);
|
||||||
Tick recvAtomic(PacketPtr pkt);
|
|
||||||
|
Tick recvAtomic(PacketPtr pkt)
|
||||||
|
{ panic("RubyPort::MemSlavePort::recvAtomic() not implemented!\n"); }
|
||||||
|
|
||||||
void recvFunctional(PacketPtr pkt);
|
void recvFunctional(PacketPtr pkt);
|
||||||
AddrRangeList getAddrRanges() const;
|
|
||||||
|
AddrRangeList getAddrRanges() const
|
||||||
|
{ AddrRangeList ranges; return ranges; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isPhysMemAddress(Addr addr) const;
|
bool isPhysMemAddress(Addr addr) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PioPort : public QueuedMasterPort
|
class PioMasterPort : public QueuedMasterPort
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MasterPacketQueue queue;
|
MasterPacketQueue queue;
|
||||||
RubyPort *ruby_port;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PioPort(const std::string &_name, RubyPort *_port);
|
PioMasterPort(const std::string &_name, RubyPort *_port);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool recvTimingResp(PacketPtr pkt)
|
bool recvTimingResp(PacketPtr pkt);
|
||||||
{ return ruby_port->recvTimingResp(pkt, id); }
|
void recvRangeChange();
|
||||||
|
};
|
||||||
|
|
||||||
|
class PioSlavePort : public QueuedSlavePort
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
SlavePacketQueue queue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PioSlavePort(const std::string &_name, RubyPort *_port);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool recvTimingReq(PacketPtr pkt);
|
||||||
|
|
||||||
|
Tick recvAtomic(PacketPtr pkt)
|
||||||
|
{ panic("recvAtomic not supported with ruby!"); }
|
||||||
|
|
||||||
|
void recvFunctional(PacketPtr pkt)
|
||||||
|
{ panic("recvFunctional should never be called on pio slave port!"); }
|
||||||
|
|
||||||
|
AddrRangeList getAddrRanges() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SenderState : public Packet::SenderState
|
||||||
|
{
|
||||||
|
MemSlavePort *port;
|
||||||
|
SenderState(MemSlavePort * _port) : port(_port)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef RubyPortParams Params;
|
typedef RubyPortParams Params;
|
||||||
|
@ -123,7 +165,6 @@ class RubyPort : public MemObject
|
||||||
unsigned int drain(DrainManager *dm);
|
unsigned int drain(DrainManager *dm);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const std::string m_name;
|
|
||||||
void ruby_hit_callback(PacketPtr pkt);
|
void ruby_hit_callback(PacketPtr pkt);
|
||||||
void testDrainComplete();
|
void testDrainComplete();
|
||||||
void ruby_eviction_callback(const Address& address);
|
void ruby_eviction_callback(const Address& address);
|
||||||
|
@ -141,11 +182,10 @@ class RubyPort : public MemObject
|
||||||
uint32_t m_version;
|
uint32_t m_version;
|
||||||
AbstractController* m_controller;
|
AbstractController* m_controller;
|
||||||
MessageBuffer* m_mandatory_q_ptr;
|
MessageBuffer* m_mandatory_q_ptr;
|
||||||
PioPort pio_port;
|
|
||||||
bool m_usingRubyTester;
|
bool m_usingRubyTester;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addToRetryList(M5Port * port)
|
void addToRetryList(MemSlavePort * port)
|
||||||
{
|
{
|
||||||
assert(std::find(retryList.begin(), retryList.end(), port) ==
|
assert(std::find(retryList.begin(), retryList.end(), port) ==
|
||||||
retryList.end());
|
retryList.end());
|
||||||
|
@ -154,10 +194,16 @@ class RubyPort : public MemObject
|
||||||
|
|
||||||
unsigned int getChildDrainCount(DrainManager *dm);
|
unsigned int getChildDrainCount(DrainManager *dm);
|
||||||
|
|
||||||
|
PioMasterPort pioMasterPort;
|
||||||
|
PioSlavePort pioSlavePort;
|
||||||
|
MemMasterPort memMasterPort;
|
||||||
|
MemSlavePort memSlavePort;
|
||||||
|
unsigned int gotAddrRanges;
|
||||||
|
|
||||||
/** Vector of M5 Ports attached to this Ruby port. */
|
/** Vector of M5 Ports attached to this Ruby port. */
|
||||||
typedef std::vector<M5Port*>::iterator CpuPortIter;
|
typedef std::vector<MemSlavePort *>::iterator CpuPortIter;
|
||||||
std::vector<M5Port*> slave_ports;
|
std::vector<MemSlavePort *> slave_ports;
|
||||||
std::vector<PioPort*> master_ports;
|
std::vector<PioMasterPort *> master_ports;
|
||||||
|
|
||||||
DrainManager *drainManager;
|
DrainManager *drainManager;
|
||||||
|
|
||||||
|
@ -168,7 +214,7 @@ class RubyPort : public MemObject
|
||||||
// Based on similar code in the M5 bus. Stores pointers to those ports
|
// Based on similar code in the M5 bus. Stores pointers to those ports
|
||||||
// that should be called when the Sequencer becomes available after a stall.
|
// that should be called when the Sequencer becomes available after a stall.
|
||||||
//
|
//
|
||||||
std::vector<M5Port*> retryList;
|
std::vector<MemSlavePort *> retryList;
|
||||||
|
|
||||||
bool access_phys_mem;
|
bool access_phys_mem;
|
||||||
};
|
};
|
||||||
|
|
|
@ -35,12 +35,16 @@ class RubyPort(MemObject):
|
||||||
type = 'RubyPort'
|
type = 'RubyPort'
|
||||||
abstract = True
|
abstract = True
|
||||||
cxx_header = "mem/ruby/system/RubyPort.hh"
|
cxx_header = "mem/ruby/system/RubyPort.hh"
|
||||||
|
version = Param.Int(0, "")
|
||||||
|
|
||||||
slave = VectorSlavePort("CPU slave port")
|
slave = VectorSlavePort("CPU slave port")
|
||||||
master = VectorMasterPort("CPU master port")
|
master = VectorMasterPort("CPU master port")
|
||||||
version = Param.Int(0, "")
|
pio_master_port = MasterPort("Ruby mem master port")
|
||||||
pio_port = MasterPort("Ruby_pio_port")
|
mem_master_port = MasterPort("Ruby mem master port")
|
||||||
|
pio_slave_port = SlavePort("Ruby pio slave port")
|
||||||
|
mem_slave_port = SlavePort("Ruby memory port")
|
||||||
|
|
||||||
using_ruby_tester = Param.Bool(False, "")
|
using_ruby_tester = Param.Bool(False, "")
|
||||||
using_network_tester = Param.Bool(False, "")
|
|
||||||
access_phys_mem = Param.Bool(False,
|
access_phys_mem = Param.Bool(False,
|
||||||
"should the rubyport atomically update phys_mem")
|
"should the rubyport atomically update phys_mem")
|
||||||
ruby_system = Param.RubySystem("")
|
ruby_system = Param.RubySystem("")
|
||||||
|
@ -58,12 +62,14 @@ class RubySequencer(RubyPort):
|
||||||
type = 'RubySequencer'
|
type = 'RubySequencer'
|
||||||
cxx_class = 'Sequencer'
|
cxx_class = 'Sequencer'
|
||||||
cxx_header = "mem/ruby/system/Sequencer.hh"
|
cxx_header = "mem/ruby/system/Sequencer.hh"
|
||||||
|
|
||||||
icache = Param.RubyCache("")
|
icache = Param.RubyCache("")
|
||||||
dcache = Param.RubyCache("")
|
dcache = Param.RubyCache("")
|
||||||
max_outstanding_requests = Param.Int(16,
|
max_outstanding_requests = Param.Int(16,
|
||||||
"max requests (incl. prefetches) outstanding")
|
"max requests (incl. prefetches) outstanding")
|
||||||
deadlock_threshold = Param.Cycles(500000,
|
deadlock_threshold = Param.Cycles(500000,
|
||||||
"max outstanding cycles for a request before deadlock/livelock declared")
|
"max outstanding cycles for a request before deadlock/livelock declared")
|
||||||
|
using_network_tester = Param.Bool(False, "")
|
||||||
|
|
||||||
class DMASequencer(RubyPort):
|
class DMASequencer(RubyPort):
|
||||||
type = 'DMASequencer'
|
type = 'DMASequencer'
|
||||||
|
|
|
@ -82,9 +82,9 @@ for (i, cpu) in enumerate(system.cpu):
|
||||||
cpu.dcache_port = system.ruby._cpu_ruby_ports[i].slave
|
cpu.dcache_port = system.ruby._cpu_ruby_ports[i].slave
|
||||||
cpu.itb.walker.port = system.ruby._cpu_ruby_ports[i].slave
|
cpu.itb.walker.port = system.ruby._cpu_ruby_ports[i].slave
|
||||||
cpu.dtb.walker.port = system.ruby._cpu_ruby_ports[i].slave
|
cpu.dtb.walker.port = system.ruby._cpu_ruby_ports[i].slave
|
||||||
cpu.interrupts.pio = system.piobus.master
|
cpu.interrupts.pio = system.ruby._cpu_ruby_ports[i].master
|
||||||
cpu.interrupts.int_master = system.piobus.slave
|
cpu.interrupts.int_master = system.ruby._cpu_ruby_ports[i].slave
|
||||||
cpu.interrupts.int_slave = system.piobus.master
|
cpu.interrupts.int_slave = system.ruby._cpu_ruby_ports[i].master
|
||||||
|
|
||||||
# Set access_phys_mem to True for ruby port
|
# Set access_phys_mem to True for ruby port
|
||||||
system.ruby._cpu_ruby_ports[i].access_phys_mem = True
|
system.ruby._cpu_ruby_ports[i].access_phys_mem = True
|
||||||
|
|
Loading…
Reference in a new issue