/[gxemul]/trunk/src/cpus/cpu_mips_coproc.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 /trunk/src/cpus/cpu_mips_coproc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (hide annotations)
Mon Oct 8 16:20:10 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 63054 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 dpavlin 14 /*
2 dpavlin 24 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 dpavlin 26 * $Id: cpu_mips_coproc.c,v 1.37 2006/06/25 02:46:07 debug Exp $
29 dpavlin 14 *
30     * Emulation of MIPS coprocessors.
31     */
32    
33     #include <stdio.h>
34     #include <stdlib.h>
35     #include <string.h>
36     #include <math.h>
37    
38     #include "cop0.h"
39     #include "cpu.h"
40     #include "cpu_mips.h"
41     #include "emul.h"
42 dpavlin 20 #include "float_emul.h"
43 dpavlin 14 #include "machine.h"
44     #include "memory.h"
45     #include "mips_cpu_types.h"
46     #include "misc.h"
47     #include "opcodes_mips.h"
48    
49    
50     #ifndef ENABLE_MIPS
51    
52    
53     struct mips_coproc *mips_coproc_new(struct cpu *cpu, int coproc_nr)
54     { return NULL; }
55    
56     void mips_coproc_tlb_set_entry(struct cpu *cpu, int entrynr, int size,
57     uint64_t vaddr, uint64_t paddr0, uint64_t paddr1,
58     int valid0, int valid1, int dirty0, int dirty1, int global, int asid,
59     int cachealgo0, int cachealgo1) { }
60    
61    
62     #else /* ENABLE_MIPS */
63    
64    
65     extern volatile int single_step;
66    
67     static char *cop0_names[] = COP0_NAMES;
68     static char *regnames[] = MIPS_REGISTER_NAMES;
69    
70    
71     /*
72     * initialize_cop0_config():
73     *
74     * Helper function, called from mips_coproc_new().
75     */
76     static void initialize_cop0_config(struct cpu *cpu, struct mips_coproc *c)
77     {
78 dpavlin 24 const int m16 = 0; /* TODO: MIPS16 support */
79     int IB, DB, SB, IC, DC, SC, IA, DA;
80 dpavlin 14
81 dpavlin 24 /* Generic case for MIPS32/64: */
82     if (cpu->cd.mips.cpu_type.isa_level == 32 ||
83     cpu->cd.mips.cpu_type.isa_level == 64) {
84     /* According to the MIPS64 (5K) User's Manual: */
85     c->reg[COP0_CONFIG] =
86     ( (uint32_t)1 << 31)/* Config 1 present bit */
87     | ( 0 << 20) /* ISD: instruction scheduling
88     disable (=1) */
89     | ( 0 << 17) /* DID: dual issue disable */
90     | ( 0 << 16) /* BM: burst mode */
91     | ((cpu->byte_order == EMUL_BIG_ENDIAN? 1 : 0) << 15)
92     /* endian mode */
93     | ((cpu->cd.mips.cpu_type.isa_level == 64? 2 : 0) << 13)
94     /* 0=MIPS32, 1=64S, 2=64 */
95     | ( 0 << 10) /* Architecture revision */
96     | ( 1 << 7) /* MMU type: 1=TLB, 3=FMT */
97     | ( 2 << 0) /* kseg0 cache coherency algorithm */
98     ;
99     /* Config select 1: caches etc. TODO: Don't use
100     cpu->machine for this stuff! */
101     IB = cpu->machine->cache_picache_linesize - 1;
102     IB = IB < 0? 0 : (IB > 7? 7 : IB);
103     DB = cpu->machine->cache_pdcache_linesize - 1;
104     DB = DB < 0? 0 : (DB > 7? 7 : DB);
105     IC = cpu->machine->cache_picache -
106     cpu->machine->cache_picache_linesize - 7;
107     DC = cpu->machine->cache_pdcache -
108     cpu->machine->cache_pdcache_linesize - 7;
109     IA = cpu->cd.mips.cpu_type.piways - 1;
110     DA = cpu->cd.mips.cpu_type.pdways - 1;
111     cpu->cd.mips.cop0_config_select1 =
112     ((cpu->cd.mips.cpu_type.nr_of_tlb_entries - 1) << 25)
113     | (IC << 22) /* IS: I-cache sets per way */
114     | (IB << 19) /* IL: I-cache line-size */
115     | (IA << 16) /* IA: I-cache assoc. (ways-1) */
116     | (DC << 13) /* DS: D-cache sets per way */
117     | (DB << 10) /* DL: D-cache line-size */
118     | (DA << 7) /* DA: D-cache assoc. (ways-1) */
119     | (16 * 0) /* Existance of PerformanceCounters */
120     | ( 8 * 0) /* Existance of Watch Registers */
121     | ( 4 * m16) /* Existance of MIPS16 */
122     | ( 2 * 0) /* Existance of EJTAG */
123     | ( 1 * 1) /* Existance of FPU */
124     ;
125 dpavlin 14
126 dpavlin 24 return;
127     }
128 dpavlin 14
129 dpavlin 24 switch (cpu->cd.mips.cpu_type.rev) {
130     case MIPS_R2000:
131     case MIPS_R3000:
132     /* No config register. */
133     break;
134 dpavlin 14 case MIPS_R4000: /* according to the R4000 manual */
135     case MIPS_R4600:
136     IB = cpu->machine->cache_picache_linesize - 4;
137     IB = IB < 0? 0 : (IB > 1? 1 : IB);
138     DB = cpu->machine->cache_pdcache_linesize - 4;
139     DB = DB < 0? 0 : (DB > 1? 1 : DB);
140     SB = cpu->machine->cache_secondary_linesize - 4;
141     SB = SB < 0? 0 : (SB > 3? 3 : SB);
142     IC = cpu->machine->cache_picache - 12;
143     IC = IC < 0? 0 : (IC > 7? 7 : IC);
144     DC = cpu->machine->cache_pdcache - 12;
145     DC = DC < 0? 0 : (DC > 7? 7 : DC);
146     SC = cpu->machine->cache_secondary? 0 : 1;
147     c->reg[COP0_CONFIG] =
148     ( 0 << 31) /* Master/Checker present bit */
149     | (0x00 << 28) /* EC: system clock divisor,
150     0x00 = '2' */
151     | (0x00 << 24) /* EP */
152     | ( SB << 22) /* SB */
153     | (0x00 << 21) /* SS: 0 = mixed i/d scache */
154     | (0x00 << 20) /* SW */
155     | (0x00 << 18) /* EW: 0=64-bit */
156     | ( SC << 17) /* SC: 0=secondary cache present,
157     1=non-present */
158     | (0x00 << 16) /* SM: (todo) */
159     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
160     /* endian mode */
161     | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */
162     | (0x00 << 13) /* EB: (todo) */
163     | (0x00 << 12) /* 0 (resered) */
164     | ( IC << 9) /* IC: I-cache = 2^(12+IC) bytes
165     (1 = 8KB, 4=64K) */
166     | ( DC << 6) /* DC: D-cache = 2^(12+DC) bytes
167     (1 = 8KB, 4=64K) */
168     | ( IB << 5) /* IB: I-cache line size (0=16,
169     1=32) */
170     | ( DB << 4) /* DB: D-cache line size (0=16,
171     1=32) */
172     | ( 0 << 3) /* CU: todo */
173     | ( 0 << 0) /* kseg0 coherency algorithm
174     (TODO) */
175     ;
176     break;
177     case MIPS_R4100: /* According to the VR4131 manual: */
178     IB = cpu->machine->cache_picache_linesize - 4;
179     IB = IB < 0? 0 : (IB > 1? 1 : IB);
180     DB = cpu->machine->cache_pdcache_linesize - 4;
181     DB = DB < 0? 0 : (DB > 1? 1 : DB);
182     IC = cpu->machine->cache_picache - 10;
183     IC = IC < 0? 0 : (IC > 7? 7 : IC);
184     DC = cpu->machine->cache_pdcache - 10;
185     DC = DC < 0? 0 : (DC > 7? 7 : DC);
186     c->reg[COP0_CONFIG] =
187     ( 0 << 31) /* IS: Instruction Streaming bit */
188     | (0x01 << 28) /* EC: system clock divisor,
189     0x01 = 2 */
190     | (0x00 << 24) /* EP */
191     | (0x00 << 23) /* AD: Accelerate data mode
192     (0=VR4000-compatible) */
193     | ( m16 << 20) /* M16: MIPS16 support */
194     | ( 1 << 17) /* '1' */
195     | (0x00 << 16) /* BP: 'Branch forecast'
196     (0 = enabled) */
197     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
198     /* endian mode */
199     | ( 2 << 13) /* '2' hardcoded on VR4131 */
200     | ( 1 << 12) /* CS: Cache size mode
201     (1 on VR4131) */
202     | ( IC << 9) /* IC: I-cache = 2^(10+IC) bytes
203     (0 = 1KB, 4=16K) */
204     | ( DC << 6) /* DC: D-cache = 2^(10+DC) bytes
205     (0 = 1KB, 4=16K) */
206     | ( IB << 5) /* IB: I-cache line size (0=16,
207     1=32) */
208     | ( DB << 4) /* DB: D-cache line size (0=16,
209     1=32) */
210     | ( 0 << 0) /* kseg0 coherency algorithm (TODO) */
211     ;
212     break;
213     case MIPS_R5000:
214     case MIPS_RM5200: /* rm5200 is just a wild guess */
215     /* These are just guesses: (the comments are wrong) */
216     c->reg[COP0_CONFIG] =
217     ( 0 << 31) /* Master/Checker present bit */
218     | (0x00 << 28) /* EC: system clock divisor,
219     0x00 = '2' */
220     | (0x00 << 24) /* EP */
221     | (0x00 << 22) /* SB */
222     | (0x00 << 21) /* SS */
223     | (0x00 << 20) /* SW */
224     | (0x00 << 18) /* EW: 0=64-bit */
225     | (0x01 << 17) /* SC: 0=secondary cache present,
226     1=non-present */
227     | (0x00 << 16) /* SM: (todo) */
228     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
229     /* endian mode */
230     | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */
231     | (0x00 << 13) /* EB: (todo) */
232     | (0x00 << 12) /* 0 (resered) */
233     | ( 3 << 9) /* IC: I-cache = 2^(12+IC) bytes
234     (1 = 8KB, 4=64K) */
235     | ( 3 << 6) /* DC: D-cache = 2^(12+DC) bytes
236     (1 = 8KB, 4=64K) */
237     | ( 1 << 5) /* IB: I-cache line size (0=16,
238     1=32) */
239     | ( 1 << 4) /* DB: D-cache line size (0=16,
240     1=32) */
241     | ( 0 << 3) /* CU: todo */
242     | ( 2 << 0) /* kseg0 coherency algorithm
243     (TODO) */
244     ;
245     break;
246     case MIPS_R10000:
247     case MIPS_R12000:
248     case MIPS_R14000:
249     IC = cpu->machine->cache_picache - 12;
250     IC = IC < 0? 0 : (IC > 7? 7 : IC);
251     DC = cpu->machine->cache_pdcache - 12;
252     DC = DC < 0? 0 : (DC > 7? 7 : DC);
253     SC = cpu->machine->cache_secondary - 19;
254     SC = SC < 0? 0 : (SC > 7? 7 : SC);
255     /* According to the R10000 User's Manual: */
256     c->reg[COP0_CONFIG] =
257     ( IC << 29) /* Primary instruction cache size
258     (3 = 32KB) */
259     | ( DC << 26) /* Primary data cache size (3 =
260     32KB) */
261     | ( 0 << 19) /* SCClkDiv */
262     | ( SC << 16) /* SCSize, secondary cache size.
263     0 = 512KB. powers of two */
264     | ( 0 << 15) /* MemEnd */
265     | ( 0 << 14) /* SCCorEn */
266     | ( 1 << 13) /* SCBlkSize. 0=16 words,
267     1=32 words */
268     | ( 0 << 9) /* SysClkDiv */
269     | ( 0 << 7) /* PrcReqMax */
270     | ( 0 << 6) /* PrcElmReq */
271     | ( 0 << 5) /* CohPrcReqTar */
272     | ( 0 << 3) /* Device number */
273     | ( 2 << 0) /* Cache coherency algorithm for
274     kseg0 */
275     ;
276     break;
277     case MIPS_R5900:
278     /*
279     * R5900 is supposed to have the following (according
280     * to NetBSD/playstation2):
281     * cpu0: 16KB/64B 2-way set-associative L1 Instruction
282     * cache, 48 TLB entries
283     * cpu0: 8KB/64B 2-way set-associative write-back L1
284     * Data cache
285     * The following settings are just guesses:
286     * (comments are incorrect)
287     */
288     c->reg[COP0_CONFIG] =
289     ( 0 << 31) /* Master/Checker present bit */
290     | (0x00 << 28) /* EC: system clock divisor,
291     0x00 = '2' */
292     | (0x00 << 24) /* EP */
293     | (0x00 << 22) /* SB */
294     | (0x00 << 21) /* SS */
295     | (0x00 << 20) /* SW */
296     | (0x00 << 18) /* EW: 0=64-bit */
297     | (0x01 << 17) /* SC: 0=secondary cache present,
298     1=non-present */
299     | (0x00 << 16) /* SM: (todo) */
300     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
301     /* endian mode */
302     | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */
303     | (0x00 << 13) /* EB: (todo) */
304     | (0x00 << 12) /* 0 (resered) */
305     | ( 3 << 9) /* IC: I-cache = 2^(12+IC) bytes
306     (1 = 8KB, 4=64K) */
307     | ( 3 << 6) /* DC: D-cache = 2^(12+DC) bytes
308     (1 = 8KB, 4=64K) */
309     | ( 1 << 5) /* IB: I-cache line size (0=16,
310     1=32) */
311     | ( 1 << 4) /* DB: D-cache line size (0=16,
312     1=32) */
313     | ( 0 << 3) /* CU: todo */
314     | ( 0 << 0) /* kseg0 coherency algorithm
315     (TODO) */
316     ;
317     break;
318 dpavlin 24 default:fatal("Internal error: No initialization code for"
319     " config0? cpu rev = 0x%x", cpu->cd.mips.cpu_type.rev);
320     exit(1);
321 dpavlin 14 }
322     }
323    
324    
325     /*
326     * initialize_cop1():
327     *
328     * Helper function, called from mips_coproc_new().
329     */
330     static void initialize_cop1(struct cpu *cpu, struct mips_coproc *c)
331     {
332     int fpu_rev;
333     uint64_t other_stuff = 0;
334    
335     switch (cpu->cd.mips.cpu_type.rev & 0xff) {
336     case MIPS_R2000: fpu_rev = MIPS_R2010; break;
337     case MIPS_R3000: fpu_rev = MIPS_R3010;
338     other_stuff |= 0x40; /* or 0x30? TODO */
339     break;
340     case MIPS_R6000: fpu_rev = MIPS_R6010; break;
341     case MIPS_R4000: fpu_rev = MIPS_R4010; break;
342     case MIPS_4Kc: /* TODO: Is this the same as 5Kc? */
343     case MIPS_5Kc: other_stuff = COP1_REVISION_DOUBLE
344     | COP1_REVISION_SINGLE;
345     case MIPS_R5000:
346     case MIPS_RM5200: fpu_rev = cpu->cd.mips.cpu_type.rev;
347     other_stuff |= 0x10;
348     /* or cpu->cd.mips.cpu_type.sub ? TODO */
349     break;
350     case MIPS_R10000: fpu_rev = MIPS_R10000; break;
351     case MIPS_R12000: fpu_rev = 0x9; break;
352     default: fpu_rev = MIPS_SOFT;
353     }
354    
355     c->fcr[COP1_REVISION] = (fpu_rev << 8) | other_stuff;
356    
357     #if 0
358     /* These are mentioned in the MIPS64 documentation: */
359     + (1 << 16) /* single */
360     + (1 << 17) /* double */
361     + (1 << 18) /* paired-single */
362     + (1 << 19) /* 3d */
363     #endif
364     }
365    
366    
367     /*
368     * mips_coproc_new():
369     *
370     * Create a new MIPS coprocessor object.
371     */
372     struct mips_coproc *mips_coproc_new(struct cpu *cpu, int coproc_nr)
373     {
374     struct mips_coproc *c;
375    
376     c = malloc(sizeof(struct mips_coproc));
377     if (c == NULL) {
378     fprintf(stderr, "out of memory\n");
379     exit(1);
380     }
381    
382     memset(c, 0, sizeof(struct mips_coproc));
383     c->coproc_nr = coproc_nr;
384    
385     if (coproc_nr == 0) {
386     c->nr_of_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;
387 dpavlin 20 c->tlbs = zeroed_alloc(c->nr_of_tlbs * sizeof(struct mips_tlb));
388 dpavlin 14
389     /*
390     * Start with nothing in the status register. This makes sure
391     * that we are running in kernel mode with all interrupts
392     * disabled.
393     */
394     c->reg[COP0_STATUS] = 0;
395    
396     /* For userland emulation, enable all four coprocessors: */
397     if (cpu->machine->userland_emul)
398     c->reg[COP0_STATUS] |=
399     ((uint32_t)0xf << STATUS_CU_SHIFT);
400    
401     /* Hm. Enable coprocessors 0 and 1 even if we're not just
402     emulating userland? TODO: Think about this. */
403     /* if (cpu->machine->prom_emulation) */
404     c->reg[COP0_STATUS] |=
405     ((uint32_t)0x3 << STATUS_CU_SHIFT);
406    
407     if (!cpu->machine->prom_emulation)
408     c->reg[COP0_STATUS] |= STATUS_BEV;
409    
410 dpavlin 24 /* Ugly hack for R5900/TX79/C790: */
411     if (cpu->cd.mips.cpu_type.rev == MIPS_R5900)
412     c->reg[COP0_STATUS] |= R5900_STATUS_EIE;
413    
414     /* Default pagesize = 4 KB (i.e. dualpage = 8KB) */
415 dpavlin 14 c->reg[COP0_PAGEMASK] = 0x1fff;
416    
417     /* Note: .rev may contain the company ID as well! */
418     c->reg[COP0_PRID] =
419 dpavlin 24 (0x00 << 24) /* Company Options */
420     | (0x00 << 16) /* Company ID */
421 dpavlin 14 | (cpu->cd.mips.cpu_type.rev << 8) /* Processor ID */
422     | (cpu->cd.mips.cpu_type.sub) /* Revision */
423     ;
424    
425     c->reg[COP0_WIRED] = 0;
426    
427     initialize_cop0_config(cpu, c);
428    
429     /* Make sure the status register is sign-extended nicely: */
430 dpavlin 24 c->reg[COP0_STATUS] = (int32_t)c->reg[COP0_STATUS];
431 dpavlin 14 }
432    
433     if (coproc_nr == 1)
434     initialize_cop1(cpu, c);
435    
436     return c;
437     }
438    
439    
440     /*
441     * mips_coproc_tlb_set_entry():
442     *
443     * Used by machine setup code, if a specific machine emulation starts up
444     * with hardcoded virtual to physical mappings.
445     */
446     void mips_coproc_tlb_set_entry(struct cpu *cpu, int entrynr, int size,
447     uint64_t vaddr, uint64_t paddr0, uint64_t paddr1,
448     int valid0, int valid1, int dirty0, int dirty1, int global, int asid,
449     int cachealgo0, int cachealgo1)
450     {
451     if (entrynr < 0 || entrynr >= cpu->cd.mips.coproc[0]->nr_of_tlbs) {
452     printf("mips_coproc_tlb_set_entry(): invalid entry nr: %i\n",
453     entrynr);
454     exit(1);
455     }
456    
457     switch (cpu->cd.mips.cpu_type.mmu_model) {
458     case MMU3K:
459     if (size != 4096) {
460     printf("mips_coproc_tlb_set_entry(): invalid pagesize "
461     "(%i) for MMU3K\n", size);
462     exit(1);
463     }
464     cpu->cd.mips.coproc[0]->tlbs[entrynr].hi =
465     (vaddr & R2K3K_ENTRYHI_VPN_MASK) |
466     ((asid << R2K3K_ENTRYHI_ASID_SHIFT) &
467     R2K3K_ENTRYHI_ASID_MASK);
468     cpu->cd.mips.coproc[0]->tlbs[entrynr].lo0 =
469     (paddr0 & R2K3K_ENTRYLO_PFN_MASK) |
470     (cachealgo0? R2K3K_ENTRYLO_N : 0) |
471     (dirty0? R2K3K_ENTRYLO_D : 0) |
472     (valid0? R2K3K_ENTRYLO_V : 0) |
473     (global? R2K3K_ENTRYLO_G : 0);
474     break;
475     default:
476     /* MMU4K and MMU10K, etc: */
477     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
478     cpu->cd.mips.coproc[0]->tlbs[entrynr].hi =
479     (vaddr & ENTRYHI_VPN2_MASK_R10K) |
480     (vaddr & ENTRYHI_R_MASK) |
481     (asid & ENTRYHI_ASID) |
482     (global? TLB_G : 0);
483     else
484     cpu->cd.mips.coproc[0]->tlbs[entrynr].hi =
485     (vaddr & ENTRYHI_VPN2_MASK) |
486     (vaddr & ENTRYHI_R_MASK) |
487     (asid & ENTRYHI_ASID) |
488     (global? TLB_G : 0);
489     /* NOTE: The pagemask size is for a "dual" page: */
490     cpu->cd.mips.coproc[0]->tlbs[entrynr].mask =
491     (2*size - 1) & ~0x1fff;
492     cpu->cd.mips.coproc[0]->tlbs[entrynr].lo0 =
493     (((paddr0 >> 12) << ENTRYLO_PFN_SHIFT) &
494     ENTRYLO_PFN_MASK) |
495     (dirty0? ENTRYLO_D : 0) |
496     (valid0? ENTRYLO_V : 0) |
497     (global? ENTRYLO_G : 0) |
498     ((cachealgo0 << ENTRYLO_C_SHIFT) & ENTRYLO_C_MASK);
499     cpu->cd.mips.coproc[0]->tlbs[entrynr].lo1 =
500     (((paddr1 >> 12) << ENTRYLO_PFN_SHIFT) &
501     ENTRYLO_PFN_MASK) |
502     (dirty1? ENTRYLO_D : 0) |
503     (valid1? ENTRYLO_V : 0) |
504     (global? ENTRYLO_G : 0) |
505     ((cachealgo1 << ENTRYLO_C_SHIFT) & ENTRYLO_C_MASK);
506     /* TODO: R4100, 1KB pages etc */
507     }
508     }
509    
510    
511     /*
512 dpavlin 24 * invalidate_asid():
513     *
514     * Go through all entries in the TLB. If an entry has a matching asid, is
515     * valid, and is not global (i.e. the ASID matters), then its virtual address
516     * translation is invalidated.
517     *
518     * Note: In the R3000 case, the asid argument is shifted 6 bits.
519 dpavlin 14 */
520 dpavlin 24 static void invalidate_asid(struct cpu *cpu, int asid)
521 dpavlin 14 {
522 dpavlin 24 struct mips_coproc *cp = cpu->cd.mips.coproc[0];
523     int i, ntlbs = cp->nr_of_tlbs;
524     struct mips_tlb *tlb = cp->tlbs;
525 dpavlin 14
526 dpavlin 24 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
527     for (i=0; i<ntlbs; i++)
528     if ((tlb[i].hi & R2K3K_ENTRYHI_ASID_MASK) == asid
529     && (tlb[i].lo0 & R2K3K_ENTRYLO_V)
530     && !(tlb[i].lo0 & R2K3K_ENTRYLO_G)) {
531     cpu->invalidate_translation_caches(cpu,
532     tlb[i].hi & R2K3K_ENTRYHI_VPN_MASK,
533     INVALIDATE_VADDR);
534 dpavlin 14 }
535     } else {
536 dpavlin 24 /* TODO: Implement support for other. */
537     cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);
538 dpavlin 14 }
539     }
540    
541    
542     /*
543     * coproc_register_read();
544     *
545     * Read a value from a MIPS coprocessor register.
546     */
547     void coproc_register_read(struct cpu *cpu,
548     struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int select)
549     {
550     int unimpl = 1;
551    
552     if (cp->coproc_nr==0 && reg_nr==COP0_INDEX) unimpl = 0;
553     if (cp->coproc_nr==0 && reg_nr==COP0_RANDOM) unimpl = 0;
554     if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYLO0) unimpl = 0;
555     if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYLO1) unimpl = 0;
556     if (cp->coproc_nr==0 && reg_nr==COP0_CONTEXT) unimpl = 0;
557     if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK) unimpl = 0;
558     if (cp->coproc_nr==0 && reg_nr==COP0_WIRED) unimpl = 0;
559     if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR) unimpl = 0;
560 dpavlin 26 if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) unimpl = 0;
561 dpavlin 14 if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI) unimpl = 0;
562     if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE) unimpl = 0;
563     if (cp->coproc_nr==0 && reg_nr==COP0_STATUS) unimpl = 0;
564     if (cp->coproc_nr==0 && reg_nr==COP0_CAUSE) unimpl = 0;
565     if (cp->coproc_nr==0 && reg_nr==COP0_EPC) unimpl = 0;
566     if (cp->coproc_nr==0 && reg_nr==COP0_PRID) unimpl = 0;
567     if (cp->coproc_nr==0 && reg_nr==COP0_CONFIG) {
568     if (select > 0) {
569     switch (select) {
570     case 1: *ptr = cpu->cd.mips.cop0_config_select1;
571     break;
572     default:fatal("coproc_register_read(): unimplemented"
573     " config register select %i\n", select);
574     exit(1);
575     }
576     return;
577     }
578     unimpl = 0;
579     }
580     if (cp->coproc_nr==0 && reg_nr==COP0_LLADDR) unimpl = 0;
581     if (cp->coproc_nr==0 && reg_nr==COP0_WATCHLO) unimpl = 0;
582     if (cp->coproc_nr==0 && reg_nr==COP0_WATCHHI) unimpl = 0;
583     if (cp->coproc_nr==0 && reg_nr==COP0_XCONTEXT) unimpl = 0;
584     if (cp->coproc_nr==0 && reg_nr==COP0_ERRCTL) unimpl = 0;
585     if (cp->coproc_nr==0 && reg_nr==COP0_CACHEERR) unimpl = 0;
586     if (cp->coproc_nr==0 && reg_nr==COP0_TAGDATA_LO) unimpl = 0;
587     if (cp->coproc_nr==0 && reg_nr==COP0_TAGDATA_HI) unimpl = 0;
588     if (cp->coproc_nr==0 && reg_nr==COP0_ERROREPC) unimpl = 0;
589     if (cp->coproc_nr==0 && reg_nr==COP0_RESERV22) {
590     /* Used by Linux on Linksys WRT54G */
591     unimpl = 0;
592     }
593     if (cp->coproc_nr==0 && reg_nr==COP0_DEBUG) unimpl = 0;
594     if (cp->coproc_nr==0 && reg_nr==COP0_PERFCNT) unimpl = 0;
595     if (cp->coproc_nr==0 && reg_nr==COP0_DESAVE) unimpl = 0;
596    
597     if (cp->coproc_nr==1) unimpl = 0;
598    
599     if (unimpl) {
600     fatal("cpu%i: warning: read from unimplemented coproc%i"
601     " register %i (%s)\n", cpu->cpu_id, cp->coproc_nr, reg_nr,
602     cp->coproc_nr==0? cop0_names[reg_nr] : "?");
603    
604     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0,
605     cp->coproc_nr, 0, 0, 0);
606     return;
607     }
608    
609     *ptr = cp->reg[reg_nr];
610     }
611    
612    
613     /*
614     * coproc_register_write();
615     *
616     * Write a value to a MIPS coprocessor register.
617     */
618     void coproc_register_write(struct cpu *cpu,
619     struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int flag64,
620     int select)
621     {
622     int unimpl = 1;
623     int readonly = 0;
624     uint64_t tmp = *ptr;
625     uint64_t tmp2 = 0, old;
626     int inval = 0, old_asid, oldmode;
627    
628     switch (cp->coproc_nr) {
629     case 0:
630     /* COPROC 0: */
631     switch (reg_nr) {
632     case COP0_INDEX:
633     case COP0_RANDOM:
634     unimpl = 0;
635     break;
636     case COP0_ENTRYLO0:
637     unimpl = 0;
638     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
639     (tmp & 0xff)!=0) {
640     /* char *symbol;
641     uint64_t offset;
642 dpavlin 24 symbol = get_symbol_name(cpu->pc, &offset);
643 dpavlin 14 fatal("YO! pc = 0x%08llx <%s> "
644     "lo=%016llx\n", (long long)
645 dpavlin 24 cpu->pc, symbol? symbol :
646 dpavlin 14 "no symbol", (long long)tmp); */
647     tmp &= (R2K3K_ENTRYLO_PFN_MASK |
648     R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |
649     R2K3K_ENTRYLO_V | R2K3K_ENTRYLO_G);
650     } else if (cpu->cd.mips.cpu_type.mmu_model == MMU4K) {
651     tmp &= (ENTRYLO_PFN_MASK | ENTRYLO_C_MASK |
652     ENTRYLO_D | ENTRYLO_V | ENTRYLO_G);
653     }
654     break;
655     case COP0_BADVADDR:
656     /* Hm. Irix writes to this register. (Why?) */
657     unimpl = 0;
658     break;
659     case COP0_ENTRYLO1:
660     unimpl = 0;
661     if (cpu->cd.mips.cpu_type.mmu_model == MMU4K) {
662     tmp &= (ENTRYLO_PFN_MASK | ENTRYLO_C_MASK |
663     ENTRYLO_D | ENTRYLO_V | ENTRYLO_G);
664     }
665     break;
666     case COP0_CONTEXT:
667     old = cp->reg[COP0_CONTEXT];
668     cp->reg[COP0_CONTEXT] = tmp;
669     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
670     cp->reg[COP0_CONTEXT] &=
671     ~R2K3K_CONTEXT_BADVPN_MASK;
672     cp->reg[COP0_CONTEXT] |=
673     (old & R2K3K_CONTEXT_BADVPN_MASK);
674     } else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
675     cp->reg[COP0_CONTEXT] &=
676     ~CONTEXT_BADVPN2_MASK_R4100;
677     cp->reg[COP0_CONTEXT] |=
678     (old & CONTEXT_BADVPN2_MASK_R4100);
679     } else {
680     cp->reg[COP0_CONTEXT] &=
681     ~CONTEXT_BADVPN2_MASK;
682     cp->reg[COP0_CONTEXT] |=
683     (old & CONTEXT_BADVPN2_MASK);
684     }
685     return;
686     case COP0_PAGEMASK:
687     tmp2 = tmp >> PAGEMASK_SHIFT;
688     if (tmp2 != 0x000 &&
689     tmp2 != 0x003 &&
690     tmp2 != 0x00f &&
691     tmp2 != 0x03f &&
692     tmp2 != 0x0ff &&
693     tmp2 != 0x3ff &&
694     tmp2 != 0xfff)
695     fatal("cpu%i: trying to write an invalid"
696     " pagemask 0x%08lx to COP0_PAGEMASK\n",
697     cpu->cpu_id, (long)tmp);
698     unimpl = 0;
699     break;
700     case COP0_WIRED:
701     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
702     fatal("cpu%i: r2k/r3k wired register must "
703     "always be 8\n", cpu->cpu_id);
704     tmp = 8;
705     }
706     cp->reg[COP0_RANDOM] = cp->nr_of_tlbs-1;
707     tmp &= INDEX_MASK;
708     unimpl = 0;
709     break;
710     case COP0_COUNT:
711 dpavlin 22 if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
712 dpavlin 14 fatal("WARNING: trying to write a 64-bit value"
713     " to the COUNT register!\n");
714     tmp = (int64_t)(int32_t)tmp;
715     unimpl = 0;
716     break;
717     case COP0_COMPARE:
718     /* Clear the timer interrupt bit (bit 7): */
719     cpu->cd.mips.compare_register_set = 1;
720     mips_cpu_interrupt_ack(cpu, 7);
721 dpavlin 22 if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
722 dpavlin 14 fatal("WARNING: trying to write a 64-bit value"
723     " to the COMPARE register!\n");
724     tmp = (int64_t)(int32_t)tmp;
725     unimpl = 0;
726     break;
727     case COP0_ENTRYHI:
728     /*
729 dpavlin 24 * Translation caches must be invalidated if the
730     * ASID changes:
731 dpavlin 14 */
732     switch (cpu->cd.mips.cpu_type.mmu_model) {
733     case MMU3K:
734 dpavlin 24 old_asid = cp->reg[COP0_ENTRYHI] &
735     R2K3K_ENTRYHI_ASID_MASK;
736 dpavlin 14 if ((cp->reg[COP0_ENTRYHI] &
737     R2K3K_ENTRYHI_ASID_MASK) !=
738     (tmp & R2K3K_ENTRYHI_ASID_MASK))
739     inval = 1;
740     break;
741     default:
742     old_asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
743     if ((cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID) !=
744     (tmp & ENTRYHI_ASID))
745     inval = 1;
746     break;
747     }
748 dpavlin 24
749 dpavlin 14 if (inval)
750 dpavlin 24 invalidate_asid(cpu, old_asid);
751    
752 dpavlin 14 unimpl = 0;
753     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
754     (tmp & 0x3f)!=0) {
755     /* char *symbol;
756     uint64_t offset;
757 dpavlin 24 symbol = get_symbol_name(cpu->pc,
758     &offset);
759 dpavlin 14 fatal("YO! pc = 0x%08llx <%s> "
760 dpavlin 24 "hi=%016llx\n", (long long)cpu->pc,
761     symbol? symbol :
762 dpavlin 14 "no symbol", (long long)tmp); */
763     tmp &= ~0x3f;
764     }
765     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
766     tmp &= (R2K3K_ENTRYHI_VPN_MASK |
767     R2K3K_ENTRYHI_ASID_MASK);
768     else if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
769     tmp &= (ENTRYHI_R_MASK |
770     ENTRYHI_VPN2_MASK_R10K | ENTRYHI_ASID);
771     else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
772     tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK |
773     0x1800 | ENTRYHI_ASID);
774     else
775     tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK |
776     ENTRYHI_ASID);
777     break;
778     case COP0_EPC:
779     unimpl = 0;
780     break;
781     case COP0_PRID:
782     readonly = 1;
783     break;
784     case COP0_CONFIG:
785     if (select > 0) {
786     switch (select) {
787     case 1: cpu->cd.mips.cop0_config_select1 = tmp;
788     break;
789     default:fatal("coproc_register_write(): unimpl"
790     "emented config register select "
791     "%i\n", select);
792     exit(1);
793     }
794     return;
795     }
796    
797     /* fatal("COP0_CONFIG: modifying K0 bits: "
798     "0x%08x => ", cp->reg[reg_nr]); */
799     tmp = *ptr;
800     tmp &= 0x3; /* only bits 2..0 can be written */
801     cp->reg[reg_nr] &= ~(0x3); cp->reg[reg_nr] |= tmp;
802     /* fatal("0x%08x\n", cp->reg[reg_nr]); */
803     return;
804     case COP0_STATUS:
805     oldmode = cp->reg[COP0_STATUS];
806     tmp &= ~(1 << 21); /* bit 21 is read-only */
807 dpavlin 26
808 dpavlin 24 /*
809 dpavlin 26 * When isolating caches, invalidate all translations.
810     * During the isolation, a special hack in memory_rw.c
811     * prevents translation tables from being updated, so
812     * the translation caches don't have to be invalidated
813     * when switching back to normal mode.
814 dpavlin 24 */
815 dpavlin 14 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
816 dpavlin 24 (oldmode & MIPS1_ISOL_CACHES) !=
817 dpavlin 14 (tmp & MIPS1_ISOL_CACHES)) {
818 dpavlin 26 /* Invalidate everything if we are switching
819     to isolated mode: */
820     if (tmp & MIPS1_ISOL_CACHES) {
821     cpu->invalidate_translation_caches(
822     cpu, 0, INVALIDATE_ALL);
823     }
824 dpavlin 14
825 dpavlin 26 #if 1
826     /*
827     * NOTE: This is not needed for NetBSD, but
828     * Ultrix and Linux still needs this. They
829     * shouldn't, though. Something else is buggy.
830     */
831 dpavlin 24 cpu_create_or_reset_tc(cpu);
832 dpavlin 26 #endif
833 dpavlin 14 }
834     unimpl = 0;
835     break;
836     case COP0_CAUSE:
837     /* A write to the cause register only
838     affects IM bits 0 and 1: */
839     cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);
840     cp->reg[reg_nr] |= (tmp & (0x3 << STATUS_IM_SHIFT));
841     return;
842     case COP0_FRAMEMASK:
843     /* TODO: R10000 */
844     unimpl = 0;
845     break;
846     case COP0_TAGDATA_LO:
847     case COP0_TAGDATA_HI:
848     /* TODO: R4300 and others? */
849     unimpl = 0;
850     break;
851     case COP0_LLADDR:
852     unimpl = 0;
853     break;
854     case COP0_WATCHLO:
855     case COP0_WATCHHI:
856     unimpl = 0;
857     break;
858     case COP0_XCONTEXT:
859     /*
860     * TODO: According to the R10000 manual, the R4400
861     * shares the PTEbase portion of the context registers
862     * (that is, xcontext and context). On R10000, they
863     * are separate registers.
864     */
865     /* debug("[ xcontext 0x%016llx ]\n", tmp); */
866     unimpl = 0;
867     break;
868    
869     /* Most of these are actually TODOs: */
870     case COP0_ERROREPC:
871     case COP0_DEPC:
872     case COP0_RESERV22: /* Used by Linux on Linksys WRT54G */
873     case COP0_DESAVE:
874     case COP0_PERFCNT:
875     case COP0_ERRCTL: /* R10000 */
876     unimpl = 0;
877     break;
878     }
879     break;
880    
881     case 1:
882     /* COPROC 1: */
883     unimpl = 0;
884     break;
885     }
886    
887     if (unimpl) {
888     fatal("cpu%i: warning: write to unimplemented coproc%i "
889     "register %i (%s), data = 0x%016llx\n", cpu->cpu_id,
890     cp->coproc_nr, reg_nr, cp->coproc_nr==0?
891     cop0_names[reg_nr] : "?", (long long)tmp);
892    
893     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0,
894     cp->coproc_nr, 0, 0, 0);
895     return;
896     }
897    
898     if (readonly) {
899     fatal("cpu%i: warning: write to READONLY coproc%i register "
900     "%i ignored\n", cpu->cpu_id, cp->coproc_nr, reg_nr);
901     return;
902     }
903    
904     cp->reg[reg_nr] = tmp;
905    
906     if (!flag64)
907     cp->reg[reg_nr] = (int64_t)(int32_t)cp->reg[reg_nr];
908     }
909    
910    
911     /*
912     * MIPS floating-point stuff:
913     *
914     * TODO: Move this to some other file?
915     */
916 dpavlin 20 static int mips_fmt_to_ieee_fmt[32] = {
917     0, 0, 0, 0, 0, 0, 0, 0,
918     0, 0, 0, 0, 0, 0, 0, 0,
919     IEEE_FMT_S, IEEE_FMT_D, 0, 0,
920     IEEE_FMT_W, IEEE_FMT_L, /* PS (Paired Single) */ 0, 0,
921     0, 0, 0, 0, 0, 0, 0, 0 };
922    
923 dpavlin 24 static char *fmtname[32] = {
924     "0", "1", "2", "3", "4", "5", "6", "7",
925     "8", "9", "10", "11", "12", "13", "14", "15",
926     "s", "d", "18", "19", "w", "l", "ps", "23",
927     "24", "25", "26", "27", "28", "29", "30", "31" };
928 dpavlin 14
929 dpavlin 24 static char *ccname[16] = {
930     "f", "un", "eq", "ueq", "olt", "ult", "ole", "ule",
931     "sf", "ngle", "seq", "ngl", "lt", "nge", "le", "ngt" };
932    
933 dpavlin 14 #define FPU_OP_ADD 1
934     #define FPU_OP_SUB 2
935     #define FPU_OP_MUL 3
936     #define FPU_OP_DIV 4
937     #define FPU_OP_SQRT 5
938     #define FPU_OP_MOV 6
939     #define FPU_OP_CVT 7
940     #define FPU_OP_C 8
941     #define FPU_OP_ABS 9
942     #define FPU_OP_NEG 10
943 dpavlin 20 /* TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W, RSQRT */
944 dpavlin 14
945    
946     /*
947     * fpu_store_float_value():
948     *
949     * Stores a float value (actually a double) in fmt format.
950     */
951     static void fpu_store_float_value(struct mips_coproc *cp, int fd,
952     double nf, int fmt, int nan)
953     {
954 dpavlin 20 int ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
955     uint64_t r = ieee_store_float_value(nf, ieee_fmt, nan);
956 dpavlin 14
957     /*
958 dpavlin 20 * TODO: This is for 32-bit mode. It has to be updated later
959     * for 64-bit coprocessor functionality!
960 dpavlin 14 */
961 dpavlin 24 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) {
962 dpavlin 14 cp->reg[fd] = r & 0xffffffffULL;
963     cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;
964    
965     if (cp->reg[fd] & 0x80000000ULL)
966     cp->reg[fd] |= 0xffffffff00000000ULL;
967     if (cp->reg[fd+1] & 0x80000000ULL)
968     cp->reg[fd+1] |= 0xffffffff00000000ULL;
969     } else {
970     cp->reg[fd] = r & 0xffffffffULL;
971    
972     if (cp->reg[fd] & 0x80000000ULL)
973     cp->reg[fd] |= 0xffffffff00000000ULL;
974     }
975     }
976    
977    
978     /*
979     * fpu_op():
980     *
981 dpavlin 20 * Perform a floating-point operation. For those of fs and ft that are >= 0,
982     * those numbers are interpreted into local variables.
983 dpavlin 14 *
984 dpavlin 20 * Only FPU_OP_C (compare) returns anything of interest, 1 for true, 0 for
985     * false.
986 dpavlin 14 */
987     static int fpu_op(struct cpu *cpu, struct mips_coproc *cp, int op, int fmt,
988     int ft, int fs, int fd, int cond, int output_fmt)
989     {
990     /* Potentially two input registers, fs and ft */
991 dpavlin 20 struct ieee_float_value float_value[2];
992     int unordered, nan, ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
993 dpavlin 14 uint64_t fs_v = 0;
994     double nf;
995    
996     if (fs >= 0) {
997     fs_v = cp->reg[fs];
998     /* TODO: register-pair mode and plain
999     register mode? "FR" bit? */
1000 dpavlin 24 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1001 dpavlin 14 fs_v = (fs_v & 0xffffffffULL) +
1002     (cp->reg[(fs + 1) & 31] << 32);
1003 dpavlin 20 ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);
1004 dpavlin 14 }
1005     if (ft >= 0) {
1006     uint64_t v = cp->reg[ft];
1007     /* TODO: register-pair mode and
1008     plain register mode? "FR" bit? */
1009 dpavlin 24 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1010 dpavlin 14 v = (v & 0xffffffffULL) +
1011     (cp->reg[(ft + 1) & 31] << 32);
1012 dpavlin 20 ieee_interpret_float_value(v, &float_value[1], ieee_fmt);
1013 dpavlin 14 }
1014    
1015     switch (op) {
1016     case FPU_OP_ADD:
1017     nf = float_value[0].f + float_value[1].f;
1018     /* debug(" add: %f + %f = %f\n",
1019     float_value[0].f, float_value[1].f, nf); */
1020     fpu_store_float_value(cp, fd, nf, output_fmt,
1021     float_value[0].nan || float_value[1].nan);
1022     break;
1023     case FPU_OP_SUB:
1024     nf = float_value[0].f - float_value[1].f;
1025     /* debug(" sub: %f - %f = %f\n",
1026     float_value[0].f, float_value[1].f, nf); */
1027     fpu_store_float_value(cp, fd, nf, output_fmt,
1028     float_value[0].nan || float_value[1].nan);
1029     break;
1030     case FPU_OP_MUL:
1031     nf = float_value[0].f * float_value[1].f;
1032     /* debug(" mul: %f * %f = %f\n",
1033     float_value[0].f, float_value[1].f, nf); */
1034     fpu_store_float_value(cp, fd, nf, output_fmt,
1035     float_value[0].nan || float_value[1].nan);
1036     break;
1037     case FPU_OP_DIV:
1038     nan = float_value[0].nan || float_value[1].nan;
1039     if (fabs(float_value[1].f) > 0.00000000001)
1040     nf = float_value[0].f / float_value[1].f;
1041     else {
1042     fatal("DIV by zero !!!!\n");
1043     nf = 0.0; /* TODO */
1044     nan = 1;
1045     }
1046     /* debug(" div: %f / %f = %f\n",
1047     float_value[0].f, float_value[1].f, nf); */
1048     fpu_store_float_value(cp, fd, nf, output_fmt, nan);
1049     break;
1050     case FPU_OP_SQRT:
1051     nan = float_value[0].nan;
1052     if (float_value[0].f >= 0.0)
1053     nf = sqrt(float_value[0].f);
1054     else {
1055     fatal("SQRT by less than zero, %f !!!!\n",
1056     float_value[0].f);
1057     nf = 0.0; /* TODO */
1058     nan = 1;
1059     }
1060     /* debug(" sqrt: %f => %f\n", float_value[0].f, nf); */
1061     fpu_store_float_value(cp, fd, nf, output_fmt, nan);
1062     break;
1063     case FPU_OP_ABS:
1064     nf = fabs(float_value[0].f);
1065     /* debug(" abs: %f => %f\n", float_value[0].f, nf); */
1066     fpu_store_float_value(cp, fd, nf, output_fmt,
1067     float_value[0].nan);
1068     break;
1069     case FPU_OP_NEG:
1070     nf = - float_value[0].f;
1071     /* debug(" neg: %f => %f\n", float_value[0].f, nf); */
1072     fpu_store_float_value(cp, fd, nf, output_fmt,
1073     float_value[0].nan);
1074     break;
1075     case FPU_OP_CVT:
1076     nf = float_value[0].f;
1077     /* debug(" mov: %f => %f\n", float_value[0].f, nf); */
1078     fpu_store_float_value(cp, fd, nf, output_fmt,
1079     float_value[0].nan);
1080     break;
1081     case FPU_OP_MOV:
1082     /* Non-arithmetic move: */
1083     /*
1084     * TODO: this is for 32-bit mode. It has to be updated later
1085     * for 64-bit coprocessor stuff.
1086     */
1087 dpavlin 24 if (output_fmt == COP1_FMT_D || output_fmt == COP1_FMT_L) {
1088 dpavlin 14 cp->reg[fd] = fs_v & 0xffffffffULL;
1089     cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;
1090     if (cp->reg[fd] & 0x80000000ULL)
1091     cp->reg[fd] |= 0xffffffff00000000ULL;
1092     if (cp->reg[fd+1] & 0x80000000ULL)
1093     cp->reg[fd+1] |= 0xffffffff00000000ULL;
1094     } else {
1095     cp->reg[fd] = fs_v & 0xffffffffULL;
1096     if (cp->reg[fd] & 0x80000000ULL)
1097     cp->reg[fd] |= 0xffffffff00000000ULL;
1098     }
1099     break;
1100     case FPU_OP_C:
1101     /* debug(" c: cond=%i\n", cond); */
1102    
1103     unordered = 0;
1104     if (float_value[0].nan || float_value[1].nan)
1105     unordered = 1;
1106    
1107     switch (cond) {
1108     case 2: /* Equal */
1109     return (float_value[0].f == float_value[1].f);
1110     case 4: /* Ordered or Less than */
1111     return (float_value[0].f < float_value[1].f)
1112     || !unordered;
1113     case 5: /* Unordered or Less than */
1114     return (float_value[0].f < float_value[1].f)
1115     || unordered;
1116     case 6: /* Ordered or Less than or Equal */
1117     return (float_value[0].f <= float_value[1].f)
1118     || !unordered;
1119     case 7: /* Unordered or Less than or Equal */
1120     return (float_value[0].f <= float_value[1].f)
1121     || unordered;
1122     case 12:/* Less than */
1123     return (float_value[0].f < float_value[1].f);
1124     case 14:/* Less than or equal */
1125     return (float_value[0].f <= float_value[1].f);
1126    
1127     /* The following are not commonly used, so I'll move these out
1128     of the if-0 on a case-by-case basis. */
1129     #if 0
1130     case 0: return 0; /* False */
1131     case 1: return 0; /* Unordered */
1132     case 3: return (float_value[0].f == float_value[1].f);
1133     /* Unordered or Equal */
1134     case 8: return 0; /* Signaling false */
1135     case 9: return 0; /* Not Greater than or Less than or Equal */
1136     case 10:return (float_value[0].f == float_value[1].f); /* Signaling Equal */
1137     case 11:return (float_value[0].f == float_value[1].f); /* Not Greater
1138     than or Less than */
1139     case 13:return !(float_value[0].f >= float_value[1].f); /* Not greater
1140     than or equal */
1141     case 15:return !(float_value[0].f > float_value[1].f); /* Not greater than */
1142     #endif
1143    
1144     default:
1145     fatal("fpu_op(): unimplemented condition "
1146     "code %i. see cpu_mips_coproc.c\n", cond);
1147     }
1148     break;
1149     default:
1150     fatal("fpu_op(): unimplemented op %i\n", op);
1151     }
1152    
1153     return 0;
1154     }
1155    
1156    
1157     /*
1158     * fpu_function():
1159     *
1160     * Returns 1 if function was implemented, 0 otherwise.
1161     * Debug trace should be printed for known instructions.
1162     */
1163     static int fpu_function(struct cpu *cpu, struct mips_coproc *cp,
1164     uint32_t function, int unassemble_only)
1165     {
1166     int fd, fs, ft, fmt, cond, cc;
1167    
1168     fmt = (function >> 21) & 31;
1169     ft = (function >> 16) & 31;
1170     fs = (function >> 11) & 31;
1171     cc = (function >> 8) & 7;
1172     fd = (function >> 6) & 31;
1173     cond = (function >> 0) & 15;
1174    
1175    
1176     /* bc1f, bc1t, bc1fl, bc1tl: */
1177     if ((function & 0x03e00000) == 0x01000000) {
1178     int nd, tf, imm, cond_true;
1179     char *instr_mnem;
1180    
1181     /* cc are bits 20..18: */
1182     cc = (function >> 18) & 7;
1183     nd = (function >> 17) & 1;
1184     tf = (function >> 16) & 1;
1185     imm = function & 65535;
1186     if (imm >= 32768)
1187     imm -= 65536;
1188    
1189     instr_mnem = NULL;
1190     if (nd == 0 && tf == 0) instr_mnem = "bc1f";
1191     if (nd == 0 && tf == 1) instr_mnem = "bc1t";
1192     if (nd == 1 && tf == 0) instr_mnem = "bc1fl";
1193     if (nd == 1 && tf == 1) instr_mnem = "bc1tl";
1194    
1195     if (cpu->machine->instruction_trace || unassemble_only)
1196     debug("%s\t%i,0x%016llx\n", instr_mnem, cc,
1197     (long long) (cpu->pc + (imm << 2)));
1198     if (unassemble_only)
1199     return 1;
1200    
1201 dpavlin 24 if (cpu->delay_slot) {
1202 dpavlin 14 fatal("%s: jump inside a jump's delay slot, "
1203     "or similar. TODO\n", instr_mnem);
1204     cpu->running = 0;
1205     return 1;
1206     }
1207    
1208     /* Both the FCCR and FCSR contain condition code bits... */
1209     if (cc == 0)
1210 dpavlin 24 cond_true = (cp->fcr[MIPS_FPU_FCSR] >>
1211     MIPS_FCSR_FCC0_SHIFT) & 1;
1212 dpavlin 14 else
1213 dpavlin 24 cond_true = (cp->fcr[MIPS_FPU_FCSR] >>
1214     (MIPS_FCSR_FCC1_SHIFT + cc-1)) & 1;
1215 dpavlin 14
1216     if (!tf)
1217     cond_true = !cond_true;
1218    
1219     if (cond_true) {
1220 dpavlin 24 cpu->delay_slot = TO_BE_DELAYED;
1221     cpu->delay_jmpaddr = cpu->pc + (imm << 2);
1222 dpavlin 14 } else {
1223     /* "likely": */
1224     if (nd) {
1225     /* nullify the delay slot */
1226     cpu->cd.mips.nullify_next = 1;
1227     }
1228     }
1229    
1230     return 1;
1231     }
1232    
1233     /* add.fmt: Floating-point add */
1234     if ((function & 0x0000003f) == 0x00000000) {
1235     if (cpu->machine->instruction_trace || unassemble_only)
1236 dpavlin 24 debug("add.%s\tr%i,r%i,r%i\n",
1237     fmtname[fmt], fd, fs, ft);
1238 dpavlin 14 if (unassemble_only)
1239     return 1;
1240    
1241     fpu_op(cpu, cp, FPU_OP_ADD, fmt, ft, fs, fd, -1, fmt);
1242     return 1;
1243     }
1244    
1245     /* sub.fmt: Floating-point subtract */
1246     if ((function & 0x0000003f) == 0x00000001) {
1247     if (cpu->machine->instruction_trace || unassemble_only)
1248 dpavlin 24 debug("sub.%s\tr%i,r%i,r%i\n",
1249     fmtname[fmt], fd, fs, ft);
1250 dpavlin 14 if (unassemble_only)
1251     return 1;
1252    
1253     fpu_op(cpu, cp, FPU_OP_SUB, fmt, ft, fs, fd, -1, fmt);
1254     return 1;
1255     }
1256    
1257     /* mul.fmt: Floating-point multiply */
1258     if ((function & 0x0000003f) == 0x00000002) {
1259     if (cpu->machine->instruction_trace || unassemble_only)
1260 dpavlin 24 debug("mul.%s\tr%i,r%i,r%i\n",
1261     fmtname[fmt], fd, fs, ft);
1262 dpavlin 14 if (unassemble_only)
1263     return 1;
1264    
1265     fpu_op(cpu, cp, FPU_OP_MUL, fmt, ft, fs, fd, -1, fmt);
1266     return 1;
1267     }
1268    
1269     /* div.fmt: Floating-point divide */
1270     if ((function & 0x0000003f) == 0x00000003) {
1271     if (cpu->machine->instruction_trace || unassemble_only)
1272 dpavlin 24 debug("div.%s\tr%i,r%i,r%i\n",
1273     fmtname[fmt], fd, fs, ft);
1274 dpavlin 14 if (unassemble_only)
1275     return 1;
1276    
1277     fpu_op(cpu, cp, FPU_OP_DIV, fmt, ft, fs, fd, -1, fmt);
1278     return 1;
1279     }
1280    
1281     /* sqrt.fmt: Floating-point square-root */
1282     if ((function & 0x001f003f) == 0x00000004) {
1283     if (cpu->machine->instruction_trace || unassemble_only)
1284 dpavlin 24 debug("sqrt.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1285 dpavlin 14 if (unassemble_only)
1286     return 1;
1287    
1288     fpu_op(cpu, cp, FPU_OP_SQRT, fmt, -1, fs, fd, -1, fmt);
1289     return 1;
1290     }
1291    
1292     /* abs.fmt: Floating-point absolute value */
1293     if ((function & 0x001f003f) == 0x00000005) {
1294     if (cpu->machine->instruction_trace || unassemble_only)
1295 dpavlin 24 debug("abs.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1296 dpavlin 14 if (unassemble_only)
1297     return 1;
1298    
1299     fpu_op(cpu, cp, FPU_OP_ABS, fmt, -1, fs, fd, -1, fmt);
1300     return 1;
1301     }
1302    
1303     /* mov.fmt: Floating-point (non-arithmetic) move */
1304     if ((function & 0x0000003f) == 0x00000006) {
1305     if (cpu->machine->instruction_trace || unassemble_only)
1306 dpavlin 24 debug("mov.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1307 dpavlin 14 if (unassemble_only)
1308     return 1;
1309    
1310     fpu_op(cpu, cp, FPU_OP_MOV, fmt, -1, fs, fd, -1, fmt);
1311     return 1;
1312     }
1313    
1314     /* neg.fmt: Floating-point negate */
1315     if ((function & 0x001f003f) == 0x00000007) {
1316     if (cpu->machine->instruction_trace || unassemble_only)
1317 dpavlin 24 debug("neg.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1318 dpavlin 14 if (unassemble_only)
1319     return 1;
1320    
1321     fpu_op(cpu, cp, FPU_OP_NEG, fmt, -1, fs, fd, -1, fmt);
1322     return 1;
1323     }
1324    
1325     /* trunc.l.fmt: Truncate */
1326     if ((function & 0x001f003f) == 0x00000009) {
1327     if (cpu->machine->instruction_trace || unassemble_only)
1328 dpavlin 24 debug("trunc.l.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1329 dpavlin 14 if (unassemble_only)
1330     return 1;
1331    
1332     /* TODO: not CVT? */
1333    
1334 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_L);
1335 dpavlin 14 return 1;
1336     }
1337    
1338     /* trunc.w.fmt: Truncate */
1339     if ((function & 0x001f003f) == 0x0000000d) {
1340     if (cpu->machine->instruction_trace || unassemble_only)
1341 dpavlin 24 debug("trunc.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1342 dpavlin 14 if (unassemble_only)
1343     return 1;
1344    
1345     /* TODO: not CVT? */
1346    
1347 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W);
1348 dpavlin 14 return 1;
1349     }
1350    
1351     /* c.cond.fmt: Floating-point compare */
1352     if ((function & 0x000000f0) == 0x00000030) {
1353     int cond_true;
1354     int bit;
1355    
1356     if (cpu->machine->instruction_trace || unassemble_only)
1357 dpavlin 24 debug("c.%s.%s\tcc%i,r%i,r%i\n", ccname[cond],
1358     fmtname[fmt], cc, fs, ft);
1359 dpavlin 14 if (unassemble_only)
1360     return 1;
1361    
1362     cond_true = fpu_op(cpu, cp, FPU_OP_C, fmt,
1363     ft, fs, -1, cond, fmt);
1364    
1365     /*
1366     * Both the FCCR and FCSR contain condition code bits:
1367     * FCCR: bits 7..0
1368     * FCSR: bits 31..25 and 23
1369     */
1370 dpavlin 24 cp->fcr[MIPS_FPU_FCCR] &= ~(1 << cc);
1371 dpavlin 14 if (cond_true)
1372 dpavlin 24 cp->fcr[MIPS_FPU_FCCR] |= (1 << cc);
1373 dpavlin 14
1374     if (cc == 0) {
1375 dpavlin 24 bit = 1 << MIPS_FCSR_FCC0_SHIFT;
1376     cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1377 dpavlin 14 if (cond_true)
1378 dpavlin 24 cp->fcr[MIPS_FPU_FCSR] |= bit;
1379 dpavlin 14 } else {
1380 dpavlin 24 bit = 1 << (MIPS_FCSR_FCC1_SHIFT + cc-1);
1381     cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1382 dpavlin 14 if (cond_true)
1383 dpavlin 24 cp->fcr[MIPS_FPU_FCSR] |= bit;
1384 dpavlin 14 }
1385    
1386     return 1;
1387     }
1388    
1389     /* cvt.s.fmt: Convert to single floating-point */
1390     if ((function & 0x001f003f) == 0x00000020) {
1391     if (cpu->machine->instruction_trace || unassemble_only)
1392 dpavlin 24 debug("cvt.s.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1393 dpavlin 14 if (unassemble_only)
1394     return 1;
1395    
1396 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_S);
1397 dpavlin 14 return 1;
1398     }
1399    
1400     /* cvt.d.fmt: Convert to double floating-point */
1401     if ((function & 0x001f003f) == 0x00000021) {
1402     if (cpu->machine->instruction_trace || unassemble_only)
1403 dpavlin 24 debug("cvt.d.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1404 dpavlin 14 if (unassemble_only)
1405     return 1;
1406    
1407 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_D);
1408 dpavlin 14 return 1;
1409     }
1410    
1411     /* cvt.w.fmt: Convert to word fixed-point */
1412     if ((function & 0x001f003f) == 0x00000024) {
1413     if (cpu->machine->instruction_trace || unassemble_only)
1414 dpavlin 24 debug("cvt.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1415 dpavlin 14 if (unassemble_only)
1416     return 1;
1417    
1418 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W);
1419 dpavlin 14 return 1;
1420     }
1421    
1422     return 0;
1423     }
1424    
1425    
1426     /*
1427     * coproc_tlbpr():
1428     *
1429     * 'tlbp' and 'tlbr'.
1430     */
1431     void coproc_tlbpr(struct cpu *cpu, int readflag)
1432     {
1433     struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1434     int i, found, g_bit;
1435     uint64_t vpn2, xmask;
1436    
1437     /* Read: */
1438     if (readflag) {
1439     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1440     i = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK) >>
1441     R2K3K_INDEX_SHIFT;
1442     if (i >= cp->nr_of_tlbs) {
1443     /* TODO: exception? */
1444     fatal("warning: tlbr from index %i (too "
1445     "high)\n", i);
1446     return;
1447     }
1448    
1449     /*
1450     * TODO: Hm. Earlier I had an & ~0x3f on the high
1451     * assignment and an & ~0xff on the lo0 assignment.
1452     * I wonder why.
1453     */
1454    
1455     cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi; /* & ~0x3f; */
1456     cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;/* & ~0xff; */
1457     } else {
1458     /* R4000: */
1459     i = cp->reg[COP0_INDEX] & INDEX_MASK;
1460     if (i >= cp->nr_of_tlbs) /* TODO: exception */
1461     return;
1462    
1463     cp->reg[COP0_PAGEMASK] = cp->tlbs[i].mask;
1464     cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi;
1465     cp->reg[COP0_ENTRYLO1] = cp->tlbs[i].lo1;
1466     cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;
1467    
1468     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1469     /* R4100 don't have the G bit in entryhi */
1470     } else {
1471     /* R4000 etc: */
1472     cp->reg[COP0_ENTRYHI] &= ~TLB_G;
1473     g_bit = cp->tlbs[i].hi & TLB_G;
1474    
1475     cp->reg[COP0_ENTRYLO0] &= ~ENTRYLO_G;
1476     cp->reg[COP0_ENTRYLO1] &= ~ENTRYLO_G;
1477     if (g_bit) {
1478     cp->reg[COP0_ENTRYLO0] |= ENTRYLO_G;
1479     cp->reg[COP0_ENTRYLO1] |= ENTRYLO_G;
1480     }
1481     }
1482     }
1483    
1484     return;
1485     }
1486    
1487     /* Probe: */
1488     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1489     vpn2 = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1490     found = -1;
1491     for (i=0; i<cp->nr_of_tlbs; i++)
1492     if ( ((cp->tlbs[i].hi & R2K3K_ENTRYHI_ASID_MASK) ==
1493     (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK))
1494     || cp->tlbs[i].lo0 & R2K3K_ENTRYLO_G)
1495     if ((cp->tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK)
1496     == vpn2) {
1497     found = i;
1498     break;
1499     }
1500     } else {
1501     /* R4000 and R10000: */
1502     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
1503     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K;
1504     else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
1505     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800;
1506     else
1507     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK;
1508     vpn2 = cp->reg[COP0_ENTRYHI] & xmask;
1509     found = -1;
1510     for (i=0; i<cp->nr_of_tlbs; i++) {
1511     int gbit = cp->tlbs[i].hi & TLB_G;
1512     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
1513     gbit = (cp->tlbs[i].lo0 & ENTRYLO_G) &&
1514     (cp->tlbs[i].lo1 & ENTRYLO_G);
1515    
1516     if ( ((cp->tlbs[i].hi & ENTRYHI_ASID) ==
1517     (cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID)) || gbit) {
1518     uint64_t a = vpn2 & ~cp->tlbs[i].mask;
1519     uint64_t b = (cp->tlbs[i].hi & xmask) &
1520     ~cp->tlbs[i].mask;
1521     if (a == b) {
1522     found = i;
1523     break;
1524     }
1525     }
1526     }
1527     }
1528     if (found == -1)
1529     cp->reg[COP0_INDEX] = INDEX_P;
1530     else {
1531     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1532     cp->reg[COP0_INDEX] = found << R2K3K_INDEX_SHIFT;
1533     else
1534     cp->reg[COP0_INDEX] = found;
1535     }
1536    
1537     /* Sign extend the index register: */
1538     if ((cp->reg[COP0_INDEX] >> 32) == 0 &&
1539     cp->reg[COP0_INDEX] & 0x80000000)
1540     cp->reg[COP0_INDEX] |=
1541     0xffffffff00000000ULL;
1542     }
1543    
1544    
1545     /*
1546     * coproc_tlbwri():
1547     *
1548 dpavlin 24 * MIPS TLB write random (tlbwr) and write indexed (tlbwi) instructions.
1549 dpavlin 14 */
1550     void coproc_tlbwri(struct cpu *cpu, int randomflag)
1551     {
1552     struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1553 dpavlin 24 int index, g_bit, old_asid = -1;
1554 dpavlin 14 uint64_t oldvaddr;
1555    
1556     if (randomflag) {
1557 dpavlin 24 if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
1558     cp->reg[COP0_RANDOM] =
1559     ((random() % (cp->nr_of_tlbs - 8)) + 8)
1560     << R2K3K_RANDOM_SHIFT;
1561 dpavlin 14 index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
1562     >> R2K3K_RANDOM_SHIFT;
1563 dpavlin 24 } else {
1564     cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1565     % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
1566 dpavlin 14 index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
1567 dpavlin 24 }
1568 dpavlin 14 } else {
1569     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1570     index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK)
1571     >> R2K3K_INDEX_SHIFT;
1572     else
1573     index = cp->reg[COP0_INDEX] & INDEX_MASK;
1574     }
1575    
1576     if (index >= cp->nr_of_tlbs) {
1577     fatal("warning: tlb index %i too high (max is %i)\n",
1578     index, cp->nr_of_tlbs - 1);
1579     /* TODO: cause an exception? */
1580     return;
1581     }
1582    
1583 dpavlin 24
1584 dpavlin 14 #if 0
1585     /* Debug dump of the previous entry at that index: */
1586 dpavlin 24 fatal("{ old TLB entry at index %02x:", index);
1587     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1588     fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1589     fatal(" lo=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1590     } else {
1591     if (cpu->is_32bit) {
1592     fatal(" mask=%08"PRIx32,(uint32_t)cp->tlbs[index].mask);
1593     fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1594     fatal(" lo0=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1595     fatal(" lo1=%08"PRIx32, (uint32_t)cp->tlbs[index].lo1);
1596     } else {
1597     fatal(" mask=%016"PRIx64, cp->tlbs[index].mask);
1598     fatal(" hi=%016"PRIx64, cp->tlbs[index].hi);
1599     fatal(" lo0=%016"PRIx64, cp->tlbs[index].lo0);
1600     fatal(" lo1=%016"PRIx64, cp->tlbs[index].lo1);
1601     }
1602     }
1603     fatal(" }\n");
1604 dpavlin 14 #endif
1605    
1606 dpavlin 24 /*
1607     * Any virtual address translation for the old TLB entry must be
1608     * invalidated first:
1609     */
1610    
1611 dpavlin 14 switch (cpu->cd.mips.cpu_type.mmu_model) {
1612 dpavlin 24
1613 dpavlin 14 case MMU3K:
1614     oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
1615     oldvaddr &= 0xffffffffULL;
1616     if (oldvaddr & 0x80000000ULL)
1617     oldvaddr |= 0xffffffff00000000ULL;
1618     old_asid = (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK)
1619     >> R2K3K_ENTRYHI_ASID_SHIFT;
1620    
1621 dpavlin 24 cpu->invalidate_translation_caches(cpu, oldvaddr,
1622     INVALIDATE_VADDR);
1623     break;
1624 dpavlin 14
1625 dpavlin 24 default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1626 dpavlin 14 oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
1627     /* 44 addressable bits: */
1628     if (oldvaddr & 0x80000000000ULL)
1629     oldvaddr |= 0xfffff00000000000ULL;
1630 dpavlin 24 } else if (cpu->is_32bit) {
1631     /* MIPS32 etc.: */
1632     oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1633     oldvaddr = (int32_t)oldvaddr;
1634 dpavlin 14 } else {
1635     /* Assume MMU4K */
1636     oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1637     /* 40 addressable bits: */
1638     if (oldvaddr & 0x8000000000ULL)
1639     oldvaddr |= 0xffffff0000000000ULL;
1640     }
1641    
1642 dpavlin 24 #if 1
1643     cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);
1644     #else
1645 dpavlin 14 /*
1646     * TODO: non-4KB page sizes!
1647     */
1648 dpavlin 24 cpu->invalidate_translation_caches(cpu, oldvaddr,
1649     INVALIDATE_VADDR);
1650     cpu->invalidate_translation_caches(cpu, oldvaddr | 0x1000,
1651     INVALIDATE_VADDR);
1652     #endif
1653 dpavlin 14 }
1654    
1655    
1656     /*
1657     * Check for duplicate entries. (There should not be two mappings
1658     * from one virtual address to physical addresses.)
1659     *
1660     * TODO: Do this for MMU3K and R4100 too.
1661     *
1662     * TODO: Make this detection more robust.
1663     */
1664     if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&
1665     cpu->cd.mips.cpu_type.rev != MIPS_R4100) {
1666     uint64_t vaddr1, vaddr2;
1667 dpavlin 22 int i;
1668     unsigned int asid;
1669 dpavlin 14
1670     vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;
1671     asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
1672     /* Since this is just a warning, it's probably not necessary
1673     to use R4000 masks etc. */
1674    
1675     for (i=0; i<cp->nr_of_tlbs; i++) {
1676     if (i == index && !randomflag)
1677     continue;
1678    
1679     if (!(cp->tlbs[i].hi & TLB_G) &&
1680     (cp->tlbs[i].hi & ENTRYHI_ASID) != asid)
1681     continue;
1682    
1683     vaddr2 = cp->tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;
1684     if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 &
1685     ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V)))
1686     fatal("\n[ WARNING! tlbw%s to index 0x%02x "
1687     "vaddr=0x%llx (asid 0x%02x) is already in"
1688     " the TLB (entry 0x%02x) ! ]\n\n",
1689     randomflag? "r" : "i", index,
1690     (long long)vaddr1, asid, i);
1691     }
1692     }
1693    
1694    
1695     /* Write the new entry: */
1696    
1697     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1698 dpavlin 24 uint32_t vaddr, paddr;
1699 dpavlin 14 int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;
1700     unsigned char *memblock = NULL;
1701    
1702     cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI];
1703     cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0];
1704    
1705     vaddr = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1706     paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;
1707    
1708 dpavlin 24 memblock = memory_paddr_to_hostaddr(cpu->mem, paddr, 0);
1709 dpavlin 14
1710 dpavlin 24 /* Invalidate any code translation, if we are writing
1711     a Dirty page to the TLB: */
1712     if (wf) {
1713     cpu->invalidate_code_translation(cpu, paddr,
1714     INVALIDATE_PADDR);
1715     }
1716    
1717     /* If we have a memblock (host page) for the physical
1718     page, then add a translation for it immediately: */
1719 dpavlin 14 if (memblock != NULL &&
1720     cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {
1721     memblock += (paddr & ((1 << BITS_PER_PAGETABLE) - 1));
1722     cpu->update_translation_table(cpu, vaddr, memblock,
1723     wf, paddr);
1724     }
1725     } else {
1726     /* R4000: */
1727     g_bit = (cp->reg[COP0_ENTRYLO0] &
1728     cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
1729     cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];
1730     cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI];
1731     cp->tlbs[index].lo1 = cp->reg[COP0_ENTRYLO1];
1732     cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0];
1733    
1734     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1735     /* NOTE: The VR4131 (and possibly others) don't have
1736     a Global bit in entryhi */
1737     cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK];
1738     } else {
1739     cp->tlbs[index].lo0 &= ~ENTRYLO_G;
1740     cp->tlbs[index].lo1 &= ~ENTRYLO_G;
1741    
1742     cp->tlbs[index].hi &= ~TLB_G;
1743     if (g_bit)
1744     cp->tlbs[index].hi |= TLB_G;
1745     }
1746    
1747 dpavlin 24 /* Invalidate any code translations, if we are writing
1748     Dirty pages to the TLB: */
1749 dpavlin 26 if (cp->reg[COP0_PAGEMASK] != 0 &&
1750     cp->reg[COP0_PAGEMASK] != 0x1800) {
1751     printf("TODO: MASK = %08"PRIx32"\n",
1752     (uint32_t)cp->reg[COP0_PAGEMASK]);
1753     exit(1);
1754     }
1755 dpavlin 24
1756 dpavlin 26 if (cp->tlbs[index].lo0 & ENTRYLO_D)
1757 dpavlin 24 cpu->invalidate_code_translation(cpu,
1758     ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)
1759     >> ENTRYLO_PFN_SHIFT) << 12,
1760     INVALIDATE_PADDR);
1761 dpavlin 26 if (cp->tlbs[index].lo1 & ENTRYLO_D)
1762 dpavlin 24 cpu->invalidate_code_translation(cpu,
1763     ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK)
1764     >> ENTRYLO_PFN_SHIFT) << 12,
1765     INVALIDATE_PADDR);
1766    
1767 dpavlin 26 #if 1
1768 dpavlin 24 if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1769     oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
1770     /* 44 addressable bits: */
1771     if (oldvaddr & 0x80000000000ULL)
1772     oldvaddr |= 0xfffff00000000000ULL;
1773     } else if (cpu->is_32bit) {
1774     /* MIPS32 etc.: */
1775     oldvaddr = (int32_t)oldvaddr;
1776 dpavlin 14 } else {
1777 dpavlin 24 /* Assume MMU4K */
1778     oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1779     /* 40 addressable bits: */
1780     if (oldvaddr & 0x8000000000ULL)
1781     oldvaddr |= 0xffffff0000000000ULL;
1782 dpavlin 14 }
1783 dpavlin 24
1784     cpu->invalidate_translation_caches(cpu, ((cp->tlbs[index].lo0 &
1785     ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << 12, INVALIDATE_PADDR);
1786     cpu->invalidate_translation_caches(cpu, ((cp->tlbs[index].lo1 &
1787     ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << 12, INVALIDATE_PADDR);
1788    
1789     #endif
1790 dpavlin 14 }
1791     }
1792    
1793    
1794     /*
1795     * coproc_rfe():
1796     *
1797     * Return from exception. (R3000 etc.)
1798     */
1799     void coproc_rfe(struct cpu *cpu)
1800     {
1801     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =
1802     (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |
1803     ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2);
1804     }
1805    
1806    
1807     /*
1808     * coproc_eret():
1809     *
1810     * Return from exception. (R4000 etc.)
1811     */
1812     void coproc_eret(struct cpu *cpu)
1813     {
1814     if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {
1815 dpavlin 24 cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC];
1816 dpavlin 14 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
1817     } else {
1818 dpavlin 24 cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC];
1819     cpu->delay_slot = 0;
1820 dpavlin 14 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;
1821     }
1822    
1823     cpu->cd.mips.rmw = 0; /* the "LL bit" */
1824     }
1825    
1826    
1827     /*
1828     * coproc_function():
1829     *
1830     * Execute a coprocessor specific instruction. cp must be != NULL.
1831     * Debug trace should be printed for known instructions, if
1832     * unassemble_only is non-zero. (This will NOT execute the instruction.)
1833     *
1834     * TODO: This is a mess and should be restructured (again).
1835     */
1836     void coproc_function(struct cpu *cpu, struct mips_coproc *cp, int cpnr,
1837     uint32_t function, int unassemble_only, int running)
1838     {
1839     int co_bit, op, rt, rd, fs, copz;
1840     uint64_t tmpvalue;
1841    
1842     if (cp == NULL) {
1843     if (unassemble_only) {
1844     debug("cop%i\t0x%08x (coprocessor not available)\n",
1845     cpnr, (int)function);
1846     return;
1847     }
1848     fatal("[ pc=0x%016llx cop%i\t0x%08x (coprocessor not "
1849     "available)\n", (long long)cpu->pc, cpnr, (int)function);
1850     return;
1851     }
1852    
1853     /* No FPU? */
1854     if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {
1855     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);
1856     return;
1857     }
1858    
1859     /* For quick reference: */
1860     copz = (function >> 21) & 31;
1861     rt = (function >> 16) & 31;
1862     rd = (function >> 11) & 31;
1863    
1864     if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MFCz << 21))
1865     || ((function & 0x03e007f8) == (COPz_DMFCz << 21)))) {
1866     if (unassemble_only) {
1867     debug("%s%i\t%s,", copz==COPz_DMFCz? "dmfc" : "mfc",
1868     cpnr, regnames[rt]);
1869     if (cpnr == 0)
1870     debug("%s", cop0_names[rd]);
1871     else
1872 dpavlin 24 debug("r%i", rd);
1873 dpavlin 14 if (function & 7)
1874     debug(",%i", (int)(function & 7));
1875     debug("\n");
1876     return;
1877     }
1878     coproc_register_read(cpu, cpu->cd.mips.coproc[cpnr],
1879     rd, &tmpvalue, function & 7);
1880     cpu->cd.mips.gpr[rt] = tmpvalue;
1881     if (copz == COPz_MFCz) {
1882     /* Sign-extend: */
1883     cpu->cd.mips.gpr[rt] &= 0xffffffffULL;
1884     if (cpu->cd.mips.gpr[rt] & 0x80000000ULL)
1885     cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL;
1886     }
1887     return;
1888     }
1889    
1890     if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MTCz << 21))
1891     || ((function & 0x03e007f8) == (COPz_DMTCz << 21)))) {
1892     if (unassemble_only) {
1893     debug("%s%i\t%s,", copz==COPz_DMTCz? "dmtc" : "mtc",
1894     cpnr, regnames[rt]);
1895     if (cpnr == 0)
1896     debug("%s", cop0_names[rd]);
1897     else
1898 dpavlin 24 debug("r%i", rd);
1899 dpavlin 14 if (function & 7)
1900     debug(",%i", (int)(function & 7));
1901     debug("\n");
1902     return;
1903     }
1904     tmpvalue = cpu->cd.mips.gpr[rt];
1905     if (copz == COPz_MTCz) {
1906     /* Sign-extend: */
1907     tmpvalue &= 0xffffffffULL;
1908     if (tmpvalue & 0x80000000ULL)
1909     tmpvalue |= 0xffffffff00000000ULL;
1910     }
1911     coproc_register_write(cpu, cpu->cd.mips.coproc[cpnr], rd,
1912     &tmpvalue, copz == COPz_DMTCz, function & 7);
1913     return;
1914     }
1915    
1916     if (cpnr <= 1 && (((function & 0x03e007ff) == (COPz_CFCz << 21))
1917     || ((function & 0x03e007ff) == (COPz_CTCz << 21)))) {
1918     switch (copz) {
1919     case COPz_CFCz: /* Copy from FPU control register */
1920     rt = (function >> 16) & 31;
1921     fs = (function >> 11) & 31;
1922     if (unassemble_only) {
1923     debug("cfc%i\t%s,r%i\n", cpnr,
1924     regnames[rt], fs);
1925     return;
1926     }
1927 dpavlin 24 cpu->cd.mips.gpr[rt] = (int32_t)cp->fcr[fs];
1928 dpavlin 14 /* TODO: implement delay for gpr[rt]
1929     (for MIPS I,II,III only) */
1930     return;
1931     case COPz_CTCz: /* Copy to FPU control register */
1932     rt = (function >> 16) & 31;
1933     fs = (function >> 11) & 31;
1934     if (unassemble_only) {
1935     debug("ctc%i\t%s,r%i\n", cpnr,
1936     regnames[rt], fs);
1937     return;
1938     }
1939    
1940     switch (cpnr) {
1941     case 0: /* System coprocessor */
1942     fatal("[ warning: unimplemented ctc%i, "
1943     "0x%08x -> ctl reg %i ]\n", cpnr,
1944     (int)cpu->cd.mips.gpr[rt], fs);
1945     break;
1946     case 1: /* FPU */
1947     if (fs == 0)
1948     fatal("[ Attempt to write to FPU "
1949     "control register 0 (?) ]\n");
1950     else {
1951     uint64_t tmp = cpu->cd.mips.gpr[rt];
1952     cp->fcr[fs] = tmp;
1953    
1954     /* TODO: writing to control register 31
1955     should cause exceptions, depending
1956     on status bits! */
1957    
1958     switch (fs) {
1959 dpavlin 24 case MIPS_FPU_FCCR:
1960     cp->fcr[MIPS_FPU_FCSR] =
1961     (cp->fcr[MIPS_FPU_FCSR] &
1962 dpavlin 14 0x017fffffULL) | ((tmp & 1)
1963 dpavlin 24 << MIPS_FCSR_FCC0_SHIFT)
1964 dpavlin 14 | (((tmp & 0xfe) >> 1) <<
1965 dpavlin 24 MIPS_FCSR_FCC1_SHIFT);
1966 dpavlin 14 break;
1967 dpavlin 24 case MIPS_FPU_FCSR:
1968     cp->fcr[MIPS_FPU_FCCR] =
1969     (cp->fcr[MIPS_FPU_FCCR] &
1970 dpavlin 14 0xffffff00ULL) | ((tmp >>
1971 dpavlin 24 MIPS_FCSR_FCC0_SHIFT) & 1) |
1972     (((tmp >>
1973     MIPS_FCSR_FCC1_SHIFT)
1974 dpavlin 14 & 0x7f) << 1);
1975     break;
1976     default:
1977     ;
1978     }
1979     }
1980     break;
1981     }
1982    
1983     /* TODO: implement delay for gpr[rt]
1984     (for MIPS I,II,III only) */
1985     return;
1986     default:
1987     ;
1988     }
1989     }
1990    
1991     /* Math (Floating point) coprocessor calls: */
1992     if (cpnr==1) {
1993     if (fpu_function(cpu, cp, function, unassemble_only))
1994     return;
1995     }
1996    
1997    
1998     /* Ugly R5900 hacks: */
1999 dpavlin 24 if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
2000     if ((function & 0xfffff) == COP0_EI) {
2001     if (unassemble_only) {
2002     debug("ei\n");
2003     return;
2004     }
2005     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
2006     R5900_STATUS_EIE;
2007 dpavlin 14 return;
2008     }
2009    
2010 dpavlin 24 if ((function & 0xfffff) == COP0_DI) {
2011     if (unassemble_only) {
2012     debug("di\n");
2013     return;
2014     }
2015     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &=
2016     ~R5900_STATUS_EIE;
2017 dpavlin 14 return;
2018     }
2019     }
2020    
2021     co_bit = (function >> 25) & 1;
2022    
2023     /* TLB operations and other things: */
2024     if (cp->coproc_nr == 0) {
2025     op = (function) & 0xff;
2026     switch (co_bit) {
2027     case 1:
2028     switch (op) {
2029     case COP0_TLBR: /* Read indexed TLB entry */
2030     if (unassemble_only) {
2031     debug("tlbr\n");
2032     return;
2033     }
2034     coproc_tlbpr(cpu, 1);
2035     return;
2036     case COP0_TLBWI: /* Write indexed */
2037     case COP0_TLBWR: /* Write random */
2038     if (unassemble_only) {
2039     if (op == COP0_TLBWI)
2040     debug("tlbwi");
2041     else
2042     debug("tlbwr");
2043     if (!running) {
2044     debug("\n");
2045     return;
2046     }
2047     debug("\tindex=%08llx",
2048     (long long)cp->reg[COP0_INDEX]);
2049     debug(", random=%08llx",
2050     (long long)cp->reg[COP0_RANDOM]);
2051     debug(", mask=%016llx",
2052     (long long)cp->reg[COP0_PAGEMASK]);
2053     debug(", hi=%016llx",
2054     (long long)cp->reg[COP0_ENTRYHI]);
2055     debug(", lo0=%016llx",
2056     (long long)cp->reg[COP0_ENTRYLO0]);
2057     debug(", lo1=%016llx\n",
2058     (long long)cp->reg[COP0_ENTRYLO1]);
2059 dpavlin 24 return;
2060 dpavlin 14 }
2061     coproc_tlbwri(cpu, op == COP0_TLBWR);
2062     return;
2063     case COP0_TLBP: /* Probe TLB for
2064     matching entry */
2065     if (unassemble_only) {
2066     debug("tlbp\n");
2067     return;
2068     }
2069     coproc_tlbpr(cpu, 0);
2070     return;
2071     case COP0_RFE: /* R2000/R3000 only:
2072     Return from Exception */
2073     if (unassemble_only) {
2074     debug("rfe\n");
2075     return;
2076     }
2077     coproc_rfe(cpu);
2078     return;
2079     case COP0_ERET: /* R4000: Return from exception */
2080     if (unassemble_only) {
2081     debug("eret\n");
2082     return;
2083     }
2084     coproc_eret(cpu);
2085     return;
2086 dpavlin 24 case COP0_DERET:
2087     if (unassemble_only) {
2088     debug("deret\n");
2089     return;
2090     }
2091     /*
2092     * According to the MIPS64 manual, deret
2093     * loads PC from the DEPC cop0 register, and
2094     * jumps there immediately. No delay slot.
2095     *
2096     * TODO: This instruction is only available
2097     * if the processor is in debug mode. (What
2098     * does that mean?) TODO: This instruction
2099     * is undefined in a delay slot.
2100     */
2101     cpu->pc = cp->reg[COP0_DEPC];
2102     cpu->delay_slot = 0;
2103     cp->reg[COP0_STATUS] &= ~STATUS_EXL;
2104     return;
2105 dpavlin 14 case COP0_STANDBY:
2106     if (unassemble_only) {
2107     debug("standby\n");
2108     return;
2109     }
2110     /* TODO: Hm. Do something here? */
2111     return;
2112     case COP0_SUSPEND:
2113     if (unassemble_only) {
2114     debug("suspend\n");
2115     return;
2116     }
2117     /* TODO: Hm. Do something here? */
2118     return;
2119     case COP0_HIBERNATE:
2120     if (unassemble_only) {
2121     debug("hibernate\n");
2122     return;
2123     }
2124     /* TODO: Hm. Do something here? */
2125     return;
2126     default:
2127     ;
2128     }
2129     default:
2130     ;
2131     }
2132     }
2133    
2134     /* TODO: coprocessor R2020 on DECstation? */
2135     if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x0100ffff) {
2136     if (unassemble_only) {
2137     debug("decstation_r2020_writeback\n");
2138     return;
2139     }
2140     /* TODO */
2141     return;
2142     }
2143    
2144     /* TODO: RM5200 idle (?) */
2145     if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x02000020) {
2146     if (unassemble_only) {
2147     debug("idle(?)\n"); /* TODO */
2148     return;
2149     }
2150    
2151     /* Idle? TODO */
2152     return;
2153     }
2154    
2155     if (unassemble_only) {
2156     debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);
2157     return;
2158     }
2159    
2160 dpavlin 24 fatal("cpu%i: UNIMPLEMENTED coproc%i function %08"PRIx32" "
2161     "(pc = %016"PRIx64")\n", cpu->cpu_id, cp->coproc_nr,
2162     (uint32_t)function, cpu->pc);
2163    
2164 dpavlin 14 mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cp->coproc_nr, 0, 0, 0);
2165     }
2166    
2167     #endif /* ENABLE_MIPS */

  ViewVC Help
Powered by ViewVC 1.1.26