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