mem: Change warmupCycle stat to warmupTick
[gem5.git] / src / mem / mem_checker_monitor.cc
1 /*
2 * Copyright (c) 2012-2014 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 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include "mem/mem_checker_monitor.hh"
39
40 #include <memory>
41
42 #include "base/logging.hh"
43 #include "base/output.hh"
44 #include "base/trace.hh"
45 #include "debug/MemCheckerMonitor.hh"
46
47 MemCheckerMonitor::MemCheckerMonitor(const Params &params)
48 : SimObject(params),
49 memSidePort(name() + "-memSidePort", *this),
50 cpuSidePort(name() + "-cpuSidePort", *this),
51 warnOnly(params.warn_only),
52 memchecker(params.memchecker)
53 {}
54
55 MemCheckerMonitor::~MemCheckerMonitor()
56 {}
57
58 void
59 MemCheckerMonitor::init()
60 {
61 // make sure both sides of the monitor are connected
62 if (!cpuSidePort.isConnected() || !memSidePort.isConnected())
63 fatal("Communication monitor is not connected on both sides.\n");
64 }
65
66 Port &
67 MemCheckerMonitor::getPort(const std::string &if_name, PortID idx)
68 {
69 if (if_name == "request" || if_name == "mem_side_port") {
70 return memSidePort;
71 } else if (if_name == "response" || if_name == "cpu_side_port") {
72 return cpuSidePort;
73 } else {
74 return SimObject::getPort(if_name, idx);
75 }
76 }
77
78 void
79 MemCheckerMonitor::recvFunctional(PacketPtr pkt)
80 {
81 Addr addr = pkt->getAddr();
82 unsigned size = pkt->getSize();
83
84 // Conservatively reset this address-range. Alternatively we could try to
85 // update the values seen by the memchecker, however, there may be other
86 // reads/writes to these location from other devices we do not see.
87 memchecker->reset(addr, size);
88
89 memSidePort.sendFunctional(pkt);
90
91 DPRINTF(MemCheckerMonitor,
92 "Forwarded functional access: addr = %#llx, size = %d\n",
93 addr, size);
94 }
95
96 void
97 MemCheckerMonitor::recvFunctionalSnoop(PacketPtr pkt)
98 {
99 Addr addr = pkt->getAddr();
100 unsigned size = pkt->getSize();
101
102 // See above.
103 memchecker->reset(addr, size);
104
105 cpuSidePort.sendFunctionalSnoop(pkt);
106
107 DPRINTF(MemCheckerMonitor,
108 "Received functional snoop: addr = %#llx, size = %d\n",
109 addr, size);
110 }
111
112 Tick
113 MemCheckerMonitor::recvAtomic(PacketPtr pkt)
114 {
115 panic("Atomic not supported");
116 }
117
118 Tick
119 MemCheckerMonitor::recvAtomicSnoop(PacketPtr pkt)
120 {
121 panic("Atomic not supported");
122 }
123
124 bool
125 MemCheckerMonitor::recvTimingReq(PacketPtr pkt)
126 {
127 // should always see a request
128 assert(pkt->isRequest());
129
130 // Store relevant fields of packet, because packet may be modified
131 // or even deleted when sendTiming() is called.
132 //
133 // For reads we are only interested in real reads, and not prefetches, as
134 // it is not guaranteed that the prefetch returns any useful data.
135 bool is_read = pkt->isRead() && !pkt->req->isPrefetch();
136 bool is_write = pkt->isWrite();
137 unsigned size = pkt->getSize();
138 Addr addr = pkt->getAddr();
139 bool expects_response = pkt->needsResponse() && !pkt->cacheResponding();
140 std::unique_ptr<uint8_t[]> pkt_data;
141 MemCheckerMonitorSenderState* state = NULL;
142
143 if (expects_response && is_write) {
144 // On receipt of a request, only need to allocate pkt_data if this is a
145 // write. For reads, we have no data yet, so it doesn't make sense to
146 // allocate.
147 pkt_data.reset(new uint8_t[size]);
148 pkt->writeData(pkt_data.get());
149 }
150
151 // If a cache miss is served by a cache, a monitor near the memory
152 // would see a request which needs a response, but this response
153 // would not come back from the memory. Therefore
154 // we additionally have to check the inhibit flag.
155 if (expects_response && (is_read || is_write)) {
156 state = new MemCheckerMonitorSenderState(0);
157 pkt->pushSenderState(state);
158 }
159
160 // Attempt to send the packet
161 bool successful = memSidePort.sendTimingReq(pkt);
162
163 // If not successful, restore the sender state
164 if (!successful && expects_response && (is_read || is_write)) {
165 delete pkt->popSenderState();
166 }
167
168 if (successful && expects_response) {
169 if (is_read) {
170 MemChecker::Serial serial = memchecker->startRead(curTick(),
171 addr,
172 size);
173
174 // At the time where we push the sender-state, we do not yet know
175 // the serial the MemChecker class will assign to this request. We
176 // cannot call startRead at the time we push the sender-state, as
177 // the memSidePort may not be successful in executing
178 // sendTimingReq, and in case of a failure, we must not
179 // modify the state of the MemChecker.
180 //
181 // Once we know that sendTimingReq was successful, we can set the
182 // serial of the newly constructed sender-state. This is legal, as
183 // we know that nobody else will touch nor is responsible for
184 // deletion of our sender-state.
185 state->serial = serial;
186
187 DPRINTF(MemCheckerMonitor,
188 "Forwarded read request: serial = %d, addr = %#llx, "
189 "size = %d\n",
190 serial, addr, size);
191 } else if (is_write) {
192 MemChecker::Serial serial = memchecker->startWrite(curTick(),
193 addr,
194 size,
195 pkt_data.get());
196
197 state->serial = serial;
198
199 DPRINTF(MemCheckerMonitor,
200 "Forwarded write request: serial = %d, addr = %#llx, "
201 "size = %d\n",
202 serial, addr, size);
203 } else {
204 DPRINTF(MemCheckerMonitor,
205 "Forwarded non read/write request: addr = %#llx\n", addr);
206 }
207 } else if (successful) {
208 DPRINTF(MemCheckerMonitor,
209 "Forwarded request marked for cache response: addr = %#llx\n",
210 addr);
211 }
212
213 return successful;
214 }
215
216 bool
217 MemCheckerMonitor::recvTimingResp(PacketPtr pkt)
218 {
219 // should always see responses
220 assert(pkt->isResponse());
221
222 // Store relevant fields of packet, because packet may be modified
223 // or even deleted when sendTiming() is called.
224 bool is_read = pkt->isRead() && !pkt->req->isPrefetch();
225 bool is_write = pkt->isWrite();
226 bool is_failed_LLSC = pkt->isLLSC() && pkt->req->getExtraData() == 0;
227 unsigned size = pkt->getSize();
228 Addr addr = pkt->getAddr();
229 std::unique_ptr<uint8_t[]> pkt_data;
230 MemCheckerMonitorSenderState* received_state = NULL;
231
232 if (is_read) {
233 // On receipt of a response, only need to allocate pkt_data if this is
234 // a read. For writes, we have already given the MemChecker the data on
235 // the request, so it doesn't make sense to allocate on write.
236 pkt_data.reset(new uint8_t[size]);
237 pkt->writeData(pkt_data.get());
238 }
239
240 if (is_read || is_write) {
241 received_state =
242 dynamic_cast<MemCheckerMonitorSenderState*>(pkt->senderState);
243
244 // Restore initial sender state
245 panic_if(received_state == NULL,
246 "Monitor got a response without monitor sender state\n");
247
248 // Restore the state
249 pkt->senderState = received_state->predecessor;
250 }
251
252 // Attempt to send the packet
253 bool successful = cpuSidePort.sendTimingResp(pkt);
254
255 // If packet successfully send, complete transaction in MemChecker
256 // instance, and delete sender state, otherwise restore state.
257 if (successful) {
258 if (is_read) {
259 DPRINTF(MemCheckerMonitor,
260 "Received read response: serial = %d, addr = %#llx, "
261 "size = %d\n",
262 received_state->serial, addr, size);
263
264 bool result = memchecker->completeRead(received_state->serial,
265 curTick(),
266 addr,
267 size,
268 pkt_data.get());
269
270 if (!result) {
271 warn("%s: read of %#llx @ cycle %d failed:\n%s\n",
272 name(),
273 addr, curTick(),
274 memchecker->getErrorMessage().c_str());
275
276 panic_if(!warnOnly, "MemChecker violation!");
277 }
278
279 delete received_state;
280 } else if (is_write) {
281 DPRINTF(MemCheckerMonitor,
282 "Received write response: serial = %d, addr = %#llx, "
283 "size = %d\n",
284 received_state->serial, addr, size);
285
286 if (is_failed_LLSC) {
287 // The write was not successful, let MemChecker know.
288 memchecker->abortWrite(received_state->serial,
289 addr,
290 size);
291 } else {
292 memchecker->completeWrite(received_state->serial,
293 curTick(),
294 addr,
295 size);
296 }
297
298 delete received_state;
299 } else {
300 DPRINTF(MemCheckerMonitor,
301 "Received non read/write response: addr = %#llx\n", addr);
302 }
303 } else if (is_read || is_write) {
304 // Don't delete anything and let the packet look like we
305 // did not touch it
306 pkt->senderState = received_state;
307 }
308
309 return successful;
310 }
311
312 void
313 MemCheckerMonitor::recvTimingSnoopReq(PacketPtr pkt)
314 {
315 cpuSidePort.sendTimingSnoopReq(pkt);
316 }
317
318 bool
319 MemCheckerMonitor::recvTimingSnoopResp(PacketPtr pkt)
320 {
321 return memSidePort.sendTimingSnoopResp(pkt);
322 }
323
324 bool
325 MemCheckerMonitor::isSnooping() const
326 {
327 // check if the connected memSidePort is snooping
328 return cpuSidePort.isSnooping();
329 }
330
331 AddrRangeList
332 MemCheckerMonitor::getAddrRanges() const
333 {
334 // get the address ranges of the connected cpuSidePort
335 return memSidePort.getAddrRanges();
336 }
337
338 void
339 MemCheckerMonitor::recvReqRetry()
340 {
341 cpuSidePort.sendRetryReq();
342 }
343
344 void
345 MemCheckerMonitor::recvRespRetry()
346 {
347 memSidePort.sendRetryResp();
348 }
349
350 void
351 MemCheckerMonitor::recvRangeChange()
352 {
353 cpuSidePort.sendRangeChange();
354 }