2 * Copyright (c) 2017-2018 ARM Limited
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.
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.
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.
37 * Authors: Giacomo Travaglini
40 #include "arch/arm/tracers/tarmac_record.hh"
42 #include "arch/arm/insts/static_inst.hh"
43 #include "tarmac_tracer.hh"
47 // TARMAC Instruction Record static variables
48 uint64_t TarmacTracerRecord::TraceInstEntry::instCount
= 0;
51 iSetStateToStr(TarmacBaseRecord::ISetState isetstate
)
54 case TarmacBaseRecord::ISET_ARM
:
56 case TarmacBaseRecord::ISET_THUMB
:
58 case TarmacBaseRecord::ISET_A64
:
66 opModeToStr(OperatingMode opMode
)
102 return "Unsupported";
106 // TarmacTracerRecord ctor
107 TarmacTracerRecord::TarmacTracerRecord(Tick _when
, ThreadContext
*_thread
,
108 const StaticInstPtr _staticInst
,
110 TarmacTracer
& _tracer
,
111 const StaticInstPtr _macroStaticInst
)
112 : TarmacBaseRecord(_when
, _thread
, _staticInst
,
113 _pc
, _macroStaticInst
),
118 TarmacTracerRecord::TraceInstEntry::TraceInstEntry(
119 const TarmacContext
& tarmCtx
,
121 : InstEntry(tarmCtx
.thread
, tarmCtx
.pc
, tarmCtx
.staticInst
, predicate
)
123 secureMode
= inSecureState(tarmCtx
.thread
);
125 auto arm_inst
= static_cast<const ArmStaticInst
*>(
126 tarmCtx
.staticInst
.get()
129 // Get the instruction size as a number of bits:
130 // (multiply byte size by 8)
131 instSize
= (arm_inst
->instSize() << 3);
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();
138 // Update the instruction count: number of executed
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())
151 TarmacTracerRecord::TraceRegEntry::TraceRegEntry(
152 const TarmacContext
& tarmCtx
,
154 : RegEntry(tarmCtx
.pc
),
156 regClass(reg
.classValue()),
162 TarmacTracerRecord::TraceRegEntry::update(
163 const TarmacContext
& tarmCtx
166 // Fill the register entry data, according to register
170 updateCC(tarmCtx
, regRel
);
173 updateFloat(tarmCtx
, regRel
);
176 updateInt(tarmCtx
, regRel
);
179 updateMisc(tarmCtx
, regRel
);
182 // If unsupported format, do nothing: non updating
183 // the register will prevent it to be printed.
189 TarmacTracerRecord::TraceRegEntry::updateMisc(
190 const TarmacContext
& tarmCtx
,
194 auto thread
= tarmCtx
.thread
;
197 regName
= miscRegName
[regRelIdx
];
198 valueLo
= thread
->readMiscRegNoEffect(regRelIdx
);
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
);
210 // update the entry value
216 TarmacTracerRecord::TraceRegEntry::updateCC(
217 const TarmacContext
& tarmCtx
,
221 auto thread
= tarmCtx
.thread
;
224 regName
= ccRegName
[regRelIdx
];
225 valueLo
= thread
->readCCReg(regRelIdx
);
229 TarmacTracerRecord::TraceRegEntry::updateFloat(
230 const TarmacContext
& tarmCtx
,
234 auto thread
= tarmCtx
.thread
;
237 regName
= "f" + std::to_string(regRelIdx
);
238 valueLo
= bitsToFloat32(thread
->readFloatRegBits(regRelIdx
));
242 TarmacTracerRecord::TraceRegEntry::updateInt(
243 const TarmacContext
& tarmCtx
,
247 auto thread
= tarmCtx
.thread
;
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
;
255 std::string reg_suffix
;
256 if (mode
!= MODE_USER
) {
257 reg_suffix
= "_" + opModeToStr(mode
);
265 case StackPointerReg
:
266 regName
= "sp" + reg_suffix
;
268 case FramePointerReg
:
269 regName
= "fp" + reg_suffix
;
271 case ReturnAddressReg
:
272 regName
= "lr" + reg_suffix
;
275 regName
= "r" + std::to_string(regRelIdx
);
278 valueLo
= thread
->readIntReg(regRelIdx
);
282 TarmacTracerRecord::addInstEntry(std::vector
<InstPtr
>& queue
,
283 const TarmacContext
& tarmCtx
)
285 // Generate an instruction entry in the record and
286 // add it to the Instruction Queue
288 m5::make_unique
<TraceInstEntry
>(tarmCtx
, predicate
)
293 TarmacTracerRecord::addMemEntry(std::vector
<MemPtr
>& queue
,
294 const TarmacContext
& tarmCtx
)
296 // Generate a memory entry in the record if the record
297 // implies a valid memory access, and add it to the
301 m5::make_unique
<TraceMemEntry
>(tarmCtx
,
302 static_cast<uint8_t>(getSize()),
303 getAddr(), getIntData())
309 TarmacTracerRecord::addRegEntry(std::vector
<RegPtr
>& queue
,
310 const TarmacContext
& tarmCtx
)
312 // Generate an entry for every ARM register being
313 // written by the current instruction
314 for (auto reg
= 0; reg
< staticInst
->numDestRegs(); ++reg
) {
316 RegId reg_id
= staticInst
->destRegIdx(reg
);
318 // Creating a single register change entry
319 auto single_reg
= genRegister
<TraceRegEntry
>(tarmCtx
, reg_id
);
321 // Copying the entry and adding it to the "list"
322 // of entries to be dumped to trace.
324 m5::make_unique
<TraceRegEntry
>(single_reg
)
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
);
335 TarmacTracerRecord::dump()
337 // Generate and print all the record's entries.
338 auto &instQueue
= tracer
.instQueue
;
339 auto &memQueue
= tracer
.memQueue
;
340 auto ®Queue
= tracer
.regQueue
;
342 const TarmacContext
tarmCtx(
344 staticInst
->isMicroop()? macroStaticInst
: staticInst
,
348 if (!staticInst
->isMicroop()) {
349 // Current instruction is NOT a micro-instruction:
350 // Generate Tarmac entries and dump them immediately
352 // Generate Tarmac entries and add them to the respective
354 addInstEntry(instQueue
, tarmCtx
);
355 addMemEntry(memQueue
, tarmCtx
);
356 addRegEntry(regQueue
, tarmCtx
);
358 // Flush (print) any queued entry.
359 flushQueues(instQueue
, memQueue
, regQueue
);
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
367 if (staticInst
->isFirstMicroop()) {
368 addInstEntry(instQueue
, tarmCtx
);
371 addRegEntry(regQueue
, tarmCtx
);
372 addMemEntry(memQueue
, tarmCtx
);
374 if (staticInst
->isLastMicroop()) {
375 // Flush (print) any queued entry.
376 flushQueues(instQueue
, memQueue
, regQueue
);
381 template<typename Queue
>
383 TarmacTracerRecord::flushQueues(Queue
& queue
)
385 std::ostream
&outs
= Trace::output();
387 for (const auto &single_entry
: queue
) {
388 single_entry
->print(outs
);
394 template<typename Queue
, typename
... Args
>
396 TarmacTracerRecord::flushQueues(Queue
& queue
, Args
& ... args
)
399 flushQueues(args
...);
403 TarmacTracerRecord::TraceInstEntry::print(
406 const std::string
&prefix
) const
409 std::string opcode_str
= csprintf("%0*x", instSize
>> 2, opcode
);
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 */
426 TarmacTracerRecord::TraceMemEntry::print(
429 const std::string
&prefix
) const
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 */
443 TarmacTracerRecord::TraceRegEntry::print(
446 const std::string
&prefix
) const
448 // Print the register record formatted according
449 // to the Tarmac specification
451 ccprintf(outs
, "%s clk R %s %08x\n",
452 curTick(), /* Tick time */
453 regName
, /* Register name */
454 valueLo
); /* Register value */