/[gxemul]/upstream/0.3.3.1/src/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

Annotation of /upstream/0.3.3.1/src/memory_mips.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (hide annotations)
Mon Oct 8 16:18:14 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 11234 byte(s)
0.3.3.1
1 dpavlin 2 /*
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.5 2005/02/18 07:04:10 debug Exp $
29     *
30     * MIPS-specific memory routines. Included from cpu_mips.c.
31     */
32    
33     #include <sys/types.h>
34     #include <sys/mman.h>
35    
36    
37     /*
38     * insert_into_tiny_cache():
39     *
40     * If the tiny cache is enabled (USE_TINY_CACHE), then this routine inserts
41     * a vaddr to paddr translation first in the instruction (or data) tiny
42     * translation cache.
43     */
44     static void insert_into_tiny_cache(struct cpu *cpu, int instr, int writeflag,
45     uint64_t vaddr, uint64_t paddr)
46     {
47     #ifdef USE_TINY_CACHE
48     int wf = 1 + (writeflag == MEM_WRITE);
49    
50     if (cpu->machine->bintrans_enable)
51     return;
52    
53     paddr &= ~0xfff;
54     vaddr >>= 12;
55    
56     if (instr) {
57     /* Code: */
58     memmove(&cpu->cd.mips.translation_cache_instr[1],
59     &cpu->cd.mips.translation_cache_instr[0],
60     sizeof(struct translation_cache_entry) *
61     (N_TRANSLATION_CACHE_INSTR - 1));
62    
63     cpu->cd.mips.translation_cache_instr[0].wf = wf;
64     cpu->cd.mips.translation_cache_instr[0].vaddr_pfn = vaddr;
65     cpu->cd.mips.translation_cache_instr[0].paddr = paddr;
66     } else {
67     /* Data: */
68     memmove(&cpu->cd.mips.translation_cache_data[1],
69     &cpu->cd.mips.translation_cache_data[0],
70     sizeof(struct translation_cache_entry) *
71     (N_TRANSLATION_CACHE_DATA - 1));
72    
73     cpu->cd.mips.translation_cache_data[0].wf = wf;
74     cpu->cd.mips.translation_cache_data[0].vaddr_pfn = vaddr;
75     cpu->cd.mips.translation_cache_data[0].paddr = paddr;
76     }
77     #endif
78     }
79    
80    
81     /*
82     * memory_cache_R3000():
83     *
84     * R2000/R3000 specific cache handling.
85     *
86     * Return value is 1 if a jump to do_return_ok is supposed to happen directly
87     * after this routine is finished, 0 otherwise.
88     */
89     int memory_cache_R3000(struct cpu *cpu, int cache, uint64_t paddr,
90     int writeflag, size_t len, unsigned char *data)
91     {
92     #ifdef ENABLE_CACHE_EMULATION
93     struct r3000_cache_line *rp;
94     int cache_line;
95     uint32_t tag_mask;
96     unsigned char *memblock;
97     struct memory *mem = cpu->mem;
98     int offset;
99     #endif
100     unsigned int i;
101     int cache_isolated = 0, addr, hit, which_cache = cache;
102    
103    
104     if (len > 4 || cache == CACHE_NONE)
105     return 0;
106    
107    
108     #ifdef ENABLE_CACHE_EMULATION
109     if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_SWAP_CACHES)
110     which_cache ^= 1;
111    
112     tag_mask = 0xffffffff & ~cpu->cd.mips.cache_mask[which_cache];
113     cache_line = (paddr & cpu->cd.mips.cache_mask[which_cache])
114     / cpu->cd.mips.cache_linesize[which_cache];
115     rp = (struct r3000_cache_line *) cpu->cd.mips.cache_tags[which_cache];
116    
117     /* Is this a cache hit or miss? */
118     hit = (rp[cache_line].tag_valid & R3000_TAG_VALID) &&
119     (rp[cache_line].tag_paddr == (paddr & tag_mask));
120    
121     #ifdef ENABLE_INSTRUCTION_DELAYS
122     if (!hit)
123     cpu->cd.mips.instruction_delay +=
124     cpu->cd.mips.cpu_type.instrs_per_cycle
125     * cpu->cd.mips.cache_miss_penalty[which_cache];
126     #endif
127    
128     /*
129     * The cache miss bit is only set on cache reads, and only to the
130     * data cache. (?)
131     *
132     * (TODO: is this correct? I don't remember where I got this from.)
133     */
134     if (cache == CACHE_DATA && writeflag==MEM_READ) {
135     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~MIPS1_CACHE_MISS;
136     if (!hit)
137     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
138     MIPS1_CACHE_MISS;
139     }
140    
141     /*
142     * Is the Data cache isolated? Then don't access main memory:
143     */
144     if (cache == CACHE_DATA &&
145     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_ISOL_CACHES)
146     cache_isolated = 1;
147    
148     addr = paddr & cpu->cd.mips.cache_mask[which_cache];
149    
150     /*
151     * If there was a miss and the cache is not isolated, then flush
152     * the old cacheline back to main memory, and read in the new
153     * cacheline.
154     *
155     * Then access the cache.
156     */
157     /*
158     fatal("L1 CACHE isolated=%i hit=%i write=%i cache=%i cacheline=%i"
159     " paddr=%08x => addr in"
160     " cache = 0x%lx\n", cache_isolated, hit, writeflag,
161     which_cache, cache_line, (int)paddr,
162     addr);
163     */
164     if (!hit && !cache_isolated) {
165     unsigned char *dst, *src;
166     uint64_t old_cached_paddr = rp[cache_line].tag_paddr
167     + cache_line * cpu->cd.mips.cache_linesize[which_cache];
168    
169     /* Flush the old cacheline to main memory: */
170     if ((rp[cache_line].tag_valid & R3000_TAG_VALID) &&
171     (rp[cache_line].tag_valid & R3000_TAG_DIRTY)) {
172     /* fatal(" FLUSHING old tag=0%08x "
173     "old_cached_paddr=0x%08x\n",
174     rp[cache_line].tag_paddr,
175     old_cached_paddr);
176     */
177     memblock = memory_paddr_to_hostaddr(
178     mem, old_cached_paddr, MEM_WRITE);
179     offset = old_cached_paddr
180     & ((1 << BITS_PER_MEMBLOCK) - 1)
181     & ~cpu->cd.mips.cache_mask[which_cache];
182    
183     src = cpu->cd.mips.cache[which_cache];
184     dst = memblock + (offset &
185     ~cpu->cd.mips.cache_mask[which_cache]);
186    
187     src += cache_line *
188     cpu->cd.mips.cache_linesize[which_cache];
189     dst += cache_line *
190     cpu->cd.mips.cache_linesize[which_cache];
191    
192     if (memblock == NULL) {
193     fatal("BUG in memory.c! Hm.\n");
194     } else {
195     memcpy(dst, src,
196     cpu->cd.mips.cache_linesize[which_cache]);
197     }
198     /* offset is the offset within
199     * the memblock:
200     * printf("read: offset = 0x%x\n", offset);
201     */
202     }
203    
204     /* Copy from main memory into the cache: */
205     memblock = memory_paddr_to_hostaddr(mem, paddr, writeflag);
206     offset = paddr & ((1 << BITS_PER_MEMBLOCK) - 1)
207     & ~cpu->cd.mips.cache_mask[which_cache];
208     /* offset is offset within the memblock:
209     * printf("write: offset = 0x%x\n", offset);
210     */
211    
212     /* fatal(" FETCHING new paddr=0%08x\n", paddr);
213     */
214     dst = cpu->cd.mips.cache[which_cache];
215    
216     if (memblock == NULL) {
217     if (writeflag == MEM_READ)
218     memset(dst, 0,
219     cpu->cd.mips.cache_linesize[which_cache]);
220     } else {
221     src = memblock + (offset &
222     ~cpu->cd.mips.cache_mask[which_cache]);
223    
224     src += cache_line *
225     cpu->cd.mips.cache_linesize[which_cache];
226     dst += cache_line *
227     cpu->cd.mips.cache_linesize[which_cache];
228     memcpy(dst, src,
229     cpu->cd.mips.cache_linesize[which_cache]);
230     }
231    
232     rp[cache_line].tag_paddr = paddr & tag_mask;
233     rp[cache_line].tag_valid = R3000_TAG_VALID;
234     }
235    
236     if (cache_isolated && writeflag == MEM_WRITE) {
237     rp[cache_line].tag_valid = 0;
238     }
239    
240     if (writeflag==MEM_READ) {
241     for (i=0; i<len; i++)
242     data[i] = cpu->cd.mips.cache[which_cache][(addr+i) &
243     cpu->cd.mips.cache_mask[which_cache]];
244     } else {
245     for (i=0; i<len; i++) {
246     if (cpu->cd.mips.cache[which_cache][(addr+i) &
247     cpu->cd.mips.cache_mask[which_cache]] != data[i]) {
248     rp[cache_line].tag_valid |= R3000_TAG_DIRTY;
249     }
250     cpu->cd.mips.cache[which_cache][(addr+i) &
251     cpu->cd.mips.cache_mask[which_cache]] = data[i];
252     }
253     }
254    
255     /* Run instructions from the right host page: */
256     if (cache == CACHE_INSTRUCTION) {
257     memblock = memory_paddr_to_hostaddr(mem, paddr, writeflag);
258     if (memblock != NULL) {
259     cpu->cd.mips.pc_last_host_4k_page = memblock +
260     (paddr & ((1 << BITS_PER_MEMBLOCK) - 1) & ~0xfff);
261     }
262     }
263    
264     /* Write-through! (Write to main memory as well.) */
265     if (writeflag == MEM_READ || cache_isolated)
266     return 1;
267    
268     #else
269    
270     /*
271     * R2000/R3000 without correct cache emulation:
272     *
273     * TODO: This is just enough to trick NetBSD/pmax and Ultrix into
274     * being able to detect the cache sizes and think that the caches
275     * are actually working, but they are not.
276     */
277    
278     if (cache != CACHE_DATA)
279     return 0;
280    
281     /* Is this a cache hit or miss? */
282     hit = (cpu->cd.mips.cache_last_paddr[which_cache]
283     & ~cpu->cd.mips.cache_mask[which_cache])
284     == (paddr & ~(cpu->cd.mips.cache_mask[which_cache]));
285    
286     #ifdef ENABLE_INSTRUCTION_DELAYS
287     if (!hit)
288     cpu->cd.mips.instruction_delay +=
289     cpu->cd.mips.cpu_type.instrs_per_cycle
290     * cpu->cd.mips.cache_miss_penalty[which_cache];
291     #endif
292    
293     /*
294     * The cache miss bit is only set on cache reads, and only to the
295     * data cache. (?)
296     *
297     * (TODO: is this correct? I don't remember where I got this from.)
298     */
299     if (cache == CACHE_DATA && writeflag==MEM_READ) {
300     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~MIPS1_CACHE_MISS;
301     if (!hit)
302     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
303     MIPS1_CACHE_MISS;
304     }
305    
306     /*
307     * Is the Data cache isolated? Then don't access main memory:
308     */
309     if (cache == CACHE_DATA &&
310     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_ISOL_CACHES)
311     cache_isolated = 1;
312    
313     addr = paddr & cpu->cd.mips.cache_mask[which_cache];
314    
315     /* Data cache isolated? Then don't access main memory: */
316     if (cache_isolated) {
317     /* debug("ISOLATED write=%i cache=%i vaddr=%016llx "
318     "paddr=%016llx => addr in cache = 0x%lx\n",
319     writeflag, cache, (long long)vaddr,
320     (long long)paddr, addr); */
321    
322     if (writeflag==MEM_READ) {
323     for (i=0; i<len; i++)
324     data[i] = cpu->cd.mips.cache[cache][(addr+i) &
325     cpu->cd.mips.cache_mask[cache]];
326     } else {
327     for (i=0; i<len; i++)
328     cpu->cd.mips.cache[cache][(addr+i) &
329     cpu->cd.mips.cache_mask[cache]] = data[i];
330     }
331     return 1;
332     } else {
333     /* Reload caches if necessary: */
334    
335     /* No! Not when not emulating caches fully. (TODO?) */
336     cpu->cd.mips.cache_last_paddr[cache] = paddr;
337     }
338     #endif
339    
340     return 0;
341     }
342    
343    
344     #define TRANSLATE_ADDRESS translate_address_mmu3k
345     #define V2P_MMU3K
346     #include "memory_mips_v2p.c"
347     #undef TRANSLATE_ADDRESS
348     #undef V2P_MMU3K
349    
350     #define TRANSLATE_ADDRESS translate_address_mmu8k
351     #define V2P_MMU8K
352     #include "memory_mips_v2p.c"
353     #undef TRANSLATE_ADDRESS
354     #undef V2P_MMU8K
355    
356     #define TRANSLATE_ADDRESS translate_address_mmu10k
357     #define V2P_MMU10K
358     #include "memory_mips_v2p.c"
359     #undef TRANSLATE_ADDRESS
360     #undef V2P_MMU10K
361    
362     /* Almost generic :-) */
363     #define TRANSLATE_ADDRESS translate_address_mmu4100
364     #define V2P_MMU4100
365     #include "memory_mips_v2p.c"
366     #undef TRANSLATE_ADDRESS
367     #undef V2P_MMU4100
368    
369     #define TRANSLATE_ADDRESS translate_address_generic
370     #include "memory_mips_v2p.c"
371    
372    
373     #define MEMORY_RW mips_memory_rw
374     #define MEM_MIPS
375     #include "memory_rw.c"
376     #undef MEM_MIPS
377     #undef MEMORY_RW
378    

  ViewVC Help
Powered by ViewVC 1.1.26