diff options
Diffstat (limited to 'src/mem/rubymem.cc')
-rw-r--r-- | src/mem/rubymem.cc | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/src/mem/rubymem.cc b/src/mem/rubymem.cc new file mode 100644 index 000000000..6a22830ef --- /dev/null +++ b/src/mem/rubymem.cc @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2001-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. + * + * Authors: Daniel Sanchez + */ + + +#include "arch/isa_traits.hh" +#include "mem/rubymem.hh" +#include "sim/eventq.hh" +#include "sim/host.hh" +#include "base/output.hh" + +// Ruby includes +#include "mem/ruby/system/System.hh" +#include "mem/ruby/system/Sequencer.hh" +#include "mem/ruby/init.hh" +#include "mem/ruby/common/Debug.hh" + +#include "sim/sim_exit.hh" + +#include <iostream> +#include <fstream> + +using namespace std; +using namespace TheISA; + +RubyMemory::RubyMemory(const Params *p) + : PhysicalMemory(p) +{ + config_file = p->config_file; + config_options = p->config_options; + stats_file = p->stats_file; + num_cpus = p->num_cpus; + ruby_clock = p->clock; + ruby_phase = p->phase; + + debug = p->debug; + debug_file = p->debug_file; +} + +void +RubyMemory::init() +{ + init_variables(); + g_NUM_PROCESSORS = num_cpus; + + init_simulator(this); + + if (debug) { + g_debug_ptr->setVerbosityString("high"); + g_debug_ptr->setDebugTime(1); + if (debug_file != "") { + g_debug_ptr->setDebugOutputFile("ruby.debug"); + } + } + + //You may want to set some other options... + //g_debug_ptr->setVerbosityString("med"); + //g_debug_ptr->setFilterString("lsNqST"); + //g_debug_ptr->setFilterString("lsNST"); + //g_debug_ptr->setDebugTime(1); + //g_debug_ptr->setDebugOutputFile("ruby.debug"); + + + g_system_ptr->clearStats(); + + if (ports.size() == 0) { + fatal("RubyMemory object %s is unconnected!", name()); + } + + for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) { + if (*pi) + (*pi)->sendStatusChange(Port::RangeChange); + } + + //Print stats at exit + RubyExitCallback* rc = new RubyExitCallback(this); + registerExitCallback(rc); + + //Sched RubyEvent, automatically reschedules to advance ruby cycles + rubyTickEvent = new RubyEvent(this); + schedule(rubyTickEvent, curTick + ruby_clock + ruby_phase); +} + +//called by rubyTickEvent +void RubyMemory::tick() { + g_eventQueue_ptr->triggerEvents(g_eventQueue_ptr->getTime() + 1); + schedule(rubyTickEvent, curTick + ruby_clock); //dsm: clock_phase was added here. This is wrong, the phase is only added on the first tick +} + + +RubyMemory::~RubyMemory() { + delete g_system_ptr; +} + +void +RubyMemory::hitCallback(Packet* pkt) +{ + RubyMemoryPort* port = m_packet_to_port_map[pkt]; + assert(port != NULL); + m_packet_to_port_map.erase(pkt); + + DPRINTF(MemoryAccess, "Hit callback\n"); + + bool needsResponse = pkt->needsResponse(); + doAtomicAccess(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"); + port->sendTiming(pkt); + } else { + delete pkt; + } + DPRINTF(MemoryAccess, "Hit callback done!\n"); +} + +Port * +RubyMemory::getPort(const std::string &if_name, int idx) +{ + // Accept request for "functional" port for backwards compatibility + // with places where this function is called from C++. I'd prefer + // to move all these into Python someday. + if (if_name == "functional") { + return new RubyMemoryPort(csprintf("%s-functional", name()), this); + } + + if (if_name != "port") { + panic("RubyMemory::getPort: unknown port %s requested", if_name); + } + + if (idx >= ports.size()) { + ports.resize(idx+1); + } + + if (ports[idx] != NULL) { + panic("RubyMemory::getPort: port %d already assigned", idx); + } + + RubyMemoryPort *port = + new RubyMemoryPort(csprintf("%s-port%d", name(), idx), this); + + ports[idx] = port; + return port; +} + +RubyMemory::RubyMemoryPort::RubyMemoryPort(const std::string &_name, + RubyMemory *_memory) + : PhysicalMemory::MemoryPort::MemoryPort(_name, _memory) +{ + ruby_mem = _memory; +} + +bool +RubyMemory::RubyMemoryPort::recvTiming(PacketPtr pkt) +{ + DPRINTF(MemoryAccess, "Timing access caught\n"); + + //dsm: based on SimpleTimingPort::recvTiming(pkt); + + // If the device is only a slave, it should only be sending + // responses, 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; + } + + ruby_mem->m_packet_to_port_map[pkt] = this; + + Sequencer* sequencer = g_system_ptr->getSequencer(pkt->req->contextId()); + + if ( ! sequencer->isReady(pkt) ) { + DPRINTF(MemoryAccess, "Sequencer isn't ready yet!!\n"); + return false; + } + + DPRINTF(MemoryAccess, "Issuing makeRequest\n"); + + sequencer->makeRequest(pkt); + return true; +} + +void +RubyMemory::RubyMemoryPort::sendTiming(PacketPtr pkt) +{ + schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0 +} + +void RubyMemory::printConfigStats() +{ + std::ostream *os = simout.create(stats_file); + g_system_ptr->printConfig(*os); + *os << endl; + g_system_ptr->printStats(*os); +} + + +//Right now these functions seem to be called by RubySystem. If they do calls +// to RubySystem perform it intended actions, you'll get into an inf loop +//FIXME what's the purpose of these here? +void RubyMemory::printStats(std::ostream & out) const { + //g_system_ptr->printConfig(out); +} + +void RubyMemory::clearStats() { + //g_system_ptr->clearStats(); +} + +void RubyMemory::printConfig(std::ostream & out) const { + //g_system_ptr->printConfig(out); +} + + +//Python-interface code +RubyMemory * +RubyMemoryParams::create() +{ + return new RubyMemory(this); +} + |