More Changes, working towards cache.cc compiling. Headers cleaned up.
[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/exec_context.hh"
37 #include "cpu/smt.hh" //for maxThreadsPerCPU
38 #include "mem/cache/base_cache.hh"
39 #include "mem/cache/miss/blocking_buffer.hh"
40 #include "mem/cache/prefetch/base_prefetcher.hh"
41 #include "sim/eventq.hh" // for Event declaration.
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->paddr & ~(Addr)(blk_size - 1);
76 if (pkt->cmd.isWrite() && (pkt->req->isUncacheable() || !writeAllocate ||
77 pkt->cmd.isNoResponse())) {
78 if (pkt->cmd.isNoResponse()) {
79 wb.allocateAsBuffer(pkt);
80 } else {
81 wb.allocate(pkt->cmd, blk_addr, pkt->req->asid, blk_size, pkt);
82 }
83 if (cache->doData()) {
84 memcpy(wb.pkt->data, pkt->data, blk_size);
85 }
86 cache->setBlocked(Blocked_NoWBBuffers);
87 cache->setMasterRequest(Request_WB, time);
88 return;
89 }
90
91 if (pkt->cmd.isNoResponse()) {
92 miss.allocateAsBuffer(pkt);
93 } else {
94 miss.allocate(pkt->cmd, blk_addr, pkt->req->asid, 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 = pkt->senderState;
116 mshr->originalCmd = pkt->cmd;
117 if (pkt->isCacheFill())
118 pkt->cmd = cmd;
119 }
120
121 void
122 BlockingBuffer::restoreOrigCmd(Packet * &pkt)
123 {
124 pkt->cmd = pkt->senderState->originalCmd;
125 }
126
127 void
128 BlockingBuffer::markInService(Packet * &pkt)
129 {
130 if (!pkt->isCacheFill() && pkt->cmd.isWrite()) {
131 // Forwarding a write/ writeback, don't need to change
132 // the command
133 assert(pkt->senderState == &wb);
134 cache->clearMasterRequest(Request_WB);
135 if (pkt->cmd.isNoResponse()) {
136 assert(wb.getNumTargets() == 0);
137 wb.deallocate();
138 cache->clearBlocked(Blocked_NoWBBuffers);
139 } else {
140 wb.inService = true;
141 }
142 } else {
143 assert(pkt->senderState == &miss);
144 cache->clearMasterRequest(Request_MSHR);
145 if (pkt->cmd.isNoResponse()) {
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(pkt->senderState == &miss);
162 miss.deallocate();
163 cache->clearBlocked(Blocked_NoMSHRs);
164 } else {
165 if (pkt->senderState->hasTargets()) {
166 // Should only have 1 target if we had any
167 assert(pkt->senderState->getNumTargets() == 1);
168 Packet * target = pkt->senderState->getTarget();
169 pkt->senderState->popTarget();
170 if (cache->doData() && pkt->cmd.isRead()) {
171 memcpy(target->data, pkt->data, target->size);
172 }
173 cache->respond(target, time);
174 assert(!pkt->senderState->hasTargets());
175 }
176
177 if (pkt->cmd.isWrite()) {
178 assert(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 req->getThreadNum()ber)
190 {
191 if (miss.setThreadNum() == req->getThreadNum()ber) {
192 Packet * target = miss.getTarget();
193 miss.popTarget();
194 assert(target->req->setThreadNum() == req->getThreadNum()ber);
195 if (target->completionEvent != NULL) {
196 delete target->completionEvent;
197 }
198 target = NULL;
199 assert(!miss.hasTargets());
200 miss.ntargets=0;
201 if (!miss.inService) {
202 miss.deallocate();
203 cache->clearBlocked(Blocked_NoMSHRs);
204 cache->clearMasterRequest(Request_MSHR);
205 }
206 }
207 }
208
209 void
210 BlockingBuffer::doWriteback(Addr addr, int asid,
211 int size, uint8_t *data, bool compressed)
212 {
213
214 // Generate request
215 Packet * pkt = new Packet();
216 pkt->paddr = addr;
217 pkt->req->asid = asid;
218 pkt->size = size;
219 pkt->data = new uint8_t[size];
220 if (data) {
221 memcpy(pkt->data, data, size);
222 }
223 /**
224 * @todo Need to find a way to charge the writeback to the "correct"
225 * thread.
226 */
227 pkt->req->setThreadNum() = 0;
228
229 pkt->cmd = Writeback;
230 if (compressed) {
231 pkt->flags |= COMPRESSED;
232 }
233
234 writebacks[pkt->req->getThreadNum()]++;
235
236 wb.allocateAsBuffer(pkt);
237 cache->setMasterRequest(Request_WB, curTick);
238 cache->setBlocked(Blocked_NoWBBuffers);
239 }
240
241
242
243 void
244 BlockingBuffer::doWriteback(Packet * &pkt)
245 {
246 writebacks[pkt->req->getThreadNum()]++;
247
248 wb.allocateAsBuffer(pkt);
249
250 // Since allocate as buffer copies the request,
251 // need to copy data here.
252 if (cache->doData()) {
253 memcpy(wb.pkt->data, pkt->data, pkt->size);
254 }
255 cache->setBlocked(Blocked_NoWBBuffers);
256 cache->setMasterRequest(Request_WB, curTick);
257 }