Help needed: clearing the 68020 cache.

Mike Khaw khaw at parcplace.com
Wed Aug 16 05:48:35 AEST 1989


> Date:    6 Jul 89 09:26:13 GMT
> From:    agesen at daimi.dk (Ole Agesen)
> Subject: Help needed: clearing the 68020 cache.
> 
> Help needed....
> 
> The MC68020 incorporates an on-chip cache memory. The cache is used to
> store the instruction stream prefetch accesses from the main memory.  I'm
> currently implementing a kind of incremental linking implying the need to
> write self-modifying code. Therefore, I have to clear the cache upon a
> modification of the code. According to the MC68020 User's Manual the cache
> is cleared by issuing a MOVEC instruction (move control register).
> However, this is a privileged instruction (requiring supervisor state).
> 
> Can anyone tell me how to clear the cache?
>  Can I get supervisor privileges for a user process?
>  Is there a kernel operation clearing the cache?
>  Can I easily create a modified kernel with the desired operation?
>  Other (more) realistic possibilities?
>
> (We are using Unix 4.0 on sun 3/50).
> 
> Thanks in advance!
> 
> Ole Agesen

We have had to address this same issue in our Smalltalk-80 product line,
which as an integrated interactive program development environment, must
generate code on-the-fly. The basic trick for most machines is, rather
than manipulating cache-control registers (which are usually only
available to supervisor-mode programs), branch into a no-op table, which
will displace the old I-cache contents.  The structure of the table
depends on the CPU & cache architecture.

We use the following C code in our 68020 versions of our product,
including the one that runs under SunOS 4.0 on Sun-3s.

Mike Khaw
---
ParcPlace Systems, 1550 Plymouth St., Mountain View, CA 94043	415/691-6749
Domain=khaw at parcplace.com, UUCP={uunet,sun,decwrl}!parcplace!khaw

<--- CUT HERE --->
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix at uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of shell archive."
# Contents:  m68k-cacheFlush.c
# Wrapped by khaw at connecticut on Mon Aug 14 21:10:04 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'm68k-cacheFlush.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'m68k-cacheFlush.c'\"
else
echo shar: Extracting \"'m68k-cacheFlush.c'\" \(5867 characters\)
sed "s/^X//" >'m68k-cacheFlush.c' <<'END_OF_FILE'
X/************************************************************************
X * Instruction-cache flushing for the MC680x0 processor family.
X *
X * I-cache flushing is necessary (for processors which have an I-cache)
X * when you modify some portion of code space after it has been executed
X * (and plan to execute in that space in the future).  I-caches typically
X * don't keep their contents coherent with data writes, hence after you
X * modify some code which may have been executed in the past the
X * corresponding I-cache entries must be flushed (otherwise, random code
X * may be executed some time in the future).
X * 
X * 680x0 Cache notes:
X *
X * The 68000, 68008, 68010 have no I-cache at all.
X *
X * The 68020 has a 256-byte on-chip I-cache organized as 64 entries of
X * one longword each.
X *
X * The 68030 has a 256-byte on-chip I-cache organized as 16 entries of
X * four longwords each.  It also has a 256-byte on-chip D-cache, which is
X * not germane to this discussion.
X *
X * Both the 68020 & 68030 have a cache control/address registers which
X * permit flushing of individual entries (or wholesale flushing), but
X * the cache control registers can only be used in supervisor mode,
X * which makes them impossible to use under most operating systems.
X *
X * CPU-boards often implement a cache which doesn't discriminate between
X * I & D fetches.  No reasonable design of such a unified cache should
X * pose any problem to the code given here.
X *
X * It is possible for a CPU-board design to implement an off-chip I-cache
X * (using the F pins to distinguish between I & D fetches).  We know of
X * no interesting platforms which do this currently, but a platform that
X * did would need code here to accomodate it.
X *
X * Written by Allan M. Schiffman & L. Peter Deutsch
X * Copyright (C) 1989, ParcPlace Systems, Inc.
X * This program is offered free of charge and without restrictions,
X * provided that this notice remains attached.  ParcPlace accepts
X * no responsibility for any damages which may result from its use.
X ************************************************************************/
X
Xtypedef unsigned char byte;
Xtypedef unsigned long ptrBits;
Xtypedef unsigned short nOp;
Xtypedef nOp *machinePC;
X
X/* Tables for clearing the I-cache */
Xstatic machinePC codeClearICache;
Xstatic machinePC codeRemoveFromICache;
X
X/* our favorite 680x0 instructions defined here */
X#define RTS 0x4e75						/* 680x0 rts instruction */
X#define NOP 0x4e71						/* 680x0 nop instruction */
X#define ADDIL_d0 0x680					/* 680x0 addi.l #n, d0 instruction*/
X#define ORW_d0d0 0x8040					/* 680x0 or.w d0, d0 instruction */
X
X/*
X * initClearICache --
X *   Initialize tables for flushing the I-cache.  Called once at
X *   start-up. Returns count of bytes consumed (<=0 if couldn't malloc).
X *
X *   For now, we don't distinguish between the '030 & '020, even though
X *   we maybe could do slightly less work for the '030.
X *
X *   Builds two I-cache clearing tables --
X *
X *   1) full-swat code clearing table is made out of 42 6-byte no-ops
X *      (addil #0, d0), followed by a rtn.
X *      Table is to be is entered from the top.
X *      Code only occupies the first 254 bytes of the table, but
X *      since the table is long-aligned, the execution of the rtn will
X *      serve to flush the last short.
X *      Using the six-byte funny no-op is much faster than using an
X *      equivalent number of nop instructions since the nop instruction
X *      locks the pipeline (check the manual).  It's faster than the
X *      equivalent number of shorter no-ops since no instruction executes
X *      faster then 2 clocks, but a long can be fetched in 3 clocks (on
X *      the '020, at least).
X *
X *   2) single-entry code clearing table, 64 rtn/no-op pairs
X *      (no-op in this case is or d0, d0) followed by a final rtn.
X *      We expect never to be asked for less than 4 bytes to be flushed,
X *      so using rtn/rtn pairs would not be faster (but would have
X *      more complex boundary conditions).
X */
Xint
XinitClearICache()
X{
X	extern char *malloc();				/* aligns at least to shorts */
X	byte *basePtr;						/* base address of memory to use */
X	int totalSize;						/* size of tables in bytes */
X	ptrBits ptr;
X	register nOp *nptr;
X	register int i;
X#define TBL1_SIZE (256+2)				/* includes slop for alignment */
X#define TBL2_SIZE (254+256+2)			/* includes slop for alignment */
X
X	totalSize = TBL1_SIZE + TBL2_SIZE;
X	if((basePtr = (byte *)malloc(totalSize)) == (byte *)0)
X		return 0;						/* malloc failed */
X
X	/* Construct the code for clearing the entire I-cache */
X	ptr = (ptrBits)basePtr;
X	basePtr += TBL1_SIZE;				/* position to next table */
X	/* force to long-aligned */
X	nptr = (nOp *)(ptr + ((-ptr) & 3));	/* align to 0 mod 4 */
X	codeClearICache = (machinePC)nptr;
X	for (i = 0; i < 252/6; i++) {
X		*nptr++ = ADDIL_d0;
X		*nptr++ = 0;
X		*nptr++ = 0;
X	}
X	*nptr = RTS;						/* last short will be flushed anyway */
X
X	/*
X	 * Construct the code for flushing an individual I-cache entry.
X	 * Note that a request to flush an entry at 2 mod 4
X	 * must actually flush two entries, since it must handle
X	 * a 32-bit word straddling two entries.
X	 */
X	ptr = (ptrBits)basePtr;
X	nptr = (nOp *)(ptr + ((-ptr) & 255)); /* align to 0 mod 256 */
X	codeRemoveFromICache = (machinePC)nptr;
X	for ( i = 0; i < 256/4; i++ ) {
X		*nptr++ = RTS;
X		*nptr++ = ORW_d0d0;
X	}
X	*nptr = RTS;
X
X	return totalSize;						/* success return */
X}
X
X
X/*
X * flushICache --
X *
X * Flush the I-cache entries in the range (from):(to) inclusive.
X * initClearICache must have been called previously.
X */
Xvoid
XflushICache(from, to)
X  register machinePC from, to;
X{
X	if ( to - from > 40 ) {
X    	/* Faster to clear the whole I-cache */
X	    ((void (*)())codeClearICache)();
X	}
X	else {
X		/* Clear individual entries */
X	    while ( to > from ) {
X			((void (*)())(codeRemoveFromICache + ((ptrBits)(from) & 254)))();
X			from += 4;
X		}
X	}
X}

END_OF_FILE
echo shar: NEWLINE appended to \"'m68k-cacheFlush.c'\"
if test 5868 -ne `wc -c <'m68k-cacheFlush.c'`; then
    echo shar: \"'m68k-cacheFlush.c'\" unpacked with wrong size!
fi
# end of 'm68k-cacheFlush.c'
fi
echo shar: End of shell archive.
exit 0



More information about the Comp.sys.sun mailing list