home *** CD-ROM | disk | FTP | other *** search
- /* This file is derived from gcc-2.6.3/libgcc2.c, section L_clear_cache */
-
- /* Copyright (C) 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
-
- This file is part of GNU CC.
-
- GNU CC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
- /* Clear part of an instruction cache. */
-
- /* Our emphasis here is _not_ to clear as few cache lines as possible
- * or with as few machine instructions as possible, but to do it _right_.
- */
-
-
-
- /* This code is apparently untested!! */
-
- #ifdef __m68k__
- #ifdef NeXT
- #define CLEAR_INSN_CACHE(BEG, END) \
- asm volatile ("trap #2")
- #endif
- #endif
-
- /* This is from Andreas Stolcke <stolcke@ICSI.Berkeley.EDU>. */
- #ifdef __mips__
- #ifdef ultrix
- #include <mips/cachectl.h>
- #else
- #include <sys/cachectl.h>
- #endif
- #define CLEAR_INSN_CACHE(BEG, END) \
- cacheflush (BEG, END - BEG, BCACHE)
- #endif
-
- #ifdef __convex__
- #define CLEAR_INSN_CACHE(BEG, END) \
- asm ("pich")
- #endif
-
- void
- __TR_clear_cache (beg, end)
- char *beg, *end;
- {
- #ifdef CLEAR_INSN_CACHE
- CLEAR_INSN_CACHE (beg, end);
- #else
- #ifdef INSN_CACHE_SIZE /* This is actually dead code!! */
- #define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
- static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH];
- static int initialized = 0;
- int offset;
- void *start_addr;
- void *end_addr;
- typedef (*function_ptr) ();
-
- #if (INSN_CACHE_SIZE / INSN_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 + INSN_CACHE_LINE_WIDTH - 1)
- & -INSN_CACHE_LINE_WIDTH);
- int end_ptr = ptr + INSN_CACHE_SIZE;
-
- while (ptr < end_ptr)
- {
- *(INSTRUCTION_TYPE *)ptr
- = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
- ptr += INSN_CACHE_LINE_WIDTH;
- }
- *(INSTRUCTION_TYPE *)(ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
-
- initialized = 1;
- }
-
- /* Call the beginning of the sequence. */
- (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1)
- & -INSN_CACHE_LINE_WIDTH))
- ());
-
- #else /* Cache is large. */
-
- if (! initialized)
- {
- int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1)
- & -INSN_CACHE_LINE_WIDTH);
-
- while (ptr < (int) array + sizeof array)
- {
- *(INSTRUCTION_TYPE *)ptr = RETURN_INSTRUCTION;
- ptr += INSN_CACHE_LINE_WIDTH;
- }
-
- initialized = 1;
- }
-
- /* Find the location in array that occupies the same cache line as BEG. */
-
- offset = ((int) beg & -INSN_CACHE_LINE_WIDTH) & (INSN_CACHE_PLANE_SIZE - 1);
- start_addr = (((int) (array + INSN_CACHE_PLANE_SIZE - 1)
- & -INSN_CACHE_PLANE_SIZE)
- + offset);
-
- /* Compute the cache alignment of the place to stop clearing. */
- #if 0 /* This is not needed for gcc's purposes. */
- /* If the block to clear is bigger than a cache plane,
- we clear the entire cache, and OFFSET is already correct. */
- if (end < beg + INSN_CACHE_PLANE_SIZE)
- #endif
- offset = (((int) (end + INSN_CACHE_LINE_WIDTH - 1)
- & -INSN_CACHE_LINE_WIDTH)
- & (INSN_CACHE_PLANE_SIZE - 1));
-
- #if INSN_CACHE_DEPTH > 1
- end_addr = (start_addr & -INSN_CACHE_PLANE_SIZE) + offset;
- if (end_addr <= start_addr)
- end_addr += INSN_CACHE_PLANE_SIZE;
-
- for (plane = 0; plane < INSN_CACHE_DEPTH; plane++)
- {
- int addr = start_addr + plane * INSN_CACHE_PLANE_SIZE;
- int stop = end_addr + plane * INSN_CACHE_PLANE_SIZE;
-
- while (addr != stop)
- {
- /* Call the return instruction at ADDR. */
- ((function_ptr) addr) ();
-
- addr += INSN_CACHE_LINE_WIDTH;
- }
- }
- #else /* just one plane */
- do
- {
- /* Call the return instruction at START_ADDR. */
- ((function_ptr) start_addr) ();
-
- start_addr += INSN_CACHE_LINE_WIDTH;
- }
- while ((start_addr % INSN_CACHE_SIZE) != offset);
- #endif /* just one plane */
- #endif /* Cache is large */
- #endif /* Cache exists */
- #endif /* CLEAR_INSN_CACHE */
- }
-