1/*
2 * Copyright (c) 2017 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 * Copyright (c) 2001-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Steve Reinhardt
41 *          Lisa Hsu
42 *          Nathan Binkert
43 *          Steve Raasch
44 */
45
46#include "cpu/exetrace.hh"
47
48#include <iomanip>
49
50#include "arch/isa_traits.hh"
51#include "arch/utility.hh"
52#include "base/loader/symtab.hh"
53#include "config/the_isa.hh"
54#include "cpu/base.hh"
55#include "cpu/static_inst.hh"
56#include "cpu/thread_context.hh"
57#include "debug/ExecAll.hh"
58#include "enums/OpClass.hh"
59
60using namespace std;
61using namespace TheISA;
62
63namespace Trace {
64
65void
66ExeTracerRecord::dumpTicks(ostream &outs)
67{
68    ccprintf(outs, "%7d: ", when);
69}
70
71void
72Trace::ExeTracerRecord::traceInst(const StaticInstPtr &inst, bool ran)
73{
74    ostream &outs = Trace::output();
75
76    if (!Debug::ExecUser || !Debug::ExecKernel) {
77        bool in_user_mode = TheISA::inUserMode(thread);
78        if (in_user_mode && !Debug::ExecUser) return;
79        if (!in_user_mode && !Debug::ExecKernel) return;
80    }
81
82    if (Debug::ExecTicks)
83        dumpTicks(outs);
84
85    outs << thread->getCpuPtr()->name() << " ";
86
87    if (Debug::ExecAsid)
88        outs << "A" << dec << TheISA::getExecutingAsid(thread) << " ";
89
90    if (Debug::ExecThread)
91        outs << "T" << thread->threadId() << " : ";
92
93    std::string sym_str;
94    Addr sym_addr;
95    Addr cur_pc = pc.instAddr();
96    if (debugSymbolTable && Debug::ExecSymbol &&
97            (!FullSystem || !inUserMode(thread)) &&
98            debugSymbolTable->findNearestSymbol(cur_pc, sym_str, sym_addr)) {
99        if (cur_pc != sym_addr)
100            sym_str += csprintf("+%d",cur_pc - sym_addr);
101        outs << "@" << sym_str;
102    } else {
103        outs << "0x" << hex << cur_pc;
104    }
105
106    if (inst->isMicroop()) {
107        outs << "." << setw(2) << dec << pc.microPC();
108    } else {
109        outs << "   ";
110    }
111
112    outs << " : ";
113
114    //
115    //  Print decoded instruction
116    //
117
118    outs << setw(26) << left;
119    outs << inst->disassemble(cur_pc, debugSymbolTable);
120
121    if (ran) {
122        outs << " : ";
123
124        if (Debug::ExecOpClass) {
125            outs << Enums::OpClassStrings[inst->opClass()] << " : ";
126        }
127
128        if (Debug::ExecResult && !predicate) {
129            outs << "Predicated False";
130        }
131
132        if (Debug::ExecResult && data_status != DataInvalid) {
133            switch (data_status) {
134              case DataVec:
135                {
136                    ccprintf(outs, " D=0x[");
137                    auto dv = data.as_vec->as<uint32_t>();
138                    for (int i = TheISA::VecRegSizeBytes / 4 - 1; i >= 0;
139                         i--) {
140                        ccprintf(outs, "%08x", dv[i]);
141                        if (i != 0) {
142                            ccprintf(outs, "_");
143                        }
144                    }
145                    ccprintf(outs, "]");
146                }
147                break;
148              case DataVecPred:
149                {
150                    ccprintf(outs, " D=0b[");
151                    auto pv = data.as_pred->as<uint8_t>();
152                    for (int i = TheISA::VecPredRegSizeBits - 1; i >= 0; i--) {
153                        ccprintf(outs, pv[i] ? "1" : "0");
154                        if (i != 0 && i % 4 == 0) {
155                            ccprintf(outs, "_");
156                        }
157                    }
158                    ccprintf(outs, "]");
159                }
160                break;
161              default:
162                ccprintf(outs, " D=%#018x", data.as_int);
163                break;
164            }
165        }
166
167        if (Debug::ExecEffAddr && getMemValid())
168            outs << " A=0x" << hex << addr;
169
170        if (Debug::ExecFetchSeq && fetch_seq_valid)
171            outs << "  FetchSeq=" << dec << fetch_seq;
172
173        if (Debug::ExecCPSeq && cp_seq_valid)
174            outs << "  CPSeq=" << dec << cp_seq;
175
176        if (Debug::ExecFlags) {
177            outs << "  flags=(";
178            inst->printFlags(outs, "|");
179            outs << ")";
180        }
181    }
182
183    //
184    //  End of line...
185    //
186    outs << endl;
187}
188
189void
190Trace::ExeTracerRecord::dump()
191{
192    /*
193     * The behavior this check tries to achieve is that if ExecMacro is on,
194     * the macroop will be printed. If it's on and microops are also on, it's
195     * printed before the microops start printing to give context. If the
196     * microops aren't printed, then it's printed only when the final microop
197     * finishes. Macroops then behave like regular instructions and don't
198     * complete/print when they fault.
199     */
200    if (Debug::ExecMacro && staticInst->isMicroop() &&
201        ((Debug::ExecMicro &&
202            macroStaticInst && staticInst->isFirstMicroop()) ||
203            (!Debug::ExecMicro &&
204             macroStaticInst && staticInst->isLastMicroop()))) {
205        traceInst(macroStaticInst, false);
206    }
207    if (Debug::ExecMicro || !staticInst->isMicroop()) {
208        traceInst(staticInst, true);
209    }
210}
211
212} // namespace Trace
213
214////////////////////////////////////////////////////////////////////////
215//
216//  ExeTracer Simulation Object
217//
218Trace::ExeTracer *
219ExeTracerParams::create()
220{
221    return new Trace::ExeTracer(this);
222}
223