1/*
2 * Copyright (c) 2011,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 Gabrielli
38 */
39
40/**
41 * @file This module implements a bridge between TARMAC traces, as generated by
42 * other models, and gem5 (AtomicCPU model). Its goal is to detect possible
43 * inconsistencies between the two models as soon as they occur.  The module
44 * takes a TARMAC trace as input, which is used to compare the architectural
45 * state of the two models after each simulated instruction.
46 */
47
48#ifndef __ARCH_ARM_TRACERS_TARMAC_PARSER_HH__
49#define __ARCH_ARM_TRACERS_TARMAC_PARSER_HH__
50
51#include <fstream>
52#include <unordered_map>
53
54#include "arch/arm/registers.hh"
55#include "base/trace.hh"
56#include "base/types.hh"
57#include "cpu/static_inst.hh"
58#include "cpu/thread_context.hh"
59#include "mem/request.hh"
60#include "params/TarmacParser.hh"
61#include "sim/insttracer.hh"
62#include "tarmac_base.hh"
63
64namespace Trace {
65
66class TarmacParserRecord : public TarmacBaseRecord
67{
68  public:
69    /**
70     * Event triggered to check the value of the destination registers.  Needed
71     * to handle some cases where registers are modified after the trace record
72     * has been dumped.  E.g., the SVC instruction updates the CPSR and SPSR as
73     * part of the fault handling routine.
74     */
75    struct TarmacParserRecordEvent: public Event
76    {
77        /**
78         * Reference to the TARMAC trace object to which this record belongs.
79         */
80        TarmacParser& parent;
81        /** Current thread context. */
82        ThreadContext* thread;
83        /** Current instruction. */
84        const StaticInstPtr inst;
85        /** PC of the current instruction. */
86        ArmISA::PCState pc;
87        /** True if a mismatch has been detected for this instruction. */
88        bool mismatch;
89        /**
90         * True if a mismatch has been detected for this instruction on PC or
91         * opcode.
92         */
93        bool mismatchOnPcOrOpcode;
94
95        TarmacParserRecordEvent(TarmacParser& _parent,
96                                ThreadContext *_thread,
97                                const StaticInstPtr _inst,
98                                ArmISA::PCState _pc,
99                                bool _mismatch,
100                                bool _mismatch_on_pc_or_opcode) :
101            parent(_parent), thread(_thread), inst(_inst), pc(_pc),
102            mismatch(_mismatch),
103            mismatchOnPcOrOpcode(_mismatch_on_pc_or_opcode)
104        {
105        }
106
107        void process();
108        const char *description() const;
109    };
110
111    struct ParserInstEntry : public InstEntry
112    {
113      public:
114        uint64_t seq_num;
115    };
116
117    struct ParserRegEntry : public RegEntry
118    {
119      public:
120        char repr[16];
121    };
122
123    struct ParserMemEntry : public MemEntry
124    { };
125
126    static const int MaxLineLength = 256;
127
128    /**
129     * Print a mismatch header containing the instruction fields as reported
130     * by gem5.
131     */
132    static void printMismatchHeader(const StaticInstPtr inst,
133                                    ArmISA::PCState pc);
134
135    TarmacParserRecord(Tick _when, ThreadContext *_thread,
136                       const StaticInstPtr _staticInst, ArmISA::PCState _pc,
137                       TarmacParser& _parent,
138                       const StaticInstPtr _macroStaticInst = NULL);
139
140    void dump() override;
141
142    /**
143     * Performs a memory access to read the value written by a previous write.
144     * @return False if the result of the memory access should be ignored
145     * (faulty memory access, etc.).
146     */
147    bool readMemNoEffect(Addr addr, uint8_t *data, unsigned size,
148                         unsigned flags);
149
150  private:
151    /**
152     * Advances the TARMAC trace up to the next instruction,
153     * register, or memory access record. The collected data is stored
154     * in one of {inst/reg/mem}_record.
155     * @return False if EOF is reached.
156     */
157    bool advanceTrace();
158
159    /** Returns the string representation of an instruction set state. */
160    const char *iSetStateToStr(ISetState isetstate) const;
161
162    /** Buffer for instruction trace records. */
163    static ParserInstEntry instRecord;
164
165    /** Buffer for register trace records. */
166    static ParserRegEntry regRecord;
167
168    /** Buffer for memory access trace records (stores only). */
169    static ParserMemEntry memRecord;
170
171    /** Type of last parsed record. */
172    static TarmacRecordType currRecordType;
173
174    /** Buffer used for trace file parsing. */
175    static char buf[MaxLineLength];
176
177    /** List of records of destination registers. */
178    static std::list<ParserRegEntry> destRegRecords;
179
180    /** Map from misc. register names to indexes. */
181    using MiscRegMap = std::unordered_map<std::string, RegIndex>;
182    static MiscRegMap miscRegMap;
183
184    /**
185     * True if a TARMAC instruction record has already been parsed for this
186     * instruction.
187     */
188    bool parsingStarted;
189
190    /** True if a mismatch has been detected for this instruction. */
191    bool mismatch;
192
193    /**
194     * True if a mismatch has been detected for this instruction on PC or
195     * opcode.
196     */
197    bool mismatchOnPcOrOpcode;
198
199    /** Request for memory write checks. */
200    RequestPtr memReq;
201
202  protected:
203    TarmacParser& parent;
204};
205
206/**
207 * Tarmac Parser: this tracer parses an existing Tarmac trace and it
208 * diffs it with gem5 simulation status, comparing results and
209 * reporting architectural mismatches if any.
210 */
211class TarmacParser : public InstTracer
212{
213    friend class TarmacParserRecord;
214
215  public:
216    typedef TarmacParserParams Params;
217
218    TarmacParser(const Params *p) : InstTracer(p), startPc(p->start_pc),
219                                    exitOnDiff(p->exit_on_diff),
220                                    exitOnInsnDiff(p->exit_on_insn_diff),
221                                    memWrCheck(p->mem_wr_check),
222                                    ignoredAddrRange(p->ignore_mem_addr),
223                                    cpuId(p->cpu_id),
224                                    macroopInProgress(false)
225    {
226        assert(!(exitOnDiff && exitOnInsnDiff));
227
228        trace.open(p->path_to_trace.c_str());
229        if (startPc == 0x0) {
230            started = true;
231        } else {
232            advanceTraceToStartPc();
233            started = false;
234        }
235    }
236
237    virtual ~TarmacParser()
238    {
239        trace.close();
240    }
241
242    InstRecord *
243    getInstRecord(Tick when, ThreadContext *tc, const StaticInstPtr staticInst,
244                  ArmISA::PCState pc,
245                  const StaticInstPtr macroStaticInst = NULL)
246    {
247        if (!started && pc.pc() == startPc)
248            started = true;
249
250        if (started)
251            return new TarmacParserRecord(when, tc, staticInst, pc, *this,
252                                          macroStaticInst);
253        else
254            return NULL;
255    }
256
257  private:
258    /** Helper function to advance the trace up to startPc. */
259    void advanceTraceToStartPc();
260
261    /** TARMAC trace file. */
262    std::ifstream trace;
263
264    /**
265     * Tracing starts when the PC gets this value for the first time (ignored
266     * if 0x0).
267     */
268    Addr startPc;
269
270    /**
271     * If true, the simulation is stopped as the first mismatch is detected.
272     */
273    bool exitOnDiff;
274
275    /**
276     * If true, the simulation is stopped as the first mismatch is detected on
277     * PC or opcode.
278     */
279    bool exitOnInsnDiff;
280
281    /** If true, memory write accesses are checked. */
282    bool memWrCheck;
283
284    /** Ignored addresses (ignored if empty). */
285    AddrRange ignoredAddrRange;
286
287    /** If true, the trace format includes the CPU id. */
288    bool cpuId;
289
290    /** True if tracing has started. */
291    bool started;
292
293    /** True if a macroop is currently in progress. */
294    bool macroopInProgress;
295};
296
297} // namespace Trace
298
299#endif // __ARCH_ARM_TRACERS_TARMAC_PARSER_HH__
300