tc_coherence.c 3.27 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. 
 *
 */

/****************************************************************
 * tc_coherence.c
 * 
 * $Author: blythe $
 * $Date: 2002/05/29 01:09:09 $
 *****************************************************************/

#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>


#include "sim_error.h"
#include "simutil.h"
#include "tc_coherence.h"
#include "machine_params.h"
#include "arch_specifics.h"


#define CHUNK_SIZE (PAGE_SIZE)

#define NORMALIZE(_y) ( (VA)((_y)-tcCohState.start)  /CHUNK_SIZE)

#define BYTE_INDEX(_x) (NORMALIZE(_x)>>3)
#define BIT_INDEX(_x) (NORMALIZE(_x) & 0x7)
#define BIT(_x) (1<<(_x))

#define TCCOHERENCE_SIZE(_size) ((_size)/(8*CHUNK_SIZE))


/* Module private Data */
/*XXX- What we want to handle is having a cache line of code */
/*write to itself  without having the simulation get into an infinite */
/*flushing loop.  Note that such a   sequence could not execute itself */
/*without a flush operation before execution of the portion of the */
/*line written.  */
/* Unfortunately the boot code written into the first user process */
/* does write into a code line before it calls exec (even though it */
/* doesn't execute this code), so this mechanism must exist */



static struct {
   char *bm;
   MA start;
   MA end;
   VA size;
} tcCohState;


#define ICBM(_mAddr)     (tcCohState.bm[BYTE_INDEX(_mAddr)])
#define ICBMADDR(_mAddr) (&tcCohStatebm[BYTE_INDEX(_mAddr)])
#define ICBMSET(_mAddr)  (tcCohState.bm[BYTE_INDEX(_mAddr)] |= BIT(BIT_INDEX(_mAddr)))


void TCcoherence_init( MA start )
{
   VA total =0;
   int mach;
   for (mach =0; mach < NUM_MACHINES; mach++) {
      total += MEM_SIZE(mach);
   }
   ASSERT(total);
   tcCohState.start = start;
   tcCohState.end = start + total;
   tcCohState.size = TCCOHERENCE_SIZE(total);
   tcCohState.bm = ZALLOC_PERM(TCCOHERENCE_SIZE(total),"TCCoherence");
   CPUPrint("0x%x D TCCOHERE_BASE 0x%x\n",
            tcCohState.bm,
            tcCohState.bm+TCCOHERENCE_SIZE(total) );
}


void TCcoherence_flush(void)
{
   if (!tcCohState.bm) return;
   bzero(tcCohState.bm,tcCohState.size);
}

void TCcoherence_mark_code(MA start, MA finish )
{
   MA mAddr;
   ASSERT(start < finish);
   ASSERT(start >= tcCohState.start);
   ASSERT(finish <= tcCohState.end);
   for (mAddr=start; mAddr<finish;mAddr +=CHUNK_SIZE) {     
      ICBMSET(mAddr);
   }
} 


int TCcoherence_is_code( MA mAddr )
{
   if (!tcCohState.bm) return 0;
   ASSERT( tcCohState.start <= mAddr);
   ASSERT( mAddr < tcCohState.end);
   return ICBM(mAddr) & BIT(BIT_INDEX(mAddr));
}



/* vAddr only for debugging output */
/* 0 - return normally, 1 - return via set_pc... */

int TCcoherence_check( MA start, MA finish )
{
   MA mAddr;
   ASSERT(start < finish);
   ASSERT(start >= tcCohState.start);
   ASSERT(finish <= tcCohState.end);

   for( mAddr = start; mAddr < finish; mAddr += CHUNK_SIZE ) {
      if( ICBM(mAddr) & BIT(BIT_INDEX(mAddr)) ) {
         CPUPrint("TCcoherence_check. Violation for mAddr=0x%llx finish=0x%llx\n",
                   (uint64)start,(uint64)finish);
         return 1;
      }
   }
   return 0;
}