Fix the packet data allocation methods. Small fixes from changesets after my initial...
[gem5.git] / src / mem / cache / miss / blocking_buffer.cc
1 /*
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Erik Hallnor
29 */
30
31 /**
32 * @file
33 * Definitions of a simple buffer for a blocking cache.
34 */
35
36 #include "cpu/smt.hh" //for maxThreadsPerCPU
37 #include "mem/cache/base_cache.hh"
38 #include "mem/cache/miss/blocking_buffer.hh"
39 #include "mem/cache/prefetch/base_prefetcher.hh"
40 #include "sim/eventq.hh" // for Event declaration.
41 #include "mem/request.hh"
42
43 using namespace TheISA;
44
45 /**
46 * @todo Move writebacks into shared BaseBuffer class.
47 */
48 void
49 BlockingBuffer::regStats(const std::string &name)
50 {
51 using namespace Stats;
52 writebacks
53 .init(maxThreadsPerCPU)
54 .name(name + ".writebacks")
55 .desc("number of writebacks")
56 .flags(total)
57 ;
58 }
59
60 void
61 BlockingBuffer::setCache(BaseCache *_cache)
62 {
63 cache = _cache;
64 blkSize = cache->getBlockSize();
65 }
66
67 void
68 BlockingBuffer::setPrefetcher(BasePrefetcher *_prefetcher)
69 {
70 prefetcher = _prefetcher;
71 }
72 void
73 BlockingBuffer::handleMiss(Packet * &pkt, int blk_size, Tick time)
74 {
75 Addr blk_addr = pkt->getAddr() & ~(Addr)(blk_size - 1);
76 if (pkt->isWrite() && (pkt->req->isUncacheable() || !writeAllocate ||
77 !pkt->needsResponse())) {
78 if (!pkt->needsResponse()) {
79 wb.allocateAsBuffer(pkt);
80 } else {
81 wb.allocate(pkt->cmd, blk_addr, pkt->req->getAsid(), blk_size, pkt);
82 }
83
84 memcpy(wb.pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), blk_size);
85
86 cache->setBlocked(Blocked_NoWBBuffers);
87 cache->setMasterRequest(Request_WB, time);
88 return;
89 }
90
91 if (!pkt->needsResponse()) {
92 miss.allocateAsBuffer(pkt);
93 } else {
94 miss.allocate(pkt->cmd, blk_addr, pkt->req->getAsid(), blk_size, pkt);
95 }
96 if (!pkt->req->isUncacheable()) {
97 miss.pkt->flags |= CACHE_LINE_FILL;
98 }
99 cache->setBlocked(Blocked_NoMSHRs);
100 cache->setMasterRequest(Request_MSHR, time);
101 }
102
103 Packet *
104 BlockingBuffer::getPacket()
105 {
106 if (miss.pkt && !miss.inService) {
107 return miss.pkt;
108 }
109 return wb.pkt;
110 }
111
112 void
113 BlockingBuffer::setBusCmd(Packet * &pkt, Packet::Command cmd)
114 {
115 MSHR *mshr = (MSHR*) pkt->senderState;
116 mshr->originalCmd = pkt->cmd;
117 if (pkt->isCacheFill())
118 pkt->cmdOverride(cmd);
119 }
120
121 void
122 BlockingBuffer::restoreOrigCmd(Packet * &pkt)
123 {
124 pkt->cmdOverride(((MSHR*)(pkt->senderState))->originalCmd);
125 }
126
127 void
128 BlockingBuffer::markInService(Packet * &pkt)
129 {
130 if (!pkt->isCacheFill() && pkt->isWrite()) {
131 // Forwarding a write/ writeback, don't need to change
132 // the command
133 assert((MSHR*)pkt->senderState == &wb);
134 cache->clearMasterRequest(Request_WB);
135 if (!pkt->needsResponse()) {
136 assert(wb.getNumTargets() == 0);
137 wb.deallocate();
138 cache->clearBlocked(Blocked_NoWBBuffers);
139 } else {
140 wb.inService = true;
141 }
142 } else {
143 assert((MSHR*)pkt->senderState == &miss);
144 cache->clearMasterRequest(Request_MSHR);
145 if (!pkt->needsResponse()) {
146 assert(miss.getNumTargets() == 0);
147 miss.deallocate();
148 cache->clearBlocked(Blocked_NoMSHRs);
149 } else {
150 //mark in service
151 miss.inService = true;
152 }
153 }
154 }
155
156 void
157 BlockingBuffer::handleResponse(Packet * &pkt, Tick time)
158 {
159 if (pkt->isCacheFill()) {
160 // targets were handled in the cache tags
161 assert((MSHR*)pkt->senderState == &miss);
162 miss.deallocate();
163 cache->clearBlocked(Blocked_NoMSHRs);
164 } else {
165 if (((MSHR*)(pkt->senderState))->hasTargets()) {
166 // Should only have 1 target if we had any
167 assert(((MSHR*)(pkt->senderState))->getNumTargets() == 1);
168 Packet * target = ((MSHR*)(pkt->senderState))->getTarget();
169 ((MSHR*)(pkt->senderState))->popTarget();
170 if (pkt->isRead()) {
171 memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), target->getSize());
172 }
173 cache->respond(target, time);
174 assert(!((MSHR*)(pkt->senderState))->hasTargets());
175 }
176
177 if (pkt->isWrite()) {
178 assert(((MSHR*)(pkt->senderState)) == &wb);
179 wb.deallocate();
180 cache->clearBlocked(Blocked_NoWBBuffers);
181 } else {
182 miss.deallocate();
183 cache->clearBlocked(Blocked_NoMSHRs);
184 }
185 }
186 }
187
188 void
189 BlockingBuffer::squash(int threadNum)
190 {
191 if (miss.threadNum == threadNum) {
192 Packet * target = miss.getTarget();
193 miss.popTarget();
194 assert(target->req->getThreadNum() == threadNum);
195 target = NULL;
196 assert(!miss.hasTargets());
197 miss.ntargets=0;
198 if (!miss.inService) {
199 miss.deallocate();
200 cache->clearBlocked(Blocked_NoMSHRs);
201 cache->clearMasterRequest(Request_MSHR);
202 }
203 }
204 }
205
206 void
207 BlockingBuffer::doWriteback(Addr addr, int asid,
208 int size, uint8_t *data, bool compressed)
209 {
210 // Generate request
211 Request * req = new Request(addr, size, 0);
212 Packet * pkt = new Packet(req, Packet::Writeback, -1);
213 pkt->allocate();
214 if (data) {
215 memcpy(pkt->getPtr<uint8_t>(), data, size);
216 }
217
218 if (compressed) {
219 pkt->flags |= COMPRESSED;
220 }
221
222 ///All writebacks charged to same thread @todo figure this out
223 writebacks[pkt->req->getThreadNum()]++;
224
225 wb.allocateAsBuffer(pkt);
226 cache->setMasterRequest(Request_WB, curTick);
227 cache->setBlocked(Blocked_NoWBBuffers);
228 }
229
230
231
232 void
233 BlockingBuffer::doWriteback(Packet * &pkt)
234 {
235 writebacks[pkt->req->getThreadNum()]++;
236
237 wb.allocateAsBuffer(pkt);
238
239 // Since allocate as buffer copies the request,
240 // need to copy data here.
241 memcpy(wb.pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), pkt->getSize());
242
243 cache->setBlocked(Blocked_NoWBBuffers);
244 cache->setMasterRequest(Request_WB, curTick);
245 }