16145SN/A/* 28688SN/A * Copyright (c) 1999-2011 Mark D. Hill and David A. Wood 36145SN/A * All rights reserved. 46145SN/A * 56145SN/A * Redistribution and use in source and binary forms, with or without 66145SN/A * modification, are permitted provided that the following conditions are 76145SN/A * met: redistributions of source code must retain the above copyright 86145SN/A * notice, this list of conditions and the following disclaimer; 96145SN/A * redistributions in binary form must reproduce the above copyright 106145SN/A * notice, this list of conditions and the following disclaimer in the 116145SN/A * documentation and/or other materials provided with the distribution; 126145SN/A * neither the name of the copyright holders nor the names of its 136145SN/A * contributors may be used to endorse or promote products derived from 146145SN/A * this software without specific prior written permission. 156145SN/A * 166145SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176145SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186145SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196145SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206145SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216145SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226145SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236145SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246145SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256145SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266145SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276145SN/A */ 286145SN/A 2911108Sdavid.hashe@amd.com#include "mem/ruby/system/RubySystem.hh" 3011108Sdavid.hashe@amd.com 318688SN/A#include <fcntl.h> 328688SN/A#include <zlib.h> 338688SN/A 348688SN/A#include <cstdio> 3510991SN/A#include <list> 368688SN/A 377056SN/A#include "base/intmath.hh" 389350SN/A#include "base/statistics.hh" 398937SN/A#include "debug/RubyCacheTrace.hh" 409270SN/A#include "debug/RubySystem.hh" 417039SN/A#include "mem/ruby/common/Address.hh" 427039SN/A#include "mem/ruby/network/Network.hh" 4310706SN/A#include "mem/simple_mem.hh" 448937SN/A#include "sim/eventq.hh" 458688SN/A#include "sim/simulate.hh" 466145SN/A 477055SN/Ausing namespace std; 487055SN/A 496285SN/Abool RubySystem::m_randomization; 509504SN/Auint32_t RubySystem::m_block_size_bytes; 519504SN/Auint32_t RubySystem::m_block_size_bits; 529504SN/Auint32_t RubySystem::m_memory_size_bits; 5310837SN/Abool RubySystem::m_warmup_enabled = false; 5410837SN/A// To look forward to allowing multiple RubySystem instances, track the number 5510837SN/A// of RubySystems that need to be warmed up on checkpoint restore. 5610837SN/Aunsigned RubySystem::m_systems_to_warmup = 0; 5710837SN/Abool RubySystem::m_cooldown_enabled = false; 586285SN/A 596876SN/ARubySystem::RubySystem(const Params *p) 6010991SN/A : ClockedObject(p), m_access_backing_store(p->access_backing_store), 6110991SN/A m_cache_recorder(NULL) 626145SN/A{ 636876SN/A m_randomization = p->randomization; 646880SN/A 656876SN/A m_block_size_bytes = p->block_size_bytes; 667056SN/A assert(isPowerOf2(m_block_size_bytes)); 677056SN/A m_block_size_bits = floorLog2(m_block_size_bytes); 6810524SN/A m_memory_size_bits = p->memory_size_bits; 696895SN/A 709496SN/A // Resize to the size of different machine types 7110920SN/A m_abstract_controls.resize(MachineType_NUM); 7210012SN/A 7310012SN/A // Collate the statistics before they are printed. 7410012SN/A Stats::registerDumpCallback(new RubyStatsCallback(this)); 7510012SN/A // Create the profiler 7610920SN/A m_profiler = new Profiler(p, this); 7710525SN/A m_phys_mem = p->phys_mem; 786165SN/A} 796165SN/A 807039SN/Avoid 818436SN/ARubySystem::registerNetwork(Network* network_ptr) 828436SN/A{ 8310917SN/A m_network = network_ptr; 848436SN/A} 858436SN/A 868436SN/Avoid 878436SN/ARubySystem::registerAbstractController(AbstractController* cntrl) 888436SN/A{ 8910917SN/A m_abs_cntrl_vec.push_back(cntrl); 909496SN/A 9110917SN/A MachineID id = cntrl->getMachineID(); 9210920SN/A m_abstract_controls[id.getType()][id.getNum()] = cntrl; 938436SN/A} 948436SN/A 956165SN/ARubySystem::~RubySystem() 966165SN/A{ 9710012SN/A delete m_network; 9810012SN/A delete m_profiler; 996145SN/A} 1006145SN/A 1017039SN/Avoid 10210991SN/ARubySystem::makeCacheRecorder(uint8_t *uncompressed_trace, 10311061SN/A uint64_t cache_trace_size, 10411061SN/A uint64_t block_size_bytes) 10510991SN/A{ 10610991SN/A vector<Sequencer*> sequencer_map; 10710991SN/A Sequencer* sequencer_ptr = NULL; 10810991SN/A 10910991SN/A for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 11011308Santhony.gutierrez@amd.com sequencer_map.push_back(m_abs_cntrl_vec[cntrl]->getCPUSequencer()); 11110991SN/A if (sequencer_ptr == NULL) { 11210991SN/A sequencer_ptr = sequencer_map[cntrl]; 11310991SN/A } 11410991SN/A } 11510991SN/A 11610991SN/A assert(sequencer_ptr != NULL); 11710991SN/A 11810991SN/A for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 11910991SN/A if (sequencer_map[cntrl] == NULL) { 12010991SN/A sequencer_map[cntrl] = sequencer_ptr; 12110991SN/A } 12210991SN/A } 12310991SN/A 12410991SN/A // Remove the old CacheRecorder if it's still hanging about. 12510991SN/A if (m_cache_recorder != NULL) { 12610991SN/A delete m_cache_recorder; 12710991SN/A } 12810991SN/A 12910991SN/A // Create the CacheRecorder and record the cache trace 13010991SN/A m_cache_recorder = new CacheRecorder(uncompressed_trace, cache_trace_size, 13110991SN/A sequencer_map, block_size_bytes); 13210991SN/A} 13310991SN/A 13410991SN/Avoid 13510991SN/ARubySystem::memWriteback() 13610991SN/A{ 13710991SN/A m_cooldown_enabled = true; 13810991SN/A 13910991SN/A // Make the trace so we know what to write back. 14010991SN/A DPRINTF(RubyCacheTrace, "Recording Cache Trace\n"); 14110991SN/A makeCacheRecorder(NULL, 0, getBlockSizeBytes()); 14210991SN/A for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 14310991SN/A m_abs_cntrl_vec[cntrl]->recordCacheTrace(cntrl, m_cache_recorder); 14410991SN/A } 14510991SN/A DPRINTF(RubyCacheTrace, "Cache Trace Complete\n"); 14610991SN/A 14710991SN/A // save the current tick value 14810991SN/A Tick curtick_original = curTick(); 14910991SN/A DPRINTF(RubyCacheTrace, "Recording current tick %ld\n", curtick_original); 15010991SN/A 15110991SN/A // Deschedule all prior events on the event queue, but record the tick they 15210991SN/A // were scheduled at so they can be restored correctly later. 15310991SN/A list<pair<Event*, Tick> > original_events; 15410991SN/A while (!eventq->empty()) { 15510991SN/A Event *curr_head = eventq->getHead(); 15610991SN/A if (curr_head->isAutoDelete()) { 15710991SN/A DPRINTF(RubyCacheTrace, "Event %s auto-deletes when descheduled," 15810991SN/A " not recording\n", curr_head->name()); 15910991SN/A } else { 16010991SN/A original_events.push_back(make_pair(curr_head, curr_head->when())); 16110991SN/A } 16210991SN/A eventq->deschedule(curr_head); 16310991SN/A } 16410991SN/A 16510991SN/A // Schedule an event to start cache cooldown 16610991SN/A DPRINTF(RubyCacheTrace, "Starting cache flush\n"); 16710991SN/A enqueueRubyEvent(curTick()); 16810991SN/A simulate(); 16910991SN/A DPRINTF(RubyCacheTrace, "Cache flush complete\n"); 17010991SN/A 17110991SN/A // Deschedule any events left on the event queue. 17210991SN/A while (!eventq->empty()) { 17310991SN/A eventq->deschedule(eventq->getHead()); 17410991SN/A } 17510991SN/A 17610991SN/A // Restore curTick 17710991SN/A setCurTick(curtick_original); 17810991SN/A 17910991SN/A // Restore all events that were originally on the event queue. This is 18010991SN/A // done after setting curTick back to its original value so that events do 18110991SN/A // not seem to be scheduled in the past. 18210991SN/A while (!original_events.empty()) { 18310991SN/A pair<Event*, Tick> event = original_events.back(); 18410991SN/A eventq->schedule(event.first, event.second); 18510991SN/A original_events.pop_back(); 18610991SN/A } 18710991SN/A 18810991SN/A // No longer flushing back to memory. 18910991SN/A m_cooldown_enabled = false; 19010991SN/A 19110991SN/A // There are several issues with continuing simulation after calling 19210991SN/A // memWriteback() at the moment, that stem from taking events off the 19310991SN/A // queue, simulating again, and then putting them back on, whilst 19410991SN/A // pretending that no time has passed. One is that some events will have 19510991SN/A // been deleted, so can't be put back. Another is that any object 19610991SN/A // recording the tick something happens may end up storing a tick in the 19710991SN/A // future. A simple warning here alerts the user that things may not work 19810991SN/A // as expected. 19910991SN/A warn_once("Ruby memory writeback is experimental. Continuing simulation " 20010991SN/A "afterwards may not always work as intended."); 20110991SN/A 20210991SN/A // Keep the cache recorder around so that we can dump the trace if a 20310991SN/A // checkpoint is immediately taken. 20410991SN/A} 20510991SN/A 20610991SN/Avoid 2079208SN/ARubySystem::writeCompressedTrace(uint8_t *raw_data, string filename, 20811061SN/A uint64_t uncompressed_trace_size) 2098688SN/A{ 2108688SN/A // Create the checkpoint file for the memory 21110905SN/A string thefile = CheckpointIn::dir() + "/" + filename.c_str(); 2128688SN/A 2138688SN/A int fd = creat(thefile.c_str(), 0664); 2148688SN/A if (fd < 0) { 2158688SN/A perror("creat"); 2168688SN/A fatal("Can't open memory trace file '%s'\n", filename); 2178688SN/A } 2188688SN/A 2198688SN/A gzFile compressedMemory = gzdopen(fd, "wb"); 2208688SN/A if (compressedMemory == NULL) 2218688SN/A fatal("Insufficient memory to allocate compression state for %s\n", 2228688SN/A filename); 2238688SN/A 2248688SN/A if (gzwrite(compressedMemory, raw_data, uncompressed_trace_size) != 2258688SN/A uncompressed_trace_size) { 2268688SN/A fatal("Write failed on memory trace file '%s'\n", filename); 2278688SN/A } 2288688SN/A 2298688SN/A if (gzclose(compressedMemory)) { 2308688SN/A fatal("Close failed on memory trace file '%s'\n", filename); 2318688SN/A } 23210422SN/A delete[] raw_data; 2338688SN/A} 2348688SN/A 2358688SN/Avoid 23611060SN/ARubySystem::serialize(CheckpointOut &cp) const 2377562SN/A{ 23810163SN/A // Store the cache-block size, so we are able to restore on systems with a 23910163SN/A // different cache-block size. CacheRecorder depends on the correct 24010163SN/A // cache-block size upon unserializing. 24111061SN/A uint64_t block_size_bytes = getBlockSizeBytes(); 24210163SN/A SERIALIZE_SCALAR(block_size_bytes); 24310163SN/A 24410991SN/A // Check that there's a valid trace to use. If not, then memory won't be 24510991SN/A // up-to-date and the simulation will probably fail when restoring from the 24610991SN/A // checkpoint. 24710991SN/A if (m_cache_recorder == NULL) { 24810991SN/A fatal("Call memWriteback() before serialize() to create ruby trace"); 2498688SN/A } 2508688SN/A 25110917SN/A // Aggregate the trace entries together into a single array 25210524SN/A uint8_t *raw_data = new uint8_t[4096]; 25311061SN/A uint64_t cache_trace_size = m_cache_recorder->aggregateRecords(&raw_data, 2548688SN/A 4096); 2558688SN/A string cache_trace_file = name() + ".cache.gz"; 2568688SN/A writeCompressedTrace(raw_data, cache_trace_file, cache_trace_size); 2578688SN/A 2588688SN/A SERIALIZE_SCALAR(cache_trace_file); 2598688SN/A SERIALIZE_SCALAR(cache_trace_size); 26011060SN/A} 2618688SN/A 26211060SN/Avoid 26311060SN/ARubySystem::drainResume() 26411060SN/A{ 26511060SN/A // Delete the cache recorder if it was created in memWriteback() 26611060SN/A // to checkpoint the current cache state. 26711060SN/A if (m_cache_recorder) { 26811060SN/A delete m_cache_recorder; 26911060SN/A m_cache_recorder = NULL; 27011060SN/A } 2718688SN/A} 2728688SN/A 2738688SN/Avoid 2749208SN/ARubySystem::readCompressedTrace(string filename, uint8_t *&raw_data, 27511061SN/A uint64_t &uncompressed_trace_size) 2768688SN/A{ 2778688SN/A // Read the trace file 2788688SN/A gzFile compressedTrace; 2798688SN/A 2808688SN/A // trace file 2818688SN/A int fd = open(filename.c_str(), O_RDONLY); 2828688SN/A if (fd < 0) { 2838688SN/A perror("open"); 2848688SN/A fatal("Unable to open trace file %s", filename); 2858688SN/A } 2868688SN/A 2878688SN/A compressedTrace = gzdopen(fd, "rb"); 2888688SN/A if (compressedTrace == NULL) { 2898688SN/A fatal("Insufficient memory to allocate compression state for %s\n", 2908688SN/A filename); 2918688SN/A } 2928688SN/A 2938688SN/A raw_data = new uint8_t[uncompressed_trace_size]; 2948688SN/A if (gzread(compressedTrace, raw_data, uncompressed_trace_size) < 2958688SN/A uncompressed_trace_size) { 2968688SN/A fatal("Unable to read complete trace from file %s\n", filename); 2978688SN/A } 2988688SN/A 2998688SN/A if (gzclose(compressedTrace)) { 3008688SN/A fatal("Failed to close cache trace file '%s'\n", filename); 3018688SN/A } 3027562SN/A} 3037562SN/A 3047562SN/Avoid 30510905SN/ARubySystem::unserialize(CheckpointIn &cp) 3067562SN/A{ 3079208SN/A uint8_t *uncompressed_trace = NULL; 3088688SN/A 30910163SN/A // This value should be set to the checkpoint-system's block-size. 31010163SN/A // Optional, as checkpoints without it can be run if the 31110163SN/A // checkpoint-system's block-size == current block-size. 31211061SN/A uint64_t block_size_bytes = getBlockSizeBytes(); 31310163SN/A UNSERIALIZE_OPT_SCALAR(block_size_bytes); 31410163SN/A 3158688SN/A string cache_trace_file; 31611061SN/A uint64_t cache_trace_size = 0; 3178688SN/A 3188688SN/A UNSERIALIZE_SCALAR(cache_trace_file); 3198688SN/A UNSERIALIZE_SCALAR(cache_trace_size); 32010905SN/A cache_trace_file = cp.cptDir + "/" + cache_trace_file; 3218688SN/A 3228688SN/A readCompressedTrace(cache_trace_file, uncompressed_trace, 3238688SN/A cache_trace_size); 3248688SN/A m_warmup_enabled = true; 32510837SN/A m_systems_to_warmup++; 3268688SN/A 32710991SN/A // Create the cache recorder that will hang around until startup. 32810991SN/A makeCacheRecorder(uncompressed_trace, cache_trace_size, block_size_bytes); 3298688SN/A} 3308688SN/A 3318688SN/Avoid 3328688SN/ARubySystem::startup() 3338688SN/A{ 3349670SN/A 3359670SN/A // Ruby restores state from a checkpoint by resetting the clock to 0 and 3369670SN/A // playing the requests that can possibly re-generate the cache state. 3379670SN/A // The clock value is set to the actual checkpointed value once all the 3389670SN/A // requests have been executed. 3399670SN/A // 3409670SN/A // This way of restoring state is pretty finicky. For example, if a 3419670SN/A // Ruby component reads time before the state has been restored, it would 3429670SN/A // cache this value and hence its clock would not be reset to 0, when 3439670SN/A // Ruby resets the global clock. This can potentially result in a 3449670SN/A // deadlock. 3459670SN/A // 3469670SN/A // The solution is that no Ruby component should read time before the 3479670SN/A // simulation starts. And then one also needs to hope that the time 3489670SN/A // Ruby finishes restoring the state is less than the time when the 3499670SN/A // state was checkpointed. 3509670SN/A 3518688SN/A if (m_warmup_enabled) { 35210991SN/A DPRINTF(RubyCacheTrace, "Starting ruby cache warmup\n"); 3538688SN/A // save the current tick value 3548688SN/A Tick curtick_original = curTick(); 3558688SN/A // save the event queue head 3568688SN/A Event* eventq_head = eventq->replaceHead(NULL); 3579296SN/A // set curTick to 0 and reset Ruby System's clock 3589356SN/A setCurTick(0); 3599296SN/A resetClock(); 3608688SN/A 3618688SN/A // Schedule an event to start cache warmup 3628937SN/A enqueueRubyEvent(curTick()); 3638688SN/A simulate(); 3648688SN/A 3658688SN/A delete m_cache_recorder; 3668688SN/A m_cache_recorder = NULL; 36710837SN/A m_systems_to_warmup--; 36810837SN/A if (m_systems_to_warmup == 0) { 36910837SN/A m_warmup_enabled = false; 37010837SN/A } 3719300SN/A 3728688SN/A // Restore eventq head 37311189Sandreas.hansson@arm.com eventq->replaceHead(eventq_head); 3749296SN/A // Restore curTick and Ruby System's clock 3759356SN/A setCurTick(curtick_original); 3769296SN/A resetClock(); 3778688SN/A } 3789670SN/A 3799670SN/A resetStats(); 3808688SN/A} 3818688SN/A 3828688SN/Avoid 38312133Sspwilson2@wisc.eduRubySystem::processRubyEvent() 3848688SN/A{ 38512133Sspwilson2@wisc.edu if (getWarmupEnabled()) { 38612133Sspwilson2@wisc.edu m_cache_recorder->enqueueNextFetchRequest(); 38712133Sspwilson2@wisc.edu } else if (getCooldownEnabled()) { 38812133Sspwilson2@wisc.edu m_cache_recorder->enqueueNextFlushRequest(); 3898688SN/A } 3907562SN/A} 3917562SN/A 3927562SN/Avoid 3939350SN/ARubySystem::resetStats() 3946145SN/A{ 39510918SN/A m_start_cycle = curCycle(); 3966145SN/A} 3976145SN/A 3989270SN/Abool 3999270SN/ARubySystem::functionalRead(PacketPtr pkt) 4009270SN/A{ 40111025SN/A Addr address(pkt->getAddr()); 40211025SN/A Addr line_address = makeLineAddress(address); 4039270SN/A 4049270SN/A AccessPermission access_perm = AccessPermission_NotPresent; 4059270SN/A int num_controllers = m_abs_cntrl_vec.size(); 4069270SN/A 40711118Snilay@cs.wisc.edu DPRINTF(RubySystem, "Functional Read request for %#x\n", address); 4089270SN/A 4099270SN/A unsigned int num_ro = 0; 4109270SN/A unsigned int num_rw = 0; 4119270SN/A unsigned int num_busy = 0; 4129270SN/A unsigned int num_backing_store = 0; 4139270SN/A unsigned int num_invalid = 0; 4149270SN/A 4159270SN/A // In this loop we count the number of controllers that have the given 4169270SN/A // address in read only, read write and busy states. 4179302SN/A for (unsigned int i = 0; i < num_controllers; ++i) { 4189270SN/A access_perm = m_abs_cntrl_vec[i]-> getAccessPermission(line_address); 4199270SN/A if (access_perm == AccessPermission_Read_Only) 4209270SN/A num_ro++; 4219270SN/A else if (access_perm == AccessPermission_Read_Write) 4229270SN/A num_rw++; 4239270SN/A else if (access_perm == AccessPermission_Busy) 4249270SN/A num_busy++; 4259270SN/A else if (access_perm == AccessPermission_Backing_Store) 4269270SN/A // See RubySlicc_Exports.sm for details, but Backing_Store is meant 4279270SN/A // to represent blocks in memory *for Broadcast/Snooping protocols*, 4289270SN/A // where memory has no idea whether it has an exclusive copy of data 4299270SN/A // or not. 4309270SN/A num_backing_store++; 4319270SN/A else if (access_perm == AccessPermission_Invalid || 4329270SN/A access_perm == AccessPermission_NotPresent) 4339270SN/A num_invalid++; 4349270SN/A } 4359270SN/A 4369270SN/A // This if case is meant to capture what happens in a Broadcast/Snoop 4379270SN/A // protocol where the block does not exist in the cache hierarchy. You 4389270SN/A // only want to read from the Backing_Store memory if there is no copy in 4399270SN/A // the cache hierarchy, otherwise you want to try to read the RO or RW 4409270SN/A // copies existing in the cache hierarchy (covered by the else statement). 4419270SN/A // The reason is because the Backing_Store memory could easily be stale, if 4429270SN/A // there are copies floating around the cache hierarchy, so you want to read 4439270SN/A // it only if it's not in the cache hierarchy at all. 44410522SN/A if (num_invalid == (num_controllers - 1) && num_backing_store == 1) { 4459270SN/A DPRINTF(RubySystem, "only copy in Backing_Store memory, read from it\n"); 4469302SN/A for (unsigned int i = 0; i < num_controllers; ++i) { 4479270SN/A access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_address); 4489270SN/A if (access_perm == AccessPermission_Backing_Store) { 44910522SN/A m_abs_cntrl_vec[i]->functionalRead(line_address, pkt); 4509270SN/A return true; 4519270SN/A } 4529270SN/A } 45314125SPouya.Fotouhi@amd.com } else if (num_ro > 0 || num_rw >= 1) { 45414125SPouya.Fotouhi@amd.com if (num_rw > 1) { 45514125SPouya.Fotouhi@amd.com // We iterate over the vector of abstract controllers, and return 45614125SPouya.Fotouhi@amd.com // the first copy found. If we have more than one cache with block 45714125SPouya.Fotouhi@amd.com // in writable permission, the first one found would be returned. 45814125SPouya.Fotouhi@amd.com warn("More than one Abstract Controller with RW permission for " 45914125SPouya.Fotouhi@amd.com "addr: %#x on cacheline: %#x.", address, line_address); 46014125SPouya.Fotouhi@amd.com } 4619270SN/A // In Broadcast/Snoop protocols, this covers if you know the block 4629270SN/A // exists somewhere in the caching hierarchy, then you want to read any 4639270SN/A // valid RO or RW block. In directory protocols, same thing, you want 4649270SN/A // to read any valid readable copy of the block. 4659270SN/A DPRINTF(RubySystem, "num_busy = %d, num_ro = %d, num_rw = %d\n", 4669270SN/A num_busy, num_ro, num_rw); 4679270SN/A // In this loop, we try to figure which controller has a read only or 4689270SN/A // a read write copy of the given address. Any valid copy would suffice 4699270SN/A // for a functional read. 4709302SN/A for (unsigned int i = 0;i < num_controllers;++i) { 4719270SN/A access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_address); 4729270SN/A if (access_perm == AccessPermission_Read_Only || 4739270SN/A access_perm == AccessPermission_Read_Write) { 47410522SN/A m_abs_cntrl_vec[i]->functionalRead(line_address, pkt); 4759270SN/A return true; 4769270SN/A } 4779270SN/A } 4789270SN/A } 4799302SN/A 4809270SN/A return false; 4819270SN/A} 4829270SN/A 4839302SN/A// The function searches through all the buffers that exist in different 4849302SN/A// cache, directory and memory controllers, and in the network components 4859302SN/A// and writes the data portion of those that hold the address specified 4869302SN/A// in the packet. 4879270SN/Abool 4889270SN/ARubySystem::functionalWrite(PacketPtr pkt) 4899270SN/A{ 49011025SN/A Addr addr(pkt->getAddr()); 49111025SN/A Addr line_addr = makeLineAddress(addr); 4929270SN/A AccessPermission access_perm = AccessPermission_NotPresent; 4939270SN/A int num_controllers = m_abs_cntrl_vec.size(); 4949270SN/A 49511118Snilay@cs.wisc.edu DPRINTF(RubySystem, "Functional Write request for %#x\n", addr); 4969270SN/A 4979572SN/A uint32_t M5_VAR_USED num_functional_writes = 0; 4989572SN/A 4999302SN/A for (unsigned int i = 0; i < num_controllers;++i) { 5009572SN/A num_functional_writes += 5019572SN/A m_abs_cntrl_vec[i]->functionalWriteBuffers(pkt); 5029270SN/A 5039302SN/A access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_addr); 5049302SN/A if (access_perm != AccessPermission_Invalid && 5059302SN/A access_perm != AccessPermission_NotPresent) { 50610522SN/A num_functional_writes += 50710522SN/A m_abs_cntrl_vec[i]->functionalWrite(line_addr, pkt); 5089270SN/A } 5099270SN/A } 5109302SN/A 51110012SN/A num_functional_writes += m_network->functionalWrite(pkt); 5129302SN/A DPRINTF(RubySystem, "Messages written = %u\n", num_functional_writes); 5139302SN/A 5149302SN/A return true; 5159270SN/A} 5169270SN/A 5176876SN/ARubySystem * 5186876SN/ARubySystemParams::create() 5196876SN/A{ 5206876SN/A return new RubySystem(this); 5216876SN/A} 522