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/**
41 * @file: The file contains the informations used to generate records
42 *        for the pre-ARMv8 cores.
43 */
44
45#ifndef __ARCH_ARM_TRACERS_TARMAC_RECORD_HH__
46#define __ARCH_ARM_TRACERS_TARMAC_RECORD_HH__
47
48#include "arch/arm/tracers/tarmac_base.hh"
49#include "base/printable.hh"
50#include "config/the_isa.hh"
51#include "cpu/reg_class.hh"
52#include "cpu/static_inst.hh"
53
54namespace Trace {
55
56class TarmacContext;
57
58class TarmacTracer;
59
60/**
61 * Returns the string representation of the instruction set being
62 * currently run according to the Tarmac format.
63 *
64 * @param isetstate: enum variable (ISetState) specifying an ARM
65 *                   instruction set.
66 * @return instruction set in string format.
67 */
68std::string
69iSetStateToStr(TarmacBaseRecord::ISetState isetstate);
70
71/**
72 * Returns the string representation of the ARM Operating Mode
73 * (CPSR.M[3:0] field) according to the Tarmac format.
74 *
75 * @param opMode: ARM operating mode.
76 * @return operating mode in string format.
77 */
78std::string
79opModeToStr(ArmISA::OperatingMode opMode);
80
81/**
82 * TarmacTracer Record:
83 * Record generated by the TarmacTracer for every executed instruction.
84 * The record is composed by a set of entries, matching the tracing
85 * capabilities provided by the Tarmac specifications:
86 *
87 * - Instruction Entry
88 * - Register Entry
89 * - Memory Entry
90 */
91class TarmacTracerRecord : public TarmacBaseRecord
92{
93  public:
94    /** Instruction Entry */
95    struct TraceInstEntry: public InstEntry, Printable
96    {
97        TraceInstEntry(const TarmacContext& tarmCtx, bool predicate);
98
99        virtual void print(std::ostream& outs,
100                           int verbosity = 0,
101                           const std::string &prefix = "") const override;
102
103      protected:
104        /** Number of instructions being traced */
105        static uint64_t instCount;
106
107        /** True if instruction is executed in secure mode */
108        bool secureMode;
109        /**
110         * Instruction size:
111         * 16 for 16-bit Thumb Instruction
112         * 32 otherwise (ARM and BigThumb)
113         */
114        uint8_t instSize;
115    };
116
117    /** Register Entry */
118    struct TraceRegEntry: public RegEntry, Printable
119    {
120      public:
121        TraceRegEntry(const TarmacContext& tarmCtx, const RegId& reg);
122
123        /**
124         * This updates the register entry using the update table. It is
125         * a required step after the register entry generation.
126         * If unupdated, the entry will be marked as invalid.
127         * The entry update cannot be done automatically at TraceRegEntry
128         * construction: the entries are extended by consequent Tarmac
129         * Tracer versions (like V8), and virtual functions should
130         * be avoided during construction.
131         */
132        void update(const TarmacContext& tarmCtx);
133
134        virtual void print(std::ostream& outs,
135                           int verbosity = 0,
136                           const std::string &prefix = "") const override;
137
138      protected:
139        /** Register update functions. */
140        virtual void
141        updateMisc(const TarmacContext& tarmCtx, RegIndex regRelIdx);
142
143        virtual void
144        updateCC(const TarmacContext& tarmCtx, RegIndex regRelIdx);
145
146        virtual void
147        updateFloat(const TarmacContext& tarmCtx, RegIndex regRelIdx);
148
149        virtual void
150        updateInt(const TarmacContext& tarmCtx, RegIndex regRelIdx);
151
152      public:
153        /** True if register entry is valid */
154        bool regValid;
155        /** Register class */
156        RegClass regClass;
157        /** Register arch number */
158        RegIndex regRel;
159        /** Register name to be printed */
160        std::string regName;
161    };
162
163    /** Memory Entry */
164    struct TraceMemEntry: public MemEntry, Printable
165    {
166      public:
167        TraceMemEntry(const TarmacContext& tarmCtx,
168                      uint8_t _size, Addr _addr, uint64_t _data);
169
170        virtual void print(std::ostream& outs,
171                           int verbosity = 0,
172                           const std::string &prefix = "") const override;
173
174      protected:
175        /** True if memory access is a load */
176        bool loadAccess;
177    };
178
179  public:
180    TarmacTracerRecord(Tick _when, ThreadContext *_thread,
181                       const StaticInstPtr _staticInst, ArmISA::PCState _pc,
182                       TarmacTracer& _tracer,
183                       const StaticInstPtr _macroStaticInst = NULL);
184
185    virtual void dump() override;
186
187    using InstPtr = std::unique_ptr<TraceInstEntry>;
188    using MemPtr = std::unique_ptr<TraceMemEntry>;
189    using RegPtr = std::unique_ptr<TraceRegEntry>;
190
191  protected:
192    /** Generates an Entry for the executed instruction. */
193    virtual void addInstEntry(std::vector<InstPtr>& queue,
194                              const TarmacContext& ptr);
195
196    /** Generates an Entry for every triggered memory access */
197    virtual void addMemEntry(std::vector<MemPtr>& queue,
198                             const TarmacContext& ptr);
199
200    /** Generate an Entry for every register being written. */
201    virtual void addRegEntry(std::vector<RegPtr>& queue,
202                             const TarmacContext& ptr);
203
204  protected:
205    /** Generate and update a register entry. */
206    template<typename RegEntry>
207    RegEntry
208    genRegister(const TarmacContext& tarmCtx, const RegId& reg)
209    {
210        RegEntry single_reg(tarmCtx, reg);
211        single_reg.update(tarmCtx);
212
213        return single_reg;
214    }
215
216    template<typename RegEntry>
217    void
218    mergeCCEntry(std::vector<RegPtr>& queue, const TarmacContext& tarmCtx)
219    {
220        // Find all CC Entries and move them at the end of the queue
221        auto it = std::remove_if(
222            queue.begin(), queue.end(),
223            [] (RegPtr& reg) ->bool { return (reg->regClass == CCRegClass); }
224        );
225
226        if (it != queue.end()) {
227            // Remove all CC Entries.
228            queue.erase(it, queue.end());
229
230            auto is_cpsr = [] (RegPtr& reg) ->bool
231            {
232                return (reg->regClass == MiscRegClass) &&
233                       (reg->regRel == ArmISA::MISCREG_CPSR);
234            };
235
236            // Looking for the presence of a CPSR register entry.
237            auto cpsr_it = std::find_if(
238                queue.begin(), queue.end(), is_cpsr
239            );
240
241            // If CPSR entry not present, generate one
242            if (cpsr_it == queue.end()) {
243                RegId reg(MiscRegClass, ArmISA::MISCREG_CPSR);
244                queue.push_back(
245                    m5::make_unique<RegEntry>(
246                        genRegister<RegEntry>(tarmCtx, reg))
247                );
248            }
249        }
250    }
251
252    /** Flush queues to the trace output */
253    template<typename Queue>
254    void flushQueues(Queue& queue);
255    template<typename Queue, typename... Args>
256    void flushQueues(Queue& queue, Args & ... args);
257
258  protected:
259    /** Reference to tracer */
260    TarmacTracer& tracer;
261};
262
263} // namespace Trace
264
265#endif // __ARCH_ARM_TRACERS_TARMAC_RECORD_HH__
266