/************************************************************************ ** ** Dinero III Cache Simulator ** $Header: /var/home/markhill/DistributeDineroIII/RCS/fetch.c,v 3.3 89/05/04 09:57:29 markhill Exp $ ** Similar to Version 3.1, Released 8/7/85 ** ** Mark D. Hill ** Computer Sciences Dept. ** Univ. of Wisconsin ** Madison, WI 53706 ** markhill@cs.wisc.edu ** ** Developed DineroIII While Affiliated With: ** ** Computer Science Division ** University of California ** Berkeley, California 94720 ** ** Source File: fetch.c ** ************************************************************************/ /* ** Copyright 1985, 1989 Mark D. Hill ** ** Permission to use, copy, modify, and distribute this ** software and its documentation for any purpose and without ** fee is hereby granted, provided that the above copyright ** notice appear in all copies. Mark D. Hill makes no ** representations about the suitability of this software ** for any purpose. It is provided "as is" without expressed ** or implied warranty. */ #include "global.h" fetch( /* Get addr from input stream & decode*/ cachep,ctrlp,metricp,dap) CACHETYPE *cachep; /* < */ CTRLTYPE *ctrlp; /* < */ METRICTYPE *metricp; /* <> */ register DECODEDADDRTYPE *dap; /* > */ /* affects: many things indirectly ** returns: EOF or ~EOF */ { long int addr; /* @ changed from int to long int */ int thelabel; static int flushcount = -2; /* No of addr since last cache flush, -1=>no flushing */ if (flushcount==-2) { /* Initialize */ flushcount = ((ctrlp->Q<1) ? -1 : 0); /* flush? */ } /* end init */ if ((flushcount>=0) && (flushcount++ >= ctrlp->Q)) { flushcount=1; flushcache(cachep,ctrlp,metricp); } /* for 370 port: 370 370 Must do file I/O on 3081. 370 */ #ifdef IBM370 if (readfrominputstream370(&thelabel,&addr,ctrlp, ctrlp->infilep)==EOF) return(EOF); #else if (readfrominputstream(&thelabel,&addr,ctrlp)==EOF) return(EOF); #endif else { #if test printf ("\nfetch.c:(fetch) addr %lx\n", addr); #endif if (thelabel == XFLUSH) flushcache(cachep,ctrlp,metricp); breakupaddr(addr,thelabel,dap,cachep); /* ******* debug -D ***** */ /* dumpaddr(0, dap); */ return(~EOF); } } /* ********************************************************************* */ prefetch( cachep,policyp,dap,miss,stackptr) CACHETYPE *cachep; /* < */ POLICYTYPE *policyp; /* < */ register DECODEDADDRTYPE *dap; /* < */ int miss; STACKNODETYPE *stackptr; /* ** This routine decides whether to start a prefetch access. ** If so the prefetch is pushed on the addrstack to be read ** instead of the next address trace address. */ { long int prefetchaddr; /* @@ changed from int to long int */ extern int random(); /* @@ changed from long to int. MAXINTPERCENT in the global.h file was changed too. */ /* ** See if prefetch needs to be aborted (because of data reference ** interference. Note: 0 <= random() <= 2^31-1 (on processors that employ 32 bit integers) and ** 0 <= random()/MAXINTPERCENT < 100. ** The definition of MAXINTPERCENT in global.h is (int)(INT_MAX/100). */ if (policyp->abortprefetchpercent > 0 ) { if (random()/MAXINTPERCENT < policyp->abortprefetchpercent) { return; } } /* ** Calculate address to prefetch */ prefetchaddr = dap->address + cachep->prefetchdisplacement; /* ** Switch on prefetch policy */ switch (policyp->fetch) { case ALWAYSPREFETCH: push_addrstack((PREFETCH+dap->accesstype),prefetchaddr); break; case LOADFORWARDPREFETCH: /* ** Don't prefetch into next block. */ if ( (dap->address/cachep->blocksize)==(prefetchaddr/cachep->blocksize) ) { push_addrstack((PREFETCH+dap->accesstype),prefetchaddr); } break; case SUBBLOCKPREFETCH: /* ** Don't prefetch into next block; wrap around within block instead. */ if ( (dap->address/cachep->blocksize)!=(prefetchaddr/cachep->blocksize) ) { prefetchaddr = prefetchaddr - cachep->blocksize; } push_addrstack((PREFETCH+dap->accesstype),prefetchaddr); break; case MISSPREFETCH: if (miss) { push_addrstack((PREFETCH+dap->accesstype),prefetchaddr); } break; /* ** Tagged prefetch (see Smith, "cache Memories," ~p.20) initiates ** a prefetch on the first demand reference to a (sub)-block. Thus, ** a prefetch is initiated on a demand miss or the first demand ** reference to a (sub)-block that was brought into the cache by a ** prefetch. ** ** Tagged prefetching is implemented using demand reference bits ** that are active only when tagged prefetching is selected. A ** prefetch is started on a demand miss and on a refernce to a ** (sub)-block whose reference bit was not previously set. */ case TAGGEDPREFETCH: if ((miss) || ((dap->validbit & stackptr->reference)==0)) { push_addrstack((PREFETCH+dap->accesstype),prefetchaddr); } break; case DEMAND: default : printf("\n---Error in prefetch policy:%c\n",policyp->fetch); exit(1); } } /* ********************************************************************* */ /* for 370 port: 370 370 Must do file I/O on 3081. 370 */ #ifdef IBM370 readfrominputstream370(labelp,addrp,ctrlp,theinfilep) /* get next addr */ int *labelp; int *addrp; CTRLTYPE *ctrlp; FILE *theinfilep; { register int readflag; char linebuffer[256]; char *fgets(); /* fgets(s,n,stream) gets n-1 chars from stream ** or until a newline; changes newline to nullchar; ** returns ptr to the sting. */ /* ** Read in ASCII from standard input ** Expect ONE label and addr in hex per line. ** Rest of data input line is ignored so it may ** be used for comments. ** ** WARNING: If more than one tuple is put on a line, ** all but the first tuple will be ignored. */ /* ** Get tuple from addrstack if any are there. */ if (pop_addrstack(labelp,addrp)>=0) return(~EOF); linebuffer[0] = NULL; fgets(linebuffer,255,theinfilep); #ifdef FAST_BUT_DANGEROUS_INPUT readflag = sscanxx(linebuffer,labelp,addrp); #else readflag = sscanf(linebuffer,"%x %x",labelp,addrp); #endif if (readflag==2) { ctrlp->tracecount++; if (ctrlp->tracecount > ctrlp->maxcount) { return(EOF); } else { return(~EOF); } } else { if (readflag!=EOF) { printf("\n **** Error in standard input.\n"); } return(EOF); } } /* ********************************************************************* */ #else readfrominputstream(labelp,addrp,ctrlp) /* get next addr */ int *labelp; long int *addrp; /* @ changed from int to long int */ CTRLTYPE *ctrlp; { register int readflag; char linebuffer[255]; char *gets(); /* Gets chars from stdin until a newline; ** changes newline to nullchar; returns ptr ** to the sting. */ /* ** Read in ASCII from standard input ** Expect ONE label and addr in hex per line. ** Rest of data input line is ignored so it may ** be used for comments. ** ** WARNING: If more than one tuple is put on a line, ** all but the first tuple will be ignored. */ /* ** Get tuple from addrstack if any are there. */ if (pop_addrstack(labelp,addrp)>=0) return(~EOF); linebuffer[0] = NULL; gets(linebuffer); #ifdef FAST_BUT_DANGEROUS_INPUT readflag = sscanxx(linebuffer,labelp,addrp); #else readflag = sscanf(linebuffer,"%x %x",labelp,addrp); #endif if (readflag==2) { ctrlp->tracecount++; /* count how many addresses were processed by now */ if (ctrlp->tracecount > ctrlp->maxcount) { if(sizeof(long) > sizeof(int)) printf ("\n*** Dinero did NOT process the entire input trace! ***\nDinero has processed %ld addresses from the input trace which is the current limit.\nIf you wish to process more addresses than this limit allows, next time please use the -z flag to change this limit.\n\n", ctrlp->maxcount); else printf ("\n*** Dinero did NOT process the entire input trace! ***\nDinero has processed %d addresses from the input trace which is the current limit.\nIf you wish to process more addresses than this limit allows, next time please use the -z flag to change this limit.\n\n", ctrlp->maxcount); return(EOF); } else { return(~EOF); } } else { if (readflag!=EOF) { printf("\n **** Error in standard input.\n"); } return(EOF); } } /* ********************************************************************* */ #endif breakupaddr( /* Decode address */ addr,labl,dap,cachep) register long int addr; /* < address @@ changed from int to long int */ register int labl; /* < type of reference */ register DECODEDADDRTYPE *dap; /* <> fields of this ptr are altered */ CACHETYPE *cachep; /* < */ /* ** affects: none ** returns: OK */ { /* ** These unsigned integers are so that a long int address with ** an MSB of 1 will be shifted correctly with a divide. */ unsigned long int theaddr; /* @@ changed from int to long int */ unsigned long int theblocksize; /* @@ changed from int to long int */ unsigned int thenumUorDsets, thenumIsets; #if 0 printf ("fetch.c: (breakupaddr) addr = %lx\n", addr); #endif theaddr = addr; theblocksize = cachep->blocksize; thenumUorDsets = cachep->numUorDsets; thenumIsets = cachep->numIsets; #if test printf ("block size: %d #of U/D sets: %d #of I sets: %d\n", theblocksize, thenumUorDsets, thenumIsets); #endif dap->address = theaddr; dap->accesstype = labl; dap->block = theaddr % theblocksize; dap->blockaddr = theaddr - dap->block; #if test printf ("dap->address: %lx dap->accesstype: %d dap->block: %d dap->blockaddr: %lx\n", dap->address, dap->accesstype, dap->block, dap->blockaddr); #endif if (cachep->subblocksize==0) { dap->validbit = VALID; } else { dap->subblocknum = dap->block / cachep->subblocksize; dap->validbit = VALID<subblocknum; #if test printf ("dap->subblocknum: %d dap->validbit=%d\n", dap->subblocknum, dap->validbit); #endif } switch ( labl ) { case XREAD : case XWRITE : case PREFETCH+XREAD : case PREFETCH+XWRITE : dap->set = (theaddr / theblocksize) % thenumUorDsets; dap->tag = (theaddr / theblocksize) / thenumUorDsets; break; case XINSTRN : case PREFETCH+XINSTRN : if (thenumIsets != 0) { /* I-Cache */ dap->set = ((theaddr / theblocksize) % thenumIsets) + thenumUorDsets; dap->tag = (theaddr / theblocksize) / thenumIsets; } else { /* Mixed Cache; put in data cache set */ dap->set = (theaddr / theblocksize) % thenumUorDsets; dap->tag = (theaddr / theblocksize) / thenumUorDsets; } break; case PREFETCH+XMISC : dap->set = (theaddr / theblocksize) % thenumUorDsets; dap->tag = (theaddr / theblocksize) / thenumUorDsets; break; default : dap->accesstype = XMISC; dap->set = (theaddr / theblocksize) % thenumUorDsets; dap->tag = (theaddr / theblocksize) / thenumUorDsets; break; } #if test printf ("dap->tag: %lx dap->set: %d\n", dap->tag, dap->set); #endif } /* ********************************************************************* */ flushcache( /* Flush cache */ cachep,ctrlp,metricp) CACHETYPE *cachep; /* < */ CTRLTYPE *ctrlp; /* < */ METRICTYPE *metricp; /* <> */ /* affects: ** returns: */ { extern int copybackstack(); extern int putonfreelist(); int stacknum; for (stacknum=0; stacknum<(cachep->numsets); stacknum++) { copybackstack(cachep,ctrlp,metricp,stacknum); putonfreelist(stacknum,&(stack[stacknum])); } } /* *************************************************** */ init_addrstack () /* ** NOTE: size_addrstack points beyond valid data. A 3-address ** stack would have array entries 0, 1, and 2 filled and ** size_addrstack equal to 3. */ { int i; for (i=0; i=0; i--) { printf("%d@%ld, ", addrstack[i].label, addrstack[i].address); } printf("end.\n"); } #ifdef FAST_BUT_DANGEROUS_INPUT /* ** The above "ifdef" enables a fast C-function called "sscanxx" ** to interpret input characters instead of the library function ** "sscanf" because a profile showed that dineroIII was spending ** 35% to 50% of this time in sscanf. The function "sscanxx" runs ** about 6 times faster than "sscanf." The function "sscanxx," ** selected by the compile-time flag FAST_BUT_DANGEROUS_INPUT in ** global.h, make dineroIII run in 60 to 70% of the time with the ** option diabled. */ #define CHAR_ZERO '0' #define CHAR_NINE '9' #define CHAR_LOWERCASE_A 'a' #define CHAR_LOWERCASE_F 'f' #define HEX 4 #define CHAR_DIGIT_OFFSET '0' #define CHAR_LOWERCASE_ABCDEF_OFFSET 'a'-10 #define WHITE_SPACE ((*ptr==' ')||(*ptr=='\t')) #define CHAR_HEX_DIGIT \ ((((digit = *ptr)>=CHAR_ZERO) && (digit<=CHAR_NINE)) \ || ((digit>=CHAR_LOWERCASE_A) && (digit<=CHAR_LOWERCASE_F))) #define HEX_CHAR_OFFSET \ ((digit>=CHAR_LOWERCASE_A) && (digit<=CHAR_LOWERCASE_F) \ ? /* a-f */ \ CHAR_LOWERCASE_ABCDEF_OFFSET \ : /* 0-9 */ \ CHAR_DIGIT_OFFSET \ ) sscanxx(linebuffer,num1p,num2p) char linebuffer[]; int *num1p; long int *num2p; /* @@ changed from int to long int */ /* ** This routine is designed to do the same function as ** sscanf(linebuffer,"%x %x",labelp,addrp). It was added ** because gprof said that 35 to 50% of dineroIII's run time ** was being spent in sscanf. This routine runs eight ** times faster. ** ** The routine is not exactly the same as sscanf: ** ** (1) It is implementation dependent. ** (2) Hex numbers cannot be preceded by "0x." ** (3) Legal digits are "0-9" and "a-f;" "A-F" will not ** be interpretted correctly. ** (4) The reponse to input errors is undefined. */ { register char digit; register char *ptr; register long int num; /* @ changed from int to long int */ #define MAX_ADDRESS_LENGTH sizeof(long int)*2 /* The max number of litterals in a legal input Hex address */ register int input_addr_length; /* counter that holds the number of literals in the input address, which should not exceed MAX_ADDRESS_LENGTH. */ char input_addr_string[MAX_ADDRESS_LENGTH+2] = ""; /* define a string to hold the literals of the current address */ /* ** Exit with EOF if the buffer is empty. */ if (*(ptr = linebuffer)==NULL) return(EOF); while (WHITE_SPACE) ptr++; /* ** Convert first hex number. */ num = 0; while (CHAR_HEX_DIGIT) { num = (num< MAX_ADDRESS_LENGTH) /* check for address length violation */ { printf ("\n\nAn address longer than %d Hex literals was found in the input trace.\nThis computer can only handle address length of up to %d bits.\nThe offensive address begins with (Hex) %s\n*** Program Terminated ***\n", MAX_ADDRESS_LENGTH, MAX_ADDRESS_LENGTH*4, input_addr_string); exit (1); } } *num2p = num; #if 0 printf ("fetch.c:(sscanxx) num2p = %ld %lx\n", num, num); #endif return(2); } #endif