/[gxemul]/trunk/src/cpus/memory_mips.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/cpus/memory_mips.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (show annotations)
Mon Oct 8 16:20:10 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 9342 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1264 2006/06/25 11:08:04 debug Exp $
20060624	Replacing the error-prone machine type initialization stuff
		with something more reasonable.
		Finally removing the old "cpu_run" kludge; moving around stuff
		in machine.c and emul.c to better suit the dyntrans system.
		Various minor dyntrans cleanups (renaming translate_address to
		translate_v2p, and experimenting with template physpages).
20060625	Removing the speed hack which separated the vph entries into
		two halves (code vs data); things seem a lot more stable now.
		Minor performance hack: R2000/R3000 cache isolation now only
		clears address translations when going into isolation, not
		when going out of it.
		Fixing the MIPS interrupt problems by letting mtc0 immediately
		cause interrupts.

==============  RELEASE 0.4.0.1  ==============


1 /*
2 * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: memory_mips.c,v 1.8 2006/06/24 21:47:23 debug Exp $
29 *
30 * MIPS-specific memory routines. Included from cpu_mips.c.
31 *
32 * NOTE: The cache emulation code (ifdef ENABLE_CACHE_EMULATION) is old
33 * and doesn't work with dyntrans. TODO: rewrite this.
34 */
35
36 #include <sys/types.h>
37 #include <sys/mman.h>
38
39
40 /*
41 * memory_cache_R3000():
42 *
43 * R2000/R3000 specific cache handling.
44 *
45 * Return value is 1 if a jump to do_return_ok is supposed to happen directly
46 * after this routine is finished, 0 otherwise.
47 */
48 int memory_cache_R3000(struct cpu *cpu, int cache, uint64_t paddr,
49 int writeflag, size_t len, unsigned char *data)
50 {
51 #ifdef ENABLE_CACHE_EMULATION
52 struct r3000_cache_line *rp;
53 int cache_line;
54 uint32_t tag_mask;
55 unsigned char *memblock;
56 struct memory *mem = cpu->mem;
57 int offset;
58 #endif
59 unsigned int i;
60 int cache_isolated = 0, addr, hit, which_cache = cache;
61
62
63 if (len > 4 || cache == CACHE_NONE)
64 return 0;
65
66
67 #ifdef ENABLE_CACHE_EMULATION
68 if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_SWAP_CACHES)
69 which_cache ^= 1;
70
71 tag_mask = 0xffffffff & ~cpu->cd.mips.cache_mask[which_cache];
72 cache_line = (paddr & cpu->cd.mips.cache_mask[which_cache])
73 / cpu->cd.mips.cache_linesize[which_cache];
74 rp = (struct r3000_cache_line *) cpu->cd.mips.cache_tags[which_cache];
75
76 /* Is this a cache hit or miss? */
77 hit = (rp[cache_line].tag_valid & R3000_TAG_VALID) &&
78 (rp[cache_line].tag_paddr == (paddr & tag_mask));
79
80 /*
81 * The cache miss bit is only set on cache reads, and only to the
82 * data cache. (?)
83 *
84 * (TODO: is this correct? I don't remember where I got this from.)
85 */
86 if (cache == CACHE_DATA && writeflag==MEM_READ) {
87 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~MIPS1_CACHE_MISS;
88 if (!hit)
89 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
90 MIPS1_CACHE_MISS;
91 }
92
93 /*
94 * Is the Data cache isolated? Then don't access main memory:
95 */
96 if (cache == CACHE_DATA &&
97 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_ISOL_CACHES)
98 cache_isolated = 1;
99
100 addr = paddr & cpu->cd.mips.cache_mask[which_cache];
101
102 /*
103 * If there was a miss and the cache is not isolated, then flush
104 * the old cacheline back to main memory, and read in the new
105 * cacheline.
106 *
107 * Then access the cache.
108 */
109 /*
110 fatal("L1 CACHE isolated=%i hit=%i write=%i cache=%i cacheline=%i"
111 " paddr=%08x => addr in"
112 " cache = 0x%lx\n", cache_isolated, hit, writeflag,
113 which_cache, cache_line, (int)paddr,
114 addr);
115 */
116 if (!hit && !cache_isolated) {
117 unsigned char *dst, *src;
118 uint64_t old_cached_paddr = rp[cache_line].tag_paddr
119 + cache_line * cpu->cd.mips.cache_linesize[which_cache];
120
121 /* Flush the old cacheline to main memory: */
122 if ((rp[cache_line].tag_valid & R3000_TAG_VALID) &&
123 (rp[cache_line].tag_valid & R3000_TAG_DIRTY)) {
124 /* fatal(" FLUSHING old tag=0%08x "
125 "old_cached_paddr=0x%08x\n",
126 rp[cache_line].tag_paddr,
127 old_cached_paddr);
128 */
129 memblock = memory_paddr_to_hostaddr(
130 mem, old_cached_paddr, MEM_WRITE);
131 offset = old_cached_paddr
132 & ((1 << BITS_PER_MEMBLOCK) - 1)
133 & ~cpu->cd.mips.cache_mask[which_cache];
134
135 src = cpu->cd.mips.cache[which_cache];
136 dst = memblock + (offset &
137 ~cpu->cd.mips.cache_mask[which_cache]);
138
139 src += cache_line *
140 cpu->cd.mips.cache_linesize[which_cache];
141 dst += cache_line *
142 cpu->cd.mips.cache_linesize[which_cache];
143
144 if (memblock == NULL) {
145 fatal("BUG in memory.c! Hm.\n");
146 } else {
147 memcpy(dst, src,
148 cpu->cd.mips.cache_linesize[which_cache]);
149 }
150 /* offset is the offset within
151 * the memblock:
152 * printf("read: offset = 0x%x\n", offset);
153 */
154 }
155
156 /* Copy from main memory into the cache: */
157 memblock = memory_paddr_to_hostaddr(mem, paddr, writeflag);
158 offset = paddr & ((1 << BITS_PER_MEMBLOCK) - 1)
159 & ~cpu->cd.mips.cache_mask[which_cache];
160 /* offset is offset within the memblock:
161 * printf("write: offset = 0x%x\n", offset);
162 */
163
164 /* fatal(" FETCHING new paddr=0%08x\n", paddr);
165 */
166 dst = cpu->cd.mips.cache[which_cache];
167
168 if (memblock == NULL) {
169 if (writeflag == MEM_READ)
170 memset(dst, 0,
171 cpu->cd.mips.cache_linesize[which_cache]);
172 } else {
173 src = memblock + (offset &
174 ~cpu->cd.mips.cache_mask[which_cache]);
175
176 src += cache_line *
177 cpu->cd.mips.cache_linesize[which_cache];
178 dst += cache_line *
179 cpu->cd.mips.cache_linesize[which_cache];
180 memcpy(dst, src,
181 cpu->cd.mips.cache_linesize[which_cache]);
182 }
183
184 rp[cache_line].tag_paddr = paddr & tag_mask;
185 rp[cache_line].tag_valid = R3000_TAG_VALID;
186 }
187
188 if (cache_isolated && writeflag == MEM_WRITE) {
189 rp[cache_line].tag_valid = 0;
190 }
191
192 if (writeflag==MEM_READ) {
193 for (i=0; i<len; i++)
194 data[i] = cpu->cd.mips.cache[which_cache][(addr+i) &
195 cpu->cd.mips.cache_mask[which_cache]];
196 } else {
197 for (i=0; i<len; i++) {
198 if (cpu->cd.mips.cache[which_cache][(addr+i) &
199 cpu->cd.mips.cache_mask[which_cache]] != data[i]) {
200 rp[cache_line].tag_valid |= R3000_TAG_DIRTY;
201 }
202 cpu->cd.mips.cache[which_cache][(addr+i) &
203 cpu->cd.mips.cache_mask[which_cache]] = data[i];
204 }
205 }
206
207 /* Write-through! (Write to main memory as well.) */
208 if (writeflag == MEM_READ || cache_isolated)
209 return 1;
210
211 #else
212
213 /*
214 * R2000/R3000 without correct cache emulation:
215 *
216 * TODO: This is just enough to trick NetBSD/pmax and Ultrix into
217 * being able to detect the cache sizes and think that the caches
218 * are actually working, but they are not.
219 */
220
221 if (cache != CACHE_DATA)
222 return 0;
223
224 /* Is this a cache hit or miss? */
225 hit = (cpu->cd.mips.cache_last_paddr[which_cache]
226 & ~cpu->cd.mips.cache_mask[which_cache])
227 == (paddr & ~(cpu->cd.mips.cache_mask[which_cache]));
228
229 /*
230 * The cache miss bit is only set on cache reads, and only to the
231 * data cache. (?)
232 *
233 * (TODO: is this correct? I don't remember where I got this from.)
234 */
235 if (cache == CACHE_DATA && writeflag==MEM_READ) {
236 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~MIPS1_CACHE_MISS;
237 if (!hit)
238 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
239 MIPS1_CACHE_MISS;
240 }
241
242 /*
243 * Is the Data cache isolated? Then don't access main memory:
244 */
245 if (cache == CACHE_DATA &&
246 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_ISOL_CACHES)
247 cache_isolated = 1;
248
249 addr = paddr & cpu->cd.mips.cache_mask[which_cache];
250
251 /* Data cache isolated? Then don't access main memory: */
252 if (cache_isolated) {
253 /* debug("ISOLATED write=%i cache=%i vaddr=%016"PRIx64" "
254 "paddr=%016"PRIx64" => addr in cache = 0x%lx\n",
255 writeflag, cache, (uint64_t) vaddr,
256 (uint64_t) paddr, addr); */
257
258 if (writeflag==MEM_READ) {
259 for (i=0; i<len; i++)
260 data[i] = cpu->cd.mips.cache[cache][(addr+i) &
261 cpu->cd.mips.cache_mask[cache]];
262 } else {
263 for (i=0; i<len; i++)
264 cpu->cd.mips.cache[cache][(addr+i) &
265 cpu->cd.mips.cache_mask[cache]] = data[i];
266 }
267 return 1;
268 } else {
269 /* Reload caches if necessary: */
270
271 /* No! Not when not emulating caches fully. (TODO?) */
272 cpu->cd.mips.cache_last_paddr[cache] = paddr;
273 }
274 #endif
275
276 return 0;
277 }
278
279
280 #define TRANSLATE_ADDRESS translate_v2p_mmu3k
281 #define V2P_MMU3K
282 #include "memory_mips_v2p.c"
283 #undef TRANSLATE_ADDRESS
284 #undef V2P_MMU3K
285
286 #define TRANSLATE_ADDRESS translate_v2p_mmu8k
287 #define V2P_MMU8K
288 #include "memory_mips_v2p.c"
289 #undef TRANSLATE_ADDRESS
290 #undef V2P_MMU8K
291
292 #define TRANSLATE_ADDRESS translate_v2p_mmu10k
293 #define V2P_MMU10K
294 #include "memory_mips_v2p.c"
295 #undef TRANSLATE_ADDRESS
296 #undef V2P_MMU10K
297
298 /* Almost generic :-) */
299 #define TRANSLATE_ADDRESS translate_v2p_mmu4100
300 #define V2P_MMU4100
301 #include "memory_mips_v2p.c"
302 #undef TRANSLATE_ADDRESS
303 #undef V2P_MMU4100
304
305 #define TRANSLATE_ADDRESS translate_v2p_generic
306 #include "memory_mips_v2p.c"
307
308

  ViewVC Help
Powered by ViewVC 1.1.26