FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

gem5の命令ダンプ機能の解析 (1. traceDataの生成方法の調査)

少しいろいろと、gem5の命令トレースの方法を解析していた。

gem5はcommit.ccにおいて、dump()により命令トレースの出力を行う。

  • src/cpu/o3/commit.cc
bool
Commit::commitHead(const DynInstPtr &head_inst, unsigned inst_num)
{
    assert(head_inst);

    ThreadID tid = head_inst->threadNumber;
/* ... 途中省略 ... */
        DPRINTF(Commit,
            "[tid:%i] [sn:%llu] Committing instruction with fault\n",
            tid, head_inst->seqNum);
        if (head_inst->traceData) {
            // We ignore ReExecution "faults" here as they are not real
            // (architectural) faults but signal flush/replays.
            if (debug::ExecFaulting
                && dynamic_cast<ReExec*>(inst_fault.get()) == nullptr) {

                head_inst->traceData->setFaulting(true);
                head_inst->traceData->setFetchSeq(head_inst->seqNum);
                head_inst->traceData->setCPSeq(thread[tid]->numOp);
                head_inst->traceData->dump();
            }
            delete head_inst->traceData;
            head_inst->traceData = NULL;
        }

traceDataに何らかの情報が入っていれば、dump()により出力を行う。

  • src/cpu/o3/dyn_inst.hh
    /** InstRecord that tracks this instructions. */
    trace::InstRecord *traceData = nullptr;

このtraceDataがどのように設定されるか、という話なのだが、これをいろいろ追いかけて行ってもよくわからないところが多い。

  • build/RISCV/arch/riscv/generated/exec-ns.cc.inc
    Fault
    Addi::execute(
        ExecContext *xc, trace::InstRecord *traceData) const
    {
        int64_t Rd = 0;
int64_t Rs1 = 0;
;
        Rs1 = xc->getRegOperand(this, 0);
;
        
                    Rd = rvSext(Rs1 + imm);
                ;
        
        {
            RegVal final_val = Rd;
            xc->setRegOperand(this, 0, final_val);
            if (traceData) {
                traceData->setData(intRegClass, final_val);
            }
        };
        return NoFault;
    }

命令をフェッチしたときに、ここでtraceDataが挿入されるのかな?

  • src/cpu/o3/fetch.cc
DynInstPtr
Fetch::buildInst(ThreadID tid, StaticInstPtr staticInst,
        StaticInstPtr curMacroop, const PCStateBase &this_pc,
        const PCStateBase &next_pc, bool trace)
{
    // Get a sequence number.
    InstSeqNum seq = cpu->getAndIncrementInstSeq();
/* ... 途中省略 ... */
#if TRACING_ON
    if (trace) {
        instruction->traceData =
            cpu->getTracer()->getInstRecord(curTick(), cpu->tcBase(tid),
                    instruction->staticInst, this_pc, curMacroop);
    }
#else
    instruction->traceData = NULL;
#endif
  • src/sim/insttracer.hh
    void
    setData(uint64_t d)
    {
        data.asInt = d;
        dataStatus = DataInt64;
    }
    void
    setData(uint32_t d)
    {
        data.asInt = d;
        dataStatus = DataInt32;
    }
    void
    setData(uint16_t d)
    {
        data.asInt = d;
        dataStatus = DataInt16;
    }
    void
    setData(uint8_t d)
    {
        data.asInt = d;
        dataStatus = DataInt8;
    }