diff options
author | Ranjith Kumaran <ranjith@cygnus.com> | 2000-03-17 22:48:54 +0000 |
---|---|---|
committer | Ranjith Kumaran <ranjith@cygnus.com> | 2000-03-17 22:48:54 +0000 |
commit | 03261851a10dd2d6900a0a00a7515a0a46fb5d76 (patch) | |
tree | 7c22ac6cbbc99fd5cd1b5426853be8d4fd7bfcf1 /libgloss/sparc/cache.c | |
parent | fae4c299f14fc23e2829c8656992eba21f79242a (diff) | |
download | cygnal-03261851a10dd2d6900a0a00a7515a0a46fb5d76.tar.gz cygnal-03261851a10dd2d6900a0a00a7515a0a46fb5d76.tar.bz2 cygnal-03261851a10dd2d6900a0a00a7515a0a46fb5d76.zip |
20000317 sourceware import
Diffstat (limited to 'libgloss/sparc/cache.c')
-rw-r--r-- | libgloss/sparc/cache.c | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/libgloss/sparc/cache.c b/libgloss/sparc/cache.c new file mode 100644 index 000000000..5b6e270d7 --- /dev/null +++ b/libgloss/sparc/cache.c @@ -0,0 +1,147 @@ +/* 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 */ + } + } +} |