148 lines
3.5 KiB
C
148 lines
3.5 KiB
C
|
/* Cache code for SPARClite
|
||
|
*
|
||
|
* Copyright (c) 1998 Cygnus Support
|
||
|
*
|
||
|
* The authors hereby grant permission to use, copy, modify, distribute,
|
||
|
* and license this software and its documentation for any purpose, provided
|
||
|
* that existing copyright notices are retained in all copies and that this
|
||
|
* notice is included verbatim in any distributions. No written agreement,
|
||
|
* license, or royalty fee is required for any of the authorized uses.
|
||
|
* Modifications to this software may be copyrighted by their authors
|
||
|
* and need not follow the licensing terms described here, provided that
|
||
|
* the new terms are clearly indicated on the first page of each file where
|
||
|
* they apply.
|
||
|
*/
|
||
|
|
||
|
#include "sparclite.h"
|
||
|
|
||
|
/* Ancillary registers on the DANlite */
|
||
|
|
||
|
#define DIAG 30
|
||
|
#define ICCR 31
|
||
|
|
||
|
/* Bits in the DIAG register */
|
||
|
|
||
|
#define ICD 0x40000000 /* ICACHE disable */
|
||
|
#define DCD 0x20000000 /* DCACHE disable */
|
||
|
|
||
|
/* Bits in the ICCR register */
|
||
|
|
||
|
#define CE 1 /* cache enable*/
|
||
|
|
||
|
|
||
|
/* Forward declarations. */
|
||
|
|
||
|
void flush_i_cache ();
|
||
|
|
||
|
|
||
|
/* Determine if this is a DANlite (MB8686x), as opposed to an earlier
|
||
|
SPARClite (MB8683x). This is done by examining the impl and ver
|
||
|
fields in the PSR:
|
||
|
|
||
|
MB8683x: impl(bit31-28)=0x0; ver(bit27-24)=0xf;
|
||
|
MB8686x: impl(bit31-28)=0x1; ver(bit27-24)=0xe;
|
||
|
*/
|
||
|
|
||
|
static int
|
||
|
is_danlite ()
|
||
|
{
|
||
|
static int checked = 0;
|
||
|
static int danlite = 0;
|
||
|
|
||
|
if (!checked)
|
||
|
{
|
||
|
int psr = read_psr ();
|
||
|
danlite = (psr & 0xff000000) == 0x1e000000;
|
||
|
checked = 1;
|
||
|
}
|
||
|
return danlite;
|
||
|
}
|
||
|
|
||
|
/* This cache code is known to work on both the 930 & 932 processors. It just
|
||
|
cheats and clears the all of the address space that could contain tags, as
|
||
|
opposed to striding the tags at 8 or 16 word intervals, or using the cache
|
||
|
flush registers, which don't exist on all processors. */
|
||
|
|
||
|
void
|
||
|
cache_off ()
|
||
|
{
|
||
|
if (is_danlite ())
|
||
|
{
|
||
|
/* Disable the ICACHE. Disabling the DCACHE crashes the machine. */
|
||
|
unsigned int diag = read_asr (DIAG);
|
||
|
write_asr (DIAG, diag | ICD);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
write_asi (1, 0, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
cache_on ()
|
||
|
{
|
||
|
if (is_danlite ())
|
||
|
{
|
||
|
unsigned int diag;
|
||
|
|
||
|
/* Flush the caches. */
|
||
|
flush_i_cache ();
|
||
|
|
||
|
/* Enable the ICACHE and DCACHE */
|
||
|
diag = read_asr (DIAG);
|
||
|
write_asr (DIAG, diag & ~ (ICD | DCD));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
unsigned long addr;
|
||
|
|
||
|
cache_off (); /* Make sure the cache is off */
|
||
|
|
||
|
/* Reset all of the cache line valid bits */
|
||
|
|
||
|
for (addr = 0; addr < 0x1000; addr += 8)
|
||
|
{
|
||
|
write_asi (0xc, addr, 0); /* Clear bank 1, icache */
|
||
|
write_asi (0xc, addr + 0x80000000, 0); /* Clear bank 2, icache */
|
||
|
|
||
|
write_asi (0xe, addr, 0); /* Clear bank 1, dcache */
|
||
|
write_asi (0xe, addr + 0x80000000, 0); /* Clear bank 2, dcache */
|
||
|
}
|
||
|
|
||
|
/* turn on the cache */
|
||
|
|
||
|
write_asi (1, 0, 0x35); /* Write buf ena, prefetch buf ena, data
|
||
|
& inst caches enab */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Flush the instruction cache. We need to do this for the debugger stub so
|
||
|
that breakpoints, et. al. become visible to the instruction stream after
|
||
|
storing them in memory.
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
flush_i_cache ()
|
||
|
{
|
||
|
if (is_danlite ())
|
||
|
{
|
||
|
write_asi (0x31, 0, 0); /* Flush entire i/d caches */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int cache_reg;
|
||
|
unsigned long addr;
|
||
|
|
||
|
cache_reg = read_asi (1, 0); /* Read cache/bus interface reg */
|
||
|
|
||
|
if (!(cache_reg & 1))
|
||
|
return; /* Just return if cache is already off */
|
||
|
|
||
|
for (addr = 0; addr < 0x1000; addr += 8)
|
||
|
{
|
||
|
write_asi (0xc, addr, 0); /* Clear bank 1, icache */
|
||
|
write_asi (0xc, addr + 0x80000000, 0); /* Clear bank 2, icache */
|
||
|
}
|
||
|
}
|
||
|
}
|