arch, cpu: Remove float type accessors.
[gem5.git] / src / arch / arm / tracers / tarmac_record.cc
1 /*
2 * Copyright (c) 2017-2018 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 default:
182 // If unsupported format, do nothing: non updating
183 // the register will prevent it to be printed.
184 break;
185 }
186 }
187
188 void
189 TarmacTracerRecord::TraceRegEntry::updateMisc(
190 const TarmacContext& tarmCtx,
191 RegIndex regRelIdx
192 )
193 {
194 auto thread = tarmCtx.thread;
195
196 regValid = true;
197 regName = miscRegName[regRelIdx];
198 valueLo = thread->readMiscRegNoEffect(regRelIdx);
199
200 // If it is the CPSR:
201 // update the value of the CPSR register and add
202 // the CC flags on top of the value
203 if (regRelIdx == MISCREG_CPSR) {
204 CPSR cpsr = thread->readMiscRegNoEffect(MISCREG_CPSR);
205 cpsr.nz = thread->readCCReg(CCREG_NZ);
206 cpsr.c = thread->readCCReg(CCREG_C);
207 cpsr.v = thread->readCCReg(CCREG_V);
208 cpsr.ge = thread->readCCReg(CCREG_GE);
209
210 // update the entry value
211 valueLo = cpsr;
212 }
213 }
214
215 void
216 TarmacTracerRecord::TraceRegEntry::updateCC(
217 const TarmacContext& tarmCtx,
218 RegIndex regRelIdx
219 )
220 {
221 auto thread = tarmCtx.thread;
222
223 regValid = true;
224 regName = ccRegName[regRelIdx];
225 valueLo = thread->readCCReg(regRelIdx);
226 }
227
228 void
229 TarmacTracerRecord::TraceRegEntry::updateFloat(
230 const TarmacContext& tarmCtx,
231 RegIndex regRelIdx
232 )
233 {
234 auto thread = tarmCtx.thread;
235
236 regValid = true;
237 regName = "f" + std::to_string(regRelIdx);
238 valueLo = bitsToFloat32(thread->readFloatRegBits(regRelIdx));
239 }
240
241 void
242 TarmacTracerRecord::TraceRegEntry::updateInt(
243 const TarmacContext& tarmCtx,
244 RegIndex regRelIdx
245 )
246 {
247 auto thread = tarmCtx.thread;
248
249 // Reading operating mode from CPSR.
250 // This is needed when printing the register name in case
251 // of banked register (e.g. lr_svc)
252 CPSR cpsr = thread->readMiscRegNoEffect(MISCREG_CPSR);
253 OperatingMode mode = (OperatingMode)(uint8_t)cpsr.mode;
254
255 std::string reg_suffix;
256 if (mode != MODE_USER) {
257 reg_suffix = "_" + opModeToStr(mode);
258 }
259
260 regValid = true;
261 switch (regRelIdx) {
262 case PCReg:
263 regName = "pc";
264 break;
265 case StackPointerReg:
266 regName = "sp" + reg_suffix ;
267 break;
268 case FramePointerReg:
269 regName = "fp" + reg_suffix;
270 break;
271 case ReturnAddressReg:
272 regName = "lr" + reg_suffix;
273 break;
274 default:
275 regName = "r" + std::to_string(regRelIdx);
276 break;
277 }
278 valueLo = thread->readIntReg(regRelIdx);
279 }
280
281 void
282 TarmacTracerRecord::addInstEntry(std::vector<InstPtr>& queue,
283 const TarmacContext& tarmCtx)
284 {
285 // Generate an instruction entry in the record and
286 // add it to the Instruction Queue
287 queue.push_back(
288 m5::make_unique<TraceInstEntry>(tarmCtx, predicate)
289 );
290 }
291
292 void
293 TarmacTracerRecord::addMemEntry(std::vector<MemPtr>& queue,
294 const TarmacContext& tarmCtx)
295 {
296 // Generate a memory entry in the record if the record
297 // implies a valid memory access, and add it to the
298 // Memory Queue
299 if (getMemValid()) {
300 queue.push_back(
301 m5::make_unique<TraceMemEntry>(tarmCtx,
302 static_cast<uint8_t>(getSize()),
303 getAddr(), getIntData())
304 );
305 }
306 }
307
308 void
309 TarmacTracerRecord::addRegEntry(std::vector<RegPtr>& queue,
310 const TarmacContext& tarmCtx)
311 {
312 // Generate an entry for every ARM register being
313 // written by the current instruction
314 for (auto reg = 0; reg < staticInst->numDestRegs(); ++reg) {
315
316 RegId reg_id = staticInst->destRegIdx(reg);
317
318 // Creating a single register change entry
319 auto single_reg = genRegister<TraceRegEntry>(tarmCtx, reg_id);
320
321 // Copying the entry and adding it to the "list"
322 // of entries to be dumped to trace.
323 queue.push_back(
324 m5::make_unique<TraceRegEntry>(single_reg)
325 );
326 }
327
328 // Gem5 is treating CPSR flags as separate registers (CC registers),
329 // in contrast with Tarmac specification: we need to merge the gem5 CC
330 // entries altogether with the CPSR register and produce a single entry.
331 mergeCCEntry<TraceRegEntry>(queue, tarmCtx);
332 }
333
334 void
335 TarmacTracerRecord::dump()
336 {
337 // Generate and print all the record's entries.
338 auto &instQueue = tracer.instQueue;
339 auto &memQueue = tracer.memQueue;
340 auto &regQueue = tracer.regQueue;
341
342 const TarmacContext tarmCtx(
343 thread,
344 staticInst->isMicroop()? macroStaticInst : staticInst,
345 pc
346 );
347
348 if (!staticInst->isMicroop()) {
349 // Current instruction is NOT a micro-instruction:
350 // Generate Tarmac entries and dump them immediately
351
352 // Generate Tarmac entries and add them to the respective
353 // queues.
354 addInstEntry(instQueue, tarmCtx);
355 addMemEntry(memQueue, tarmCtx);
356 addRegEntry(regQueue, tarmCtx);
357
358 // Flush (print) any queued entry.
359 flushQueues(instQueue, memQueue, regQueue);
360
361 } else {
362 // Current instruction is a micro-instruction:
363 // save micro entries into dedicated queues and flush them
364 // into the tracefile only when the MACRO-instruction
365 // has completed.
366
367 if (staticInst->isFirstMicroop()) {
368 addInstEntry(instQueue, tarmCtx);
369 }
370
371 addRegEntry(regQueue, tarmCtx);
372 addMemEntry(memQueue, tarmCtx);
373
374 if (staticInst->isLastMicroop()) {
375 // Flush (print) any queued entry.
376 flushQueues(instQueue, memQueue, regQueue);
377 }
378 }
379 }
380
381 template<typename Queue>
382 void
383 TarmacTracerRecord::flushQueues(Queue& queue)
384 {
385 std::ostream &outs = Trace::output();
386
387 for (const auto &single_entry : queue) {
388 single_entry->print(outs);
389 }
390
391 queue.clear();
392 }
393
394 template<typename Queue, typename... Args>
395 void
396 TarmacTracerRecord::flushQueues(Queue& queue, Args & ... args)
397 {
398 flushQueues(queue);
399 flushQueues(args...);
400 }
401
402 void
403 TarmacTracerRecord::TraceInstEntry::print(
404 std::ostream& outs,
405 int verbosity,
406 const std::string &prefix) const
407 {
408 // Pad the opcode
409 std::string opcode_str = csprintf("%0*x", instSize >> 2, opcode);
410
411 // Print the instruction record formatted according
412 // to the Tarmac specification
413 ccprintf(outs, "%s clk %s (%u) %08x %s %s %s_%s : %s\n",
414 curTick(), /* Tick time */
415 taken? "IT" : "IS", /* Instruction taken/skipped */
416 instCount, /* Instruction count */
417 addr, /* Instruction address */
418 opcode_str, /* Instruction opcode */
419 iSetStateToStr(isetstate), /* Instruction Set */
420 opModeToStr(mode), /* Exception level */
421 secureMode? "s" : "ns", /* Security */
422 disassemble); /* Instruction disass */
423 }
424
425 void
426 TarmacTracerRecord::TraceMemEntry::print(
427 std::ostream& outs,
428 int verbosity,
429 const std::string &prefix) const
430 {
431 // Print the memory record formatted according
432 // to the Tarmac specification
433 ccprintf(outs, "%s clk M%s%d %08x %0*x\n",
434 curTick(), /* Tick time */
435 loadAccess? "R" : "W", /* Access type */
436 size, /* Access size */
437 addr, /* Memory address */
438 size*2, /* Padding with access size */
439 data); /* Memory data */
440 }
441
442 void
443 TarmacTracerRecord::TraceRegEntry::print(
444 std::ostream& outs,
445 int verbosity,
446 const std::string &prefix) const
447 {
448 // Print the register record formatted according
449 // to the Tarmac specification
450 if (regValid)
451 ccprintf(outs, "%s clk R %s %08x\n",
452 curTick(), /* Tick time */
453 regName, /* Register name */
454 valueLo); /* Register value */
455 }
456
457 } // namespace Trace