| /* |
| * 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 "config/full_system.hh" |
| #if !FULL_SYSTEM |
| #error Legion tracing only works in full system! |
| #endif |
| |
| #include <sys/ipc.h> |
| #include <sys/shm.h> |
| |
| #include <cstdio> |
| #include <iomanip> |
| |
| #include "arch/sparc/predecoder.hh" |
| #include "arch/sparc/registers.hh" |
| #include "arch/sparc/utility.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/system.hh" |
| |
| #if FULL_SYSTEM |
| #include "arch/tlb.hh" |
| #endif |
| |
| //XXX This is temporary |
| #include "cpu/m5legion_interface.h" |
| |
| using namespace std; |
| using namespace TheISA; |
| |
| #if FULL_SYSTEM |
| static int diffcount = 0; |
| static bool wasMicro = false; |
| #endif |
| |
| 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(); |
| |
| static TheISA::Predecoder predecoder(NULL); |
| // 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 = 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; |
| |
| predecoder.setTC(thread); |
| predecoder.moreBytes(m5Pc, m5Pc, shared_data->instruction); |
| |
| assert(predecoder.extMachInstReady()); |
| |
| PCState tempPC = pc; |
| StaticInstPtr legionInst = |
| StaticInst::decode(predecoder.getExtMachInst(tempPC), |
| lgnPc); |
| 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[8]; |
| 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() |
| { |
| return new Trace::LegionTrace(this); |
| }; |