blob: 39cf5c38a677e2663e459184435f9fc4dc17b9e5 [file] [log] [blame]
/*
* Copyright (c) 2011,2017-2019 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file This module implements a bridge between TARMAC traces, as generated by
* other models, and gem5 (AtomicCPU model). Its goal is to detect possible
* inconsistencies between the two models as soon as they occur. The module
* takes a TARMAC trace as input, which is used to compare the architectural
* state of the two models after each simulated instruction.
*/
#ifndef __ARCH_ARM_TRACERS_TARMAC_PARSER_HH__
#define __ARCH_ARM_TRACERS_TARMAC_PARSER_HH__
#include <fstream>
#include <memory>
#include <unordered_map>
#include "base/trace.hh"
#include "base/types.hh"
#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
#include "mem/request.hh"
#include "params/TarmacParser.hh"
#include "sim/insttracer.hh"
#include "tarmac_base.hh"
namespace gem5
{
namespace Trace {
class TarmacParserRecord : public TarmacBaseRecord
{
public:
/**
* Event triggered to check the value of the destination registers. Needed
* to handle some cases where registers are modified after the trace record
* has been dumped. E.g., the SVC instruction updates the CPSR and SPSR as
* part of the fault handling routine.
*/
struct TarmacParserRecordEvent: public Event
{
/**
* Reference to the TARMAC trace object to which this record belongs.
*/
TarmacParser& parent;
/** Current thread context. */
ThreadContext* thread;
/** Current instruction. */
const StaticInstPtr inst;
/** PC of the current instruction. */
std::unique_ptr<PCStateBase> pc;
/** True if a mismatch has been detected for this instruction. */
bool mismatch;
/**
* True if a mismatch has been detected for this instruction on PC or
* opcode.
*/
bool mismatchOnPcOrOpcode;
TarmacParserRecordEvent(TarmacParser& _parent,
ThreadContext *_thread,
const StaticInstPtr _inst,
const PCStateBase &_pc,
bool _mismatch,
bool _mismatch_on_pc_or_opcode) :
parent(_parent), thread(_thread), inst(_inst), pc(_pc.clone()),
mismatch(_mismatch),
mismatchOnPcOrOpcode(_mismatch_on_pc_or_opcode)
{
}
void process();
const char *description() const;
};
struct ParserInstEntry : public InstEntry
{
public:
uint64_t seq_num;
};
struct ParserRegEntry : public RegEntry
{
public:
char repr[16];
};
struct ParserMemEntry : public MemEntry
{ };
static const int MaxLineLength = 256;
/**
* Print a mismatch header containing the instruction fields as reported
* by gem5.
*/
static void printMismatchHeader(const StaticInstPtr inst,
const PCStateBase &pc);
TarmacParserRecord(Tick _when, ThreadContext *_thread,
const StaticInstPtr _staticInst,
const PCStateBase &_pc,
TarmacParser& _parent,
const StaticInstPtr _macroStaticInst = NULL);
void dump() override;
/**
* Performs a memory access to read the value written by a previous write.
* @return False if the result of the memory access should be ignored
* (faulty memory access, etc.).
*/
bool readMemNoEffect(Addr addr, uint8_t *data, unsigned size,
unsigned flags);
private:
/**
* Advances the TARMAC trace up to the next instruction,
* register, or memory access record. The collected data is stored
* in one of {inst/reg/mem}_record.
* @return False if EOF is reached.
*/
bool advanceTrace();
/** Returns the string representation of an instruction set state. */
const char *iSetStateToStr(ISetState isetstate) const;
/** Buffer for instruction trace records. */
static ParserInstEntry instRecord;
/** Buffer for register trace records. */
static ParserRegEntry regRecord;
/** Buffer for memory access trace records (stores only). */
static ParserMemEntry memRecord;
/** Type of last parsed record. */
static TarmacRecordType currRecordType;
/** Buffer used for trace file parsing. */
static char buf[MaxLineLength];
/** List of records of destination registers. */
static std::list<ParserRegEntry> destRegRecords;
/** Map from misc. register names to indexes. */
using MiscRegMap = std::unordered_map<std::string, RegIndex>;
static MiscRegMap miscRegMap;
/**
* True if a TARMAC instruction record has already been parsed for this
* instruction.
*/
bool parsingStarted;
/** True if a mismatch has been detected for this instruction. */
bool mismatch;
/**
* True if a mismatch has been detected for this instruction on PC or
* opcode.
*/
bool mismatchOnPcOrOpcode;
/** Request for memory write checks. */
RequestPtr memReq;
/** Max. vector length (SVE). */
static int8_t maxVectorLength;
protected:
TarmacParser& parent;
};
/**
* Tarmac Parser: this tracer parses an existing Tarmac trace and it
* diffs it with gem5 simulation status, comparing results and
* reporting architectural mismatches if any.
*/
class TarmacParser : public InstTracer
{
friend class TarmacParserRecord;
public:
typedef TarmacParserParams Params;
TarmacParser(const Params &p) : InstTracer(p), startPc(p.start_pc),
exitOnDiff(p.exit_on_diff),
exitOnInsnDiff(p.exit_on_insn_diff),
memWrCheck(p.mem_wr_check),
ignoredAddrRange(p.ignore_mem_addr),
cpuId(p.cpu_id),
macroopInProgress(false)
{
assert(!(exitOnDiff && exitOnInsnDiff));
trace.open(p.path_to_trace.c_str());
if (startPc == 0x0) {
started = true;
} else {
advanceTraceToStartPc();
started = false;
}
}
virtual ~TarmacParser()
{
trace.close();
}
InstRecord *
getInstRecord(Tick when, ThreadContext *tc, const StaticInstPtr staticInst,
const PCStateBase &pc,
const StaticInstPtr macroStaticInst=nullptr) override
{
if (!started && pc.instAddr() == startPc)
started = true;
if (started) {
return new TarmacParserRecord(when, tc, staticInst, pc, *this,
macroStaticInst);
} else {
return nullptr;
}
}
private:
/** Helper function to advance the trace up to startPc. */
void advanceTraceToStartPc();
/** TARMAC trace file. */
std::ifstream trace;
/**
* Tracing starts when the PC gets this value for the first time (ignored
* if 0x0).
*/
Addr startPc;
/**
* If true, the simulation is stopped as the first mismatch is detected.
*/
bool exitOnDiff;
/**
* If true, the simulation is stopped as the first mismatch is detected on
* PC or opcode.
*/
bool exitOnInsnDiff;
/** If true, memory write accesses are checked. */
bool memWrCheck;
/** Ignored addresses (ignored if empty). */
AddrRange ignoredAddrRange;
/** If true, the trace format includes the CPU id. */
bool cpuId;
/** True if tracing has started. */
bool started;
/** True if a macroop is currently in progress. */
bool macroopInProgress;
};
} // namespace Trace
} // namespace gem5
#endif // __ARCH_ARM_TRACERS_TARMAC_PARSER_HH__