mshr_queue.cc revision 9347:b02075171b57
1/*
2 * Copyright (c) 2012 ARM Limited
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2003-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Erik Hallnor
41 *          Andreas Sandberg
42 */
43
44/** @file
45 * Definition of MSHRQueue class functions.
46 */
47
48#include "mem/cache/mshr_queue.hh"
49
50using namespace std;
51
52MSHRQueue::MSHRQueue(const std::string &_label,
53                     int num_entries, int reserve, int _index)
54    : label(_label),
55      numEntries(num_entries + reserve - 1), numReserve(reserve),
56      drainManager(NULL), index(_index)
57{
58    allocated = 0;
59    inServiceEntries = 0;
60    registers = new MSHR[numEntries];
61    for (int i = 0; i < numEntries; ++i) {
62        registers[i].queue = this;
63        freeList.push_back(&registers[i]);
64    }
65}
66
67MSHRQueue::~MSHRQueue()
68{
69    delete [] registers;
70}
71
72MSHR *
73MSHRQueue::findMatch(Addr addr) const
74{
75    MSHR::ConstIterator i = allocatedList.begin();
76    MSHR::ConstIterator end = allocatedList.end();
77    for (; i != end; ++i) {
78        MSHR *mshr = *i;
79        if (mshr->addr == addr) {
80            return mshr;
81        }
82    }
83    return NULL;
84}
85
86bool
87MSHRQueue::findMatches(Addr addr, vector<MSHR*>& matches) const
88{
89    // Need an empty vector
90    assert(matches.empty());
91    bool retval = false;
92    MSHR::ConstIterator i = allocatedList.begin();
93    MSHR::ConstIterator end = allocatedList.end();
94    for (; i != end; ++i) {
95        MSHR *mshr = *i;
96        if (mshr->addr == addr) {
97            retval = true;
98            matches.push_back(mshr);
99        }
100    }
101    return retval;
102}
103
104
105bool
106MSHRQueue::checkFunctional(PacketPtr pkt, Addr blk_addr)
107{
108    pkt->pushLabel(label);
109    MSHR::ConstIterator i = allocatedList.begin();
110    MSHR::ConstIterator end = allocatedList.end();
111    for (; i != end; ++i) {
112        MSHR *mshr = *i;
113        if (mshr->addr == blk_addr && mshr->checkFunctional(pkt)) {
114            pkt->popLabel();
115            return true;
116        }
117    }
118    pkt->popLabel();
119    return false;
120}
121
122
123MSHR *
124MSHRQueue::findPending(Addr addr, int size) const
125{
126    MSHR::ConstIterator i = readyList.begin();
127    MSHR::ConstIterator end = readyList.end();
128    for (; i != end; ++i) {
129        MSHR *mshr = *i;
130        if (mshr->addr < addr) {
131            if (mshr->addr + mshr->size > addr) {
132                return mshr;
133            }
134        } else {
135            if (addr + size > mshr->addr) {
136                return mshr;
137            }
138        }
139    }
140    return NULL;
141}
142
143
144MSHR::Iterator
145MSHRQueue::addToReadyList(MSHR *mshr)
146{
147    if (readyList.empty() || readyList.back()->readyTime <= mshr->readyTime) {
148        return readyList.insert(readyList.end(), mshr);
149    }
150
151    MSHR::Iterator i = readyList.begin();
152    MSHR::Iterator end = readyList.end();
153    for (; i != end; ++i) {
154        if ((*i)->readyTime > mshr->readyTime) {
155            return readyList.insert(i, mshr);
156        }
157    }
158    assert(false);
159    return end;  // keep stupid compilers happy
160}
161
162
163MSHR *
164MSHRQueue::allocate(Addr addr, int size, PacketPtr &pkt,
165                    Tick when, Counter order)
166{
167    assert(!freeList.empty());
168    MSHR *mshr = freeList.front();
169    assert(mshr->getNumTargets() == 0);
170    freeList.pop_front();
171
172    mshr->allocate(addr, size, pkt, when, order);
173    mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
174    mshr->readyIter = addToReadyList(mshr);
175
176    allocated += 1;
177    return mshr;
178}
179
180
181void
182MSHRQueue::deallocate(MSHR *mshr)
183{
184    deallocateOne(mshr);
185}
186
187MSHR::Iterator
188MSHRQueue::deallocateOne(MSHR *mshr)
189{
190    MSHR::Iterator retval = allocatedList.erase(mshr->allocIter);
191    freeList.push_front(mshr);
192    allocated--;
193    if (mshr->inService) {
194        inServiceEntries--;
195    } else {
196        readyList.erase(mshr->readyIter);
197    }
198    mshr->deallocate();
199    if (drainManager && allocated == 0) {
200        // Notify the drain manager that we have completed draining if
201        // there are no other outstanding requests in this MSHR queue.
202        drainManager->signalDrainDone();
203        drainManager = NULL;
204        setDrainState(Drainable::Drained);
205    }
206    return retval;
207}
208
209void
210MSHRQueue::moveToFront(MSHR *mshr)
211{
212    if (!mshr->inService) {
213        assert(mshr == *(mshr->readyIter));
214        readyList.erase(mshr->readyIter);
215        mshr->readyIter = readyList.insert(readyList.begin(), mshr);
216    }
217}
218
219void
220MSHRQueue::markInService(MSHR *mshr, PacketPtr pkt)
221{
222    if (mshr->markInService(pkt)) {
223        deallocate(mshr);
224    } else {
225        readyList.erase(mshr->readyIter);
226        inServiceEntries += 1;
227    }
228}
229
230void
231MSHRQueue::markPending(MSHR *mshr)
232{
233    assert(mshr->inService);
234    mshr->inService = false;
235    --inServiceEntries;
236    /**
237     * @ todo might want to add rerequests to front of pending list for
238     * performance.
239     */
240    mshr->readyIter = addToReadyList(mshr);
241}
242
243void
244MSHRQueue::squash(int threadNum)
245{
246    MSHR::Iterator i = allocatedList.begin();
247    MSHR::Iterator end = allocatedList.end();
248    for (; i != end;) {
249        MSHR *mshr = *i;
250        if (mshr->threadNum == threadNum) {
251            while (mshr->hasTargets()) {
252                mshr->popTarget();
253                assert(0/*target->req->threadId()*/ == threadNum);
254            }
255            assert(!mshr->hasTargets());
256            assert(mshr->ntargets==0);
257            if (!mshr->inService) {
258                i = deallocateOne(mshr);
259            } else {
260                //mshr->pkt->flags &= ~CACHE_LINE_FILL;
261                ++i;
262            }
263        } else {
264            ++i;
265        }
266    }
267}
268
269unsigned int
270MSHRQueue::drain(DrainManager *dm)
271{
272    if (allocated == 0) {
273        setDrainState(Drainable::Drained);
274        return 0;
275    } else {
276        drainManager = dm;
277        setDrainState(Drainable::Draining);
278        return 1;
279    }
280}
281