home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Education Sampler 1992 [NeXTSTEP]
/
Education_1992_Sampler.iso
/
NeXT
/
GnuSource
/
cc-61.0.1
/
cc
/
icache.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-08
|
4KB
|
136 lines
/* Clear part of an instruction cache. */
/* Total number of bytes held in instruction cache. */
#define CACHE_SIZE 256
/* Number of consecutive bytes that go into the cache together. */
#define CACHE_LINE_WIDTH 16
/* Number of cache planes. This is the number of different locations
with the same alignment that can be in the cache at once. */
#define CACHE_DEPTH 1
/* This is an integer value for a return instruction. */
#define RETURN_INSTRUCTION 0x4e75
/* This is an integer value for an instruction to jump a short distance ahead.
More precisely, this instruction should jump to itself.
We add an appropriate offset to it when using it. */
#define JUMP_AHEAD_INSTRUCTION (0x6000 - 2)
/* This type specifies the size of those instructions. */
#define INSTRUCTION_TYPE short
#define CACHE_PLANE_SIZE (CACHE_SIZE / CACHE_DEPTH)
void
clear_cache (beg, end)
char *beg, *end;
{
static char array[CACHE_SIZE + CACHE_PLANE_SIZE + CACHE_LINE_WIDTH];
static int initialized = 0;
int offset;
unsigned int start_addr, end_addr;
typedef (*function_ptr) ();
#if (CACHE_SIZE / CACHE_LINE_WIDTH) < 16
/* It's cheaper to clear the whole cache.
Put in a series of jump instructions so that calling the beginning
of the cache will clear the whole thing. */
if (! initialized)
{
int ptr = (((int) array + CACHE_LINE_WIDTH - 1)
& -CACHE_LINE_WIDTH);
int end_ptr = ptr + CACHE_SIZE;
while (ptr < end_ptr)
{
*(INSTRUCTION_TYPE *)ptr = JUMP_AHEAD_INSTRUCTION + CACHE_LINE_WIDTH;
ptr += CACHE_LINE_WIDTH;
}
*(INSTRUCTION_TYPE *)(ptr - CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
initialized = 1;
}
/* Call the beginning of the sequence. */
(((function_ptr) (((int) array + CACHE_LINE_WIDTH - 1) & -CACHE_LINE_WIDTH))
());
#else /* Cache is large. */
if (! initialized)
{
int ptr = (((int) array + CACHE_LINE_WIDTH - 1)
& -CACHE_LINE_WIDTH);
while (ptr < (int) array + sizeof array)
{
*(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION;
ptr += CACHE_LINE_WIDTH;
}
initialized = 1;
}
/* Find the location in array that occupies the same cache line as BEG. */
offset = ((int) beg & -CACHE_LINE_WIDTH) & (CACHE_PLANE_SIZE - 1);
start_addr = (((int) (array + CACHE_PLANE_SIZE - 1) & -CACHE_PLANE_SIZE)
+ offset);
/* Compute the cache alignment of the place to stop clearing.
If the block to clear is bigger than a cache plane,
we clear the entire cache, and OFFSET is already correct. */
/* if (end < beg + CACHE_PLANE_SIZE) */
offset = (((int) (end + CACHE_LINE_WIDTH - 1) & -CACHE_LINE_WIDTH)
& (CACHE_PLANE_SIZE - 1));
#if CACHE_DEPTH > 1
end_addr = (start_addr & -CACHE_PLANE_SIZE) + offset;
if (end_addr <= start_addr)
end_addr += CACHE_PLANE_SIZE;
for (plane = 0; plane < CACHE_DEPTH; plane++)
{
int addr = start_addr + plane * CACHE_PLANE_SIZE;
int stop = end_addr + plane * CACHE_PLANE_SIZE;
while (addr != stop)
{
/* Call the return instruction at ADDR. */
((function_ptr) addr) ();
addr += CACHE_LINE_WIDTH;
}
}
#else /* just one plane */
do
{
/* Call the return instruction at START_ADDR. */
((function_ptr) start_addr) ();
start_addr += CACHE_LINE_WIDTH;
}
while ((start_addr % CACHE_SIZE) != offset);
#endif /* just one plane */
#endif /* Cache is large */
}
#ifdef TEST
main (argc, argv)
int argc;
char **argv;
{
clear_cache (atoi (argv[1]), atoi (argv[2]));
}
#endif