qc.c 4.39 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.
 *
 */




#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

#include "simtypes.h"
#include "sim_error.h"

#include "machine_params.h"

#include "alpha.h"
#include "qc.h"
#include "tb.h"
#include "ev5.h"
#include "addr_layout.h"

#include "../../common/dcg_support/tc_coherence.h"
 

#define MAX_QC_TABLES 128


#define NO_VPN (1LL<<63)  /* violates VA/VPN sign extension rules */

static int numQCTables;

static QCTable *qcTables[MAX_QC_TABLES];

int qcDebugIndex = -1;



QCTable *QCInit(int isWriteable)
{
   int i;
   QCTable *table = (QCTable*)malloc(sizeof(QCTable));
   for (i=0;i<QC_INDEX;i++) {
      table->e[i].vpn = NO_VPN;
      table->e[i].mAddrWr = 0;
   }
   if (isWriteable) { 
      qcTables[numQCTables++] = table;
   }
   ASSERT( numQCTables < 128);
   return table;
}

MA QCLookup( QCTable *table, VA vAddr, int write)
{
   VA vpn = VADDR2VPN(vAddr);
   int hash = QC_HASH(vpn);
   MA mAddr;

   ASSERT( hash >=0 && hash < QC_INDEX);
   if (vpn == table->e[hash].vpn) {
      uint64 m = table->e[hash].mAddrWr;
      if (write && !QC_WRITEABLE(m)) return 0;
      mAddr = QC_TO_MEMADDR(m);
      mAddr =  mAddr + (vAddr & BITMASK(PAGE_BITS));
   } else {
      mAddr = 0;
   }
   if (hash==qcDebugIndex) {
      CPUPrint("QCDEBUG %ld: LOOKUP table=0x%lx vAddr=0x%lx write=0x%lx return 0x%lx \n",
	       CPUVec.CycleCount(0),table,vAddr,write,mAddr);
   }   
   return mAddr;
}

void QCInsert( QCTable *table, int cpuNum, Reg tag, PA pAddr, int writeable)
{
   VA vpn = VADDR2VPN(TAG2VADDR(tag));
   int hash = QC_HASH(vpn);
   PA align = (pAddr & ~BITMASK(PAGE_BITS));
   MA mAddr = PHYS_TO_MEMADDR(M_FROM_CPU(cpuNum),align);

   ASSERT( pAddr >=0 && pAddr < MEM_SIZE(0));
   ASSERT(table);
   ASSERT( writeable == 0 || writeable==1);
   if (writeable && 
       TCcoherence_is_code(PHYS_TO_MEMADDR(M_FROM_CPU(cpuNum),align))) {
      writeable = 0;
   }

   table->e[hash].vpn = vpn;
   table->e[hash].mAddrWr = (uint64)mAddr | writeable;
   if (hash==qcDebugIndex) {
      CPUPrint("QCDEBUG %ld: INS table=0x%lx tag=0x%lx pAddr=0x%lx  \n",
	       CPUVec.CycleCount(0),table,tag,pAddr);
   }
}


void QCRemove( QCTable *table, Reg tag)
{
   VA vpn = VADDR2VPN(TAG2VADDR(tag));
   int hash = QC_HASH(vpn);
    if (table->e[hash].vpn == vpn) {
      table->e[hash].vpn = NO_VPN;
      table->e[hash].mAddrWr = 0;
      if (hash==qcDebugIndex) {
	 CPUPrint("QCDEBUG %ld: REM table=0x%lx tag=0x%lx vAddr=0x%lx FOUND\n",
		  CPUVec.CycleCount(0),table,tag,TAG2VADDR(tag));
      }   
    } 
    /*  ASSERT(CPUVec.CycleCount(0)!=19327695); */
}

void QCDowngrade(int cpuNum, Reg tag)
{
   VA vpn = VADDR2VPN(TAG2VADDR(tag));
   int hash = QC_HASH(vpn);
   int i;
   for (i=0;i<numQCTables;i++) {
      if (qcTables[i]->e[hash].vpn == vpn) {
         qcTables[i]->e[hash].vpn = NO_VPN;
         qcTables[i]->e[hash].mAddrWr = 0;
      }
   }
}

          
static QCTable *analTable;

void QCConsistencyCheck(AlphaState *P, QCTable *table, int type)
{
   int i;
   CPUPrint("QC Consistency check table=0x%lx type=%d \n",table,type);
   if (!analTable) { 
      analTable = malloc(sizeof(QCTable));
   }
   bcopy((char*)table,(char*)analTable,sizeof(QCTable));

   for (i=0;i<QC_INDEX;i++) {
      if (analTable->e[i].vpn != NO_VPN) { 
         VA vAddr = PAGE2ADDR(analTable->e[i].vpn);
         
         if (type==TB_DATA) {
            PA pAddr=0;
            int writeable = QC_WRITEABLE(analTable->e[i].mAddrWr);
            MMUStatus status = EV5_DTranslateVirtual(P,vAddr,writeable,0,&pAddr);
            MA mAddr = PHYS_TO_MEMADDR(0,pAddr);
            ASSERT( status==MMU_SUCCESS);
            ASSERT( mAddr==QC_TO_MEMADDR(analTable->e[i].mAddrWr));

            if (writeable) {
               ASSERT( !TCcoherence_is_code(PHYS_TO_MEMADDR(M_FROM_CPU(P->myNum),pAddr)));
            }
         } else if (type==TB_INSTR) {
	    VA oldPC = P->PC;
            PA pAddr=0;
	    MMUStatus status;
	    MA mAddr;
	    P->PC = vAddr;
            status = EV5_ITranslateVirtual(P,&pAddr, 0);
            mAddr = PHYS_TO_MEMADDR(0,pAddr);
            ASSERT( status==MMU_SUCCESS);
            ASSERT( mAddr==QC_TO_MEMADDR(analTable->e[i].mAddrWr));  
	    P->PC = oldPC;
         } 
      }
   }
}