From 6ab6c52b0bf9c91ef9249613cb4c9d8ab579b4f3 Mon Sep 17 00:00:00 2001 From: Swapnil Haria Date: Thu, 9 Nov 2017 13:04:39 -0600 Subject: [PATCH] mem-ruby: Support atomic_noncaching acceses in ruby Ruby has no support for atomic_noncaching accesses, which prevents using it with kvm-cpu. This patch fixes this by directly forwarding atomic requests from the ruby port/sequencer to the corresponding directory based on the destination address of the packet. Change-Id: I0b4928bfda44fd9e5e48583c51d1ea422800da2d Reviewed-on: https://gem5-review.googlesource.com/5601 Reviewed-by: Andreas Sandberg Reviewed-by: Jason Lowe-Power Reviewed-by: Bradford Beckmann Maintainer: Jason Lowe-Power Maintainer: Bradford Beckmann --- configs/common/Simulation.py | 5 ++ configs/example/fs.py | 8 +-- configs/example/se.py | 6 +- .../slicc_interface/AbstractController.cc | 6 ++ .../slicc_interface/AbstractController.hh | 1 + src/mem/ruby/system/RubyPort.cc | 62 +++++++++++++++++++ src/mem/ruby/system/RubyPort.hh | 7 +-- 7 files changed, 79 insertions(+), 16 deletions(-) diff --git a/configs/common/Simulation.py b/configs/common/Simulation.py index 71a982af9..7c949b972 100644 --- a/configs/common/Simulation.py +++ b/configs/common/Simulation.py @@ -83,6 +83,11 @@ def setCPUClass(options): TmpClass = AtomicSimpleCPU test_mem_mode = 'atomic' + # Ruby only supports atomic accesses in noncaching mode + if test_mem_mode == 'atomic' and options.ruby: + warn("Memory mode will be changed to atomic_noncaching") + test_mem_mode = 'atomic_noncaching' + return (TmpClass, test_mem_mode, CPUClass) def setMemClass(options): diff --git a/configs/example/fs.py b/configs/example/fs.py index 65079372c..351d1c016 100644 --- a/configs/example/fs.py +++ b/configs/example/fs.py @@ -47,7 +47,7 @@ import sys import m5 from m5.defines import buildEnv from m5.objects import * -from m5.util import addToPath, fatal +from m5.util import addToPath, fatal, warn addToPath('../') @@ -147,12 +147,6 @@ def build_test_system(np): test_sys.kvm_vm = KvmVM() if options.ruby: - # Check for timing mode because ruby does not support atomic accesses - if not (options.cpu_type == "DerivO3CPU" or - options.cpu_type == "TimingSimpleCPU"): - print >> sys.stderr, "Ruby requires TimingSimpleCPU or O3CPU!!" - sys.exit(1) - Ruby.create_system(options, True, test_sys, test_sys.iobus, test_sys._dma_ports) diff --git a/configs/example/se.py b/configs/example/se.py index 7a19e5aef..56e4753b9 100644 --- a/configs/example/se.py +++ b/configs/example/se.py @@ -49,7 +49,7 @@ import os import m5 from m5.defines import buildEnv from m5.objects import * -from m5.util import addToPath, fatal +from m5.util import addToPath, fatal, warn addToPath('../') @@ -250,10 +250,6 @@ for i in xrange(np): system.cpu[i].createThreads() if options.ruby: - if options.cpu_type == "AtomicSimpleCPU": - print >> sys.stderr, "Ruby does not work with atomic cpu!!" - sys.exit(1) - Ruby.create_system(options, False, system) assert(options.num_cpus == len(system.ruby._cpu_ports)) diff --git a/src/mem/ruby/slicc_interface/AbstractController.cc b/src/mem/ruby/slicc_interface/AbstractController.cc index 0bc88eefa..b920ff7b0 100644 --- a/src/mem/ruby/slicc_interface/AbstractController.cc +++ b/src/mem/ruby/slicc_interface/AbstractController.cc @@ -360,6 +360,12 @@ AbstractController::recvTimingResp(PacketPtr pkt) delete pkt; } +Tick +AbstractController::recvAtomic(PacketPtr pkt) +{ + return ticksToCycles(memoryPort.sendAtomic(pkt)); +} + MachineID AbstractController::mapAddressToMachine(Addr addr, MachineType mtype) const { diff --git a/src/mem/ruby/slicc_interface/AbstractController.hh b/src/mem/ruby/slicc_interface/AbstractController.hh index 354dc80aa..35cd3d2a5 100644 --- a/src/mem/ruby/slicc_interface/AbstractController.hh +++ b/src/mem/ruby/slicc_interface/AbstractController.hh @@ -135,6 +135,7 @@ class AbstractController : public MemObject, public Consumer void queueMemoryWritePartial(const MachineID &id, Addr addr, Cycles latency, const DataBlock &block, int size); void recvTimingResp(PacketPtr pkt); + Tick recvAtomic(PacketPtr pkt); const AddrRangeList &getAddrRanges() const { return addrRanges; } diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc index fd535cca2..5977ce9ef 100644 --- a/src/mem/ruby/system/RubyPort.cc +++ b/src/mem/ruby/system/RubyPort.cc @@ -226,6 +226,26 @@ RubyPort::PioSlavePort::recvTimingReq(PacketPtr pkt) panic("Should never reach here!\n"); } +Tick +RubyPort::PioSlavePort::recvAtomic(PacketPtr pkt) +{ + RubyPort *ruby_port = static_cast(&owner); + // Only atomic_noncaching mode supported! + if (!ruby_port->system->bypassCaches()) { + panic("Ruby supports atomic accesses only in noncaching mode\n"); + } + + 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())) { + return ruby_port->master_ports[i]->sendAtomic(pkt); + } + } + } + panic("Could not find address in Ruby PIO address ranges!\n"); +} + bool RubyPort::MemSlavePort::recvTimingReq(PacketPtr pkt) { @@ -295,6 +315,48 @@ RubyPort::MemSlavePort::recvTimingReq(PacketPtr pkt) return false; } +Tick +RubyPort::MemSlavePort::recvAtomic(PacketPtr pkt) +{ + RubyPort *ruby_port = static_cast(&owner); + // Only atomic_noncaching mode supported! + if (!ruby_port->system->bypassCaches()) { + panic("Ruby supports atomic accesses only in noncaching mode\n"); + } + + // Check for pio requests and directly send them to the dedicated + // pio port. + if (pkt->cmd != MemCmd::MemFenceReq) { + if (!isPhysMemAddress(pkt->getAddr())) { + assert(ruby_port->memMasterPort.isConnected()); + DPRINTF(RubyPort, "Request address %#x assumed to be a " + "pio address\n", 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 + Tick req_ticks = ruby_port->memMasterPort.sendAtomic(pkt); + return ruby_port->ticksToCycles(req_ticks); + } + + assert(getOffset(pkt->getAddr()) + pkt->getSize() <= + RubySystem::getBlockSizeBytes()); + } + + // Find appropriate directory for address + // This assumes that protocols have a Directory machine, + // which has its memPort hooked up to memory. This can + // fail for some custom protocols. + MachineID id = ruby_port->m_controller->mapAddressToMachine( + pkt->getAddr(), MachineType_Directory); + RubySystem *rs = ruby_port->m_ruby_system; + AbstractController *directory = + rs->m_abstract_controls[id.getType()][id.getNum()]; + return directory->recvAtomic(pkt); +} + void RubyPort::MemSlavePort::addToRetryList() { diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh index 6c991c162..146443282 100644 --- a/src/mem/ruby/system/RubyPort.hh +++ b/src/mem/ruby/system/RubyPort.hh @@ -46,6 +46,7 @@ #include #include "mem/protocol/RequestStatus.hh" +#include "mem/ruby/common/MachineID.hh" #include "mem/ruby/network/MessageBuffer.hh" #include "mem/ruby/system/RubySystem.hh" #include "mem/mem_object.hh" @@ -88,8 +89,7 @@ class RubyPort : public MemObject protected: bool recvTimingReq(PacketPtr pkt); - Tick recvAtomic(PacketPtr pkt) - { panic("RubyPort::MemSlavePort::recvAtomic() not implemented!\n"); } + Tick recvAtomic(PacketPtr pkt); void recvFunctional(PacketPtr pkt); @@ -127,8 +127,7 @@ class RubyPort : public MemObject protected: bool recvTimingReq(PacketPtr pkt); - Tick recvAtomic(PacketPtr pkt) - { panic("recvAtomic not supported with ruby!"); } + Tick recvAtomic(PacketPtr pkt); void recvFunctional(PacketPtr pkt) { panic("recvFunctional should never be called on pio slave port!"); } -- 2.30.2