/************************************************************************
**
**	Dinero III Cache Simulator 
**	$Header: /var/home/markhill/DistributeDineroIII/RCS/state.c,v 3.3 89/05/04 09:57:42 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:	state.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"

update(				/* Update */
		cachep,policyp,ctrlp,metricp,dap)
CACHETYPE *cachep;		/* <  */
POLICYTYPE *policyp;		/* <  */
CTRLTYPE *ctrlp;		/* <  */
METRICTYPE *metricp;		/* <> */
register DECODEDADDRTYPE *dap;	/* <  */
/*
** affects: priority stacks & metrics
*/
{
STACKNODETYPE *stackupdate();
STACKNODETYPE *findnth();

int setnumber;
register int stackdepth;
int elements_per_set;
int miss;
int blockmiss;
STACKNODETYPE *preptr;
STACKNODETYPE *ptr;
STACKNODETYPE *replacedptr;

/*
**	Find address tag; if not TOS, update based upon replacement
**	algorithm. Do not update if the access is XWRITE and the 
**	the policy is not to allocate on writes.
**
**	NOTE: stackdepth==0 ==> the block was not found and preptr
**	and ptr are NULL.
*/
setnumber = dap->set;
elements_per_set = cachep->assoc;

stackdepth = find(dap->tag,elements_per_set,setnumber,&preptr,&ptr);
blockmiss = (stackdepth==0 || stackdepth > elements_per_set);
miss = blockmiss || ((dap->validbit & ptr->valid)==0);

/*
**	Prefetch active?  
**	Prefetch on reads and instruction fetches, but not on
**	writes, misc, and prefetch references.
*/
if ( (policyp->fetch!=DEMAND) && (
     (dap->accesstype==XREAD) || (dap->accesstype==XINSTRN)
	)) {
	prefetch(cachep,policyp,dap,miss,ptr);
 }

/*
**	If address trap occurs, then abort reference.
*/
/* if (addrtrap()) return(); */


/*
**	Update Priority Stacks
*/
if (stackdepth!=1) { 	/* if not top of stack */
	if ((policyp->writeallocate==WRITEALLOCATE)
	|| (dap->accesstype!=XWRITE)) {
		ptr = stackupdate(stackdepth,dap->tag,dap->blockaddr,
		policyp->replacement,setnumber,elements_per_set,ptr,preptr);
	}
	else { /* also update on a write hit with NOWRITEALLOCATE when data is already in the cache */
		if ((stackdepth>1) && (stackdepth<=elements_per_set)) {
			ptr = stackupdate(stackdepth,dap->tag,dap->blockaddr,
			policyp->replacement,setnumber,elements_per_set,ptr,preptr);
		}
	}
 }


/*
**	Update state bits unless access is a WRITE miss w/o WRITEALLOCATE.
*/
if ((policyp->writeallocate==NOWRITEALLOCATE) 
   && (dap->accesstype==XWRITE)
   && (miss)) {
	/* do nothing */
 }
else {

/*
**	Reset reference, dirty, and valid bits on block miss.
*/
	if (blockmiss) {
		ptr->reference = NOTREFERENCED;
		ptr->dirty = NOTDIRTY;
		ptr->valid = NOTVALID;
 	}

/*
**	Set valid bit.
*/
	ptr->valid |= dap->validbit;

/*
**	Set dirty if bit necessary.
*/
	if ((dap->accesstype==XWRITE) && (policyp->write==COPYBACK)) {
		ptr->dirty |= dap->validbit;
 	}

/*
**	Set reference bit for tagged prefetch if demand fetch
*/
	if ((policyp->fetch==TAGGEDPREFETCH) && (
	   (dap->accesstype==XINSTRN) ||
	   (dap->accesstype==XREAD) ||
	   (dap->accesstype==XWRITE) ||
	   (dap->accesstype==XMISC) )) {
		ptr->reference |= dap->validbit;
	}

 }

/*
**	Update metrics. 
*/
metricp->fetch[dap->accesstype]++;
if (miss) {
	metricp->miss[dap->accesstype]++;
	if (blockmiss) {
		metricp->blockmiss[dap->accesstype]++;
	}
 }

/*
**	Calculate bus traffic
*/
if (blockmiss) {
	replacedptr = findnth(setnumber,(elements_per_set+1));
 }
else {
	replacedptr = NULL;
 }

busupdate(cachep,policyp,ctrlp,metricp,dap,miss,blockmiss,replacedptr);

} /* ***************************************************************** */






STACKNODETYPE *stackupdate(			/* Update priority stacks */
    stackdepth,addr_tag,block_addr,replace_policy,
    setnum,elements_per_set,ptr,preptr)

int stackdepth;			/* <  */
long int addr_tag;		/* <  */  /* @@ changed from int to long int */
long int block_addr;		/* <  */  /* @@ changed from int to long int */
char replace_policy;		/* <  */
int setnum;			/* <  */
int elements_per_set;		/* <  */
STACKNODETYPE *ptr;		/* <> */
STACKNODETYPE *preptr;		/* <  */
{
int level;
int position;
STACKNODETYPE *ptr1;
STACKNODETYPE *makenode();
extern int random();  /* @@ changed from long to int */


switch (replace_policy) {

case LRU :	
if (stackdepth==0) {	/* All misses? */
		ptr = makenode(addr_tag,block_addr);
		push(ptr,setnum);
	}
	else { 		/* LRU */
		movetotop(preptr,ptr,setnum);
	}
	break;

case FIFO :
	if (stackdepth==0) {	/* All misses? */
		ptr = makenode(addr_tag,block_addr);
		push(ptr,setnum);
	}
	else {	/* FIFO is NOT a stack algorithm; thus,  */
		/* results are valid only for set size 0 */
		/* Note: node does NOT move up in stack  */
		/* unless it was previously out of the   */
		/* cache.				 */

		if (stackdepth > elements_per_set) {
			movetotop(preptr,ptr,setnum);
		}
	}
	break;


case RANDOM	 :
	if (stackdepth==0) {	/* All misses? */
		ptr = makenode(addr_tag,block_addr);
		push(ptr,setnum);
		position = ( (elements_per_set < stack[setnum].tag)
			    ? elements_per_set : stack[setnum].tag);
	}
	else {	/* RANDOM is a stack algorithm if updates */
		/* are done properly (See Coffman & Denning */
		/* OS Theory, pp. 260-261). Basically,    */
		/* stack elements between where the new   */
		/* TOS came from and the top have a       */
		/* (level - 1)/level chance of maintaining */
		/* their previous position. Since the     */
		/* "movetotop" function initially pushes  */
		/* elements a level down in the stack, an */
		/* element must be swapped up once to     */
		/* return to its previous spot.		  */

		movetotop(preptr,ptr,setnum);
		position = stackdepth - 1;
	}
	preptr = ptr;	/* adjust priority stack */
	ptr1 = ptr->next;
	for (level = 2; ((level <= position) && (ptr1 != NULL));
	level++) {
		if (random()%level > 0) {
			swap(preptr,ptr1,ptr1->next,setnum);
			preptr = preptr->next;
		}
		else {
			preptr = ptr1;
			ptr1 = ptr1->next;
		}
	}
	break;

	default :
	printf("***error: illegal replacement algorithm");
	exit(ERR);

 }

return(ptr);
} /* ************************************************************** */






push(ptr,stacknum)		/* Push node on priority stack "stacknum." */
STACKNODETYPE *ptr;		/* <  ptr to node */
int stacknum;			/* <  which stack */
/*
** affects: priority stacks
** returns: number in stack "stacknum"
*/
{
extern STACKNODETYPE *stack;	/* global ptr to top of stacks */

ptr->next = stack[stacknum].next;
stack[stacknum].next = ptr;

return(++(stack[stacknum].tag));		/* Return number in stack */
} /* ***************************************************************** */



remove1(preptr,ptr,stacknum)  	/* Remove node from a priority stack  */
STACKNODETYPE *preptr;		/* < ptr to node preceeding the one to be
				   removed */
STACKNODETYPE *ptr;		/* < ptr to node to be removed */
int stacknum;			/* < which stack */
/*
** affects: priority stacks
** returns: number left in stack "stacknum"
*/
{
extern STACKNODETYPE *stack;	/* global ptr to top of stacks */
extern STACKNODETYPE freelist;	/* List head for free list */

preptr->next = ptr->next;	/* Remove */

ptr->next = freelist.next;	/* Push on freelist */
freelist.next = ptr;
freelist.tag++;

return(--(stack[stacknum].tag));		/* Return number in stack */
} /* ***************************************************************** */



movetotop(preptr,ptr,stacknum)	/* Move node to top of priority stack. */
STACKNODETYPE *preptr;		/* < ptr to node preceeding the one to be
				   moved to top */
STACKNODETYPE *ptr;		/* < ptr to node to be moved */
int stacknum;			/* < which stack */
/*
** affects: priority stacks
** returns: number in stack "stacknum"
*/
{
extern STACKNODETYPE *stack;	/* global ptr to top of stacks */

preptr->next = ptr->next;		/* Remove */

ptr->next = stack[stacknum].next;	/* Push */
stack[stacknum].next = ptr;

return(stack[stacknum].tag);		/* Return number in stack */
} /* ***************************************************************** */



swap(preptr,ptr1,ptr2,stacknum)	/* Swap nodes on priority stack */
STACKNODETYPE *preptr;		/* < node preceeding pair to be swapped */
STACKNODETYPE *ptr1;		/* < first node in pair */
STACKNODETYPE *ptr2;		/* < second node in pair */
int stacknum;			/* < which stack */
/*
** affects: priority stacks
** returns: number in stack "stacknum"
*/
{
extern STACKNODETYPE *stack;	/* global ptr to top of stacks */

if ((ptr1!=NULL)&&(ptr2!=NULL)) {
	preptr->next = ptr2;
	ptr1->next = ptr2->next;
	ptr2->next = ptr1;
}

return(stack[stacknum].tag);		/* Return number in stack */
} /* ***************************************************************** */



find(				/* Find address in stack. */
     addrtag,setsize,stacknum,preptrptr,ptrptr)
register long int addrtag;	/* <  address tag being looked for. @@ changed from int to long int */
int setsize;			/* <  associativity */
int stacknum;			/* <  which stack is for this set? */
STACKNODETYPE **preptrptr;	/* <> points to node preceeding found node */
STACKNODETYPE **ptrptr;		/* <> points to found node (NULL otherwise) */
/*
** affects: none
** returns: stackdepth if found
**	    NULL otherwise
*/
{
extern STACKNODETYPE *stack;	/* global ptr to top of stacks */
register int stackdepth;
register STACKNODETYPE *preptr,*ptr;

preptr = &stack[stacknum];      /* gets a pointer to the stack of the current set (for this current address) */
ptr = stack[stacknum].next;     /* gets a pointer to the next stack for this current set */

for (stackdepth = 1; ((ptr != NULL)
		   && (ptr->tag != addrtag)
		   && (stackdepth <= setsize)); 
			stackdepth++) {
	preptr = ptr;
	ptr = ptr->next;
 }

if ((ptr != NULL) && (ptr->tag == addrtag)) {
	*preptrptr = preptr;	/* found */
	*ptrptr = ptr;
	return(stackdepth);
 }
else {				/* free balance of stack if there  */
	if ((ptr != NULL)	/* are FREETHRESHOLD nodes to free */
	  &&(stack[stacknum].tag - setsize >= FREETHRESHOLD))
		putonfreelist(stacknum,preptr);

	*preptrptr = *ptrptr = NULL;	/* not found */
	return(0);
 }
} /* ***************************************************************** */



STACKNODETYPE *findnth(			/* Find nth address in stack. */
     	stacknum,n)
int stacknum;			/* <  which stack */
int n;				/* <  index of record */
/*
** returns: ptr to n-th record in stack; the 1st record is the
**	    one pointed to by the header. If the stack has less
**	    than n reocrds, NULL is returned.
*/
{
extern STACKNODETYPE *stack;	/* global ptr to top of stacks */
register int stackdepth;
register STACKNODETYPE *ptr;

ptr = stack[stacknum].next;

/*
**	Less than n in stack?
*/
if (stack[stacknum].tag < n) {
	ptr = NULL;
 }
else {
	for (stackdepth = 1; stackdepth < n; stackdepth++) {
		ptr = ptr->next;
 	}
 }

return(ptr);
} /* ***************************************************************** */



putonfreelist(stacknum,last)	/* Move nodes from prio stack to free list */
int stacknum;			/* <  */
register STACKNODETYPE *last;	/* <  */
/*
** affects: stack[stacknum], freelist
** returns: number of nodes freed 
*/
{
extern STACKNODETYPE *stack;	/* global ptr to top of stacks */
extern STACKNODETYPE freelist;	/* List head for free list */
STACKNODETYPE *first;
register int numtofree;
/*
**	Remove Balance of list from stack & get ready to add to
**	freelist.
*/
if (last->next==NULL)	/* Any to free? */
	return(0);
else {
	first = last->next;
	last->next = NULL;
	last = first;
	/*
 	*	See how many nodes to free.
 	*/
	for (numtofree = 1; last->next!=NULL; numtofree++)
		last = last->next;
	/*
 	*	Put on free list. Adjust counts.
 	*/
	last->next = freelist.next;
	freelist.next = first;
	stack[stacknum].tag -= numtofree;
	freelist.tag += numtofree;
	
	return(numtofree);
 }
} /* ***************************************************************** */



STACKNODETYPE *makenode(		/* Returns node from buffer. */
			Tag,Blockaddr)	 
long int Tag;        /* @@ changed from int to long int */
long int Blockaddr;  /* @@ changed from int to long int */
{
static STACKNODETYPE *buffer;
extern int bufferindex;		/* global index to buffer */
extern STACKNODETYPE freelist;	/* List head for free list */
extern char *calloc();
extern int numnodes;		/* Count on storage allocated */
STACKNODETYPE *ptr;
/*
**	Allocate node from freelist or buffer; if buffer is used up,
**	then get more.
*/
if ((ptr = freelist.next) != NULL) {
	freelist.next = ptr->next;	/* Allocate from freelist */
	freelist.tag--;
}
else {		/* Allocate from buffer */
	if (bufferindex >= BUFFERSIZE) {
		bufferindex = 0;	/* buffer used up */
		/* *** buffer = (STACKNODETYPE *)malloc
				(BUFFERSIZE * sizeof(STACKNODETYPE)); */

		buffer = (STACKNODETYPE *)calloc
			(BUFFERSIZE,SIZEOFSTACKNODETYPE);

		if (buffer == NULL) {
			/* printf("*** error: Malloc failed."); */
			/* return(NULL); */
			printf("***error: calloc failed.\n");
			fflush(stdout); /* Paraniod flush of stdout buffer */
			fprintf(stderr,"***error: calloc failed.\n");
			fflush(stderr); /* Paraniod flush of stderr buffer */
			exit(ERR);
		}
		numnodes += BUFFERSIZE;		/* Keep track of storage */
 	}
ptr = buffer + (bufferindex++);		/* Allocate */
 }
/*
**	Initialize node 
*/
ptr->tag = Tag;
ptr->blockaddr = Blockaddr;
ptr->next = NULL;

return(ptr);
} /* ***************************************************************** */





copybackstack(			/* Copies back dirty blocks */
     	cachep,ctrlp,metricp,stacknum)
CACHETYPE *cachep;
CTRLTYPE *ctrlp;
METRICTYPE *metricp;
int stacknum;			/* <  which stack */
/*
*/
{
extern STACKNODETYPE *stack;	/* global ptr to top of stacks */
register int stackdepth;
register int numinstack;		
register STACKNODETYPE *ptr;

ptr = stack[stacknum].next;

/*
**	How many in stack?
*/
numinstack = ((stack[stacknum].tag < cachep->assoc) 
		? stack[stacknum].tag : cachep->assoc);

for (stackdepth = 0; stackdepth < numinstack; stackdepth++) {
	if (cachep->subblocksize==0) {
		/* 
		**  No sub-blocks 
		*/
		if (ptr->dirty!=NOTDIRTY) {
			/*
			**  Write dirty block
			*/
			bustraffic(ctrlp->output,metricp, cachep,
			    cachep->transfersize, cachep->buswidth, BUSWRITE,
			    ptr->blockaddr);
		}
			/*
			**  Snoop announces clean block replaced.
			*/
		else {
			bustraffic(ctrlp->output,metricp, cachep,
			    cachep->transfersize, cachep->buswidth, BUSSNOOP,
			    ptr->blockaddr);
		}
	}
		/*
		**  Sub-blocks
		*/
	else {
			replacesubblocks(ctrlp,metricp,cachep,
			    ptr);
	}

	/*
	**	Invalidate block and go on to next one.
	*/
	ptr->dirty = NOTDIRTY;
	ptr->valid = NOTVALID;
	ptr->reference = NOTREFERENCED;

	ptr = ptr->next;
 }

} /* ***************************************************************** */





busupdate(				/* Update bus traffic stuff. */
		cachep,policyp,ctrlp,metricp,
		dap,miss,blockmiss,replacedptr)
CACHETYPE *cachep;		/* <  */
POLICYTYPE *policyp;		/* <  */
CTRLTYPE *ctrlp;		/* <  */
METRICTYPE *metricp;		/* <> */
register DECODEDADDRTYPE *dap;	/* <  */
int miss;			/* <  */
int blockmiss;			/* <  */
STACKNODETYPE *replacedptr;	/* <  */
{

/* 
**  Increment Rcount for all demand fetches.
**  Increment Icount for all demand instruction fetches.
*/
if (DEMANDFETCHP(dap->accesstype)) metricp->Rcount++;

if (dap->accesstype==XINSTRN) metricp->Icount++;

/*
**	Handle reference.
*/
/*
**	Not a write?
*/
if (dap->accesstype!=XWRITE) {
	/*
	**	A non-write hit?
	*/
	if (!miss) {
		/* do nothing */
	}
	else {  /* a miss -- (pre-)fetch (sub-)block */
		if (DEMANDFETCHP(dap->accesstype)) {
			bustraffic(ctrlp->output,metricp, cachep,cachep->transfersize, cachep->buswidth,
				BUSREAD,dap->address);
		}
		else {
			bustraffic(ctrlp->output,metricp, cachep,cachep->transfersize, cachep->buswidth,
				BUSPREFETCH,dap->address);
		}
	}
 }
/*
**	A write:
**	(CB==copy-back, WT==write-through)
**
**		  write-allocate		no-write-allocate
**		CB		WT		CB		WT
**		--		--		--		--
**	Hit	dirty		w-word		dirty		w-word
**
**	Miss	r-block		r-block	
**		dirty		w-word		w-word		w-word
*/
else {  
	/*
	**	A write hit?
	*/
	if (!miss) { 
		if (policyp->write==WRITETHROUGH) {
			/* write word */
			bustraffic(ctrlp->output,metricp, cachep,cachep->wordsize, cachep->buswidth,
				BUSWRITE,dap->address);
		}
		else { /* copy-back */
			/* block (re)marked dirty in "update" */
		}
	}
	/*
	**	A write miss
	*/
	else {
		if (policyp->writeallocate==WRITEALLOCATE) {
			/* read (sub)-block */
			bustraffic(ctrlp->output,metricp, cachep,cachep->transfersize, cachep->buswidth,
				BUSREAD,dap->address);
		}
		if ((policyp->write==WRITETHROUGH) || 
		(policyp->writeallocate==NOWRITEALLOCATE)) {
			/* write word */
			bustraffic(ctrlp->output,metricp, cachep,cachep->wordsize, cachep->buswidth,
				BUSWRITE,dap->address);
		}
		else {
			/* block marked dirty in "update" */
		}
	}
 }

/*
**  If something replaced
*/
if ((blockmiss) && (replacedptr!=NULL)) {

	if (cachep->subblocksize==0) {
		/* 
		**  No sub-blocks 
		*/
		if (replacedptr->dirty!=NOTDIRTY) {
			/*
			**  Write dirty block
			*/
			bustraffic(ctrlp->output,metricp, cachep,
			    cachep->transfersize, cachep->buswidth, BUSWRITE,
			    replacedptr->blockaddr);
		}
			/*
			**  Snoop announces clean block replaced.
			*/
		else {
			bustraffic(ctrlp->output,metricp, cachep,
			    cachep->transfersize, cachep->buswidth, BUSSNOOP,
			    replacedptr->blockaddr);
		}
	}
		/*
		**  Sub-blocks
		*/
	else {
			replacesubblocks(ctrlp,metricp,cachep,
			    replacedptr);
	}

	/*
	**	Zero out what was replaced.
	*/
	replacedptr->dirty = NOTDIRTY;
	replacedptr->valid = NOTVALID;
	replacedptr->reference = NOTREFERENCED;
 }

} /* ***************************************************************** */





replacesubblocks(
		ctrlp,metricp,cachep,aptr)
CTRLTYPE *ctrlp;		/* <  */
METRICTYPE *metricp;		/* <> */
CACHETYPE *cachep;		/* <  */
STACKNODETYPE *aptr;
{
unsigned int validmask;
unsigned int dirtymask;
long int subblockaddr;   /* @@ changed from int to long int */

/*
**  Performance Hack: If not -o3 and not dirty, then return.
*/
if ((ctrlp->output!=BUS_SNOOP) && (aptr->dirty==NOTDIRTY)) return;


validmask = aptr->valid;
dirtymask = aptr->dirty;
subblockaddr = aptr->blockaddr;

while (validmask!=NOTVALID) {
	/*
	** For a valid sub-block
	*/
	if (validmask & LOWVALIDMASK) {
		if (dirtymask & LOWDIRTYMASK) {
			/*
			**  Write dirty sub-block
			*/
			bustraffic(ctrlp->output,metricp, cachep,
			   	cachep->transfersize, cachep->buswidth, BUSWRITE,
		 	   	subblockaddr);
		}
		else {
			/*
			**  Snoop announces clean sub-block replaced.
			*/
			bustraffic(ctrlp->output,metricp, cachep,
			   	cachep->transfersize, cachep->buswidth, BUSSNOOP,
		 	   	subblockaddr);
		}
	}

	validmask >>= 1;
	dirtymask >>= 1;
	subblockaddr += cachep->transfersize;
 }

} /* ***************************************************************** */





bustraffic(				/* put stuff on memory bus. */
		output_option, metricp, cachep, transfersize, bussize, access, addr)
/*
**	Called for every bus transaction and every (sub)-block
**	replaced.
*/
int output_option;
METRICTYPE *metricp;		/* <> */
CACHETYPE *cachep;
int transfersize;       /* the number of bytes that are to be moved between the cache and a lower level memory */
int bussize;            /* the bus width in bytes which can be different than the required transfersize */
char access;
long int addr;          /* @@ changed from int to long int */

{

int size;               /* the number of bytes put on the output bus when there is a write. Can be just one word written back or an entire (sub-)block. */

long int lastaddr;      /* a bigger address than the last address that is put on the output bus while going to a lower level memory. Is used when the bus width is smaller than a (sub-)block size, thus requiring several bus cycles in order to move all the required data. */

long int baseaddr;     /* the address of the beginning of this address' (sub-)block */



baseaddr = (cachep->subblocksize == 0) ?
                           (addr - (addr % cachep->blocksize))              
                         : (addr - (addr % cachep->subblocksize));

lastaddr = baseaddr + ((cachep->subblocksize == 0) ?
                           cachep->blocksize
                         : cachep->subblocksize);


#if 0
/*printf ("sub(%d)  (block)%d  (mod)%d  base(%lx)\n", cachep->subblocksize, cachep->blocksize, addr % cachep->blocksize, baseaddr);*/
printf ("addr(%lx)  trans(%d)  base(%lx)  last(%lx)\n", addr, transfersize, baseaddr, lastaddr);
#endif

if (metricp->bus_traffic_in < 0)
  {
    printf ("\nmetricp->bus_traffic_in (%ld) < 0\n\n",metricp->bus_traffic_in); 
    exit (0);
  }

switch (access) {

case BUSREAD :
case BUSPREFETCH :
	metricp->bus_traffic_in  += transfersize;
	metricp->bus_transactions_initiated++;
	metricp->bus_usage += transfersize/bussize;
	addr = baseaddr;   /* start address of fetched (sub-)block */

	if (output_option>=BUS) {	/* BUS or BUS_SNOOP */
	  for ( ; addr < lastaddr ; addr += bussize ){
	    printf("BUS2 %c %d %lx ", access, bussize, addr);      /* @@ changed from %x to %lx */
	    printf("%d %d\n",metricp->Rcount,metricp->Icount);
	  }
	  metricp->Icount = metricp->Rcount = 0;
 	}
	break;

case BUSWRITE :
	metricp->bus_traffic_out += transfersize;
	metricp->bus_transactions_initiated++;
	metricp->bus_usage += (transfersize <= bussize) ? 1 : transfersize/bussize;

	if (output_option>=BUS) {	/* BUS or BUS_SNOOP */
	  if (transfersize == cachep->wordsize)
	    {  /* one word is written back */
	    printf("BUS2 %c %d %lx ", access, transfersize, addr);      /* @@ changed from %x to %lx */
	    printf("%d %d\n",metricp->Rcount,metricp->Icount);
	    }
	  else
	    {  /* an entire (sub-)block is written back */
	      for ( ; addr < lastaddr ; addr += bussize ){
		printf("BUS2 %c %d %lx ", access, bussize, addr);      /* @@ changed from %x to %lx */
		printf("%d %d\n",metricp->Rcount,metricp->Icount);
	      }
	    }
	  metricp->Icount = metricp->Rcount = 0;
 	}
	break;

case BUSSNOOP :
	if (output_option==BUS_SNOOP) {	/* BUS_SNOOP only */
	  metricp->bus_transactions_initiated++;
	  metricp->bus_usage += transfersize/bussize;
	  addr = baseaddr;   /* start address of fetched (sub-)block */

	  for ( ; addr < lastaddr ; addr += bussize ){
	    printf("BUS2 %c %d %lx ", access, bussize, addr);      /* @@ changed from %x to %lx */
	    printf("%d %d\n",metricp->Rcount,metricp->Icount);
	  }
	  metricp->Icount = metricp->Rcount = 0;
 	}
	break;

default :
	printf("\n---Error in bustraffic switch stmt; access=%d.\n",
		access);
	break;
 }

}





