diff options
Diffstat (limited to 'src/mem/ruby/system')
-rw-r--r-- | src/mem/ruby/system/Cache.py | 1 | ||||
-rw-r--r-- | src/mem/ruby/system/CacheMemory.cc | 35 | ||||
-rw-r--r-- | src/mem/ruby/system/CacheMemory.hh | 7 | ||||
-rw-r--r-- | src/mem/ruby/system/DirectoryMemory.cc | 3 | ||||
-rw-r--r-- | src/mem/ruby/system/DirectoryMemory.hh | 3 | ||||
-rw-r--r-- | src/mem/ruby/system/DirectoryMemory.py | 1 | ||||
-rw-r--r-- | src/mem/ruby/system/RubyPort.cc | 275 | ||||
-rw-r--r-- | src/mem/ruby/system/RubyPort.hh | 90 | ||||
-rw-r--r-- | src/mem/ruby/system/Sequencer.hh | 3 | ||||
-rw-r--r-- | src/mem/ruby/system/Sequencer.py | 3 |
10 files changed, 371 insertions, 50 deletions
diff --git a/src/mem/ruby/system/Cache.py b/src/mem/ruby/system/Cache.py index 250d8e888..209d6f6e2 100644 --- a/src/mem/ruby/system/Cache.py +++ b/src/mem/ruby/system/Cache.py @@ -9,4 +9,3 @@ class RubyCache(SimObject): latency = Param.Int(""); assoc = Param.Int(""); replacement_policy = Param.String("PSEUDO_LRU", ""); - controller = Param.RubyController(""); diff --git a/src/mem/ruby/system/CacheMemory.cc b/src/mem/ruby/system/CacheMemory.cc index 43a0e13e9..11dd8ca96 100644 --- a/src/mem/ruby/system/CacheMemory.cc +++ b/src/mem/ruby/system/CacheMemory.cc @@ -31,9 +31,6 @@ int CacheMemory::m_num_last_level_caches = 0; MachineType CacheMemory::m_last_level_machine_type = MachineType_FIRST; -// Output operator declaration -//ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj); - // ******************* Definitions ******************* // Output operator definition @@ -56,29 +53,27 @@ RubyCacheParams::create() CacheMemory::CacheMemory(const Params *p) : SimObject(p) { - int cache_size = p->size; + m_cache_size = p->size; m_latency = p->latency; m_cache_assoc = p->assoc; - string policy = p->replacement_policy; - m_controller = p->controller; - - int num_lines = cache_size/RubySystem::getBlockSizeBytes(); - m_cache_num_sets = num_lines / m_cache_assoc; - m_cache_num_set_bits = log_int(m_cache_num_sets); - assert(m_cache_num_set_bits > 0); - - if(policy == "PSEUDO_LRU") - m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc); - else if (policy == "LRU") - m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc); - else - assert(false); - + m_policy = p->replacement_policy; } void CacheMemory::init() { + m_cache_num_sets = (m_cache_size / m_cache_assoc) / RubySystem::getBlockSizeBytes(); + assert(m_cache_num_sets > 1); + m_cache_num_set_bits = log_int(m_cache_num_sets); + assert(m_cache_num_set_bits > 0); + + if(m_policy == "PSEUDO_LRU") + m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc); + else if (m_policy == "LRU") + m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc); + else + assert(false); + m_num_last_level_caches = MachineType_base_count(MachineType_FIRST); #if 0 @@ -126,8 +121,6 @@ CacheMemory::numberOfLastLevelCaches() void CacheMemory::printConfig(ostream& out) { out << "Cache config: " << m_cache_name << endl; - if (m_controller != NULL) - out << " controller: " << m_controller->getName() << endl; out << " cache_associativity: " << m_cache_assoc << endl; out << " num_cache_sets_bits: " << m_cache_num_set_bits << endl; const int cache_num_sets = 1 << m_cache_num_set_bits; diff --git a/src/mem/ruby/system/CacheMemory.hh b/src/mem/ruby/system/CacheMemory.hh index fac076da9..f70427f2d 100644 --- a/src/mem/ruby/system/CacheMemory.hh +++ b/src/mem/ruby/system/CacheMemory.hh @@ -72,10 +72,6 @@ public: // Destructor ~CacheMemory(); - // factory - // static CacheMemory* createCache(int level, int num, char split_type, AbstractCacheEntry* (*entry_factory)()); - // static CacheMemory* getCache(int cache_id); - // Public Methods void printConfig(ostream& out); @@ -155,7 +151,6 @@ private: private: const string m_cache_name; - AbstractController* m_controller; int m_latency; // Data Members (m_prefix) @@ -172,6 +167,8 @@ private: CacheProfiler* m_profiler_ptr; + int m_cache_size; + string m_policy; int m_cache_num_sets; int m_cache_num_set_bits; int m_cache_assoc; diff --git a/src/mem/ruby/system/DirectoryMemory.cc b/src/mem/ruby/system/DirectoryMemory.cc index b0b33b048..e4801594c 100644 --- a/src/mem/ruby/system/DirectoryMemory.cc +++ b/src/mem/ruby/system/DirectoryMemory.cc @@ -39,7 +39,6 @@ #include "mem/ruby/system/System.hh" #include "mem/ruby/system/DirectoryMemory.hh" #include "mem/ruby/slicc_interface/RubySlicc_Util.hh" -#include "mem/ruby/slicc_interface/AbstractController.hh" #include "mem/gems_common/util.hh" int DirectoryMemory::m_num_directories = 0; @@ -52,7 +51,6 @@ DirectoryMemory::DirectoryMemory(const Params *p) m_version = p->version; m_size_bytes = p->size_mb * static_cast<uint64>(1<<20); m_size_bits = log_int(m_size_bytes); - m_controller = p->controller; } void DirectoryMemory::init() @@ -85,7 +83,6 @@ DirectoryMemory::~DirectoryMemory() void DirectoryMemory::printConfig(ostream& out) const { out << "DirectoryMemory module config: " << m_name << endl; - out << " controller: " << m_controller->getName() << endl; out << " version: " << m_version << endl; out << " memory_bits: " << m_size_bits << endl; out << " memory_size_bytes: " << m_size_bytes << endl; diff --git a/src/mem/ruby/system/DirectoryMemory.hh b/src/mem/ruby/system/DirectoryMemory.hh index 1575187b0..0f4368b2c 100644 --- a/src/mem/ruby/system/DirectoryMemory.hh +++ b/src/mem/ruby/system/DirectoryMemory.hh @@ -46,8 +46,6 @@ #include "sim/sim_object.hh" #include "params/RubyDirectoryMemory.hh" -class AbstractController; - class DirectoryMemory : public SimObject { public: // Constructors @@ -83,7 +81,6 @@ private: private: const string m_name; - AbstractController* m_controller; // Data Members (m_ prefix) Directory_Entry **m_entries; // int m_size; // # of memory module blocks this directory is responsible for diff --git a/src/mem/ruby/system/DirectoryMemory.py b/src/mem/ruby/system/DirectoryMemory.py index 55c2d82bd..e3becc4fc 100644 --- a/src/mem/ruby/system/DirectoryMemory.py +++ b/src/mem/ruby/system/DirectoryMemory.py @@ -7,4 +7,3 @@ class RubyDirectoryMemory(SimObject): cxx_class = 'DirectoryMemory' version = Param.Int(0, "") size_mb = Param.Int(1024, "") - controller = Param.RubyController(Parent.any, "") diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc index b83ba43e3..d8fb6b470 100644 --- a/src/mem/ruby/system/RubyPort.cc +++ b/src/mem/ruby/system/RubyPort.cc @@ -31,27 +31,290 @@ #include "mem/ruby/system/RubyPort.hh" #include "mem/ruby/slicc_interface/AbstractController.hh" -//void (*RubyPort::m_hit_callback)(int64_t) = NULL; uint16_t RubyPort::m_num_ports = 0; +RubyPort::RequestMap RubyPort::pending_cpu_requests; + RubyPort::RubyPort(const Params *p) - : MemObject(p) + : MemObject(p), + funcMemPort(csprintf("%s-funcmem_port", name()), this) { m_version = p->version; assert(m_version != -1); - m_controller = p->controller; - assert(m_controller != NULL); - m_mandatory_q_ptr = m_controller->getMandatoryQueue(); + m_controller = NULL; + m_mandatory_q_ptr = NULL; m_port_id = m_num_ports++; m_request_cnt = 0; - m_hit_callback = NULL; + m_hit_callback = ruby_hit_callback; + pio_port = NULL; assert(m_num_ports <= 2048); // see below for reason } +void RubyPort::init() +{ + assert(m_controller != NULL); + m_mandatory_q_ptr = m_controller->getMandatoryQueue(); +} + Port * RubyPort::getPort(const std::string &if_name, int idx) { + if (if_name == "port") { + return new M5Port(csprintf("%s-port%d", name(), idx), this); + } else if (if_name == "pio_port") { + // + // ensure there is only one pio port + // + assert(pio_port == NULL); + + pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx), + this); + + return pio_port; + } else if (if_name == "funcmem_port") { + return &funcMemPort; + } return NULL; } + +RubyPort::PioPort::PioPort(const std::string &_name, + RubyPort *_port) + : SimpleTimingPort(_name, _port) +{ + DPRINTF(Ruby, "creating port to ruby sequencer to cpu %s\n", _name); + ruby_port = _port; +} + +RubyPort::M5Port::M5Port(const std::string &_name, + RubyPort *_port) + : SimpleTimingPort(_name, _port) +{ + DPRINTF(Ruby, "creating port from ruby sequcner to cpu %s\n", _name); + ruby_port = _port; +} + +Tick +RubyPort::PioPort::recvAtomic(PacketPtr pkt) +{ + panic("RubyPort::PioPort::recvAtomic() not implemented!\n"); + return 0; +} + + +Tick +RubyPort::M5Port::recvAtomic(PacketPtr pkt) +{ + panic("RubyPort::M5Port::recvAtomic() not implemented!\n"); + return 0; +} + + +bool +RubyPort::PioPort::recvTiming(PacketPtr pkt) +{ + // + // In FS mode, ruby memory will receive pio responses from devices and + // it must forward these responses back to the particular CPU. + // + DPRINTF(MemoryAccess, + "Pio response for address %#x\n", + pkt->getAddr()); + + assert(pkt->isResponse()); + + // + // First we must retrieve the request port from the sender State + // + RubyPort::SenderState *senderState = + safe_cast<RubyPort::SenderState *>(pkt->senderState); + M5Port *port = senderState->port; + assert(port != NULL); + + // pop the sender state from the packet + pkt->senderState = senderState->saved; + delete senderState; + + port->sendTiming(pkt); + + return true; +} + +bool +RubyPort::M5Port::recvTiming(PacketPtr pkt) +{ + DPRINTF(MemoryAccess, + "Timing access caught for address %#x\n", + pkt->getAddr()); + + //dsm: based on SimpleTimingPort::recvTiming(pkt); + + // + // After checking for pio responses, the remainder of packets + // received by ruby should only be M5 requests, which should never + // get nacked. There used to be code to hanldle nacks here, but + // I'm pretty sure it didn't work correctly with the drain code, + // so that would need to be fixed if we ever added it back. + // + assert(pkt->isRequest()); + + if (pkt->memInhibitAsserted()) { + warn("memInhibitAsserted???"); + // snooper will supply based on copy of packet + // still target's responsibility to delete packet + delete pkt; + return true; + } + + // + // Check for pio requests and directly send them to the dedicated + // pio port. + // + if (!isPhysMemAddress(pkt->getAddr())) { + assert(ruby_port->pio_port != NULL); + + // + // Save the port in the sender state object to be used later to + // route the response + // + pkt->senderState = new SenderState(this, pkt->senderState); + + return ruby_port->pio_port->sendTiming(pkt); + } + + // + // For DMA and CPU requests, translate them to ruby requests before + // sending them to our assigned ruby port. + // + RubyRequestType type = RubyRequestType_NULL; + Addr pc = 0; + if (pkt->isRead()) { + if (pkt->req->isInstFetch()) { + type = RubyRequestType_IFETCH; + pc = pkt->req->getPC(); + } else { + type = RubyRequestType_LD; + } + } else if (pkt->isWrite()) { + type = RubyRequestType_ST; + } else if (pkt->isReadWrite()) { + type = RubyRequestType_RMW_Write; + } + + RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(), + pkt->getSize(), pc, type, + RubyAccessMode_Supervisor); + + // Submit the ruby request + int64_t req_id = ruby_port->makeRequest(ruby_request); + if (req_id == -1) { + return false; + } + + // Save the request for the callback + RubyPort::pending_cpu_requests[req_id] = new RequestCookie(pkt, this); + + return true; +} + +void +RubyPort::ruby_hit_callback(int64_t req_id) +{ + // + // Note: This single fuction can be called by cpu and dma ports, + // as well as the functional port. + // + RequestMap::iterator i = pending_cpu_requests.find(req_id); + if (i == pending_cpu_requests.end()) + panic("could not find pending request %d\n", req_id); + + RequestCookie *cookie = i->second; + pending_cpu_requests.erase(i); + + Packet *pkt = cookie->pkt; + M5Port *port = cookie->m5Port; + delete cookie; + + port->hitCallback(pkt); +} + +void +RubyPort::M5Port::hitCallback(PacketPtr pkt) +{ + + bool needsResponse = pkt->needsResponse(); + + DPRINTF(MemoryAccess, "Hit callback needs response %d\n", + needsResponse); + + ruby_port->funcMemPort.sendFunctional(pkt); + + // turn packet around to go back to requester if response expected + if (needsResponse) { + // recvAtomic() should already have turned packet into + // atomic response + assert(pkt->isResponse()); + DPRINTF(MemoryAccess, "Sending packet back over port\n"); + sendTiming(pkt); + } else { + delete pkt; + } + DPRINTF(MemoryAccess, "Hit callback done!\n"); +} + +bool +RubyPort::M5Port::sendTiming(PacketPtr pkt) +{ + schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0 + return true; +} + +bool +RubyPort::PioPort::sendTiming(PacketPtr pkt) +{ + schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0 + return true; +} + +bool +RubyPort::M5Port::isPhysMemAddress(Addr addr) +{ + AddrRangeList physMemAddrList; + bool snoop = false; + ruby_port->funcMemPort.getPeerAddressRanges(physMemAddrList, snoop); + for(AddrRangeIter iter = physMemAddrList.begin(); + iter != physMemAddrList.end(); + iter++) { + if (addr >= iter->start && addr <= iter->end) { + DPRINTF(MemoryAccess, "Request found in %#llx - %#llx range\n", + iter->start, iter->end); + return true; + } + } + assert(isPioAddress(addr)); + return false; +} + +bool +RubyPort::M5Port::isPioAddress(Addr addr) +{ + AddrRangeList pioAddrList; + bool snoop = false; + if (ruby_port->pio_port == NULL) { + return false; + } + + ruby_port->pio_port->getPeerAddressRanges(pioAddrList, snoop); + for(AddrRangeIter iter = pioAddrList.begin(); + iter != pioAddrList.end(); + iter++) { + if (addr >= iter->start && addr <= iter->end) { + DPRINTF(MemoryAccess, "Pio request found in %#llx - %#llx range\n", + iter->start, iter->end); + return true; + } + } + return false; +} + diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh index 20557669a..a03c4dce2 100644 --- a/src/mem/ruby/system/RubyPort.hh +++ b/src/mem/ruby/system/RubyPort.hh @@ -46,18 +46,81 @@ class AbstractController; class RubyPort : public MemObject { public: + + class M5Port : public SimpleTimingPort + { + + RubyPort *ruby_port; + + public: + M5Port(const std::string &_name, + RubyPort *_port); + bool sendTiming(PacketPtr pkt); + void hitCallback(PacketPtr pkt); + + protected: + virtual bool recvTiming(PacketPtr pkt); + virtual Tick recvAtomic(PacketPtr pkt); + + private: + bool isPioAddress(Addr addr); + bool isPhysMemAddress(Addr addr); + }; + + friend class M5Port; + + class PioPort : public SimpleTimingPort + { + + RubyPort *ruby_port; + + public: + PioPort(const std::string &_name, + RubyPort *_port); + bool sendTiming(PacketPtr pkt); + + protected: + virtual bool recvTiming(PacketPtr pkt); + virtual Tick recvAtomic(PacketPtr pkt); + }; + + friend class PioPort; + + struct SenderState : public Packet::SenderState + { + M5Port* port; + Packet::SenderState *saved; + + SenderState(M5Port* _port, + Packet::SenderState *sender_state = NULL) + : port(_port), saved(sender_state) + {} + }; + typedef RubyPortParams Params; RubyPort(const Params *p); - virtual ~RubyPort() {} + virtual ~RubyPort() {} + + void init(); Port *getPort(const std::string &if_name, int idx); - virtual int64_t makeRequest(const RubyRequest & request) = 0; + virtual int64_t makeRequest(const RubyRequest & request) = 0; - void registerHitCallback(void (*hit_callback)(int64_t request_id)) { - assert(m_hit_callback == NULL); // can't assign hit_callback twice - m_hit_callback = hit_callback; - } + void registerHitCallback(void (*hit_callback)(int64_t request_id)) { + // + // Can't assign hit_callback twice and by default it is set to the + // RubyPort's default callback function. + // + assert(m_hit_callback == ruby_hit_callback); + m_hit_callback = hit_callback; + } + + // + // Called by the controller to give the sequencer a pointer. + // A pointer to the controller is needed for atomic support. + // + void setController(AbstractController* _cntrl) { m_controller = _cntrl; } protected: const string m_name; @@ -87,11 +150,26 @@ protected: int m_version; AbstractController* m_controller; MessageBuffer* m_mandatory_q_ptr; + PioPort* pio_port; private: static uint16_t m_num_ports; uint16_t m_port_id; uint64_t m_request_cnt; + + struct RequestCookie { + Packet *pkt; + M5Port *m5Port; + RequestCookie(Packet *p, M5Port *m5p) + : pkt(p), m5Port(m5p) + {} + }; + + typedef std::map<int64_t, RequestCookie*> RequestMap; + static RequestMap pending_cpu_requests; + static void ruby_hit_callback(int64_t req_id); + + FunctionalPort funcMemPort; }; #endif diff --git a/src/mem/ruby/system/Sequencer.hh b/src/mem/ruby/system/Sequencer.hh index d2dc5bbb3..974b251f0 100644 --- a/src/mem/ruby/system/Sequencer.hh +++ b/src/mem/ruby/system/Sequencer.hh @@ -118,9 +118,6 @@ private: CacheMemory* m_dataCache_ptr; CacheMemory* m_instCache_ptr; - // indicates what processor on the chip this sequencer is associated with - int m_controller_type; - Map<Address, SequencerRequest*> m_writeRequestTable; Map<Address, SequencerRequest*> m_readRequestTable; // Global outstanding request count, across all request tables diff --git a/src/mem/ruby/system/Sequencer.py b/src/mem/ruby/system/Sequencer.py index add5a06a1..1333204a2 100644 --- a/src/mem/ruby/system/Sequencer.py +++ b/src/mem/ruby/system/Sequencer.py @@ -1,12 +1,13 @@ from m5.params import * +from m5.proxy import * from MemObject import MemObject class RubyPort(MemObject): type = 'RubyPort' abstract = True port = VectorPort("M5 port") - controller = Param.RubyController("") version = Param.Int(0, "") + pio_port = Port("Ruby_pio_port") class RubySequencer(RubyPort): type = 'RubySequencer' |