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_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
46namespace Trace {
47
48TarmacTracerRecordV8::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
63TarmacTracerRecordV8::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
77TarmacTracerRecordV8::TraceRegEntryV8::TraceRegEntryV8(
78    const TarmacContext& tarmCtx,
79    const RegId& reg)
80      : TraceRegEntry(tarmCtx, reg),
81        TraceEntryV8(tarmCtx.tarmacCpuName()),
82        regWidth(64)
83{
84}
85
86void
87TarmacTracerRecordV8::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
117void
118TarmacTracerRecordV8::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
128void
129TarmacTracerRecordV8::addInstEntry(std::vector<InstPtr>& queue,
130                                   const TarmacContext& tarmCtx)
131{
132    // Generate an instruction entry in the record and
133    // add it to the Instruction Queue
134    queue.push_back(
135        m5::make_unique<TraceInstEntryV8>(tarmCtx, predicate)
136    );
137}
138
139void
140TarmacTracerRecordV8::addMemEntry(std::vector<MemPtr>& queue,
141                                  const TarmacContext& tarmCtx)
142{
143    // Generate a memory entry in the record if the record
144    // implies a valid memory access, and add it to the
145    // Memory Queue
146    if (getMemValid()) {
147        queue.push_back(
148            m5::make_unique<TraceMemEntryV8>(tarmCtx,
149                                             static_cast<uint8_t>(getSize()),
150                                             getAddr(), getIntData())
151        );
152    }
153}
154
155void
156TarmacTracerRecordV8::addRegEntry(std::vector<RegPtr>& queue,
157                                  const TarmacContext& tarmCtx)
158{
159    // Generate an entry for every ARM register being
160    // written by the current instruction
161    for (auto reg = 0; reg < staticInst->numDestRegs(); ++reg) {
162
163        RegId reg_id = staticInst->destRegIdx(reg);
164
165        // Creating a single register change entry
166        auto single_reg = genRegister<TraceRegEntryV8>(tarmCtx, reg_id);
167
168        // Copying the entry and adding it to the "list"
169        // of entries to be dumped to trace.
170        queue.push_back(
171            m5::make_unique<TraceRegEntryV8>(single_reg)
172        );
173    }
174
175    // Gem5 is treating CPSR flags as separate registers (CC registers),
176    // in contrast with Tarmac specification: we need to merge the gem5 CC
177    // entries altogether with the CPSR register and produce a single entry.
178    mergeCCEntry<TraceRegEntryV8>(queue, tarmCtx);
179}
180
181void
182TarmacTracerRecordV8::TraceInstEntryV8::print(
183    std::ostream& outs,
184    int verbosity,
185    const std::string &prefix) const
186{
187    // If there is a valid vaddr->paddr translation, print the
188    // physical address, otherwise print the virtual address only.
189    std::string paddr_str = paddrValid? csprintf(":%012x",paddr) :
190                                        std::string();
191
192    // Pad the opcode.
193    std::string opcode_str = csprintf("%0*x", instSize >> 2, opcode);
194
195    // Print the instruction record formatted according
196    // to the Tarmac specification
197    ccprintf(outs, "%s clk %s %s (%u) %08x%s %s %s %s_%s : %s\n",
198             curTick(),                     /* Tick time */
199             cpuName,                       /* Cpu name */
200             taken? "IT" : "IS",            /* Instruction taken/skipped */
201             instCount,                     /* Instruction count */
202             addr,                          /* Instruction virt address */
203             paddr_str,                     /* Instruction phys address */
204             opcode_str,                    /* Instruction opcode */
205             iSetStateToStr(isetstate),     /* Instruction Set */
206             opModeToStr(mode),             /* Exception level */
207             secureMode? "s" : "ns",        /* Security */
208             disassemble);                  /* Instruction disass */
209}
210
211void
212TarmacTracerRecordV8::TraceMemEntryV8::print(
213    std::ostream& outs,
214    int verbosity,
215    const std::string &prefix) const
216{
217    // Print the memory record formatted according
218    // to the Tarmac specification
219    ccprintf(outs, "%s clk %s M%s%d %08x:%012x %0*x\n",
220             curTick(),                 /* Tick time */
221             cpuName,                   /* Cpu name */
222             loadAccess? "R" : "W",     /* Access type */
223             size,                      /* Access size */
224             addr,                      /* Virt Memory address */
225             paddr,                     /* Phys Memory address */
226             size*2,                    /* Padding with access size */
227             data);                     /* Memory data */
228}
229
230void
231TarmacTracerRecordV8::TraceRegEntryV8::print(
232    std::ostream& outs,
233    int verbosity,
234    const std::string &prefix) const
235{
236    // Print the register record formatted according
237    // to the Tarmac specification
238    if (regValid) {
239        ccprintf(outs, "%s clk %s R %s %0*x\n",
240                 curTick(),            /* Tick time */
241                 cpuName,              /* Cpu name */
242                 regName,              /* Register name */
243                 regWidth >> 2,        /* Register value padding */
244                 valueLo);             /* Register value */
245    }
246}
247
248} // namespace Trace
249