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