mem-cache: Add multiple eviction stats
[gem5.git] / src / arch / arm / tracers / tarmac_record.cc
1 /*
2 * Copyright (c) 2017-2019 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 * Authors: Giacomo Travaglini
38 */
39
40 #include "arch/arm/tracers/tarmac_record.hh"
41
42 #include "arch/arm/insts/static_inst.hh"
43 #include "tarmac_tracer.hh"
44
45 namespace Trace {
46
47 // TARMAC Instruction Record static variables
48 uint64_t TarmacTracerRecord::TraceInstEntry::instCount = 0;
49
50 std::string
51 iSetStateToStr(TarmacBaseRecord::ISetState isetstate)
52 {
53 switch (isetstate) {
54 case TarmacBaseRecord::ISET_ARM:
55 return "A";
56 case TarmacBaseRecord::ISET_THUMB:
57 return "T";
58 case TarmacBaseRecord::ISET_A64:
59 return "O";
60 default:
61 return "Unsupported";
62 }
63 }
64
65 std::string
66 opModeToStr(OperatingMode opMode)
67 {
68 switch (opMode) {
69 case MODE_EL0T:
70 return "EL0t";
71 case MODE_EL1T:
72 return "EL1t";
73 case MODE_EL1H:
74 return "EL1h";
75 case MODE_EL2T:
76 return "EL2t";
77 case MODE_EL2H:
78 return "EL2h";
79 case MODE_EL3T:
80 return "EL3t";
81 case MODE_EL3H:
82 return "EL3h";
83 case MODE_USER:
84 return "usr";
85 case MODE_FIQ:
86 return "fiq";
87 case MODE_IRQ:
88 return "irq";
89 case MODE_SVC:
90 return "svc";
91 case MODE_MON:
92 return "mon";
93 case MODE_ABORT:
94 return "abt";
95 case MODE_HYP:
96 return "hyp";
97 case MODE_UNDEFINED:
98 return "und";
99 case MODE_SYSTEM:
100 return "sys";
101 default:
102 return "Unsupported";
103 }
104 }
105
106 // TarmacTracerRecord ctor
107 TarmacTracerRecord::TarmacTracerRecord(Tick _when, ThreadContext *_thread,
108 const StaticInstPtr _staticInst,
109 PCState _pc,
110 TarmacTracer& _tracer,
111 const StaticInstPtr _macroStaticInst)
112 : TarmacBaseRecord(_when, _thread, _staticInst,
113 _pc, _macroStaticInst),
114 tracer(_tracer)
115 {
116 }
117
118 TarmacTracerRecord::TraceInstEntry::TraceInstEntry(
119 const TarmacContext& tarmCtx,
120 bool predicate)
121 : InstEntry(tarmCtx.thread, tarmCtx.pc, tarmCtx.staticInst, predicate)
122 {
123 secureMode = inSecureState(tarmCtx.thread);
124
125 auto arm_inst = static_cast<const ArmStaticInst*>(
126 tarmCtx.staticInst.get()
127 );
128
129 // Get the instruction size as a number of bits:
130 // (multiply byte size by 8)
131 instSize = (arm_inst->instSize() << 3);
132
133 // Mask the opcode using the instruction size: the
134 // opcode field will otherwise be 32 bit wide even
135 // for 16bit (Thumb) instruction.
136 opcode = arm_inst->encoding();
137
138 // Update the instruction count: number of executed
139 // instructions.
140 instCount++;
141 }
142
143 TarmacTracerRecord::TraceMemEntry::TraceMemEntry(
144 const TarmacContext& tarmCtx,
145 uint8_t _size, Addr _addr, uint64_t _data)
146 : MemEntry(_size, _addr, _data),
147 loadAccess(tarmCtx.staticInst->isLoad())
148 {
149 }
150
151 TarmacTracerRecord::TraceRegEntry::TraceRegEntry(
152 const TarmacContext& tarmCtx,
153 const RegId& reg)
154 : RegEntry(tarmCtx.pc),
155 regValid(false),
156 regClass(reg.classValue()),
157 regRel(reg.index())
158 {
159 }
160
161 void
162 TarmacTracerRecord::TraceRegEntry::update(
163 const TarmacContext& tarmCtx
164 )
165 {
166 // Fill the register entry data, according to register
167 // class.
168 switch (regClass) {
169 case CCRegClass:
170 updateCC(tarmCtx, regRel);
171 break;
172 case FloatRegClass:
173 updateFloat(tarmCtx, regRel);
174 break;
175 case IntRegClass:
176 updateInt(tarmCtx, regRel);
177 break;
178 case MiscRegClass:
179 updateMisc(tarmCtx, regRel);
180 break;
181 case VecRegClass:
182 updateVec(tarmCtx, regRel);
183 break;
184 case VecPredRegClass:
185 updatePred(tarmCtx, regRel);
186 break;
187 default:
188 // If unsupported format, do nothing: non updating
189 // the register will prevent it to be printed.
190 break;
191 }
192 }
193
194 void
195 TarmacTracerRecord::TraceRegEntry::updateMisc(
196 const TarmacContext& tarmCtx,
197 RegIndex regRelIdx
198 )
199 {
200 auto thread = tarmCtx.thread;
201
202 regValid = true;
203 regName = miscRegName[regRelIdx];
204 values[Lo] = thread->readMiscRegNoEffect(regRelIdx);
205
206 // If it is the CPSR:
207 // update the value of the CPSR register and add
208 // the CC flags on top of the value
209 if (regRelIdx == MISCREG_CPSR) {
210 CPSR cpsr = thread->readMiscRegNoEffect(MISCREG_CPSR);
211 cpsr.nz = thread->readCCReg(CCREG_NZ);
212 cpsr.c = thread->readCCReg(CCREG_C);
213 cpsr.v = thread->readCCReg(CCREG_V);
214 cpsr.ge = thread->readCCReg(CCREG_GE);
215
216 // update the entry value
217 values[Lo] = cpsr;
218 }
219 }
220
221 void
222 TarmacTracerRecord::TraceRegEntry::updateCC(
223 const TarmacContext& tarmCtx,
224 RegIndex regRelIdx
225 )
226 {
227 auto thread = tarmCtx.thread;
228
229 regValid = true;
230 regName = ccRegName[regRelIdx];
231 values[Lo] = thread->readCCReg(regRelIdx);
232 }
233
234 void
235 TarmacTracerRecord::TraceRegEntry::updateFloat(
236 const TarmacContext& tarmCtx,
237 RegIndex regRelIdx
238 )
239 {
240 auto thread = tarmCtx.thread;
241
242 regValid = true;
243 regName = "f" + std::to_string(regRelIdx);
244 values[Lo] = bitsToFloat32(thread->readFloatReg(regRelIdx));
245 }
246
247 void
248 TarmacTracerRecord::TraceRegEntry::updateInt(
249 const TarmacContext& tarmCtx,
250 RegIndex regRelIdx
251 )
252 {
253 auto thread = tarmCtx.thread;
254
255 // Reading operating mode from CPSR.
256 // This is needed when printing the register name in case
257 // of banked register (e.g. lr_svc)
258 CPSR cpsr = thread->readMiscRegNoEffect(MISCREG_CPSR);
259 OperatingMode mode = (OperatingMode)(uint8_t)cpsr.mode;
260
261 std::string reg_suffix;
262 if (mode != MODE_USER) {
263 reg_suffix = "_" + opModeToStr(mode);
264 }
265
266 regValid = true;
267 switch (regRelIdx) {
268 case PCReg:
269 regName = "pc";
270 break;
271 case StackPointerReg:
272 regName = "sp" + reg_suffix ;
273 break;
274 case FramePointerReg:
275 regName = "fp" + reg_suffix;
276 break;
277 case ReturnAddressReg:
278 regName = "lr" + reg_suffix;
279 break;
280 default:
281 regName = "r" + std::to_string(regRelIdx);
282 break;
283 }
284 values[Lo] = thread->readIntReg(regRelIdx);
285 }
286
287 void
288 TarmacTracerRecord::addInstEntry(std::vector<InstPtr>& queue,
289 const TarmacContext& tarmCtx)
290 {
291 // Generate an instruction entry in the record and
292 // add it to the Instruction Queue
293 queue.push_back(
294 m5::make_unique<TraceInstEntry>(tarmCtx, predicate)
295 );
296 }
297
298 void
299 TarmacTracerRecord::addMemEntry(std::vector<MemPtr>& queue,
300 const TarmacContext& tarmCtx)
301 {
302 // Generate a memory entry in the record if the record
303 // implies a valid memory access, and add it to the
304 // Memory Queue
305 if (getMemValid()) {
306 queue.push_back(
307 m5::make_unique<TraceMemEntry>(tarmCtx,
308 static_cast<uint8_t>(getSize()),
309 getAddr(), getIntData())
310 );
311 }
312 }
313
314 void
315 TarmacTracerRecord::addRegEntry(std::vector<RegPtr>& queue,
316 const TarmacContext& tarmCtx)
317 {
318 // Generate an entry for every ARM register being
319 // written by the current instruction
320 for (auto reg = 0; reg < staticInst->numDestRegs(); ++reg) {
321
322 RegId reg_id = staticInst->destRegIdx(reg);
323
324 // Creating a single register change entry
325 auto single_reg = genRegister<TraceRegEntry>(tarmCtx, reg_id);
326
327 // Copying the entry and adding it to the "list"
328 // of entries to be dumped to trace.
329 queue.push_back(
330 m5::make_unique<TraceRegEntry>(single_reg)
331 );
332 }
333
334 // Gem5 is treating CPSR flags as separate registers (CC registers),
335 // in contrast with Tarmac specification: we need to merge the gem5 CC
336 // entries altogether with the CPSR register and produce a single entry.
337 mergeCCEntry<TraceRegEntry>(queue, tarmCtx);
338 }
339
340 void
341 TarmacTracerRecord::dump()
342 {
343 // Generate and print all the record's entries.
344 auto &instQueue = tracer.instQueue;
345 auto &memQueue = tracer.memQueue;
346 auto &regQueue = tracer.regQueue;
347
348 const TarmacContext tarmCtx(
349 thread,
350 staticInst->isMicroop()? macroStaticInst : staticInst,
351 pc
352 );
353
354 if (!staticInst->isMicroop()) {
355 // Current instruction is NOT a micro-instruction:
356 // Generate Tarmac entries and dump them immediately
357
358 // Generate Tarmac entries and add them to the respective
359 // queues.
360 addInstEntry(instQueue, tarmCtx);
361 addMemEntry(memQueue, tarmCtx);
362 addRegEntry(regQueue, tarmCtx);
363
364 // Flush (print) any queued entry.
365 flushQueues(instQueue, memQueue, regQueue);
366
367 } else {
368 // Current instruction is a micro-instruction:
369 // save micro entries into dedicated queues and flush them
370 // into the tracefile only when the MACRO-instruction
371 // has completed.
372
373 if (staticInst->isFirstMicroop()) {
374 addInstEntry(instQueue, tarmCtx);
375 }
376
377 addRegEntry(regQueue, tarmCtx);
378 addMemEntry(memQueue, tarmCtx);
379
380 if (staticInst->isLastMicroop()) {
381 // Flush (print) any queued entry.
382 flushQueues(instQueue, memQueue, regQueue);
383 }
384 }
385 }
386
387 template<typename Queue>
388 void
389 TarmacTracerRecord::flushQueues(Queue& queue)
390 {
391 std::ostream &outs = Trace::output();
392
393 for (const auto &single_entry : queue) {
394 single_entry->print(outs);
395 }
396
397 queue.clear();
398 }
399
400 template<typename Queue, typename... Args>
401 void
402 TarmacTracerRecord::flushQueues(Queue& queue, Args & ... args)
403 {
404 flushQueues(queue);
405 flushQueues(args...);
406 }
407
408 void
409 TarmacTracerRecord::TraceInstEntry::print(
410 std::ostream& outs,
411 int verbosity,
412 const std::string &prefix) const
413 {
414 // Pad the opcode
415 std::string opcode_str = csprintf("%0*x", instSize >> 2, opcode);
416
417 // Print the instruction record formatted according
418 // to the Tarmac specification
419 ccprintf(outs, "%s clk %s (%u) %08x %s %s %s_%s : %s\n",
420 curTick(), /* Tick time */
421 taken? "IT" : "IS", /* Instruction taken/skipped */
422 instCount, /* Instruction count */
423 addr, /* Instruction address */
424 opcode_str, /* Instruction opcode */
425 iSetStateToStr(isetstate), /* Instruction Set */
426 opModeToStr(mode), /* Exception level */
427 secureMode? "s" : "ns", /* Security */
428 disassemble); /* Instruction disass */
429 }
430
431 void
432 TarmacTracerRecord::TraceMemEntry::print(
433 std::ostream& outs,
434 int verbosity,
435 const std::string &prefix) const
436 {
437 // Print the memory record formatted according
438 // to the Tarmac specification
439 ccprintf(outs, "%s clk M%s%d %08x %0*x\n",
440 curTick(), /* Tick time */
441 loadAccess? "R" : "W", /* Access type */
442 size, /* Access size */
443 addr, /* Memory address */
444 size*2, /* Padding with access size */
445 data); /* Memory data */
446 }
447
448 void
449 TarmacTracerRecord::TraceRegEntry::print(
450 std::ostream& outs,
451 int verbosity,
452 const std::string &prefix) const
453 {
454 // Print the register record formatted according
455 // to the Tarmac specification
456 if (regValid)
457 ccprintf(outs, "%s clk R %s %08x\n",
458 curTick(), /* Tick time */
459 regName, /* Register name */
460 values[Lo]); /* Register value */
461 }
462
463 } // namespace Trace