2 * Copyright (c) 2017-2019 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.
38 #include "arch/arm/tracers/tarmac_record.hh"
40 #include "arch/arm/insts/static_inst.hh"
41 #include "tarmac_tracer.hh"
45 // TARMAC Instruction Record static variables
46 uint64_t TarmacTracerRecord::TraceInstEntry::instCount
= 0;
49 iSetStateToStr(TarmacBaseRecord::ISetState isetstate
)
52 case TarmacBaseRecord::ISET_ARM
:
54 case TarmacBaseRecord::ISET_THUMB
:
56 case TarmacBaseRecord::ISET_A64
:
64 opModeToStr(OperatingMode opMode
)
100 return "Unsupported";
104 // TarmacTracerRecord ctor
105 TarmacTracerRecord::TarmacTracerRecord(Tick _when
, ThreadContext
*_thread
,
106 const StaticInstPtr _staticInst
,
108 TarmacTracer
& _tracer
,
109 const StaticInstPtr _macroStaticInst
)
110 : TarmacBaseRecord(_when
, _thread
, _staticInst
,
111 _pc
, _macroStaticInst
),
116 TarmacTracerRecord::TraceInstEntry::TraceInstEntry(
117 const TarmacContext
& tarmCtx
,
119 : InstEntry(tarmCtx
.thread
, tarmCtx
.pc
, tarmCtx
.staticInst
, predicate
)
121 secureMode
= inSecureState(tarmCtx
.thread
);
123 auto arm_inst
= static_cast<const ArmStaticInst
*>(
124 tarmCtx
.staticInst
.get()
127 // Get the instruction size as a number of bits:
128 // (multiply byte size by 8)
129 instSize
= (arm_inst
->instSize() << 3);
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();
136 // Update the instruction count: number of executed
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())
149 TarmacTracerRecord::TraceRegEntry::TraceRegEntry(
150 const TarmacContext
& tarmCtx
,
152 : RegEntry(tarmCtx
.pc
),
154 regClass(reg
.classValue()),
160 TarmacTracerRecord::TraceRegEntry::update(
161 const TarmacContext
& tarmCtx
164 // Fill the register entry data, according to register
168 updateCC(tarmCtx
, regRel
);
171 updateFloat(tarmCtx
, regRel
);
174 updateInt(tarmCtx
, regRel
);
177 updateMisc(tarmCtx
, regRel
);
180 updateVec(tarmCtx
, regRel
);
182 case VecPredRegClass
:
183 updatePred(tarmCtx
, regRel
);
186 // If unsupported format, do nothing: non updating
187 // the register will prevent it to be printed.
193 TarmacTracerRecord::TraceRegEntry::updateMisc(
194 const TarmacContext
& tarmCtx
,
198 auto thread
= tarmCtx
.thread
;
201 regName
= miscRegName
[regRelIdx
];
202 values
[Lo
] = thread
->readMiscRegNoEffect(regRelIdx
);
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
);
214 // update the entry value
220 TarmacTracerRecord::TraceRegEntry::updateCC(
221 const TarmacContext
& tarmCtx
,
225 auto thread
= tarmCtx
.thread
;
228 regName
= ccRegName
[regRelIdx
];
229 values
[Lo
] = thread
->readCCReg(regRelIdx
);
233 TarmacTracerRecord::TraceRegEntry::updateFloat(
234 const TarmacContext
& tarmCtx
,
238 auto thread
= tarmCtx
.thread
;
241 regName
= "f" + std::to_string(regRelIdx
);
242 values
[Lo
] = bitsToFloat32(thread
->readFloatReg(regRelIdx
));
246 TarmacTracerRecord::TraceRegEntry::updateInt(
247 const TarmacContext
& tarmCtx
,
251 auto thread
= tarmCtx
.thread
;
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
;
259 std::string reg_suffix
;
260 if (mode
!= MODE_USER
) {
261 reg_suffix
= "_" + opModeToStr(mode
);
269 case StackPointerReg
:
270 regName
= "sp" + reg_suffix
;
272 case FramePointerReg
:
273 regName
= "fp" + reg_suffix
;
275 case ReturnAddressReg
:
276 regName
= "lr" + reg_suffix
;
279 regName
= "r" + std::to_string(regRelIdx
);
282 values
[Lo
] = thread
->readIntReg(regRelIdx
);
286 TarmacTracerRecord::addInstEntry(std::vector
<InstPtr
>& queue
,
287 const TarmacContext
& tarmCtx
)
289 // Generate an instruction entry in the record and
290 // add it to the Instruction Queue
292 m5::make_unique
<TraceInstEntry
>(tarmCtx
, predicate
)
297 TarmacTracerRecord::addMemEntry(std::vector
<MemPtr
>& queue
,
298 const TarmacContext
& tarmCtx
)
300 // Generate a memory entry in the record if the record
301 // implies a valid memory access, and add it to the
305 m5::make_unique
<TraceMemEntry
>(tarmCtx
,
306 static_cast<uint8_t>(getSize()),
307 getAddr(), getIntData())
313 TarmacTracerRecord::addRegEntry(std::vector
<RegPtr
>& queue
,
314 const TarmacContext
& tarmCtx
)
316 // Generate an entry for every ARM register being
317 // written by the current instruction
318 for (auto reg
= 0; reg
< staticInst
->numDestRegs(); ++reg
) {
320 RegId reg_id
= staticInst
->destRegIdx(reg
);
322 // Creating a single register change entry
323 auto single_reg
= genRegister
<TraceRegEntry
>(tarmCtx
, reg_id
);
325 // Copying the entry and adding it to the "list"
326 // of entries to be dumped to trace.
328 m5::make_unique
<TraceRegEntry
>(single_reg
)
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
);
339 TarmacTracerRecord::dump()
341 // Generate and print all the record's entries.
342 auto &instQueue
= tracer
.instQueue
;
343 auto &memQueue
= tracer
.memQueue
;
344 auto ®Queue
= tracer
.regQueue
;
346 const TarmacContext
tarmCtx(
348 staticInst
->isMicroop()? macroStaticInst
: staticInst
,
352 if (!staticInst
->isMicroop()) {
353 // Current instruction is NOT a micro-instruction:
354 // Generate Tarmac entries and dump them immediately
356 // Generate Tarmac entries and add them to the respective
358 addInstEntry(instQueue
, tarmCtx
);
359 addMemEntry(memQueue
, tarmCtx
);
360 addRegEntry(regQueue
, tarmCtx
);
362 // Flush (print) any queued entry.
363 flushQueues(instQueue
, memQueue
, regQueue
);
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
371 if (staticInst
->isFirstMicroop()) {
372 addInstEntry(instQueue
, tarmCtx
);
375 addRegEntry(regQueue
, tarmCtx
);
376 addMemEntry(memQueue
, tarmCtx
);
378 if (staticInst
->isLastMicroop()) {
379 // Flush (print) any queued entry.
380 flushQueues(instQueue
, memQueue
, regQueue
);
385 template<typename Queue
>
387 TarmacTracerRecord::flushQueues(Queue
& queue
)
389 std::ostream
&outs
= Trace::output();
391 for (const auto &single_entry
: queue
) {
392 single_entry
->print(outs
);
398 template<typename Queue
, typename
... Args
>
400 TarmacTracerRecord::flushQueues(Queue
& queue
, Args
& ... args
)
403 flushQueues(args
...);
407 TarmacTracerRecord::TraceInstEntry::print(
410 const std::string
&prefix
) const
413 std::string opcode_str
= csprintf("%0*x", instSize
>> 2, opcode
);
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 */
430 TarmacTracerRecord::TraceMemEntry::print(
433 const std::string
&prefix
) const
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 */
447 TarmacTracerRecord::TraceRegEntry::print(
450 const std::string
&prefix
) const
452 // Print the register record formatted according
453 // to the Tarmac specification
455 ccprintf(outs
, "%s clk R %s %08x\n",
456 curTick(), /* Tick time */
457 regName
, /* Register name */
458 values
[Lo
]); /* Register value */