diff -r e64989c69263 -r 66f543a6cac7 configs/ruby/MESI_Two_Level.py --- a/configs/ruby/MESI_Two_Level.py Fri Jan 17 11:27:34 2014 -0600 +++ b/configs/ruby/MESI_Two_Level.py Fri Jan 17 11:45:50 2014 -0600 @@ -106,7 +106,9 @@ l1_cntrl.sequencer = cpu_seq 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) diff -r e64989c69263 -r 66f543a6cac7 src/mem/ruby/system/RubyPort.hh --- a/src/mem/ruby/system/RubyPort.hh Fri Jan 17 11:27:34 2014 -0600 +++ b/src/mem/ruby/system/RubyPort.hh Fri Jan 17 11:45:50 2014 -0600 @@ -58,18 +58,31 @@ class RubyPort : public MemObject { public: - class M5Port : public QueuedSlavePort + class MemMasterPort : public QueuedMasterPort { private: + MasterPacketQueue queue; + public: + MemMasterPort(const std::string &_name, RubyPort *_port); + + protected: + virtual bool recvTimingResp(PacketPtr pkt); + virtual void recvRangeChange() {} + }; + + friend class MemMasterPort; + + class MemSlavePort : public QueuedSlavePort + { + private: SlavePacketQueue queue; - RubyPort *ruby_port; RubySystem* ruby_system; bool _onRetryList; bool access_phys_mem; public: - M5Port(const std::string &_name, RubyPort *_port, + MemSlavePort(const std::string &_name, RubyPort *_port, RubySystem*_system, bool _access_phys_mem); void hitCallback(PacketPtr pkt); void evictionCallback(const Address& address); @@ -82,36 +95,61 @@ protected: virtual bool recvTimingReq(PacketPtr pkt); - virtual Tick recvAtomic(PacketPtr pkt); + + virtual Tick recvAtomic(PacketPtr pkt) + { panic("RubyPort::MemSlavePort::recvAtomic() not implemented!\n"); } + virtual void recvFunctional(PacketPtr pkt); - virtual AddrRangeList getAddrRanges() const; + + virtual AddrRangeList getAddrRanges() const + { AddrRangeList ranges; return ranges; } private: bool isPhysMemAddress(Addr addr); }; - friend class M5Port; + friend class MemSlavePort; - class PioPort : public QueuedMasterPort + class PioMasterPort : public QueuedMasterPort { private: - MasterPacketQueue queue; public: - PioPort(const std::string &_name, RubyPort *_port); + PioMasterPort(const std::string &_name, RubyPort *_port); protected: virtual bool recvTimingResp(PacketPtr pkt); + virtual void recvRangeChange(); }; - friend class PioPort; + friend class PioMasterPort; + + class PioSlavePort : public QueuedSlavePort + { + private: + SlavePacketQueue queue; + + public: + PioSlavePort(const std::string &_name, RubyPort *_port); + + protected: + virtual bool recvTimingReq(PacketPtr pkt); + + virtual Tick recvAtomic(PacketPtr pkt) + { panic("recvAtomic not supported with ruby!"); } + + virtual void recvFunctional(PacketPtr pkt) + { panic("recvFunctional should never be called on pio slave port!"); } + + virtual AddrRangeList getAddrRanges() const; + }; struct SenderState : public Packet::SenderState { - M5Port* port; + MemSlavePort* port; - SenderState(M5Port* _port) : port(_port) + SenderState(MemSlavePort* _port) : port(_port) {} }; @@ -140,7 +178,6 @@ unsigned int drain(DrainManager *dm); protected: - const std::string m_name; void ruby_hit_callback(PacketPtr pkt); void testDrainComplete(); void ruby_eviction_callback(const Address& address); @@ -148,11 +185,10 @@ uint32_t m_version; AbstractController* m_controller; MessageBuffer* m_mandatory_q_ptr; - PioPort pio_port; bool m_usingRubyTester; private: - void addToRetryList(M5Port * port) + void addToRetryList(MemSlavePort * port) { if (!port->onRetryList()) { port->onRetryList(true); @@ -163,13 +199,16 @@ unsigned int getChildDrainCount(DrainManager *dm); - uint16_t m_port_id; - uint64_t m_request_cnt; + PioMasterPort pioMasterPort; + PioSlavePort pioSlavePort; + MemMasterPort memMasterPort; + MemSlavePort memSlavePort; + unsigned int gotAddrRanges; /** Vector of M5 Ports attached to this Ruby port. */ - typedef std::vector::iterator CpuPortIter; - std::vector slave_ports; - std::vector master_ports; + typedef std::vector::iterator CpuPortIter; + std::vector slave_ports; + std::vector master_ports; DrainManager *drainManager; @@ -180,7 +219,7 @@ // 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. // - std::list retryList; + std::list retryList; bool waitingOnSequencer; bool access_phys_mem; diff -r e64989c69263 -r 66f543a6cac7 src/mem/ruby/system/RubyPort.cc --- a/src/mem/ruby/system/RubyPort.cc Fri Jan 17 11:27:34 2014 -0600 +++ b/src/mem/ruby/system/RubyPort.cc Fri Jan 17 11:45:50 2014 -0600 @@ -50,9 +50,12 @@ RubyPort::RubyPort(const Params *p) : MemObject(p), m_version(p->version), m_controller(NULL), - m_mandatory_q_ptr(NULL), - pio_port(csprintf("%s-pio-port", name()), this), - m_usingRubyTester(p->using_ruby_tester), m_request_cnt(0), + m_mandatory_q_ptr(NULL), m_usingRubyTester(p->using_ruby_tester), + pioMasterPort(csprintf("%s.pio-master-port", name()), this), + pioSlavePort(csprintf("%s.pio-slave-port", name()), this), + memMasterPort(csprintf("%s.mem-master-port", name()), this), + memSlavePort(csprintf("%s-mem-slave-port", name()), this, p->ruby_system, + p->access_phys_mem), gotAddrRanges(p->port_master_connection_count), drainManager(NULL), ruby_system(p->ruby_system), system(p->system), waitingOnSequencer(false), access_phys_mem(p->access_phys_mem) { @@ -60,14 +63,14 @@ // create the slave ports based on the number of connected ports for (size_t i = 0; i < p->port_slave_connection_count; ++i) { - slave_ports.push_back(new M5Port(csprintf("%s-slave%d", name(), i), - this, ruby_system, access_phys_mem)); + slave_ports.push_back(new MemSlavePort(csprintf("%s.slave%d", name(), + i), this, ruby_system, access_phys_mem)); } // create the master ports based on the number of connected ports for (size_t i = 0; i < p->port_master_connection_count; ++i) { - master_ports.push_back(new PioPort(csprintf("%s-master%d", name(), i), - this)); + master_ports.push_back(new PioMasterPort(csprintf("%s.master%d", + name(), i), this)); } } @@ -82,8 +85,12 @@ BaseMasterPort & RubyPort::getMasterPort(const std::string &if_name, PortID idx) { - if (if_name == "pio_port") { - return pio_port; + if (if_name == "mem_master_port") { + return memMasterPort; + } + + if (if_name == "pio_master_port") { + return pioMasterPort; } // used by the x86 CPUs to connect the interrupt PIO and interrupt slave @@ -103,6 +110,13 @@ BaseSlavePort & 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 // for the x86 case also the interrupt master if (if_name != "slave") { @@ -117,32 +131,49 @@ } } -RubyPort::PioPort::PioPort(const std::string &_name, +RubyPort::PioMasterPort::PioMasterPort(const std::string &_name, RubyPort *_port) : QueuedMasterPort(_name, _port, queue), queue(*_port, *this) { - DPRINTF(RubyPort, "creating master port on ruby sequencer %s\n", _name); + DPRINTF(RubyPort, "creating master pioport on sequencer %s\n", _name); } -RubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port, +RubyPort::MemMasterPort::MemMasterPort(const std::string &_name, + RubyPort *_port) + : QueuedMasterPort(_name, _port, queue), queue(*_port, *this) +{ + DPRINTF(RubyPort, "creating master memport on sequencer %s\n", _name); +} + +RubyPort::PioSlavePort::PioSlavePort(const std::string &_name, RubyPort *_port) + : QueuedSlavePort(_name, _port, queue), queue(*_port, *this) +{ + DPRINTF(RubyPort, "creating slave pioport on sequencer %s\n", _name); +} + +RubyPort::MemSlavePort::MemSlavePort(const std::string &_name, RubyPort *_port, RubySystem *_system, bool _access_phys_mem) : QueuedSlavePort(_name, _port, queue), queue(*_port, *this), - ruby_port(_port), ruby_system(_system), + ruby_system(_system), _onRetryList(false), access_phys_mem(_access_phys_mem) { DPRINTF(RubyPort, "creating slave port on ruby sequencer %s\n", _name); } -Tick -RubyPort::M5Port::recvAtomic(PacketPtr pkt) +bool +RubyPort::PioMasterPort::recvTimingResp(PacketPtr pkt) { - panic("RubyPort::M5Port::recvAtomic() not implemented!\n"); - return 0; + RubyPort *ruby_port = static_cast(&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::PioPort::recvTimingResp(PacketPtr pkt) +RubyPort::MemMasterPort::recvTimingResp(PacketPtr pkt) { // In FS mode, ruby memory will receive pio responses from devices // and it must forward these responses back to the particular CPU. @@ -151,17 +182,33 @@ // First we must retrieve the request port from the sender State RubyPort::SenderState *senderState = safe_cast(pkt->popSenderState()); - M5Port *port = senderState->port; + MemSlavePort *port = senderState->port; assert(port != NULL); delete senderState; port->sendTimingResp(pkt); - return true; } bool -RubyPort::M5Port::recvTimingReq(PacketPtr pkt) +RubyPort::PioSlavePort::recvTimingReq(PacketPtr pkt) +{ + RubyPort *ruby_port = static_cast(&owner); + + 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 access caught for address %#x\n", pkt->getAddr()); @@ -174,17 +221,18 @@ // Save the port in the sender state object to be used later to // route the response pkt->pushSenderState(new SenderState(this)); + RubyPort *ruby_port = static_cast(&owner); // Check for pio requests and directly send them to the dedicated // pio port. if (!isPhysMemAddress(pkt->getAddr())) { - assert(ruby_port->pio_port.isConnected()); + assert(ruby_port->memMasterPort.isConnected()); DPRINTF(RubyPort, "Request for address 0x%#x is assumed to be a pio request\n", pkt->getAddr()); // send next cycle - ruby_port->pio_port.schedTimingReq(pkt, + ruby_port->memMasterPort.schedTimingReq(pkt, curTick() + g_system_ptr->clockPeriod()); return true; } @@ -211,8 +259,7 @@ ruby_port->addToRetryList(this); } - DPRINTF(RubyPort, - "Request for address %#x did not issue because %s\n", + DPRINTF(RubyPort, "Request for address %#x not issued because %s\n", pkt->getAddr(), RequestStatus_to_string(requestStatus)); SenderState* senderState = safe_cast(pkt->senderState); @@ -222,18 +269,17 @@ } void -RubyPort::M5Port::recvFunctional(PacketPtr pkt) +RubyPort::MemSlavePort::recvFunctional(PacketPtr pkt) { - DPRINTF(RubyPort, "Functional access caught for address %#x\n", - pkt->getAddr()); + DPRINTF(RubyPort, "Functional access for address: %#x\n", pkt->getAddr()); + RubyPort *ruby_port = static_cast(&owner); // Check for pio requests and directly send them to the dedicated // pio port. if (!isPhysMemAddress(pkt->getAddr())) { - assert(ruby_port->pio_port.isConnected()); - DPRINTF(RubyPort, "Request for address 0x%#x is a pio request\n", - pkt->getAddr()); - panic("RubyPort::PioPort::recvFunctional() not implemented!\n"); + assert(ruby_port->memMasterPort.isConnected()); + DPRINTF(RubyPort, "Pio Request for address: 0x%#x\n", pkt->getAddr()); + panic("RubyPort::PioMasterPort::recvFunctional() not implemented!\n"); } assert(pkt->getAddr() + pkt->getSize() <= @@ -249,8 +295,7 @@ } else if (pkt->isWrite()) { accessSucceeded = ruby_system->functionalWrite(pkt); } else { - panic("RubyPort: unsupported functional command %s\n", - pkt->cmdString()); + panic("Unsupported functional command %s\n", pkt->cmdString()); } // Unless the requester explicitly said otherwise, generate an error if @@ -287,7 +332,7 @@ // Retrieve the request port from the sender State RubyPort::SenderState *senderState = safe_cast(pkt->senderState); - M5Port *port = senderState->port; + MemSlavePort *port = senderState->port; assert(port != NULL); // pop the sender state from the packet @@ -297,7 +342,7 @@ port->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. // if (waitingOnSequencer) { @@ -308,12 +353,12 @@ // list. Therefore we want to clear the retryList before calling // sendRetry. // - std::list curRetryList(retryList); + std::list curRetryList(retryList); retryList.clear(); waitingOnSequencer = false; - for (std::list::iterator i = curRetryList.begin(); + for (std::list::iterator i = curRetryList.begin(); i != curRetryList.end(); ++i) { DPRINTF(RubyPort, "Sequencer may now be free. SendRetry to port %s\n", @@ -347,8 +392,8 @@ { int count = 0; - if (pio_port.isConnected()) { - count += pio_port.drain(dm); + if (memMasterPort.isConnected()) { + count += memMasterPort.drain(dm); DPRINTF(Config, "count after pio check %d\n", count); } @@ -357,7 +402,7 @@ DPRINTF(Config, "count after slave port check %d\n", count); } - for (std::vector::iterator p = master_ports.begin(); + for (std::vector::iterator p = master_ports.begin(); p != master_ports.end(); ++p) { count += (*p)->drain(dm); DPRINTF(Config, "count after master port check %d\n", count); @@ -403,7 +448,7 @@ } void -RubyPort::M5Port::hitCallback(PacketPtr pkt) +RubyPort::MemSlavePort::hitCallback(PacketPtr pkt) { bool needsResponse = pkt->needsResponse(); @@ -446,6 +491,7 @@ DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse); if (accessPhysMem) { + RubyPort *ruby_port = static_cast(&owner); ruby_port->system->getPhysMem().access(pkt); } else if (needsResponse) { pkt->makeResponse(); @@ -463,16 +509,24 @@ } AddrRangeList -RubyPort::M5Port::getAddrRanges() const +RubyPort::PioSlavePort::getAddrRanges() const { - // at the moment the assumption is that the master does not care AddrRangeList ranges; + RubyPort *ruby_port = static_cast(&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; } bool -RubyPort::M5Port::isPhysMemAddress(Addr addr) +RubyPort::MemSlavePort::isPhysMemAddress(Addr addr) { + RubyPort *ruby_port = static_cast(&owner); return ruby_port->system->isMemAddr(addr); } @@ -496,3 +550,13 @@ } } } + +void +RubyPort::PioMasterPort::recvRangeChange() +{ + RubyPort &r = static_cast(owner); + r.gotAddrRanges--; + if (r.gotAddrRanges == 0) { + r.pioSlavePort.sendRangeChange(); + } +} diff -r e64989c69263 -r 66f543a6cac7 src/mem/ruby/system/Sequencer.py --- a/src/mem/ruby/system/Sequencer.py Fri Jan 17 11:27:34 2014 -0600 +++ b/src/mem/ruby/system/Sequencer.py Fri Jan 17 11:45:50 2014 -0600 @@ -35,12 +35,16 @@ type = 'RubyPort' abstract = True cxx_header = "mem/ruby/system/RubyPort.hh" + version = Param.Int(0, "") + slave = VectorSlavePort("CPU slave port") master = VectorMasterPort("CPU master port") - version = Param.Int(0, "") - pio_port = MasterPort("Ruby_pio_port") + pio_master_port = MasterPort("Ruby mem master 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_network_tester = Param.Bool(False, "") access_phys_mem = Param.Bool(False, "should the rubyport atomically update phys_mem") ruby_system = Param.RubySystem("") @@ -58,12 +62,14 @@ type = 'RubySequencer' cxx_class = 'Sequencer' cxx_header = "mem/ruby/system/Sequencer.hh" + icache = Param.RubyCache("") dcache = Param.RubyCache("") max_outstanding_requests = Param.Int(16, "max requests (incl. prefetches) outstanding") deadlock_threshold = Param.Cycles(500000, "max outstanding cycles for a request before deadlock/livelock declared") + using_network_tester = Param.Bool(False, "") class DMASequencer(RubyPort): type = 'DMASequencer' diff -r e64989c69263 -r 66f543a6cac7 tests/configs/pc-simple-timing-ruby.py --- a/tests/configs/pc-simple-timing-ruby.py Fri Jan 17 11:27:34 2014 -0600 +++ b/tests/configs/pc-simple-timing-ruby.py Fri Jan 17 11:45:50 2014 -0600 @@ -82,9 +82,9 @@ cpu.dcache_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.interrupts.pio = system.piobus.master - cpu.interrupts.int_master = system.piobus.slave - cpu.interrupts.int_slave = system.piobus.master + cpu.interrupts.pio = system.ruby._cpu_ruby_ports[i].master + cpu.interrupts.int_master = system.ruby._cpu_ruby_ports[i].slave + cpu.interrupts.int_slave = system.ruby._cpu_ruby_ports[i].master # Set access_phys_mem to True for ruby port system.ruby._cpu_ruby_ports[i].access_phys_mem = True