/* * Copyright (c) 2001-2005 The Regents of The University of Michigan * All rights reserved. * * 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. * * Authors: Steve Reinhardt * Lisa Hsu * Nathan Binkert * Steve Raasch */ #include "config/the_isa.hh" #if THE_ISA != SPARC_ISA #error Legion tracing only works with SPARC simulations! #endif #include #include #include #include #include "arch/sparc/decoder.hh" #include "arch/sparc/registers.hh" #include "arch/sparc/utility.hh" #include "arch/tlb.hh" #include "base/socket.hh" #include "cpu/base.hh" #include "cpu/legiontrace.hh" #include "cpu/static_inst.hh" #include "cpu/thread_context.hh" #include "sim/full_system.hh" #include "sim/system.hh" //XXX This is temporary #include "cpu/m5legion_interface.h" using namespace std; using namespace TheISA; static int diffcount = 0; static bool wasMicro = false; namespace Trace { SharedData *shared_data = NULL; void setupSharedData() { int shmfd = shmget('M' << 24 | getuid(), sizeof(SharedData), 0777); if (shmfd < 0) fatal("Couldn't get shared memory fd. Is Legion running?"); shared_data = (SharedData*)shmat(shmfd, NULL, SHM_RND); if (shared_data == (SharedData*)-1) fatal("Couldn't allocate shared memory"); if (shared_data->flags != OWN_M5) fatal("Shared memory has invalid owner"); if (shared_data->version != VERSION) fatal("Shared Data is wrong version! M5: %d Legion: %d", VERSION, shared_data->version); // step legion forward one cycle so we can get register values shared_data->flags = OWN_LEGION; } //////////////////////////////////////////////////////////////////////// // // Utility methods for pretty printing a report about a difference // inline char * genCenteredLabel(int length, char * buffer, const char * label) { int labelLength = strlen(label); assert(labelLength <= length); int leftPad = (length - labelLength) / 2; int rightPad = length - leftPad - labelLength; char format[64]; sprintf(format, "%%%ds%%s%%%ds", leftPad, rightPad); sprintf(buffer, format, "", label, ""); return buffer; } inline void printRegPair(ostream & os, char const * title, uint64_t a, uint64_t b) { ccprintf(os, " %16s | %#018x %s %#-018x \n", title, a, (a == b) ? "|" : "X", b); } inline void printColumnLabels(ostream & os) { static char * regLabel = genCenteredLabel(16, new char[17], "Register"); static char * m5Label = genCenteredLabel(18, new char[18], "M5"); static char * legionLabel = genCenteredLabel(18, new char[18], "Legion"); ccprintf(os, " %s | %s | %s \n", regLabel, m5Label, legionLabel); ccprintf(os, "--------------------+-----------------------+-----------------------\n"); } inline void printSectionHeader(ostream & os, const char * name) { char sectionString[70]; genCenteredLabel(69, sectionString, name); ccprintf(os, "====================================================================\n"); ccprintf(os, "%69s\n", sectionString); ccprintf(os, "====================================================================\n"); } inline void printLevelHeader(ostream & os, int level) { char sectionString[70]; char levelName[70]; sprintf(levelName, "Trap stack level %d", level); genCenteredLabel(69, sectionString, levelName); ccprintf(os, "====================================================================\n"); ccprintf(os, "%69s\n", sectionString); ccprintf(os, "====================================================================\n"); } void Trace::LegionTraceRecord::dump() { ostream &outs = Trace::output(); // Compare bool compared = false; bool diffPC = false; bool diffCC = false; bool diffInst = false; bool diffIntRegs = false; bool diffFpRegs = false; bool diffTpc = false; bool diffTnpc = false; bool diffTstate = false; bool diffTt = false; bool diffTba M5_VAR_USED = false; bool diffHpstate = false; bool diffHtstate = false; bool diffHtba = false; bool diffPstate = false; bool diffY = false; bool diffFsr = false; bool diffCcr = false; bool diffTl = false; bool diffGl = false; bool diffAsi = false; bool diffPil = false; bool diffCwp = false; bool diffCansave = false; bool diffCanrestore = false; bool diffOtherwin = false; bool diffCleanwin = false; bool diffTlb = false; Addr m5Pc, lgnPc; if (!shared_data) setupSharedData(); // We took a trap on a micro-op... if (wasMicro && !staticInst->isMicroop()) { // let's skip comparing this tick while (!compared) if (shared_data->flags == OWN_M5) { shared_data->flags = OWN_LEGION; compared = true; } compared = false; wasMicro = false; } if (staticInst->isLastMicroop()) wasMicro = false; else if (staticInst->isMicroop()) wasMicro = true; if(!staticInst->isMicroop() || staticInst->isLastMicroop()) { while (!compared) { if (shared_data->flags == OWN_M5) { m5Pc = pc.instAddr() & SparcISA::PAddrImplMask; if (bits(shared_data->pstate,3,3)) { m5Pc &= mask(32); } lgnPc = shared_data->pc & SparcISA::PAddrImplMask; if (lgnPc != m5Pc) diffPC = true; if (shared_data->cycle_count != thread->getCpuPtr()->instCount()) diffCC = true; if (shared_data->instruction != (SparcISA::MachInst)staticInst->machInst) { diffInst = true; } // assume we have %g0 working correctly for (int i = 1; i < TheISA::NumIntArchRegs; i++) { if (thread->readIntReg(i) != shared_data->intregs[i]) { diffIntRegs = true; } } for (int i = 0; i < TheISA::NumFloatRegs/2; i++) { if (thread->readFloatRegBits(i*2) != shared_data->fpregs[i]) { diffFpRegs = true; } } uint64_t oldTl = thread->readMiscRegNoEffect(MISCREG_TL); if (oldTl != shared_data->tl) diffTl = true; for (int i = 1; i <= MaxTL; i++) { thread->setMiscRegNoEffect(MISCREG_TL, i); if (thread->readMiscRegNoEffect(MISCREG_TPC) != shared_data->tpc[i-1]) diffTpc = true; if (thread->readMiscRegNoEffect(MISCREG_TNPC) != shared_data->tnpc[i-1]) diffTnpc = true; if (thread->readMiscRegNoEffect(MISCREG_TSTATE) != shared_data->tstate[i-1]) diffTstate = true; if (thread->readMiscRegNoEffect(MISCREG_TT) != shared_data->tt[i-1]) diffTt = true; if (thread->readMiscRegNoEffect(MISCREG_HTSTATE) != shared_data->htstate[i-1]) diffHtstate = true; } thread->setMiscRegNoEffect(MISCREG_TL, oldTl); if(shared_data->tba != thread->readMiscRegNoEffect(MISCREG_TBA)) diffTba = true; //When the hpstate register is read by an instruction, //legion has bit 11 set. When it's in storage, it doesn't. //Since we don't directly support seperate interpretations //of the registers like that, the bit is always set to 1 and //we just don't compare it. It's not supposed to matter //anyway. if((shared_data->hpstate | (1 << 11)) != thread->readMiscRegNoEffect(MISCREG_HPSTATE)) diffHpstate = true; if(shared_data->htba != thread->readMiscRegNoEffect(MISCREG_HTBA)) diffHtba = true; if(shared_data->pstate != thread->readMiscRegNoEffect(MISCREG_PSTATE)) diffPstate = true; //if(shared_data->y != // thread->readMiscRegNoEffect(MISCREG_Y)) if(shared_data->y != thread->readIntReg(NumIntArchRegs + 1)) diffY = true; if(shared_data->fsr != thread->readMiscRegNoEffect(MISCREG_FSR)) { diffFsr = true; if (mbits(shared_data->fsr, 63,10) == mbits(thread->readMiscRegNoEffect(MISCREG_FSR), 63,10)) { thread->setMiscRegNoEffect(MISCREG_FSR, shared_data->fsr); diffFsr = false; } } //if(shared_data->ccr != // thread->readMiscRegNoEffect(MISCREG_CCR)) if(shared_data->ccr != thread->readIntReg(NumIntArchRegs + 2)) diffCcr = true; if(shared_data->gl != thread->readMiscRegNoEffect(MISCREG_GL)) diffGl = true; if(shared_data->asi != thread->readMiscRegNoEffect(MISCREG_ASI)) diffAsi = true; if(shared_data->pil != thread->readMiscRegNoEffect(MISCREG_PIL)) diffPil = true; if(shared_data->cwp != thread->readMiscRegNoEffect(MISCREG_CWP)) diffCwp = true; //if(shared_data->cansave != // thread->readMiscRegNoEffect(MISCREG_CANSAVE)) if(shared_data->cansave != thread->readIntReg(NumIntArchRegs + 3)) diffCansave = true; //if(shared_data->canrestore != // thread->readMiscRegNoEffect(MISCREG_CANRESTORE)) if(shared_data->canrestore != thread->readIntReg(NumIntArchRegs + 4)) diffCanrestore = true; //if(shared_data->otherwin != // thread->readMiscRegNoEffect(MISCREG_OTHERWIN)) if(shared_data->otherwin != thread->readIntReg(NumIntArchRegs + 6)) diffOtherwin = true; //if(shared_data->cleanwin != // thread->readMiscRegNoEffect(MISCREG_CLEANWIN)) if(shared_data->cleanwin != thread->readIntReg(NumIntArchRegs + 5)) diffCleanwin = true; for (int i = 0; i < 64; i++) { if (shared_data->itb[i] != thread->getITBPtr()->TteRead(i)) diffTlb = true; if (shared_data->dtb[i] != thread->getDTBPtr()->TteRead(i)) diffTlb = true; } if (diffPC || diffCC || diffInst || diffIntRegs || diffFpRegs || diffTpc || diffTnpc || diffTstate || diffTt || diffHpstate || diffHtstate || diffHtba || diffPstate || diffY || diffCcr || diffTl || diffFsr || diffGl || diffAsi || diffPil || diffCwp || diffCansave || diffCanrestore || diffOtherwin || diffCleanwin || diffTlb) { outs << "Differences found between M5 and Legion:"; if (diffPC) outs << " [PC]"; if (diffCC) outs << " [CC]"; if (diffInst) outs << " [Instruction]"; if (diffIntRegs) outs << " [IntRegs]"; if (diffFpRegs) outs << " [FpRegs]"; if (diffTpc) outs << " [Tpc]"; if (diffTnpc) outs << " [Tnpc]"; if (diffTstate) outs << " [Tstate]"; if (diffTt) outs << " [Tt]"; if (diffHpstate) outs << " [Hpstate]"; if (diffHtstate) outs << " [Htstate]"; if (diffHtba) outs << " [Htba]"; if (diffPstate) outs << " [Pstate]"; if (diffY) outs << " [Y]"; if (diffFsr) outs << " [FSR]"; if (diffCcr) outs << " [Ccr]"; if (diffTl) outs << " [Tl]"; if (diffGl) outs << " [Gl]"; if (diffAsi) outs << " [Asi]"; if (diffPil) outs << " [Pil]"; if (diffCwp) outs << " [Cwp]"; if (diffCansave) outs << " [Cansave]"; if (diffCanrestore) outs << " [Canrestore]"; if (diffOtherwin) outs << " [Otherwin]"; if (diffCleanwin) outs << " [Cleanwin]"; if (diffTlb) outs << " [Tlb]"; outs << endl << endl; outs << right << setfill(' ') << setw(15) << "M5 PC: " << "0x"<< setw(16) << setfill('0') << hex << m5Pc << endl; outs << setfill(' ') << setw(15) << "Legion PC: " << "0x" << setw(16) << setfill('0') << hex << lgnPc << endl << endl; outs << right << setfill(' ') << setw(15) << "M5 CC: " << "0x" << setw(16) << setfill('0') << hex << thread->getCpuPtr()->instCount() << endl; outs << setfill(' ') << setw(15) << "Legion CC: " << "0x" << setw(16) << setfill('0') << hex << shared_data->cycle_count << endl << endl; outs << setfill(' ') << setw(15) << "M5 Inst: " << "0x" << setw(8) << setfill('0') << hex << staticInst->machInst << staticInst->disassemble(m5Pc, debugSymbolTable) << endl; TheISA::Decoder *decoder = thread->getDecoderPtr(); decoder->moreBytes(m5Pc, m5Pc, shared_data->instruction); assert(decoder->instReady()); PCState tempPC = pc; StaticInstPtr legionInst = decoder->decode(tempPC); outs << setfill(' ') << setw(15) << " Legion Inst: " << "0x" << setw(8) << setfill('0') << hex << shared_data->instruction << legionInst->disassemble(lgnPc, debugSymbolTable) << endl << endl; printSectionHeader(outs, "General State"); printColumnLabels(outs); printRegPair(outs, "HPstate", thread->readMiscRegNoEffect(MISCREG_HPSTATE), shared_data->hpstate | (1 << 11)); printRegPair(outs, "Htba", thread->readMiscRegNoEffect(MISCREG_HTBA), shared_data->htba); printRegPair(outs, "Pstate", thread->readMiscRegNoEffect(MISCREG_PSTATE), shared_data->pstate); printRegPair(outs, "Y", //thread->readMiscRegNoEffect(MISCREG_Y), thread->readIntReg(NumIntArchRegs + 1), shared_data->y); printRegPair(outs, "FSR", thread->readMiscRegNoEffect(MISCREG_FSR), shared_data->fsr); printRegPair(outs, "Ccr", //thread->readMiscRegNoEffect(MISCREG_CCR), thread->readIntReg(NumIntArchRegs + 2), shared_data->ccr); printRegPair(outs, "Tl", thread->readMiscRegNoEffect(MISCREG_TL), shared_data->tl); printRegPair(outs, "Gl", thread->readMiscRegNoEffect(MISCREG_GL), shared_data->gl); printRegPair(outs, "Asi", thread->readMiscRegNoEffect(MISCREG_ASI), shared_data->asi); printRegPair(outs, "Pil", thread->readMiscRegNoEffect(MISCREG_PIL), shared_data->pil); printRegPair(outs, "Cwp", thread->readMiscRegNoEffect(MISCREG_CWP), shared_data->cwp); printRegPair(outs, "Cansave", //thread->readMiscRegNoEffect(MISCREG_CANSAVE), thread->readIntReg(NumIntArchRegs + 3), shared_data->cansave); printRegPair(outs, "Canrestore", //thread->readMiscRegNoEffect(MISCREG_CANRESTORE), thread->readIntReg(NumIntArchRegs + 4), shared_data->canrestore); printRegPair(outs, "Otherwin", //thread->readMiscRegNoEffect(MISCREG_OTHERWIN), thread->readIntReg(NumIntArchRegs + 6), shared_data->otherwin); printRegPair(outs, "Cleanwin", //thread->readMiscRegNoEffect(MISCREG_CLEANWIN), thread->readIntReg(NumIntArchRegs + 5), shared_data->cleanwin); outs << endl; for (int i = 1; i <= MaxTL; i++) { printLevelHeader(outs, i); printColumnLabels(outs); thread->setMiscRegNoEffect(MISCREG_TL, i); printRegPair(outs, "Tpc", thread->readMiscRegNoEffect(MISCREG_TPC), shared_data->tpc[i-1]); printRegPair(outs, "Tnpc", thread->readMiscRegNoEffect(MISCREG_TNPC), shared_data->tnpc[i-1]); printRegPair(outs, "Tstate", thread->readMiscRegNoEffect(MISCREG_TSTATE), shared_data->tstate[i-1]); printRegPair(outs, "Tt", thread->readMiscRegNoEffect(MISCREG_TT), shared_data->tt[i-1]); printRegPair(outs, "Htstate", thread->readMiscRegNoEffect(MISCREG_HTSTATE), shared_data->htstate[i-1]); } thread->setMiscRegNoEffect(MISCREG_TL, oldTl); outs << endl; printSectionHeader(outs, "General Purpose Registers"); static const char * regtypes[4] = {"%g", "%o", "%l", "%i"}; for(int y = 0; y < 4; y++) { for(int x = 0; x < 8; x++) { char label[8]; sprintf(label, "%s%d", regtypes[y], x); printRegPair(outs, label, thread->readIntReg(y*8+x), shared_data->intregs[y*8+x]); } } if (diffFpRegs) { for (int x = 0; x < 32; x++) { char label[8]; sprintf(label, "%%f%d", x); printRegPair(outs, label, thread->readFloatRegBits(x*2), shared_data->fpregs[x]); } } if (diffTlb) { printColumnLabels(outs); char label[9]; for (int x = 0; x < 64; x++) { if (shared_data->itb[x] != ULL(0xFFFFFFFFFFFFFFFF) || thread->getITBPtr()->TteRead(x) != ULL(0xFFFFFFFFFFFFFFFF)) { sprintf(label, "I-TLB:%02d", x); printRegPair(outs, label, thread->getITBPtr()->TteRead(x), shared_data->itb[x]); } } for (int x = 0; x < 64; x++) { if (shared_data->dtb[x] != ULL(0xFFFFFFFFFFFFFFFF) || thread->getDTBPtr()->TteRead(x) != ULL(0xFFFFFFFFFFFFFFFF)) { sprintf(label, "D-TLB:%02d", x); printRegPair(outs, label, thread->getDTBPtr()->TteRead(x), shared_data->dtb[x]); } } thread->getITBPtr()->dumpAll(); thread->getDTBPtr()->dumpAll(); } diffcount++; if (diffcount > 3) fatal("Differences found between Legion and M5\n"); } else diffcount = 0; compared = true; shared_data->flags = OWN_LEGION; } } // while } // if not microop } } // namespace Trace //////////////////////////////////////////////////////////////////////// // // ExeTracer Simulation Object // Trace::LegionTrace * LegionTraceParams::create() { if (!FullSystem) panic("Legion tracing only works in full system!"); return new Trace::LegionTrace(this); };