mem-cache: Add multiple eviction stats
[gem5.git] / src / arch / arm / tracers / tarmac_record_v8.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 * Authors: Giacomo Travaglini
38 */
39
40 #include "arch/arm/tracers/tarmac_record_v8.hh"
41
42 #include "arch/arm/insts/static_inst.hh"
43 #include "arch/arm/tlb.hh"
44 #include "arch/arm/tracers/tarmac_tracer.hh"
45
46 namespace Trace {
47
48 TarmacTracerRecordV8::TraceInstEntryV8::TraceInstEntryV8(
49 const TarmacContext& tarmCtx,
50 bool predicate)
51 : TraceInstEntry(tarmCtx, predicate),
52 TraceEntryV8(tarmCtx.tarmacCpuName()),
53 paddr(0),
54 paddrValid(false)
55 {
56 const auto thread = tarmCtx.thread;
57
58 // Evaluate physical address
59 ArmISA::TLB* dtb = static_cast<TLB*>(thread->getDTBPtr());
60 paddrValid = dtb->translateFunctional(thread, addr, paddr);
61 }
62
63 TarmacTracerRecordV8::TraceMemEntryV8::TraceMemEntryV8(
64 const TarmacContext& tarmCtx,
65 uint8_t _size, Addr _addr, uint64_t _data)
66 : TraceMemEntry(tarmCtx, _size, _addr, _data),
67 TraceEntryV8(tarmCtx.tarmacCpuName()),
68 paddr(_addr)
69 {
70 const auto thread = tarmCtx.thread;
71
72 // Evaluate physical address
73 ArmISA::TLB* dtb = static_cast<TLB*>(thread->getDTBPtr());
74 dtb->translateFunctional(thread, addr, paddr);
75 }
76
77 TarmacTracerRecordV8::TraceRegEntryV8::TraceRegEntryV8(
78 const TarmacContext& tarmCtx,
79 const RegId& reg)
80 : TraceRegEntry(tarmCtx, reg),
81 TraceEntryV8(tarmCtx.tarmacCpuName()),
82 regWidth(64)
83 {
84 }
85
86 void
87 TarmacTracerRecordV8::TraceRegEntryV8::updateInt(
88 const TarmacContext& tarmCtx,
89 RegIndex regRelIdx
90 )
91 {
92 // Do not trace pseudo register accesses: invalid
93 // register entry.
94 if (regRelIdx > NUM_ARCH_INTREGS) {
95 regValid = false;
96 return;
97 }
98
99 TraceRegEntry::updateInt(tarmCtx, regRelIdx);
100
101 if ((regRelIdx != PCReg) || (regRelIdx != StackPointerReg) ||
102 (regRelIdx != FramePointerReg) || (regRelIdx != ReturnAddressReg)) {
103
104 const auto* arm_inst = static_cast<const ArmStaticInst*>(
105 tarmCtx.staticInst.get()
106 );
107
108 regWidth = (arm_inst->getIntWidth());
109 if (regWidth == 32) {
110 regName = "W" + std::to_string(regRelIdx);
111 } else {
112 regName = "X" + std::to_string(regRelIdx);
113 }
114 }
115 }
116
117 void
118 TarmacTracerRecordV8::TraceRegEntryV8::updateMisc(
119 const TarmacContext& tarmCtx,
120 RegIndex regRelIdx
121 )
122 {
123 TraceRegEntry::updateMisc(tarmCtx, regRelIdx);
124 // System registers are 32bit wide
125 regWidth = 32;
126 }
127
128 void
129 TarmacTracerRecordV8::TraceRegEntryV8::updateVec(
130 const TarmacContext& tarmCtx,
131 RegIndex regRelIdx
132 )
133 {
134 auto thread = tarmCtx.thread;
135 const auto& vec_container = thread->readVecReg(
136 RegId(regClass, regRelIdx));
137 auto vv = vec_container.as<VecElem>();
138
139 regWidth = ArmStaticInst::getCurSveVecLenInBits(thread);
140 auto num_elements = regWidth / (sizeof(VecElem) * 8);
141
142 // Resize vector of values
143 values.resize(num_elements);
144
145 for (auto i = 0; i < num_elements; i++) {
146 values[i] = vv[i];
147 }
148
149 regValid = true;
150 regName = "Z" + std::to_string(regRelIdx);
151 }
152
153 void
154 TarmacTracerRecordV8::TraceRegEntryV8::updatePred(
155 const TarmacContext& tarmCtx,
156 RegIndex regRelIdx
157 )
158 {
159 auto thread = tarmCtx.thread;
160 const auto& pred_container = thread->readVecPredReg(
161 RegId(regClass, regRelIdx));
162
163 // Predicate registers are always 1/8 the size of related vector
164 // registers. (getCurSveVecLenInBits(thread) / 8)
165 regWidth = ArmStaticInst::getCurSveVecLenInBits(thread) / 8;
166 auto num_elements = regWidth / 16;
167
168 // Resize vector of values
169 values.resize(num_elements);
170
171 // Get a copy of pred_container as a vector of half-words
172 auto vv = pred_container.as<uint16_t>();
173 for (auto i = 0; i < num_elements; i++) {
174 values[i] = vv[i];
175 }
176
177 regValid = true;
178 regName = "P" + std::to_string(regRelIdx);
179 }
180
181 void
182 TarmacTracerRecordV8::addInstEntry(std::vector<InstPtr>& queue,
183 const TarmacContext& tarmCtx)
184 {
185 // Generate an instruction entry in the record and
186 // add it to the Instruction Queue
187 queue.push_back(
188 m5::make_unique<TraceInstEntryV8>(tarmCtx, predicate)
189 );
190 }
191
192 void
193 TarmacTracerRecordV8::addMemEntry(std::vector<MemPtr>& queue,
194 const TarmacContext& tarmCtx)
195 {
196 // Generate a memory entry in the record if the record
197 // implies a valid memory access, and add it to the
198 // Memory Queue
199 if (getMemValid()) {
200 queue.push_back(
201 m5::make_unique<TraceMemEntryV8>(tarmCtx,
202 static_cast<uint8_t>(getSize()),
203 getAddr(), getIntData())
204 );
205 }
206 }
207
208 void
209 TarmacTracerRecordV8::addRegEntry(std::vector<RegPtr>& queue,
210 const TarmacContext& tarmCtx)
211 {
212 // Generate an entry for every ARM register being
213 // written by the current instruction
214 for (auto reg = 0; reg < staticInst->numDestRegs(); ++reg) {
215
216 RegId reg_id = staticInst->destRegIdx(reg);
217
218 // Creating a single register change entry
219 auto single_reg = genRegister<TraceRegEntryV8>(tarmCtx, reg_id);
220
221 // Copying the entry and adding it to the "list"
222 // of entries to be dumped to trace.
223 queue.push_back(
224 m5::make_unique<TraceRegEntryV8>(single_reg)
225 );
226 }
227
228 // Gem5 is treating CPSR flags as separate registers (CC registers),
229 // in contrast with Tarmac specification: we need to merge the gem5 CC
230 // entries altogether with the CPSR register and produce a single entry.
231 mergeCCEntry<TraceRegEntryV8>(queue, tarmCtx);
232 }
233
234 void
235 TarmacTracerRecordV8::TraceInstEntryV8::print(
236 std::ostream& outs,
237 int verbosity,
238 const std::string &prefix) const
239 {
240 // If there is a valid vaddr->paddr translation, print the
241 // physical address, otherwise print the virtual address only.
242 std::string paddr_str = paddrValid? csprintf(":%012x",paddr) :
243 std::string();
244
245 // Pad the opcode.
246 std::string opcode_str = csprintf("%0*x", instSize >> 2, opcode);
247
248 // Print the instruction record formatted according
249 // to the Tarmac specification
250 ccprintf(outs, "%s clk %s %s (%u) %08x%s %s %s %s_%s : %s\n",
251 curTick(), /* Tick time */
252 cpuName, /* Cpu name */
253 taken? "IT" : "IS", /* Instruction taken/skipped */
254 instCount, /* Instruction count */
255 addr, /* Instruction virt address */
256 paddr_str, /* Instruction phys address */
257 opcode_str, /* Instruction opcode */
258 iSetStateToStr(isetstate), /* Instruction Set */
259 opModeToStr(mode), /* Exception level */
260 secureMode? "s" : "ns", /* Security */
261 disassemble); /* Instruction disass */
262 }
263
264 void
265 TarmacTracerRecordV8::TraceMemEntryV8::print(
266 std::ostream& outs,
267 int verbosity,
268 const std::string &prefix) const
269 {
270 // Print the memory record formatted according
271 // to the Tarmac specification
272 ccprintf(outs, "%s clk %s M%s%d %08x:%012x %0*x\n",
273 curTick(), /* Tick time */
274 cpuName, /* Cpu name */
275 loadAccess? "R" : "W", /* Access type */
276 size, /* Access size */
277 addr, /* Virt Memory address */
278 paddr, /* Phys Memory address */
279 size*2, /* Padding with access size */
280 data); /* Memory data */
281 }
282
283 void
284 TarmacTracerRecordV8::TraceRegEntryV8::print(
285 std::ostream& outs,
286 int verbosity,
287 const std::string &prefix) const
288 {
289 // Print the register record formatted according
290 // to the Tarmac specification
291 if (regValid) {
292 ccprintf(outs, "%s clk %s R %s %s\n",
293 curTick(), /* Tick time */
294 cpuName, /* Cpu name */
295 regName, /* Register name */
296 formatReg()); /* Register value */
297 }
298 }
299
300 std::string
301 TarmacTracerRecordV8::TraceRegEntryV8::formatReg() const
302 {
303 if (regWidth <= 64) {
304 // Register width is < 64 bit (scalar register).
305 return csprintf("%0*x", regWidth / 4, values[Lo]);
306 } else {
307
308 // Register width is > 64 bit (vector). Iterate over every vector
309 // element. Since the vector values are stored in Little Endian, print
310 // starting from the last element.
311 std::string reg_val;
312 for (auto it = values.rbegin(); it != values.rend(); it++) {
313 reg_val += csprintf("%0*x_",
314 static_cast<int>(sizeof(VecElem) * 2), *it);
315 }
316
317 // Remove trailing underscore
318 reg_val.pop_back();
319
320 return reg_val;
321 }
322 }
323
324 } // namespace Trace