mshr_queue.cc (10766:b2071d0eb5f1) mshr_queue.cc (10768:9a34e28cd2c2)
1/*
2 * Copyright (c) 2012-2013, 2015 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 "base/trace.hh"
49#include "mem/cache/mshr_queue.hh"
50#include "debug/Drain.hh"
51
52using namespace std;
53
54MSHRQueue::MSHRQueue(const std::string &_label,
55 int num_entries, int reserve, int demand_reserve,
56 int _index)
57 : label(_label), numEntries(num_entries + reserve - 1),
58 numReserve(reserve), demandReserve(demand_reserve),
59 registers(numEntries), drainManager(NULL), allocated(0),
60 inServiceEntries(0), index(_index)
61{
62 for (int i = 0; i < numEntries; ++i) {
63 registers[i].queue = this;
64 freeList.push_back(&registers[i]);
65 }
66}
67
68MSHR *
69MSHRQueue::findMatch(Addr blk_addr, bool is_secure) const
70{
71 for (const auto& mshr : allocatedList) {
1/*
2 * Copyright (c) 2012-2013, 2015 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 "base/trace.hh"
49#include "mem/cache/mshr_queue.hh"
50#include "debug/Drain.hh"
51
52using namespace std;
53
54MSHRQueue::MSHRQueue(const std::string &_label,
55 int num_entries, int reserve, int demand_reserve,
56 int _index)
57 : label(_label), numEntries(num_entries + reserve - 1),
58 numReserve(reserve), demandReserve(demand_reserve),
59 registers(numEntries), drainManager(NULL), allocated(0),
60 inServiceEntries(0), index(_index)
61{
62 for (int i = 0; i < numEntries; ++i) {
63 registers[i].queue = this;
64 freeList.push_back(&registers[i]);
65 }
66}
67
68MSHR *
69MSHRQueue::findMatch(Addr blk_addr, bool is_secure) const
70{
71 for (const auto& mshr : allocatedList) {
72 if (mshr->blkAddr == blk_addr && mshr->isSecure == is_secure) {
72 // we ignore any MSHRs allocated for uncacheable accesses and
73 // simply ignore them when matching, in the cache we never
74 // check for matches when adding new uncacheable entries, and
75 // we do not want normal cacheable accesses being added to an
76 // MSHR serving an uncacheable access
77 if (!mshr->isUncacheable() && mshr->blkAddr == blk_addr &&
78 mshr->isSecure == is_secure) {
73 return mshr;
74 }
75 }
76 return NULL;
77}
78
79bool
80MSHRQueue::findMatches(Addr blk_addr, bool is_secure,
81 vector<MSHR*>& matches) const
82{
83 // Need an empty vector
84 assert(matches.empty());
85 bool retval = false;
86 for (const auto& mshr : allocatedList) {
79 return mshr;
80 }
81 }
82 return NULL;
83}
84
85bool
86MSHRQueue::findMatches(Addr blk_addr, bool is_secure,
87 vector<MSHR*>& matches) const
88{
89 // Need an empty vector
90 assert(matches.empty());
91 bool retval = false;
92 for (const auto& mshr : allocatedList) {
87 if (mshr->blkAddr == blk_addr && mshr->isSecure == is_secure) {
93 if (!mshr->isUncacheable() && mshr->blkAddr == blk_addr &&
94 mshr->isSecure == is_secure) {
88 retval = true;
89 matches.push_back(mshr);
90 }
91 }
92 return retval;
93}
94
95
96bool
97MSHRQueue::checkFunctional(PacketPtr pkt, Addr blk_addr)
98{
99 pkt->pushLabel(label);
100 for (const auto& mshr : allocatedList) {
101 if (mshr->blkAddr == blk_addr && mshr->checkFunctional(pkt)) {
102 pkt->popLabel();
103 return true;
104 }
105 }
106 pkt->popLabel();
107 return false;
108}
109
110
111MSHR *
112MSHRQueue::findPending(Addr blk_addr, bool is_secure) const
113{
114 for (const auto& mshr : readyList) {
115 if (mshr->blkAddr == blk_addr && mshr->isSecure == is_secure) {
116 return mshr;
117 }
118 }
119 return NULL;
120}
121
122
123MSHR::Iterator
124MSHRQueue::addToReadyList(MSHR *mshr)
125{
126 if (readyList.empty() || readyList.back()->readyTime <= mshr->readyTime) {
127 return readyList.insert(readyList.end(), mshr);
128 }
129
130 for (auto i = readyList.begin(); i != readyList.end(); ++i) {
131 if ((*i)->readyTime > mshr->readyTime) {
132 return readyList.insert(i, mshr);
133 }
134 }
135 assert(false);
136 return readyList.end(); // keep stupid compilers happy
137}
138
139
140MSHR *
141MSHRQueue::allocate(Addr blk_addr, unsigned blk_size, PacketPtr pkt,
142 Tick when_ready, Counter order)
143{
144 assert(!freeList.empty());
145 MSHR *mshr = freeList.front();
146 assert(mshr->getNumTargets() == 0);
147 freeList.pop_front();
148
149 mshr->allocate(blk_addr, blk_size, pkt, when_ready, order);
150 mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
151 mshr->readyIter = addToReadyList(mshr);
152
153 allocated += 1;
154 return mshr;
155}
156
157
158void
159MSHRQueue::deallocate(MSHR *mshr)
160{
161 deallocateOne(mshr);
162}
163
164MSHR::Iterator
165MSHRQueue::deallocateOne(MSHR *mshr)
166{
167 MSHR::Iterator retval = allocatedList.erase(mshr->allocIter);
168 freeList.push_front(mshr);
169 allocated--;
170 if (mshr->inService) {
171 inServiceEntries--;
172 } else {
173 readyList.erase(mshr->readyIter);
174 }
175 mshr->deallocate();
176 if (drainManager && allocated == 0) {
177 // Notify the drain manager that we have completed draining if
178 // there are no other outstanding requests in this MSHR queue.
179 DPRINTF(Drain, "MSHRQueue now empty, signalling drained\n");
180 drainManager->signalDrainDone();
181 drainManager = NULL;
182 setDrainState(Drainable::Drained);
183 }
184 return retval;
185}
186
187void
188MSHRQueue::moveToFront(MSHR *mshr)
189{
190 if (!mshr->inService) {
191 assert(mshr == *(mshr->readyIter));
192 readyList.erase(mshr->readyIter);
193 mshr->readyIter = readyList.insert(readyList.begin(), mshr);
194 }
195}
196
197void
198MSHRQueue::markInService(MSHR *mshr, bool pending_dirty_resp)
199{
200 if (mshr->markInService(pending_dirty_resp)) {
201 deallocate(mshr);
202 } else {
203 readyList.erase(mshr->readyIter);
204 inServiceEntries += 1;
205 }
206}
207
208void
209MSHRQueue::markPending(MSHR *mshr)
210{
211 assert(mshr->inService);
212 mshr->inService = false;
213 --inServiceEntries;
214 /**
215 * @ todo might want to add rerequests to front of pending list for
216 * performance.
217 */
218 mshr->readyIter = addToReadyList(mshr);
219}
220
221bool
222MSHRQueue::forceDeallocateTarget(MSHR *mshr)
223{
224 bool was_full = isFull();
225 assert(mshr->hasTargets());
226 // Pop the prefetch off of the target list
227 mshr->popTarget();
228 // Delete mshr if no remaining targets
229 if (!mshr->hasTargets() && !mshr->promoteDeferredTargets()) {
230 deallocateOne(mshr);
231 }
232
233 // Notify if MSHR queue no longer full
234 return was_full && !isFull();
235}
236
237void
238MSHRQueue::squash(int threadNum)
239{
240 for (auto i = allocatedList.begin(); i != allocatedList.end();) {
241 MSHR *mshr = *i;
242 if (mshr->threadNum == threadNum) {
243 while (mshr->hasTargets()) {
244 mshr->popTarget();
245 assert(0/*target->req->threadId()*/ == threadNum);
246 }
247 assert(!mshr->hasTargets());
248 assert(mshr->getNumTargets()==0);
249 if (!mshr->inService) {
250 i = deallocateOne(mshr);
251 } else {
252 //mshr->pkt->flags &= ~CACHE_LINE_FILL;
253 ++i;
254 }
255 } else {
256 ++i;
257 }
258 }
259}
260
261unsigned int
262MSHRQueue::drain(DrainManager *dm)
263{
264 if (allocated == 0) {
265 setDrainState(Drainable::Drained);
266 return 0;
267 } else {
268 drainManager = dm;
269 setDrainState(Drainable::Draining);
270 return 1;
271 }
272}
95 retval = true;
96 matches.push_back(mshr);
97 }
98 }
99 return retval;
100}
101
102
103bool
104MSHRQueue::checkFunctional(PacketPtr pkt, Addr blk_addr)
105{
106 pkt->pushLabel(label);
107 for (const auto& mshr : allocatedList) {
108 if (mshr->blkAddr == blk_addr && mshr->checkFunctional(pkt)) {
109 pkt->popLabel();
110 return true;
111 }
112 }
113 pkt->popLabel();
114 return false;
115}
116
117
118MSHR *
119MSHRQueue::findPending(Addr blk_addr, bool is_secure) const
120{
121 for (const auto& mshr : readyList) {
122 if (mshr->blkAddr == blk_addr && mshr->isSecure == is_secure) {
123 return mshr;
124 }
125 }
126 return NULL;
127}
128
129
130MSHR::Iterator
131MSHRQueue::addToReadyList(MSHR *mshr)
132{
133 if (readyList.empty() || readyList.back()->readyTime <= mshr->readyTime) {
134 return readyList.insert(readyList.end(), mshr);
135 }
136
137 for (auto i = readyList.begin(); i != readyList.end(); ++i) {
138 if ((*i)->readyTime > mshr->readyTime) {
139 return readyList.insert(i, mshr);
140 }
141 }
142 assert(false);
143 return readyList.end(); // keep stupid compilers happy
144}
145
146
147MSHR *
148MSHRQueue::allocate(Addr blk_addr, unsigned blk_size, PacketPtr pkt,
149 Tick when_ready, Counter order)
150{
151 assert(!freeList.empty());
152 MSHR *mshr = freeList.front();
153 assert(mshr->getNumTargets() == 0);
154 freeList.pop_front();
155
156 mshr->allocate(blk_addr, blk_size, pkt, when_ready, order);
157 mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
158 mshr->readyIter = addToReadyList(mshr);
159
160 allocated += 1;
161 return mshr;
162}
163
164
165void
166MSHRQueue::deallocate(MSHR *mshr)
167{
168 deallocateOne(mshr);
169}
170
171MSHR::Iterator
172MSHRQueue::deallocateOne(MSHR *mshr)
173{
174 MSHR::Iterator retval = allocatedList.erase(mshr->allocIter);
175 freeList.push_front(mshr);
176 allocated--;
177 if (mshr->inService) {
178 inServiceEntries--;
179 } else {
180 readyList.erase(mshr->readyIter);
181 }
182 mshr->deallocate();
183 if (drainManager && allocated == 0) {
184 // Notify the drain manager that we have completed draining if
185 // there are no other outstanding requests in this MSHR queue.
186 DPRINTF(Drain, "MSHRQueue now empty, signalling drained\n");
187 drainManager->signalDrainDone();
188 drainManager = NULL;
189 setDrainState(Drainable::Drained);
190 }
191 return retval;
192}
193
194void
195MSHRQueue::moveToFront(MSHR *mshr)
196{
197 if (!mshr->inService) {
198 assert(mshr == *(mshr->readyIter));
199 readyList.erase(mshr->readyIter);
200 mshr->readyIter = readyList.insert(readyList.begin(), mshr);
201 }
202}
203
204void
205MSHRQueue::markInService(MSHR *mshr, bool pending_dirty_resp)
206{
207 if (mshr->markInService(pending_dirty_resp)) {
208 deallocate(mshr);
209 } else {
210 readyList.erase(mshr->readyIter);
211 inServiceEntries += 1;
212 }
213}
214
215void
216MSHRQueue::markPending(MSHR *mshr)
217{
218 assert(mshr->inService);
219 mshr->inService = false;
220 --inServiceEntries;
221 /**
222 * @ todo might want to add rerequests to front of pending list for
223 * performance.
224 */
225 mshr->readyIter = addToReadyList(mshr);
226}
227
228bool
229MSHRQueue::forceDeallocateTarget(MSHR *mshr)
230{
231 bool was_full = isFull();
232 assert(mshr->hasTargets());
233 // Pop the prefetch off of the target list
234 mshr->popTarget();
235 // Delete mshr if no remaining targets
236 if (!mshr->hasTargets() && !mshr->promoteDeferredTargets()) {
237 deallocateOne(mshr);
238 }
239
240 // Notify if MSHR queue no longer full
241 return was_full && !isFull();
242}
243
244void
245MSHRQueue::squash(int threadNum)
246{
247 for (auto i = allocatedList.begin(); i != allocatedList.end();) {
248 MSHR *mshr = *i;
249 if (mshr->threadNum == threadNum) {
250 while (mshr->hasTargets()) {
251 mshr->popTarget();
252 assert(0/*target->req->threadId()*/ == threadNum);
253 }
254 assert(!mshr->hasTargets());
255 assert(mshr->getNumTargets()==0);
256 if (!mshr->inService) {
257 i = deallocateOne(mshr);
258 } else {
259 //mshr->pkt->flags &= ~CACHE_LINE_FILL;
260 ++i;
261 }
262 } else {
263 ++i;
264 }
265 }
266}
267
268unsigned int
269MSHRQueue::drain(DrainManager *dm)
270{
271 if (allocated == 0) {
272 setDrainState(Drainable::Drained);
273 return 0;
274 } else {
275 drainManager = dm;
276 setDrainState(Drainable::Draining);
277 return 1;
278 }
279}