tb.c 8.74 KB
/*
 * Copyright (C) 1998 by the Board of Trustees
 *    of Leland Stanford Junior University.
 * Copyright (C) 1998 Digital Equipment Corporation
 *
 * This file is part of the SimOS distribution.
 * See LICENSE file for terms of the license.
 *
 */




/*
 * tb.c: handling of the alpha TB. 
 */


#include "simtypes.h"
#include "sim_error.h"
#include "alpha.h"
#include "alpha_params.h"
#include "cpu_interface.h"
#include "tb.h"
#include "qc.h"
#include "ev5.h"
#include "ev5_ipr.h" /* for MAX_ITB, MAX_SDTB */
#include "external_trace.h"

#include <stdlib.h>
#include <string.h>


typedef struct TBState {
   struct TBEntry itb[MAX_ITB];
   struct TBEntry dtb[MAX_SDTB];
   int iASN;
   uint64 quickITB[MAX_ITB];
   int dASN;
   uint64 quickDTB[MAX_DTB];
   QCTable *curIQC;
   QCTable *curDQC;
   QCTable *iQC[NUM_QC_MODES];
   QCTable *dQC[NUM_QC_MODES];
  
} TBState;

/*
 * Quick tag format:
 * (tag<<3) |  gh<<1 | (valid) )
 */

static inline void UpdateQuick(TBEntry *tbe, uint64*quick, int valid)
{
   ASSERT((tbe->tag & BITMASK(47))==tbe->tag);
   ASSERT(tbe->asn < (1<<12));
   ASSERT(tbe->gh < (1<<3)); 
   ASSERT(tbe->asma < 2); 

   if (valid) {
      *quick = (tbe->tag<<3) | (tbe->gh<1) |1;
   } else {
      *quick = 0;
   }
}


static void TBRenewQuick(struct TBState *tb, TBType type,Reg currentASN)
{
   int i;
   int max       = (type==TB_DATA?MAX_DTB:MAX_ITB);
   TBEntry *tbe  = (type==TB_DATA?tb->dtb:tb->itb);
   uint64 *quick = ((type==TB_DATA)?tb->quickDTB:tb->quickITB);
   if (type==TB_DATA) {
      tb->dASN = currentASN;
   } else {
      tb->iASN = currentASN;
   }
   for (i=0;i<max;i++) {
      if (tbe[i].valid && (tbe[i].asma || tbe[i].asn==currentASN)) {
         UpdateQuick(&tbe[i],&quick[i],1);
      } else {
         UpdateQuick(&tbe[i],&quick[i],0);
      }
   }
}

TBEntry *TBLookup(struct TBState *tb, TBType type, Reg pfn, Reg currentASN )
{
   int i;
   int max =  (type==TB_DATA?MAX_DTB:MAX_ITB);
   int asn = ((type==TB_DATA)?tb->dASN:tb->iASN);
   uint64 *quick = ((type==TB_DATA)?tb->quickDTB:tb->quickITB);
   TBEntry *tbe = (type==TB_DATA?tb->dtb:tb->itb);
   
   if (asn != currentASN) {
      TBRenewQuick(tb,type,currentASN);
   }

   for (i=0;i<max;i++, quick++) {
      uint64 val = *quick;
      Reg gh,tag,mask;
      if (!val) continue;
      gh   = ((val>>1)&3) * 3;
      tag  = (val>>3)& ~BITMASK(gh);
      mask = pfn & ~BITMASK(gh);
      if (tag==mask) return &tbe[i];
   }
   
   
#ifdef slow
   int max = (type==TB_DATA?MAX_DTB:MAX_ITB);
   TBEntry *tbe = (type==TB_DATA?tb->dtb:tb->itb);
   TBEntry *maxTBE = &tbe[max];
   for ( ; tbe != maxTBE; tbe++) {
      if (tbe->valid &&
	  (tbe->asma || tbe->asn==currentASN)) {
         Reg gh = tbe->gh * 3;
         Reg tag = tbe->tag & ~BITMASK(gh);
         Reg mask = pfn & ~BITMASK(gh);
         if (tag==mask) { 
            return tbe;
         }
      }
   }
#endif
   return 0;
}

 
void TBInsert(struct TBState *tb, TBType type, int index,
	      Reg pte, Reg tag, Reg asn)
{
   TBEntry *tbe = ((type==TB_DATA)?&tb->dtb[index]:&tb->itb[index]);
   uint64  *quick = ((type==TB_DATA)?&tb->quickDTB[index]:&tb->quickITB[index]);

   if (tbe->valid) { 
      TBRemove(tb,type,index);
   }
   
   tbe->pfn  = (pte & 0x07FFFFFF00000000)>>32; 	     /*ITB_PTE <58:32>*/
   tbe->ford = pte>>1 & 1;			     /*DTB_PTE <1>*/
   tbe->fow  = pte>>2 & 1;			     /*DTB_PTE <2>*/
   tbe->asma = pte>>4 & 1;			     /*DTB_PTE <4>*/
   tbe->xre  = pte>>8 & 0xf;			     /*ITB_PTE <11:8>*/
   tbe->xwe  = pte>>12& 0xf;			     /*DTB_PTE <15:12>*/
   tbe->gh   = pte>>5 & 0x3;		             /*xTB_PTE <6:5>*/
   tbe->tag  = tag;
   tbe->asn  = asn;
   tbe->valid =1; 
   
   UpdateQuick(tbe,quick,1);
  
   if (alphaDebugParams.debugTBInsert) {
     CPUWarning("TBInsert: PTE tag=0x%08lx pfn=0x%lx pte=0x%lx asn=%d \n",tag,tbe->pfn,pte,asn);
   }

   EXTERNAL_TRACE_PTE(EXTERNAL_TRACE_CURPE, TAG2VADDR(tag), pte);
}



void TBRemove(struct TBState *tb, TBType type, int index)
{
   TBEntry *tbe = (type==TB_DATA?&tb->dtb[index]:&tb->itb[index]);
   QCTable **qc = (type==TB_DATA?tb->dQC:tb->iQC);
   uint64  *quick = ((type==TB_DATA)?&tb->quickDTB[index]:&tb->quickITB[index]);

   if (tbe->valid) { 
      int i;
      int numPages=1;
      Reg gh = tbe->gh * 3;
      Reg tag = tbe->tag & ~BITMASK(gh);
      for (i=0;i<gh;i++) {
         numPages *=2;
      }
      for (i=0;i<NUM_QC_MODES;i++) {
         int page;
         for (page=0;page<numPages;page++) { 
            if (qc[i]) QCRemove(qc[i],tag+page);
         }
      }
      tbe->valid = 0;

      {
          Reg pte;
          EXTERNAL_TRACE_PTE_FROM_TBE(&pte, tbe);
          EXTERNAL_TRACE_PTE(EXTERNAL_TRACE_CURPE, TAG2VADDR(tag), pte);
      }
   }
   UpdateQuick(tbe,quick,0);
}


struct TBEntry *TBIndex(struct TBState *tb,TBType type, int index)
{
   TBEntry *tbe = (type==TB_DATA?&tb->dtb[index]:&tb->itb[index]);
   if (type==TB_DATA) {
      ASSERT( index>=0 && index < MAX_DTB);
   } else if (type == TB_INSTR) { 
      ASSERT (index>=0 && index<MAX_ITB);
   } else {
      ASSERT(0);
   }
   return tbe;
}

struct TBState *TBInit(void)
{
   int i;
   TBState *tb = malloc(sizeof(TBState));
   bzero((char*)tb,sizeof(TBState));
   tb->iASN = -1;
   tb->dASN = -1;
   for (i=0;i<MAX_ITB;i++) {
      tb->itb[i].index = i;

   }
   for (i=0;i<MAX_DTB;i++) {
      tb->dtb[i].index = i;
   }


   return tb;
}

struct QCTable *TBNewMode( struct TBState *tb, TBType type, int newMode)
{
   ASSERT( newMode >=0 && newMode < NUM_QC_MODES);
   if (type==TB_INSTR) {
      if (!tb->iQC[newMode]) {
         tb->iQC[newMode] = QCInit(0);
      }
      tb->curIQC = tb->iQC[newMode];
      return   tb->curIQC;
   } else if (type==TB_DATA) {
      if (!tb->dQC[newMode]) {
         tb->dQC[newMode] = QCInit(1);
      }
      tb->curDQC = tb->dQC[newMode];
      return  tb->curDQC ;
   }
   ASSERT(0);
   return 0;
}


void TBNewASN(struct TBState *tb, TBType type, int oldASN)
{
   int idx;
   int max      = (type==TB_DATA?MAX_DTB:MAX_ITB);
   TBEntry *tbe = (type==TB_DATA?tb->dtb:tb->itb);
   QCTable **qc = (type==TB_DATA?tb->dQC:tb->iQC);


   for (idx=0;idx<max;idx++,tbe++) {
      if (tbe->valid && tbe->asn==oldASN) {
	 int i;
	 int numPages=1;
	 Reg gh = tbe->gh * 3;
	 Reg tag = tbe->tag & ~BITMASK(gh);

	 for (i=0;i<gh;i++) {
	    numPages *=2;
	 }
	 for (i=0;i<NUM_QC_MODES;i++) {
	    int page;
	    for (page=0;page<numPages;page++) { 
	       if (qc[i]) QCRemove(qc[i],tag+page);
	    }
	 }
      }
   }
}

         
#define TBSTRSIZE (128*64)

char *TBPrint(struct TBState *tb, TBType type )
{
   int i;
   int max = (type==TB_DATA?MAX_DTB:MAX_ITB);
   TBEntry *tbe = (type==TB_DATA?tb->dtb:tb->itb);
   static char str[TBSTRSIZE];
   int offset = 0;

   for (i=0;i<max;i++) {
      if (tbe[i].valid) {
	int nchars =
	  sprintf(str+offset, "index=%d reg=%lx tag=%lx pfn=%lx xre=%x xwe=%x asma=%x ford=%x fow=%x asn=%x gh=%x\n",
		  tbe[i].index,
		  tbe[i].reg,
		  tbe[i].tag,
		  tbe[i].pfn,
		  tbe[i].xre,
		  tbe[i].xwe,
		  tbe[i].asma,
		  tbe[i].ford,
		  tbe[i].fow,
		  tbe[i].asn,
		  tbe[i].gh);
	offset += nchars;
	ASSERT(offset < TBSTRSIZE);
      }
   }
   return strdup(str);
}


void TBCheckpoint(CptDescriptor *cptd, int cpu, struct TBState *tb)
{
   int tlb;
   
   for(tlb=0;tlb<MAX_ITB;tlb++) {       
      Simcpt_CptInt(cptd,"ITBINDEX",cpu,tlb,&(tb->itb[tlb].index));
      Simcpt_CptUlong(cptd,"ITBREG",cpu,tlb,&(tb->itb[tlb].reg));
      Simcpt_CptUint(cptd,"ITBVALID",cpu,tlb,&(tb->itb[tlb].valid));
      Simcpt_CptUlong(cptd,"ITBTAG",cpu,tlb,&(tb->itb[tlb].tag));
      Simcpt_CptUlong(cptd,"ITBPFN",cpu,tlb,&(tb->itb[tlb].pfn));
      Simcpt_CptUint(cptd,"ITBXRE",cpu,tlb,&(tb->itb[tlb].xre));
      Simcpt_CptUint(cptd,"ITBXWE",cpu,tlb,&(tb->itb[tlb].xwe));
      Simcpt_CptUint(cptd,"ITBASMA",cpu,tlb,&(tb->itb[tlb].asma));
      Simcpt_CptUint(cptd,"ITBFORD",cpu,tlb,&(tb->itb[tlb].ford));
      Simcpt_CptUint(cptd,"ITBFOW",cpu,tlb,&(tb->itb[tlb].fow));
      Simcpt_CptUint(cptd,"ITBASN",cpu,tlb,&(tb->itb[tlb].asn));
      Simcpt_CptUint(cptd,"ITBGH",cpu,tlb,&(tb->itb[tlb].gh));
   }
   
   for(tlb=0;tlb<MAX_SDTB;tlb++) {
      Simcpt_CptInt(cptd,"DTBINDEX",cpu,tlb,&(tb->dtb[tlb].index));
      Simcpt_CptUlong(cptd,"DTBREG",cpu,tlb,&(tb->dtb[tlb].reg));
      Simcpt_CptUint(cptd,"DTBVALID",cpu,tlb,&(tb->dtb[tlb].valid));
      Simcpt_CptUlong(cptd,"DTBTAG",cpu,tlb,&(tb->dtb[tlb].tag));
      Simcpt_CptUlong(cptd,"DTBPFN",cpu,tlb,&(tb->dtb[tlb].pfn));
      Simcpt_CptUint(cptd,"DTBXRE",cpu,tlb,&(tb->dtb[tlb].xre));
      Simcpt_CptUint(cptd,"DTBXWE",cpu,tlb,&(tb->dtb[tlb].xwe));
      Simcpt_CptUint(cptd,"DTBASMA",cpu,tlb,&(tb->dtb[tlb].asma));
      Simcpt_CptUint(cptd,"DTBFORD",cpu,tlb,&(tb->dtb[tlb].ford));
      Simcpt_CptUint(cptd,"DTBFOW",cpu,tlb,&(tb->dtb[tlb].fow));
      Simcpt_CptUint(cptd,"DTBASN",cpu,tlb,&(tb->dtb[tlb].asn));
      Simcpt_CptUint(cptd,"DTBGH",cpu,tlb,&(tb->dtb[tlb].gh));
   }
}