RubyPort.cc revision 8436
113531Sjairo.balart@metempsy.com/* 213531Sjairo.balart@metempsy.com * Copyright (c) 2009 Advanced Micro Devices, Inc. 313531Sjairo.balart@metempsy.com * All rights reserved. 413531Sjairo.balart@metempsy.com * 513531Sjairo.balart@metempsy.com * Redistribution and use in source and binary forms, with or without 613531Sjairo.balart@metempsy.com * modification, are permitted provided that the following conditions are 713531Sjairo.balart@metempsy.com * met: redistributions of source code must retain the above copyright 813531Sjairo.balart@metempsy.com * notice, this list of conditions and the following disclaimer; 913531Sjairo.balart@metempsy.com * redistributions in binary form must reproduce the above copyright 1013531Sjairo.balart@metempsy.com * notice, this list of conditions and the following disclaimer in the 1113531Sjairo.balart@metempsy.com * documentation and/or other materials provided with the distribution; 1213531Sjairo.balart@metempsy.com * neither the name of the copyright holders nor the names of its 1313531Sjairo.balart@metempsy.com * contributors may be used to endorse or promote products derived from 1413531Sjairo.balart@metempsy.com * this software without specific prior written permission. 1513531Sjairo.balart@metempsy.com * 1613531Sjairo.balart@metempsy.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1713531Sjairo.balart@metempsy.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1813531Sjairo.balart@metempsy.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1913531Sjairo.balart@metempsy.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2013531Sjairo.balart@metempsy.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2113531Sjairo.balart@metempsy.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2213531Sjairo.balart@metempsy.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2313531Sjairo.balart@metempsy.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2413531Sjairo.balart@metempsy.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2513531Sjairo.balart@metempsy.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2613531Sjairo.balart@metempsy.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2713531Sjairo.balart@metempsy.com */ 2813531Sjairo.balart@metempsy.com 2913531Sjairo.balart@metempsy.com#include "config/the_isa.hh" 3013531Sjairo.balart@metempsy.com#if THE_ISA == X86_ISA 3113531Sjairo.balart@metempsy.com#include "arch/x86/insts/microldstop.hh" 3213531Sjairo.balart@metempsy.com#endif // X86_ISA 3313531Sjairo.balart@metempsy.com#include "cpu/testers/rubytest/RubyTester.hh" 3413531Sjairo.balart@metempsy.com#include "debug/Ruby.hh" 3513531Sjairo.balart@metempsy.com#include "mem/protocol/AccessPermission.hh" 3613531Sjairo.balart@metempsy.com#include "mem/ruby/slicc_interface/AbstractController.hh" 3713531Sjairo.balart@metempsy.com#include "mem/ruby/system/RubyPort.hh" 3813531Sjairo.balart@metempsy.com#include "mem/physical.hh" 3913531Sjairo.balart@metempsy.com 4013531Sjairo.balart@metempsy.comRubyPort::RubyPort(const Params *p) 4113531Sjairo.balart@metempsy.com : MemObject(p) 4213531Sjairo.balart@metempsy.com{ 4313531Sjairo.balart@metempsy.com m_version = p->version; 4413531Sjairo.balart@metempsy.com assert(m_version != -1); 4513531Sjairo.balart@metempsy.com 4613531Sjairo.balart@metempsy.com physmem = p->physmem; 4713531Sjairo.balart@metempsy.com 4813531Sjairo.balart@metempsy.com m_controller = NULL; 4913531Sjairo.balart@metempsy.com m_mandatory_q_ptr = NULL; 5013531Sjairo.balart@metempsy.com 5113531Sjairo.balart@metempsy.com m_request_cnt = 0; 5213531Sjairo.balart@metempsy.com pio_port = NULL; 5313531Sjairo.balart@metempsy.com physMemPort = NULL; 5413531Sjairo.balart@metempsy.com 5513531Sjairo.balart@metempsy.com m_usingRubyTester = p->using_ruby_tester; 5613531Sjairo.balart@metempsy.com access_phys_mem = p->access_phys_mem; 5713531Sjairo.balart@metempsy.com 5813531Sjairo.balart@metempsy.com ruby_system = p->ruby_system; 5913531Sjairo.balart@metempsy.com} 6013531Sjairo.balart@metempsy.com 6113531Sjairo.balart@metempsy.comvoid 6213531Sjairo.balart@metempsy.comRubyPort::init() 6313531Sjairo.balart@metempsy.com{ 6413531Sjairo.balart@metempsy.com assert(m_controller != NULL); 6513531Sjairo.balart@metempsy.com m_mandatory_q_ptr = m_controller->getMandatoryQueue(); 6613531Sjairo.balart@metempsy.com} 6713531Sjairo.balart@metempsy.com 6813760Sjairo.balart@metempsy.comPort * 6913531Sjairo.balart@metempsy.comRubyPort::getPort(const std::string &if_name, int idx) 7013531Sjairo.balart@metempsy.com{ 7113531Sjairo.balart@metempsy.com if (if_name == "port") { 7213531Sjairo.balart@metempsy.com return new M5Port(csprintf("%s-port%d", name(), idx), this, 7313531Sjairo.balart@metempsy.com ruby_system, access_phys_mem); 7413531Sjairo.balart@metempsy.com } 7513531Sjairo.balart@metempsy.com 7613531Sjairo.balart@metempsy.com if (if_name == "pio_port") { 7713531Sjairo.balart@metempsy.com // ensure there is only one pio port 7813531Sjairo.balart@metempsy.com assert(pio_port == NULL); 7913531Sjairo.balart@metempsy.com 8013531Sjairo.balart@metempsy.com pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx), this); 8113531Sjairo.balart@metempsy.com 8213760Sjairo.balart@metempsy.com return pio_port; 8313531Sjairo.balart@metempsy.com } 8413531Sjairo.balart@metempsy.com 8513531Sjairo.balart@metempsy.com if (if_name == "physMemPort") { 8613531Sjairo.balart@metempsy.com // RubyPort should only have one port to physical memory 8713531Sjairo.balart@metempsy.com assert (physMemPort == NULL); 8813531Sjairo.balart@metempsy.com 8913531Sjairo.balart@metempsy.com physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this, 9013531Sjairo.balart@metempsy.com ruby_system, access_phys_mem); 9113531Sjairo.balart@metempsy.com 9213531Sjairo.balart@metempsy.com return physMemPort; 9313531Sjairo.balart@metempsy.com } 9413531Sjairo.balart@metempsy.com 9513580Sgabeblack@google.com if (if_name == "functional") { 9613531Sjairo.balart@metempsy.com // Calls for the functional port only want to access 9713531Sjairo.balart@metempsy.com // functional memory. Therefore, directly pass these calls 9813580Sgabeblack@google.com // ports to physmem. 9913531Sjairo.balart@metempsy.com assert(physmem != NULL); 10013531Sjairo.balart@metempsy.com return physmem->getPort(if_name, idx); 10113531Sjairo.balart@metempsy.com } 10213531Sjairo.balart@metempsy.com 10313760Sjairo.balart@metempsy.com return NULL; 10413531Sjairo.balart@metempsy.com} 10513531Sjairo.balart@metempsy.com 10613531Sjairo.balart@metempsy.comRubyPort::PioPort::PioPort(const std::string &_name, 10713531Sjairo.balart@metempsy.com RubyPort *_port) 10813531Sjairo.balart@metempsy.com : SimpleTimingPort(_name, _port) 10913531Sjairo.balart@metempsy.com{ 11013531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "creating port to ruby sequencer to cpu %s\n", _name); 11113531Sjairo.balart@metempsy.com ruby_port = _port; 11213531Sjairo.balart@metempsy.com} 11313531Sjairo.balart@metempsy.com 11413531Sjairo.balart@metempsy.comRubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port, 11513531Sjairo.balart@metempsy.com RubySystem *_system, bool _access_phys_mem) 11613531Sjairo.balart@metempsy.com : SimpleTimingPort(_name, _port) 11713531Sjairo.balart@metempsy.com{ 11813531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "creating port from ruby sequcner to cpu %s\n", _name); 11913531Sjairo.balart@metempsy.com ruby_port = _port; 12013531Sjairo.balart@metempsy.com ruby_system = _system; 12113531Sjairo.balart@metempsy.com _onRetryList = false; 12213531Sjairo.balart@metempsy.com access_phys_mem = _access_phys_mem; 12313531Sjairo.balart@metempsy.com} 12413531Sjairo.balart@metempsy.com 12513531Sjairo.balart@metempsy.comTick 12613760Sjairo.balart@metempsy.comRubyPort::PioPort::recvAtomic(PacketPtr pkt) 12713531Sjairo.balart@metempsy.com{ 12813531Sjairo.balart@metempsy.com panic("RubyPort::PioPort::recvAtomic() not implemented!\n"); 12913531Sjairo.balart@metempsy.com return 0; 13013531Sjairo.balart@metempsy.com} 13113531Sjairo.balart@metempsy.com 13213531Sjairo.balart@metempsy.comTick 13313531Sjairo.balart@metempsy.comRubyPort::M5Port::recvAtomic(PacketPtr pkt) 13413531Sjairo.balart@metempsy.com{ 13513531Sjairo.balart@metempsy.com panic("RubyPort::M5Port::recvAtomic() not implemented!\n"); 13613531Sjairo.balart@metempsy.com return 0; 13713531Sjairo.balart@metempsy.com} 13813531Sjairo.balart@metempsy.com 13913531Sjairo.balart@metempsy.com 14013531Sjairo.balart@metempsy.combool 14113531Sjairo.balart@metempsy.comRubyPort::PioPort::recvTiming(PacketPtr pkt) 14213531Sjairo.balart@metempsy.com{ 14313531Sjairo.balart@metempsy.com // In FS mode, ruby memory will receive pio responses from devices 14413531Sjairo.balart@metempsy.com // and it must forward these responses back to the particular CPU. 14513531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Pio response for address %#x\n", pkt->getAddr()); 14613531Sjairo.balart@metempsy.com 14713531Sjairo.balart@metempsy.com assert(pkt->isResponse()); 14813531Sjairo.balart@metempsy.com 14913760Sjairo.balart@metempsy.com // First we must retrieve the request port from the sender State 15013531Sjairo.balart@metempsy.com RubyPort::SenderState *senderState = 15113531Sjairo.balart@metempsy.com safe_cast<RubyPort::SenderState *>(pkt->senderState); 15213531Sjairo.balart@metempsy.com M5Port *port = senderState->port; 15313760Sjairo.balart@metempsy.com assert(port != NULL); 15413531Sjairo.balart@metempsy.com 15513531Sjairo.balart@metempsy.com // pop the sender state from the packet 15613531Sjairo.balart@metempsy.com pkt->senderState = senderState->saved; 15713531Sjairo.balart@metempsy.com delete senderState; 15813531Sjairo.balart@metempsy.com 15913760Sjairo.balart@metempsy.com port->sendTiming(pkt); 16013531Sjairo.balart@metempsy.com 16113531Sjairo.balart@metempsy.com return true; 16213531Sjairo.balart@metempsy.com} 16313760Sjairo.balart@metempsy.com 16413531Sjairo.balart@metempsy.combool 16513531Sjairo.balart@metempsy.comRubyPort::M5Port::recvTiming(PacketPtr pkt) 16613531Sjairo.balart@metempsy.com{ 16713531Sjairo.balart@metempsy.com DPRINTF(RubyPort, 16813531Sjairo.balart@metempsy.com "Timing access caught for address %#x\n", pkt->getAddr()); 16913760Sjairo.balart@metempsy.com 17013760Sjairo.balart@metempsy.com //dsm: based on SimpleTimingPort::recvTiming(pkt); 17113760Sjairo.balart@metempsy.com 17213739Sgiacomo.travaglini@arm.com // The received packets should only be M5 requests, which should never 17313760Sjairo.balart@metempsy.com // get nacked. There used to be code to hanldle nacks here, but 17413760Sjairo.balart@metempsy.com // I'm pretty sure it didn't work correctly with the drain code, 17513531Sjairo.balart@metempsy.com // so that would need to be fixed if we ever added it back. 17613531Sjairo.balart@metempsy.com assert(pkt->isRequest()); 17713531Sjairo.balart@metempsy.com 17813760Sjairo.balart@metempsy.com if (pkt->memInhibitAsserted()) { 17913531Sjairo.balart@metempsy.com warn("memInhibitAsserted???"); 18013531Sjairo.balart@metempsy.com // snooper will supply based on copy of packet 18113531Sjairo.balart@metempsy.com // still target's responsibility to delete packet 18213531Sjairo.balart@metempsy.com delete pkt; 18313531Sjairo.balart@metempsy.com return true; 18413531Sjairo.balart@metempsy.com } 18513760Sjairo.balart@metempsy.com 18613760Sjairo.balart@metempsy.com // Save the port in the sender state object to be used later to 18713760Sjairo.balart@metempsy.com // route the response 18813531Sjairo.balart@metempsy.com pkt->senderState = new SenderState(this, pkt->senderState); 18913760Sjairo.balart@metempsy.com 19013760Sjairo.balart@metempsy.com // Check for pio requests and directly send them to the dedicated 19113531Sjairo.balart@metempsy.com // pio port. 19213531Sjairo.balart@metempsy.com if (!isPhysMemAddress(pkt->getAddr())) { 19313760Sjairo.balart@metempsy.com assert(ruby_port->pio_port != NULL); 19413760Sjairo.balart@metempsy.com DPRINTF(RubyPort, 19513760Sjairo.balart@metempsy.com "Request for address 0x%#x is assumed to be a pio request\n", 19613531Sjairo.balart@metempsy.com pkt->getAddr()); 19713531Sjairo.balart@metempsy.com 19813531Sjairo.balart@metempsy.com return ruby_port->pio_port->sendTiming(pkt); 19913531Sjairo.balart@metempsy.com } 20013531Sjairo.balart@metempsy.com 20113531Sjairo.balart@metempsy.com // For DMA and CPU requests, translate them to ruby requests before 20213531Sjairo.balart@metempsy.com // sending them to our assigned ruby port. 20313531Sjairo.balart@metempsy.com RubyRequestType type = RubyRequestType_NULL; 20413760Sjairo.balart@metempsy.com 20513531Sjairo.balart@metempsy.com // If valid, copy the pc to the ruby request 20613531Sjairo.balart@metempsy.com Addr pc = 0; 20713531Sjairo.balart@metempsy.com if (pkt->req->hasPC()) { 20813531Sjairo.balart@metempsy.com pc = pkt->req->getPC(); 20913531Sjairo.balart@metempsy.com } 21013760Sjairo.balart@metempsy.com 21113531Sjairo.balart@metempsy.com if (pkt->isLLSC()) { 21213531Sjairo.balart@metempsy.com if (pkt->isWrite()) { 21313531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Issuing SC\n"); 21413531Sjairo.balart@metempsy.com type = RubyRequestType_Store_Conditional; 21513531Sjairo.balart@metempsy.com } else { 21613531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Issuing LL\n"); 21713531Sjairo.balart@metempsy.com assert(pkt->isRead()); 21813531Sjairo.balart@metempsy.com type = RubyRequestType_Load_Linked; 21913531Sjairo.balart@metempsy.com } 22013531Sjairo.balart@metempsy.com } else if (pkt->req->isLocked()) { 22113760Sjairo.balart@metempsy.com if (pkt->isWrite()) { 22213531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Issuing Locked RMW Write\n"); 22313531Sjairo.balart@metempsy.com type = RubyRequestType_Locked_RMW_Write; 22413531Sjairo.balart@metempsy.com } else { 22513531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Issuing Locked RMW Read\n"); 22613531Sjairo.balart@metempsy.com assert(pkt->isRead()); 22713760Sjairo.balart@metempsy.com type = RubyRequestType_Locked_RMW_Read; 22813531Sjairo.balart@metempsy.com } 22913531Sjairo.balart@metempsy.com } else { 23013760Sjairo.balart@metempsy.com if (pkt->isRead()) { 23113531Sjairo.balart@metempsy.com if (pkt->req->isInstFetch()) { 23213531Sjairo.balart@metempsy.com type = RubyRequestType_IFETCH; 23313760Sjairo.balart@metempsy.com } else { 23413531Sjairo.balart@metempsy.com#if THE_ISA == X86_ISA 23513531Sjairo.balart@metempsy.com uint32_t flags = pkt->req->getFlags(); 23613531Sjairo.balart@metempsy.com bool storeCheck = flags & 23713531Sjairo.balart@metempsy.com (TheISA::StoreCheck << TheISA::FlagShift); 23813531Sjairo.balart@metempsy.com#else 23913531Sjairo.balart@metempsy.com bool storeCheck = false; 24013760Sjairo.balart@metempsy.com#endif // X86_ISA 24113531Sjairo.balart@metempsy.com if (storeCheck) { 24213531Sjairo.balart@metempsy.com type = RubyRequestType_RMW_Read; 24313531Sjairo.balart@metempsy.com } else { 24413531Sjairo.balart@metempsy.com type = RubyRequestType_LD; 24513531Sjairo.balart@metempsy.com } 24613531Sjairo.balart@metempsy.com } 24713531Sjairo.balart@metempsy.com } else if (pkt->isWrite()) { 24813531Sjairo.balart@metempsy.com // 24913531Sjairo.balart@metempsy.com // Note: M5 packets do not differentiate ST from RMW_Write 25013531Sjairo.balart@metempsy.com // 25113760Sjairo.balart@metempsy.com type = RubyRequestType_ST; 25213531Sjairo.balart@metempsy.com } else if (pkt->isFlush()) { 25313531Sjairo.balart@metempsy.com type = RubyRequestType_FLUSH; 25413531Sjairo.balart@metempsy.com } else { 25513531Sjairo.balart@metempsy.com panic("Unsupported ruby packet type\n"); 25613531Sjairo.balart@metempsy.com } 25713760Sjairo.balart@metempsy.com } 25813531Sjairo.balart@metempsy.com 25913531Sjairo.balart@metempsy.com RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(true), 26013760Sjairo.balart@metempsy.com pkt->getSize(), pc, type, 26113531Sjairo.balart@metempsy.com RubyAccessMode_Supervisor, pkt); 26213531Sjairo.balart@metempsy.com 26313760Sjairo.balart@metempsy.com assert(ruby_request.m_PhysicalAddress.getOffset() + ruby_request.m_Size <= 26413531Sjairo.balart@metempsy.com RubySystem::getBlockSizeBytes()); 26513531Sjairo.balart@metempsy.com 26613531Sjairo.balart@metempsy.com // Submit the ruby request 26713531Sjairo.balart@metempsy.com RequestStatus requestStatus = ruby_port->makeRequest(ruby_request); 26813531Sjairo.balart@metempsy.com 26913531Sjairo.balart@metempsy.com // If the request successfully issued then we should return true. 27013760Sjairo.balart@metempsy.com // Otherwise, we need to delete the senderStatus we just created and return 27113531Sjairo.balart@metempsy.com // false. 27213531Sjairo.balart@metempsy.com if (requestStatus == RequestStatus_Issued) { 27313531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Request %#x issued\n", pkt->getAddr()); 27413531Sjairo.balart@metempsy.com return true; 27513531Sjairo.balart@metempsy.com } 27613531Sjairo.balart@metempsy.com 27713531Sjairo.balart@metempsy.com // 27813531Sjairo.balart@metempsy.com // Unless one is using the ruby tester, record the stalled M5 port for 27913760Sjairo.balart@metempsy.com // later retry when the sequencer becomes free. 28013531Sjairo.balart@metempsy.com // 28113760Sjairo.balart@metempsy.com if (!ruby_port->m_usingRubyTester) { 28213760Sjairo.balart@metempsy.com ruby_port->addToRetryList(this); 28313760Sjairo.balart@metempsy.com } 28413760Sjairo.balart@metempsy.com 28513760Sjairo.balart@metempsy.com DPRINTF(RubyPort, 28613531Sjairo.balart@metempsy.com "Request for address %#x did not issue because %s\n", 28713531Sjairo.balart@metempsy.com pkt->getAddr(), RequestStatus_to_string(requestStatus)); 28813531Sjairo.balart@metempsy.com 28913531Sjairo.balart@metempsy.com SenderState* senderState = safe_cast<SenderState*>(pkt->senderState); 29013531Sjairo.balart@metempsy.com pkt->senderState = senderState->saved; 29113531Sjairo.balart@metempsy.com delete senderState; 29213531Sjairo.balart@metempsy.com return false; 29313760Sjairo.balart@metempsy.com} 29413760Sjairo.balart@metempsy.com 29513760Sjairo.balart@metempsy.combool 29613760Sjairo.balart@metempsy.comRubyPort::M5Port::doFunctionalRead(PacketPtr pkt) 29713760Sjairo.balart@metempsy.com{ 29813531Sjairo.balart@metempsy.com Address address(pkt->getAddr()); 29913531Sjairo.balart@metempsy.com Address line_address(address); 30013531Sjairo.balart@metempsy.com line_address.makeLineAddress(); 30113531Sjairo.balart@metempsy.com 30213531Sjairo.balart@metempsy.com AccessPermission accessPerm = AccessPermission_NotPresent; 30313760Sjairo.balart@metempsy.com int num_controllers = ruby_system->m_abs_cntrl_vec.size(); 30413760Sjairo.balart@metempsy.com 30513760Sjairo.balart@metempsy.com // In this loop, we try to figure which controller has a read only or 30613760Sjairo.balart@metempsy.com // a read write copy of the given address. Any valid copy would suffice 30713760Sjairo.balart@metempsy.com // for a functional read. 30813531Sjairo.balart@metempsy.com 30913531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Functional Read request for %s\n",address); 31013531Sjairo.balart@metempsy.com for(int i = 0;i < num_controllers;++i) 31113531Sjairo.balart@metempsy.com { 31213531Sjairo.balart@metempsy.com accessPerm = ruby_system->m_abs_cntrl_vec[i] 31313531Sjairo.balart@metempsy.com ->getAccessPermission(line_address); 31413531Sjairo.balart@metempsy.com if(accessPerm == AccessPermission_Read_Only || 31513531Sjairo.balart@metempsy.com accessPerm == AccessPermission_Read_Write) 31613531Sjairo.balart@metempsy.com { 31713531Sjairo.balart@metempsy.com unsigned startByte = address.getAddress() - line_address.getAddress(); 31813531Sjairo.balart@metempsy.com 31913531Sjairo.balart@metempsy.com uint8* data = pkt->getPtr<uint8_t>(true); 32013531Sjairo.balart@metempsy.com unsigned int size_in_bytes = pkt->getSize(); 32113531Sjairo.balart@metempsy.com DataBlock& block = ruby_system->m_abs_cntrl_vec[i] 32213531Sjairo.balart@metempsy.com ->getDataBlock(line_address); 32313531Sjairo.balart@metempsy.com 32413531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "reading from %s block %s\n", 32513531Sjairo.balart@metempsy.com ruby_system->m_abs_cntrl_vec[i]->name(), block); 32613531Sjairo.balart@metempsy.com for (unsigned i = 0; i < size_in_bytes; ++i) 32713531Sjairo.balart@metempsy.com { 32813531Sjairo.balart@metempsy.com data[i] = block.getByte(i + startByte); 32913531Sjairo.balart@metempsy.com } 33013531Sjairo.balart@metempsy.com return true; 33113760Sjairo.balart@metempsy.com } 33213760Sjairo.balart@metempsy.com } 33313760Sjairo.balart@metempsy.com return false; 33413531Sjairo.balart@metempsy.com} 33513531Sjairo.balart@metempsy.com 33613531Sjairo.balart@metempsy.combool 33713531Sjairo.balart@metempsy.comRubyPort::M5Port::doFunctionalWrite(PacketPtr pkt) 33813760Sjairo.balart@metempsy.com{ 33913531Sjairo.balart@metempsy.com Address addr(pkt->getAddr()); 34013531Sjairo.balart@metempsy.com Address line_addr = line_address(addr); 34113531Sjairo.balart@metempsy.com AccessPermission accessPerm = AccessPermission_NotPresent; 34213760Sjairo.balart@metempsy.com int num_controllers = ruby_system->m_abs_cntrl_vec.size(); 34313760Sjairo.balart@metempsy.com 34413531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Functional Write request for %s\n",addr); 34513531Sjairo.balart@metempsy.com 34613531Sjairo.balart@metempsy.com unsigned int num_ro = 0; 34713531Sjairo.balart@metempsy.com unsigned int num_rw = 0; 34813531Sjairo.balart@metempsy.com unsigned int num_busy = 0; 34913531Sjairo.balart@metempsy.com 35013531Sjairo.balart@metempsy.com // In this loop we count the number of controllers that have the given 35113760Sjairo.balart@metempsy.com // address in read only, read write and busy states. 35213531Sjairo.balart@metempsy.com for(int i = 0;i < num_controllers;++i) 35313760Sjairo.balart@metempsy.com { 35413531Sjairo.balart@metempsy.com accessPerm = ruby_system->m_abs_cntrl_vec[i]-> 35513531Sjairo.balart@metempsy.com getAccessPermission(line_addr); 35613531Sjairo.balart@metempsy.com if(accessPerm == AccessPermission_Read_Only) num_ro++; 35713531Sjairo.balart@metempsy.com else if(accessPerm == AccessPermission_Read_Write) num_rw++; 35813531Sjairo.balart@metempsy.com else if(accessPerm == AccessPermission_Busy) num_busy++; 35913531Sjairo.balart@metempsy.com } 36013531Sjairo.balart@metempsy.com 36113531Sjairo.balart@metempsy.com // If the number of read write copies is more than 1, then there is bug in 36213531Sjairo.balart@metempsy.com // coherence protocol. Otherwise, if all copies are in stable states, i.e. 36313531Sjairo.balart@metempsy.com // num_busy == 0, we update all the copies. If there is at least one copy 36413531Sjairo.balart@metempsy.com // in busy state, then we check if there is read write copy. If yes, then 36513531Sjairo.balart@metempsy.com // also we let the access go through. 36613531Sjairo.balart@metempsy.com 36713531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "num_busy = %d, num_ro = %d, num_rw = %d\n", 36813760Sjairo.balart@metempsy.com num_busy, num_ro, num_rw); 36913531Sjairo.balart@metempsy.com assert(num_rw <= 1); 37013760Sjairo.balart@metempsy.com if((num_busy == 0 && num_ro > 0) || num_rw == 1) 37113760Sjairo.balart@metempsy.com { 37213760Sjairo.balart@metempsy.com uint8* data = pkt->getPtr<uint8_t>(true); 37313531Sjairo.balart@metempsy.com unsigned int size_in_bytes = pkt->getSize(); 37413531Sjairo.balart@metempsy.com unsigned startByte = addr.getAddress() - line_addr.getAddress(); 37513531Sjairo.balart@metempsy.com 37613760Sjairo.balart@metempsy.com for(int i = 0; i < num_controllers;++i) 37713760Sjairo.balart@metempsy.com { 37813760Sjairo.balart@metempsy.com accessPerm = ruby_system->m_abs_cntrl_vec[i]-> 37913531Sjairo.balart@metempsy.com getAccessPermission(line_addr); 38013760Sjairo.balart@metempsy.com if(accessPerm == AccessPermission_Read_Only || 38113760Sjairo.balart@metempsy.com accessPerm == AccessPermission_Read_Write|| 38213531Sjairo.balart@metempsy.com accessPerm == AccessPermission_Maybe_Stale) 38313531Sjairo.balart@metempsy.com { 38413760Sjairo.balart@metempsy.com DataBlock& block = ruby_system->m_abs_cntrl_vec[i] 38513760Sjairo.balart@metempsy.com ->getDataBlock(line_addr); 38613760Sjairo.balart@metempsy.com 38713531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "%s\n",block); 38813531Sjairo.balart@metempsy.com for (unsigned i = 0; i < size_in_bytes; ++i) 38913531Sjairo.balart@metempsy.com { 39013531Sjairo.balart@metempsy.com block.setByte(i + startByte, data[i]); 39113531Sjairo.balart@metempsy.com } 39213531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "%s\n",block); 39313760Sjairo.balart@metempsy.com } 39413531Sjairo.balart@metempsy.com } 39513760Sjairo.balart@metempsy.com return true; 39613531Sjairo.balart@metempsy.com } 39713531Sjairo.balart@metempsy.com return false; 39813531Sjairo.balart@metempsy.com} 39913531Sjairo.balart@metempsy.com 40013531Sjairo.balart@metempsy.comvoid 40113531Sjairo.balart@metempsy.comRubyPort::M5Port::recvFunctional(PacketPtr pkt) 40213531Sjairo.balart@metempsy.com{ 40313531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Functional access caught for address %#x\n", 40413531Sjairo.balart@metempsy.com pkt->getAddr()); 40513531Sjairo.balart@metempsy.com 40613531Sjairo.balart@metempsy.com // Check for pio requests and directly send them to the dedicated 40713531Sjairo.balart@metempsy.com // pio port. 40813531Sjairo.balart@metempsy.com if (!isPhysMemAddress(pkt->getAddr())) { 40913531Sjairo.balart@metempsy.com assert(ruby_port->pio_port != NULL); 41013531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Request for address 0x%#x is a pio request\n", 41113531Sjairo.balart@metempsy.com pkt->getAddr()); 41213531Sjairo.balart@metempsy.com panic("RubyPort::PioPort::recvFunctional() not implemented!\n"); 41313531Sjairo.balart@metempsy.com } 41413531Sjairo.balart@metempsy.com 41513531Sjairo.balart@metempsy.com assert(pkt->getAddr() + pkt->getSize() <= 41613531Sjairo.balart@metempsy.com line_address(Address(pkt->getAddr())).getAddress() + 41713760Sjairo.balart@metempsy.com RubySystem::getBlockSizeBytes()); 41813531Sjairo.balart@metempsy.com 41913531Sjairo.balart@metempsy.com bool accessSucceeded = false; 42013531Sjairo.balart@metempsy.com bool needsResponse = pkt->needsResponse(); 42113531Sjairo.balart@metempsy.com 42213531Sjairo.balart@metempsy.com // Do the functional access on ruby memory 42313760Sjairo.balart@metempsy.com if (pkt->isRead()) { 42413531Sjairo.balart@metempsy.com accessSucceeded = doFunctionalRead(pkt); 42513531Sjairo.balart@metempsy.com } else if (pkt->isWrite()) { 42613760Sjairo.balart@metempsy.com accessSucceeded = doFunctionalWrite(pkt); 42713760Sjairo.balart@metempsy.com } else { 42813531Sjairo.balart@metempsy.com panic("RubyPort: unsupported functional command %s\n", 42913531Sjairo.balart@metempsy.com pkt->cmdString()); 43013760Sjairo.balart@metempsy.com } 43113531Sjairo.balart@metempsy.com 43213531Sjairo.balart@metempsy.com // Unless the requester explicitly said otherwise, generate an error if 43313531Sjairo.balart@metempsy.com // the functional request failed 43413531Sjairo.balart@metempsy.com if (!accessSucceeded && !pkt->suppressFuncError()) { 43513531Sjairo.balart@metempsy.com fatal("Ruby functional %s failed for address %#x\n", 43613760Sjairo.balart@metempsy.com pkt->isWrite() ? "write" : "read", pkt->getAddr()); 43713531Sjairo.balart@metempsy.com } 43813760Sjairo.balart@metempsy.com 43913531Sjairo.balart@metempsy.com if (access_phys_mem) { 44013531Sjairo.balart@metempsy.com // The attached physmem contains the official version of data. 44113531Sjairo.balart@metempsy.com // The following command performs the real functional access. 44213531Sjairo.balart@metempsy.com // This line should be removed once Ruby supplies the official version 44313531Sjairo.balart@metempsy.com // of data. 44413531Sjairo.balart@metempsy.com ruby_port->physMemPort->sendFunctional(pkt); 44513531Sjairo.balart@metempsy.com } 44613531Sjairo.balart@metempsy.com 44713531Sjairo.balart@metempsy.com // turn packet around to go back to requester if response expected 44813760Sjairo.balart@metempsy.com if (needsResponse) { 44913531Sjairo.balart@metempsy.com pkt->setFunctionalResponseStatus(accessSucceeded); 45013760Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Sending packet back over port\n"); 45113531Sjairo.balart@metempsy.com sendFunctional(pkt); 45213531Sjairo.balart@metempsy.com } 45313531Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Functional access %s!\n", 45413531Sjairo.balart@metempsy.com accessSucceeded ? "successful":"failed"); 45513531Sjairo.balart@metempsy.com} 45613531Sjairo.balart@metempsy.com 45713531Sjairo.balart@metempsy.comvoid 45813531Sjairo.balart@metempsy.comRubyPort::ruby_hit_callback(PacketPtr pkt) 45913531Sjairo.balart@metempsy.com{ 46013531Sjairo.balart@metempsy.com // Retrieve the request port from the sender State 46113531Sjairo.balart@metempsy.com RubyPort::SenderState *senderState = 46213531Sjairo.balart@metempsy.com safe_cast<RubyPort::SenderState *>(pkt->senderState); 46313531Sjairo.balart@metempsy.com M5Port *port = senderState->port; 46413531Sjairo.balart@metempsy.com assert(port != NULL); 46513531Sjairo.balart@metempsy.com 46613531Sjairo.balart@metempsy.com // pop the sender state from the packet 46713531Sjairo.balart@metempsy.com pkt->senderState = senderState->saved; 46813531Sjairo.balart@metempsy.com delete senderState; 46913531Sjairo.balart@metempsy.com 47013531Sjairo.balart@metempsy.com port->hitCallback(pkt); 47113531Sjairo.balart@metempsy.com 47213760Sjairo.balart@metempsy.com // 47313531Sjairo.balart@metempsy.com // If we had to stall the M5Ports, wake them up because the sequencer 47413531Sjairo.balart@metempsy.com // likely has free resources now. 47513531Sjairo.balart@metempsy.com // 47613531Sjairo.balart@metempsy.com if (waitingOnSequencer) { 47713531Sjairo.balart@metempsy.com // 47813760Sjairo.balart@metempsy.com // Record the current list of ports to retry on a temporary list before 47913531Sjairo.balart@metempsy.com // calling sendRetry on those ports. sendRetry will cause an 48013531Sjairo.balart@metempsy.com // immediate retry, which may result in the ports being put back on the 48113760Sjairo.balart@metempsy.com // list. Therefore we want to clear the retryList before calling 48213760Sjairo.balart@metempsy.com // sendRetry. 48313531Sjairo.balart@metempsy.com // 48413531Sjairo.balart@metempsy.com std::list<M5Port*> curRetryList(retryList); 48513760Sjairo.balart@metempsy.com 48613531Sjairo.balart@metempsy.com retryList.clear(); 48713531Sjairo.balart@metempsy.com waitingOnSequencer = false; 48813531Sjairo.balart@metempsy.com 48913531Sjairo.balart@metempsy.com for (std::list<M5Port*>::iterator i = curRetryList.begin(); 49013531Sjairo.balart@metempsy.com i != curRetryList.end(); ++i) { 49113760Sjairo.balart@metempsy.com DPRINTF(RubyPort, 49213531Sjairo.balart@metempsy.com "Sequencer may now be free. SendRetry to port %s\n", 49313760Sjairo.balart@metempsy.com (*i)->name()); 49413531Sjairo.balart@metempsy.com (*i)->onRetryList(false); 49513531Sjairo.balart@metempsy.com (*i)->sendRetry(); 49613531Sjairo.balart@metempsy.com } 49713531Sjairo.balart@metempsy.com } 49813531Sjairo.balart@metempsy.com} 49913531Sjairo.balart@metempsy.com 50013531Sjairo.balart@metempsy.comvoid 50113531Sjairo.balart@metempsy.comRubyPort::M5Port::hitCallback(PacketPtr pkt) 50213531Sjairo.balart@metempsy.com{ 50313760Sjairo.balart@metempsy.com bool needsResponse = pkt->needsResponse(); 50413531Sjairo.balart@metempsy.com 50513760Sjairo.balart@metempsy.com // 50613531Sjairo.balart@metempsy.com // Unless specified at configuraiton, all responses except failed SC 50713531Sjairo.balart@metempsy.com // and Flush operations access M5 physical memory. 50813531Sjairo.balart@metempsy.com // 50913531Sjairo.balart@metempsy.com bool accessPhysMem = access_phys_mem; 51013531Sjairo.balart@metempsy.com 51113760Sjairo.balart@metempsy.com if (pkt->isLLSC()) { 51213760Sjairo.balart@metempsy.com if (pkt->isWrite()) { 51313760Sjairo.balart@metempsy.com if (pkt->req->getExtraData() != 0) { 51413760Sjairo.balart@metempsy.com // 51513760Sjairo.balart@metempsy.com // Successful SC packets convert to normal writes 51613760Sjairo.balart@metempsy.com // 51713760Sjairo.balart@metempsy.com pkt->convertScToWrite(); 51813760Sjairo.balart@metempsy.com } else { 51913760Sjairo.balart@metempsy.com // 52013760Sjairo.balart@metempsy.com // Failed SC packets don't access physical memory and thus 52113760Sjairo.balart@metempsy.com // the RubyPort itself must convert it to a response. 52213531Sjairo.balart@metempsy.com // 52313531Sjairo.balart@metempsy.com accessPhysMem = false; 52413760Sjairo.balart@metempsy.com } 52513531Sjairo.balart@metempsy.com } else { 52613531Sjairo.balart@metempsy.com // 52713531Sjairo.balart@metempsy.com // All LL packets convert to normal loads so that M5 PhysMem does 52813531Sjairo.balart@metempsy.com // not lock the blocks. 52913760Sjairo.balart@metempsy.com // 53013760Sjairo.balart@metempsy.com pkt->convertLlToRead(); 53113760Sjairo.balart@metempsy.com } 53213760Sjairo.balart@metempsy.com } 53313760Sjairo.balart@metempsy.com 53413760Sjairo.balart@metempsy.com // 53513531Sjairo.balart@metempsy.com // Flush requests don't access physical memory 53613760Sjairo.balart@metempsy.com // 53713760Sjairo.balart@metempsy.com if (pkt->isFlush()) { 53813760Sjairo.balart@metempsy.com accessPhysMem = false; 53913760Sjairo.balart@metempsy.com } 54013760Sjairo.balart@metempsy.com 54113760Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse); 54213760Sjairo.balart@metempsy.com 54313760Sjairo.balart@metempsy.com if (accessPhysMem) { 54413760Sjairo.balart@metempsy.com ruby_port->physMemPort->sendAtomic(pkt); 54513760Sjairo.balart@metempsy.com } else if (needsResponse) { 54613760Sjairo.balart@metempsy.com pkt->makeResponse(); 54713760Sjairo.balart@metempsy.com } 54813760Sjairo.balart@metempsy.com 54913760Sjairo.balart@metempsy.com // turn packet around to go back to requester if response expected 55013760Sjairo.balart@metempsy.com if (needsResponse) { 55113760Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Sending packet back over port\n"); 55213760Sjairo.balart@metempsy.com sendTiming(pkt); 55313760Sjairo.balart@metempsy.com } else { 55413760Sjairo.balart@metempsy.com delete pkt; 55513760Sjairo.balart@metempsy.com } 55613760Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Hit callback done!\n"); 55713760Sjairo.balart@metempsy.com} 55813760Sjairo.balart@metempsy.com 55913760Sjairo.balart@metempsy.combool 56013531Sjairo.balart@metempsy.comRubyPort::M5Port::sendTiming(PacketPtr pkt) 56113760Sjairo.balart@metempsy.com{ 56213760Sjairo.balart@metempsy.com //minimum latency, must be > 0 56313531Sjairo.balart@metempsy.com schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock())); 56413531Sjairo.balart@metempsy.com return true; 56513531Sjairo.balart@metempsy.com} 56613760Sjairo.balart@metempsy.com 56713760Sjairo.balart@metempsy.combool 56813760Sjairo.balart@metempsy.comRubyPort::PioPort::sendTiming(PacketPtr pkt) 56913760Sjairo.balart@metempsy.com{ 57013760Sjairo.balart@metempsy.com //minimum latency, must be > 0 57113760Sjairo.balart@metempsy.com schedSendTiming(pkt, curTick() + (1 * g_eventQueue_ptr->getClock())); 57213531Sjairo.balart@metempsy.com return true; 57313531Sjairo.balart@metempsy.com} 57413760Sjairo.balart@metempsy.com 57513760Sjairo.balart@metempsy.combool 57613760Sjairo.balart@metempsy.comRubyPort::M5Port::isPhysMemAddress(Addr addr) 57713760Sjairo.balart@metempsy.com{ 57813760Sjairo.balart@metempsy.com AddrRangeList physMemAddrList; 57913760Sjairo.balart@metempsy.com bool snoop = false; 58013760Sjairo.balart@metempsy.com ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop); 58113760Sjairo.balart@metempsy.com for (AddrRangeIter iter = physMemAddrList.begin(); 58213531Sjairo.balart@metempsy.com iter != physMemAddrList.end(); 58313531Sjairo.balart@metempsy.com iter++) { 58413531Sjairo.balart@metempsy.com if (addr >= iter->start && addr <= iter->end) { 58513760Sjairo.balart@metempsy.com DPRINTF(RubyPort, "Request found in %#llx - %#llx range\n", 58613531Sjairo.balart@metempsy.com iter->start, iter->end); 58713760Sjairo.balart@metempsy.com return true; 58813760Sjairo.balart@metempsy.com } 58913760Sjairo.balart@metempsy.com } 59013760Sjairo.balart@metempsy.com return false; 59113760Sjairo.balart@metempsy.com} 59213760Sjairo.balart@metempsy.com 59313760Sjairo.balart@metempsy.comunsigned 59413531Sjairo.balart@metempsy.comRubyPort::M5Port::deviceBlockSize() const 59513531Sjairo.balart@metempsy.com{ 59613531Sjairo.balart@metempsy.com return (unsigned) RubySystem::getBlockSizeBytes(); 59713760Sjairo.balart@metempsy.com} 59813531Sjairo.balart@metempsy.com