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.
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 updateVec(tarmCtx
, regRel
);
184 case VecPredRegClass
:
185 updatePred(tarmCtx
, regRel
);
188 // If unsupported format, do nothing: non updating
189 // the register will prevent it to be printed.
195 TarmacTracerRecord::TraceRegEntry::updateMisc(
196 const TarmacContext
& tarmCtx
,
200 auto thread
= tarmCtx
.thread
;
203 regName
= miscRegName
[regRelIdx
];
204 values
[Lo
] = thread
->readMiscRegNoEffect(regRelIdx
);
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
);
216 // update the entry value
222 TarmacTracerRecord::TraceRegEntry::updateCC(
223 const TarmacContext
& tarmCtx
,
227 auto thread
= tarmCtx
.thread
;
230 regName
= ccRegName
[regRelIdx
];
231 values
[Lo
] = thread
->readCCReg(regRelIdx
);
235 TarmacTracerRecord::TraceRegEntry::updateFloat(
236 const TarmacContext
& tarmCtx
,
240 auto thread
= tarmCtx
.thread
;
243 regName
= "f" + std::to_string(regRelIdx
);
244 values
[Lo
] = bitsToFloat32(thread
->readFloatReg(regRelIdx
));
248 TarmacTracerRecord::TraceRegEntry::updateInt(
249 const TarmacContext
& tarmCtx
,
253 auto thread
= tarmCtx
.thread
;
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
;
261 std::string reg_suffix
;
262 if (mode
!= MODE_USER
) {
263 reg_suffix
= "_" + opModeToStr(mode
);
271 case StackPointerReg
:
272 regName
= "sp" + reg_suffix
;
274 case FramePointerReg
:
275 regName
= "fp" + reg_suffix
;
277 case ReturnAddressReg
:
278 regName
= "lr" + reg_suffix
;
281 regName
= "r" + std::to_string(regRelIdx
);
284 values
[Lo
] = thread
->readIntReg(regRelIdx
);
288 TarmacTracerRecord::addInstEntry(std::vector
<InstPtr
>& queue
,
289 const TarmacContext
& tarmCtx
)
291 // Generate an instruction entry in the record and
292 // add it to the Instruction Queue
294 m5::make_unique
<TraceInstEntry
>(tarmCtx
, predicate
)
299 TarmacTracerRecord::addMemEntry(std::vector
<MemPtr
>& queue
,
300 const TarmacContext
& tarmCtx
)
302 // Generate a memory entry in the record if the record
303 // implies a valid memory access, and add it to the
307 m5::make_unique
<TraceMemEntry
>(tarmCtx
,
308 static_cast<uint8_t>(getSize()),
309 getAddr(), getIntData())
315 TarmacTracerRecord::addRegEntry(std::vector
<RegPtr
>& queue
,
316 const TarmacContext
& tarmCtx
)
318 // Generate an entry for every ARM register being
319 // written by the current instruction
320 for (auto reg
= 0; reg
< staticInst
->numDestRegs(); ++reg
) {
322 RegId reg_id
= staticInst
->destRegIdx(reg
);
324 // Creating a single register change entry
325 auto single_reg
= genRegister
<TraceRegEntry
>(tarmCtx
, reg_id
);
327 // Copying the entry and adding it to the "list"
328 // of entries to be dumped to trace.
330 m5::make_unique
<TraceRegEntry
>(single_reg
)
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
);
341 TarmacTracerRecord::dump()
343 // Generate and print all the record's entries.
344 auto &instQueue
= tracer
.instQueue
;
345 auto &memQueue
= tracer
.memQueue
;
346 auto ®Queue
= tracer
.regQueue
;
348 const TarmacContext
tarmCtx(
350 staticInst
->isMicroop()? macroStaticInst
: staticInst
,
354 if (!staticInst
->isMicroop()) {
355 // Current instruction is NOT a micro-instruction:
356 // Generate Tarmac entries and dump them immediately
358 // Generate Tarmac entries and add them to the respective
360 addInstEntry(instQueue
, tarmCtx
);
361 addMemEntry(memQueue
, tarmCtx
);
362 addRegEntry(regQueue
, tarmCtx
);
364 // Flush (print) any queued entry.
365 flushQueues(instQueue
, memQueue
, regQueue
);
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
373 if (staticInst
->isFirstMicroop()) {
374 addInstEntry(instQueue
, tarmCtx
);
377 addRegEntry(regQueue
, tarmCtx
);
378 addMemEntry(memQueue
, tarmCtx
);
380 if (staticInst
->isLastMicroop()) {
381 // Flush (print) any queued entry.
382 flushQueues(instQueue
, memQueue
, regQueue
);
387 template<typename Queue
>
389 TarmacTracerRecord::flushQueues(Queue
& queue
)
391 std::ostream
&outs
= Trace::output();
393 for (const auto &single_entry
: queue
) {
394 single_entry
->print(outs
);
400 template<typename Queue
, typename
... Args
>
402 TarmacTracerRecord::flushQueues(Queue
& queue
, Args
& ... args
)
405 flushQueues(args
...);
409 TarmacTracerRecord::TraceInstEntry::print(
412 const std::string
&prefix
) const
415 std::string opcode_str
= csprintf("%0*x", instSize
>> 2, opcode
);
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 */
432 TarmacTracerRecord::TraceMemEntry::print(
435 const std::string
&prefix
) const
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 */
449 TarmacTracerRecord::TraceRegEntry::print(
452 const std::string
&prefix
) const
454 // Print the register record formatted according
455 // to the Tarmac specification
457 ccprintf(outs
, "%s clk R %s %08x\n",
458 curTick(), /* Tick time */
459 regName
, /* Register name */
460 values
[Lo
]); /* Register value */