trace.c 5.83 KB
/*
 * Copyright (C) 1996-1998 by the Board of Trustees
 *    of Leland Stanford Junior University.
 * 
 * This file is part of the SimOS distribution. 
 * See LICENSE file for terms of the license. 
 *
 */

/*****************************************************************
 * 
 * trace.c 
 * 
 *  ISSUES - 
 *  Exception: cause, epc (check branch delay slot issue), badVaddr
 *  Don't send asid with each subtype
 *  send uncached too
 ****************************************************************/
#include "sim_error.h"
#include "machine_params.h"
#include "cpu_state.h"
#include "simtypes.h"
#include "TraceDef.h"
#include "tcl_init.h"

#define MAX_CPUS 128

void *packetManager;
TracePacket_t *packet;
int asid[MAX_CPUS];
int tracingActive = 1;

struct {
   Boolean active;
   VA   dataVA;
   PA   dataPA;
   VA   dataInstPC;
} dataEvent[MAX_CPUS];

char traceDumpMask[MAX_CPUS];

extern CPUState   *PE;
/*****************************************************************
 * TraceInit
 *****************************************************************/
void
TraceInit()
{
   int i;

   packetManager = (void *)InitTrace("trace.out", TRUE);
   packet        = (TracePacket_t *)InitPacket();
   for (i=0; i< TOTAL_CPUS; i++) {
      asid[i]    = GET_ASID(PE[i].CP0[C0_TLBHI]);
      dataEvent[i].active = FALSE;
      traceDumpMask[i] = 0;
   }
}

/*****************************************************************
 * TraceInstruction
 *****************************************************************/
void 
TraceInstruction(CPUState *P, Inst instr)
{
   int cpuNum = P->myNum;

   if (!traceDumpMask[cpuNum]) return;

   packet->Id          = Instr_e;
   packet->processorId = cpuNum;
   packet->instWord    = instr;
   packet->instVAddr   = P->PC;
   packet->instPAddr   = P->pcPaddrcache + PAGE_OFFSET(P->PC);
   packet->instASID    = asid[cpuNum];

   if (P->branchStatus == BranchStatus_taken) {
      packet->Id = JumpBranchTaken_e;
   } else if (dataEvent[cpuNum].active) {

      ASSERT(P->PC == dataEvent[cpuNum].dataInstPC);

      packet->Id               = MemRef_e;
      packet->packetValue.memRef.dataVAddr = dataEvent[cpuNum].dataVA;
      packet->packetValue.memRef.dataPAddr = dataEvent[cpuNum].dataPA;
      packet->packetValue.memRef.dataASID  = asid[cpuNum]; 
      dataEvent[cpuNum].active = FALSE;
   }
 
   SendPacket(packet, packetManager);
}

/*****************************************************************
 * TraceDataRef
 *****************************************************************/
void 
TraceDataRef(CPUState *P, VA vAddr, PA pAddr)
{
   int cpuNum = P->myNum;

   if (!traceDumpMask[cpuNum]) return;

   if (dataEvent[cpuNum].active != FALSE) {
      /* The implementation of sdl and sdr cause two memory references
      */ 
      ASSERT(dataEvent[cpuNum].dataInstPC == P->PC);
   }

   dataEvent[cpuNum].active = TRUE;
   dataEvent[cpuNum].dataVA = vAddr;
   dataEvent[cpuNum].dataPA = pAddr;
   dataEvent[cpuNum].dataInstPC = P->PC;
}
void 
TraceUncachedDataRef(CPUState *P, VA vAddr, PA pAddr)
{
   int cpuNum = P->myNum;

   if (!traceDumpMask[cpuNum]) return;

   if (dataEvent[cpuNum].active != FALSE) {
      /* The implementation of sdl and sdr cause two memory references
      */ 
      ASSERT(dataEvent[cpuNum].dataInstPC == P->PC);
   }

   dataEvent[cpuNum].active = TRUE;
   dataEvent[cpuNum].dataVA = vAddr;
   dataEvent[cpuNum].dataPA = pAddr;
   dataEvent[cpuNum].dataInstPC = P->PC;
}

void
TraceCheckASID(CPUState *P)
{
   int cpuNum  = P->myNum;
   int newASID = GET_ASID(P->CP0[C0_TLBHI]);

   asid[cpuNum] = GET_ASID(P->CP0[C0_TLBHI]);   
   if (!traceDumpMask[cpuNum]) return;

   if (asid[cpuNum] != newASID) {
      CPUWarning("ASID[%d]:\t %d to %d at %#x\n", P->myNum, asid[P->myNum], 
                 GET_ASID(P->CP0[C0_TLBHI]), P->PC);
   }
}

void
TraceException(CPUState *P, int code)
{
   int cpuNum = 0;

   if (!traceDumpMask[cpuNum]) return;

   packet->Id                      = Event_e;

   packet->processorId = cpuNum;
   /* PROBLEM -> hard to get this field again*/
   packet->instWord    = 0;

   packet->instVAddr   = P->PC;
   /* this might not be right for interrupts */
   packet->instPAddr   = P->pcPaddrcache + PAGE_OFFSET(P->PC);
   packet->instASID    = asid[cpuNum];

   /* Treat interrupts differently? */
   packet->packetValue.event.event = code >> 2;

   /* Clear cached load or store address */
   dataEvent[cpuNum].active = FALSE;

   SendPacket(packet, packetManager);
}

   
int 
TraceDumpTclCmd(ClientData clientData, Tcl_Interp *interp, 
                int argc, char *argv[])
{
#ifndef TRACING
   Tcl_AppendResult(interp, 
                    "traceDump not supported unless mipsy compiled -DTRACING",
                    NULL);
   return TCL_ERROR;
#else 
   int i;

#ifndef SOLO
   if (simosCPUType != MIPSY) {
      Tcl_AppendResult(interp, "traceDump only supported in mipsy",
                       NULL);
      return TCL_ERROR;
   }
#endif
   if (argc < 2) {
      Tcl_AppendResult(interp, 
                       "Usage: traceDump <all|off|list of cpunumbers>", 
                       NULL);
      return TCL_ERROR;
   }

   if (!strcmp(argv[1], "off")) {
      CPUWarning("traceDump: Turning trace dumping OFF\n");
      for (i = 0; i < MAX_CPUS; i++) {
         traceDumpMask[i] = 0;
      }
   } else if (!strcmp(argv[1], "all")) {
      CPUWarning("traceDump: Turning trace dumping on for ALL cpus\n");
      for (i = 0; i < MAX_CPUS; i++) {
         traceDumpMask[i] = 1;
      }
   } else {
      for (i=1; i<argc; i++) {
         int cpuNum;
         if ((Tcl_GetInt(interp, argv[i], &cpuNum) != TCL_OK)
             || cpuNum >= MAX_CPUS ) {
            Tcl_AppendResult(interp, "Bad cpu num to traceDump command",
                             NULL);
            return TCL_ERROR;
         }
         traceDumpMask[cpuNum] = 1;
         CPUWarning("traceDump: Enabling trace dumping for cpu %d\n", cpuNum);
      }
   }

   return TCL_OK;
#endif
}