Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cache.c « sparc « libgloss - cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 5b6e270d77d0e60f8d2cf58d785cf15964a40f0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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 */
	}
    }
}