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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 79765 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 0.3.4  ==============


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 dpavlin 10 * $Id: cpu_mips_coproc.c,v 1.23 2005/06/26 11:36:27 debug Exp $
29 dpavlin 2 *
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 "bintrans.h"
39     #include "cop0.h"
40     #include "cpu.h"
41     #include "cpu_mips.h"
42     #include "emul.h"
43     #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     /* FPU control registers: */
72     #define FPU_FCIR 0
73     #define FPU_FCCR 25
74     #define FPU_FCSR 31
75     #define FCSR_FCC0_SHIFT 23
76     #define FCSR_FCC1_SHIFT 25
77    
78    
79     /*
80     * initialize_cop0_config():
81     *
82     * Helper function, called from mips_coproc_new().
83     */
84     static void initialize_cop0_config(struct cpu *cpu, struct mips_coproc *c)
85     {
86     #ifdef ENABLE_MIPS16
87     const int m16 = 1;
88     #else
89     const int m16 = 0;
90     #endif
91 dpavlin 10 int cpu_type, IB, DB, SB, IC, DC, SC;
92 dpavlin 2
93     /* Default values: */
94     c->reg[COP0_CONFIG] =
95     ( 0 << 31) /* config1 present */
96     | (0x00 << 16) /* implementation dependant */
97     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
98     /* endian mode */
99     | ( 2 << 13) /* 0 = MIPS32,
100     1 = MIPS64 with 32-bit segments,
101     2 = MIPS64 with all segments,
102     3 = reserved */
103     | ( 0 << 10) /* architecture revision level,
104     0 = "Revision 1", other
105     values are reserved */
106     | ( 1 << 7) /* MMU type: 0 = none,
107     1 = Standard TLB,
108     2 = Standard BAT,
109     3 = fixed mapping, 4-7=reserved */
110     | ( 0 << 0) /* kseg0 coherency algorithm
111     (TODO) */
112     ;
113    
114 dpavlin 10 cpu_type = cpu->cd.mips.cpu_type.rev & 0xff;
115    
116     /* AU1x00 are treated as 4Kc (MIPS32 cores): */
117     if ((cpu->cd.mips.cpu_type.rev & 0xffff) == 0x0301)
118     cpu_type = MIPS_4Kc;
119    
120     switch (cpu_type) {
121 dpavlin 2 case MIPS_R4000: /* according to the R4000 manual */
122     case MIPS_R4600:
123     IB = cpu->machine->cache_picache_linesize - 4;
124     IB = IB < 0? 0 : (IB > 1? 1 : IB);
125     DB = cpu->machine->cache_pdcache_linesize - 4;
126     DB = DB < 0? 0 : (DB > 1? 1 : DB);
127     SB = cpu->machine->cache_secondary_linesize - 4;
128     SB = SB < 0? 0 : (SB > 3? 3 : SB);
129     IC = cpu->machine->cache_picache - 12;
130     IC = IC < 0? 0 : (IC > 7? 7 : IC);
131     DC = cpu->machine->cache_pdcache - 12;
132     DC = DC < 0? 0 : (DC > 7? 7 : DC);
133     SC = cpu->machine->cache_secondary? 0 : 1;
134     c->reg[COP0_CONFIG] =
135     ( 0 << 31) /* Master/Checker present bit */
136     | (0x00 << 28) /* EC: system clock divisor,
137     0x00 = '2' */
138     | (0x00 << 24) /* EP */
139     | ( SB << 22) /* SB */
140     | (0x00 << 21) /* SS: 0 = mixed i/d scache */
141     | (0x00 << 20) /* SW */
142     | (0x00 << 18) /* EW: 0=64-bit */
143     | ( SC << 17) /* SC: 0=secondary cache present,
144     1=non-present */
145     | (0x00 << 16) /* SM: (todo) */
146     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
147     /* endian mode */
148     | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */
149     | (0x00 << 13) /* EB: (todo) */
150     | (0x00 << 12) /* 0 (resered) */
151     | ( IC << 9) /* IC: I-cache = 2^(12+IC) bytes
152     (1 = 8KB, 4=64K) */
153     | ( DC << 6) /* DC: D-cache = 2^(12+DC) bytes
154     (1 = 8KB, 4=64K) */
155     | ( IB << 5) /* IB: I-cache line size (0=16,
156     1=32) */
157     | ( DB << 4) /* DB: D-cache line size (0=16,
158     1=32) */
159     | ( 0 << 3) /* CU: todo */
160     | ( 0 << 0) /* kseg0 coherency algorithm
161     (TODO) */
162     ;
163     break;
164     case MIPS_R4100: /* According to the VR4131 manual: */
165     IB = cpu->machine->cache_picache_linesize - 4;
166     IB = IB < 0? 0 : (IB > 1? 1 : IB);
167     DB = cpu->machine->cache_pdcache_linesize - 4;
168     DB = DB < 0? 0 : (DB > 1? 1 : DB);
169     IC = cpu->machine->cache_picache - 10;
170     IC = IC < 0? 0 : (IC > 7? 7 : IC);
171     DC = cpu->machine->cache_pdcache - 10;
172     DC = DC < 0? 0 : (DC > 7? 7 : DC);
173     c->reg[COP0_CONFIG] =
174     ( 0 << 31) /* IS: Instruction Streaming bit */
175     | (0x01 << 28) /* EC: system clock divisor,
176     0x01 = 2 */
177     | (0x00 << 24) /* EP */
178     | (0x00 << 23) /* AD: Accelerate data mode
179     (0=VR4000-compatible) */
180     | ( m16 << 20) /* M16: MIPS16 support */
181     | ( 1 << 17) /* '1' */
182     | (0x00 << 16) /* BP: 'Branch forecast'
183     (0 = enabled) */
184     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
185     /* endian mode */
186     | ( 2 << 13) /* '2' hardcoded on VR4131 */
187     | ( 1 << 12) /* CS: Cache size mode
188     (1 on VR4131) */
189     | ( IC << 9) /* IC: I-cache = 2^(10+IC) bytes
190     (0 = 1KB, 4=16K) */
191     | ( DC << 6) /* DC: D-cache = 2^(10+DC) bytes
192     (0 = 1KB, 4=16K) */
193     | ( IB << 5) /* IB: I-cache line size (0=16,
194     1=32) */
195     | ( DB << 4) /* DB: D-cache line size (0=16,
196     1=32) */
197     | ( 0 << 0) /* kseg0 coherency algorithm (TODO) */
198     ;
199     break;
200     case MIPS_R5000:
201     case MIPS_RM5200: /* rm5200 is just a wild guess */
202     /* These are just guesses: (the comments are wrong) */
203     c->reg[COP0_CONFIG] =
204     ( 0 << 31) /* Master/Checker present bit */
205     | (0x00 << 28) /* EC: system clock divisor,
206     0x00 = '2' */
207     | (0x00 << 24) /* EP */
208     | (0x00 << 22) /* SB */
209     | (0x00 << 21) /* SS */
210     | (0x00 << 20) /* SW */
211     | (0x00 << 18) /* EW: 0=64-bit */
212     | (0x01 << 17) /* SC: 0=secondary cache present,
213     1=non-present */
214     | (0x00 << 16) /* SM: (todo) */
215     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
216     /* endian mode */
217     | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */
218     | (0x00 << 13) /* EB: (todo) */
219     | (0x00 << 12) /* 0 (resered) */
220     | ( 3 << 9) /* IC: I-cache = 2^(12+IC) bytes
221     (1 = 8KB, 4=64K) */
222     | ( 3 << 6) /* DC: D-cache = 2^(12+DC) bytes
223     (1 = 8KB, 4=64K) */
224     | ( 1 << 5) /* IB: I-cache line size (0=16,
225     1=32) */
226     | ( 1 << 4) /* DB: D-cache line size (0=16,
227     1=32) */
228     | ( 0 << 3) /* CU: todo */
229     | ( 2 << 0) /* kseg0 coherency algorithm
230     (TODO) */
231     ;
232     break;
233     case MIPS_R10000:
234     case MIPS_R12000:
235     case MIPS_R14000:
236     IC = cpu->machine->cache_picache - 12;
237     IC = IC < 0? 0 : (IC > 7? 7 : IC);
238     DC = cpu->machine->cache_pdcache - 12;
239     DC = DC < 0? 0 : (DC > 7? 7 : DC);
240     SC = cpu->machine->cache_secondary - 19;
241     SC = SC < 0? 0 : (SC > 7? 7 : SC);
242     /* According to the R10000 User's Manual: */
243     c->reg[COP0_CONFIG] =
244     ( IC << 29) /* Primary instruction cache size
245     (3 = 32KB) */
246     | ( DC << 26) /* Primary data cache size (3 =
247     32KB) */
248     | ( 0 << 19) /* SCClkDiv */
249     | ( SC << 16) /* SCSize, secondary cache size.
250     0 = 512KB. powers of two */
251     | ( 0 << 15) /* MemEnd */
252     | ( 0 << 14) /* SCCorEn */
253     | ( 1 << 13) /* SCBlkSize. 0=16 words,
254     1=32 words */
255     | ( 0 << 9) /* SysClkDiv */
256     | ( 0 << 7) /* PrcReqMax */
257     | ( 0 << 6) /* PrcElmReq */
258     | ( 0 << 5) /* CohPrcReqTar */
259     | ( 0 << 3) /* Device number */
260     | ( 2 << 0) /* Cache coherency algorithm for
261     kseg0 */
262     ;
263     break;
264     case MIPS_R5900:
265     /*
266     * R5900 is supposed to have the following (according
267     * to NetBSD/playstation2):
268     * cpu0: 16KB/64B 2-way set-associative L1 Instruction
269     * cache, 48 TLB entries
270     * cpu0: 8KB/64B 2-way set-associative write-back L1
271     * Data cache
272     * The following settings are just guesses:
273     * (comments are incorrect)
274     */
275     c->reg[COP0_CONFIG] =
276     ( 0 << 31) /* Master/Checker present bit */
277     | (0x00 << 28) /* EC: system clock divisor,
278     0x00 = '2' */
279     | (0x00 << 24) /* EP */
280     | (0x00 << 22) /* SB */
281     | (0x00 << 21) /* SS */
282     | (0x00 << 20) /* SW */
283     | (0x00 << 18) /* EW: 0=64-bit */
284     | (0x01 << 17) /* SC: 0=secondary cache present,
285     1=non-present */
286     | (0x00 << 16) /* SM: (todo) */
287     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
288     /* endian mode */
289     | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */
290     | (0x00 << 13) /* EB: (todo) */
291     | (0x00 << 12) /* 0 (resered) */
292     | ( 3 << 9) /* IC: I-cache = 2^(12+IC) bytes
293     (1 = 8KB, 4=64K) */
294     | ( 3 << 6) /* DC: D-cache = 2^(12+DC) bytes
295     (1 = 8KB, 4=64K) */
296     | ( 1 << 5) /* IB: I-cache line size (0=16,
297     1=32) */
298     | ( 1 << 4) /* DB: D-cache line size (0=16,
299     1=32) */
300     | ( 0 << 3) /* CU: todo */
301     | ( 0 << 0) /* kseg0 coherency algorithm
302     (TODO) */
303     ;
304     break;
305     case MIPS_4Kc:
306     case MIPS_5Kc:
307 dpavlin 10 /* According to the MIPS64 (5K) User's Manual: */
308 dpavlin 2 c->reg[COP0_CONFIG] =
309     ( (uint32_t)1 << 31)/* Config 1 present bit */
310     | ( 0 << 20) /* ISD: instruction scheduling
311     disable (=1) */
312     | ( 0 << 17) /* DID: dual issue disable */
313     | ( 0 << 16) /* BM: burst mode */
314 dpavlin 10 | ((cpu->byte_order == EMUL_BIG_ENDIAN? 1 : 0) << 15)
315 dpavlin 2 /* endian mode */
316 dpavlin 10 | ((cpu_type == MIPS_5Kc? 2 : 0) << 13)
317     /* 0=MIPS32, 1=64S, 2=64 */
318 dpavlin 2 | ( 0 << 10) /* Architecture revision */
319     | ( 1 << 7) /* MMU type: 1=TLB, 3=FMT */
320     | ( 2 << 0) /* kseg0 cache coherency algorithm */
321     ;
322 dpavlin 10 /* Config select 1: caches etc. TODO: Associativity? */
323     IB = cpu->machine->cache_picache_linesize - 1;
324     IB = IB < 0? 0 : (IB > 7? 7 : IB);
325     DB = cpu->machine->cache_pdcache_linesize - 1;
326     DB = DB < 0? 0 : (DB > 7? 7 : DB);
327     IC = cpu->machine->cache_picache -
328     cpu->machine->cache_picache_linesize - 7;
329     DC = cpu->machine->cache_pdcache -
330     cpu->machine->cache_pdcache_linesize - 7;
331     cpu->cd.mips.cop0_config_select1 =
332     ((cpu->cd.mips.cpu_type.nr_of_tlb_entries - 1) << 25)
333     | (IC << 22) /* IS: I-cache sets per way */
334     | (IB << 19) /* IL: I-cache line-size */
335     | (1 << 16) /* IA: I-cache assoc. (ways-1) */
336     | (DC << 13) /* DS: D-cache sets per way */
337     | (DB << 10) /* DL: D-cache line-size */
338     | (1 << 7) /* DA: D-cache assoc. (ways-1) */
339     | (16 * 0) /* Existance of PerformanceCounters */
340     | ( 8 * 0) /* Existance of Watch Registers */
341     | ( 4 * m16) /* Existance of MIPS16 */
342     | ( 2 * 0) /* Existance of EJTAG */
343     | ( 1 * 1) /* Existance of FPU */
344     ;
345 dpavlin 2 break;
346     default:
347     ;
348     }
349     }
350    
351    
352     /*
353     * initialize_cop1():
354     *
355     * Helper function, called from mips_coproc_new().
356     */
357     static void initialize_cop1(struct cpu *cpu, struct mips_coproc *c)
358     {
359     int fpu_rev;
360     uint64_t other_stuff = 0;
361    
362     switch (cpu->cd.mips.cpu_type.rev & 0xff) {
363     case MIPS_R2000: fpu_rev = MIPS_R2010; break;
364     case MIPS_R3000: fpu_rev = MIPS_R3010;
365     other_stuff |= 0x40; /* or 0x30? TODO */
366     break;
367     case MIPS_R6000: fpu_rev = MIPS_R6010; break;
368     case MIPS_R4000: fpu_rev = MIPS_R4010; break;
369     case MIPS_4Kc: /* TODO: Is this the same as 5Kc? */
370     case MIPS_5Kc: other_stuff = COP1_REVISION_DOUBLE
371     | COP1_REVISION_SINGLE;
372     case MIPS_R5000:
373     case MIPS_RM5200: fpu_rev = cpu->cd.mips.cpu_type.rev;
374     other_stuff |= 0x10;
375     /* or cpu->cd.mips.cpu_type.sub ? TODO */
376     break;
377     case MIPS_R10000: fpu_rev = MIPS_R10000; break;
378     case MIPS_R12000: fpu_rev = 0x9; break;
379     default: fpu_rev = MIPS_SOFT;
380     }
381    
382     c->fcr[COP1_REVISION] = (fpu_rev << 8) | other_stuff;
383    
384     #if 0
385     /* These are mentioned in the MIPS64 documentation: */
386     + (1 << 16) /* single */
387     + (1 << 17) /* double */
388     + (1 << 18) /* paired-single */
389     + (1 << 19) /* 3d */
390     #endif
391     }
392    
393    
394     /*
395     * mips_coproc_new():
396     *
397     * Create a new MIPS coprocessor object.
398     */
399     struct mips_coproc *mips_coproc_new(struct cpu *cpu, int coproc_nr)
400     {
401     struct mips_coproc *c;
402    
403     c = malloc(sizeof(struct mips_coproc));
404     if (c == NULL) {
405     fprintf(stderr, "out of memory\n");
406     exit(1);
407     }
408    
409     memset(c, 0, sizeof(struct mips_coproc));
410     c->coproc_nr = coproc_nr;
411    
412     if (coproc_nr == 0) {
413     c->nr_of_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;
414     c->tlbs = malloc(c->nr_of_tlbs * sizeof(struct mips_tlb));
415     if (c->tlbs == NULL) {
416     fprintf(stderr, "mips_coproc_new(): out of memory\n");
417     exit(1);
418     }
419    
420     /*
421     * Start with nothing in the status register. This makes sure
422     * that we are running in kernel mode with all interrupts
423     * disabled.
424     */
425     c->reg[COP0_STATUS] = 0;
426    
427     /* For userland emulation, enable all four coprocessors: */
428     if (cpu->machine->userland_emul)
429     c->reg[COP0_STATUS] |=
430     ((uint32_t)0xf << STATUS_CU_SHIFT);
431    
432     /* Hm. Enable coprocessors 0 and 1 even if we're not just
433     emulating userland? TODO: Think about this. */
434     if (cpu->machine->prom_emulation)
435     c->reg[COP0_STATUS] |=
436     ((uint32_t)0x3 << STATUS_CU_SHIFT);
437    
438     if (!cpu->machine->prom_emulation)
439     c->reg[COP0_STATUS] |= STATUS_BEV;
440    
441     /* Note: .rev may contain the company ID as well! */
442     c->reg[COP0_PRID] =
443     (0x00 << 24) /* Company Options */
444     | (0x00 << 16) /* Company ID */
445     | (cpu->cd.mips.cpu_type.rev << 8) /* Processor ID */
446     | (cpu->cd.mips.cpu_type.sub) /* Revision */
447     ;
448    
449     c->reg[COP0_WIRED] = 0;
450    
451     initialize_cop0_config(cpu, c);
452    
453     /* Make sure the status register is sign-extended nicely: */
454     c->reg[COP0_STATUS] = (int64_t)(int32_t)c->reg[COP0_STATUS];
455     }
456    
457     if (coproc_nr == 1)
458     initialize_cop1(cpu, c);
459    
460     return c;
461     }
462    
463    
464     /*
465     * mips_coproc_tlb_set_entry():
466     *
467     * Used by machine setup code, if a specific machine emulation starts up
468     * with hardcoded virtual to physical mappings.
469     */
470     void mips_coproc_tlb_set_entry(struct cpu *cpu, int entrynr, int size,
471     uint64_t vaddr, uint64_t paddr0, uint64_t paddr1,
472     int valid0, int valid1, int dirty0, int dirty1, int global, int asid,
473     int cachealgo0, int cachealgo1)
474     {
475     if (entrynr < 0 || entrynr >= cpu->cd.mips.coproc[0]->nr_of_tlbs) {
476     printf("mips_coproc_tlb_set_entry(): invalid entry nr: %i\n",
477     entrynr);
478     exit(1);
479     }
480    
481     switch (cpu->cd.mips.cpu_type.mmu_model) {
482     case MMU3K:
483     if (size != 4096) {
484     printf("mips_coproc_tlb_set_entry(): invalid pagesize "
485     "(%i) for MMU3K\n", size);
486     exit(1);
487     }
488     cpu->cd.mips.coproc[0]->tlbs[entrynr].hi =
489     (vaddr & R2K3K_ENTRYHI_VPN_MASK) |
490     ((asid << R2K3K_ENTRYHI_ASID_SHIFT) &
491     R2K3K_ENTRYHI_ASID_MASK);
492     cpu->cd.mips.coproc[0]->tlbs[entrynr].lo0 =
493     (paddr0 & R2K3K_ENTRYLO_PFN_MASK) |
494     (cachealgo0? R2K3K_ENTRYLO_N : 0) |
495     (dirty0? R2K3K_ENTRYLO_D : 0) |
496     (valid0? R2K3K_ENTRYLO_V : 0) |
497     (global? R2K3K_ENTRYLO_G : 0);
498     break;
499     default:
500     /* MMU4K and MMU10K, etc: */
501     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
502     cpu->cd.mips.coproc[0]->tlbs[entrynr].hi =
503     (vaddr & ENTRYHI_VPN2_MASK_R10K) |
504     (vaddr & ENTRYHI_R_MASK) |
505     (asid & ENTRYHI_ASID) |
506     (global? TLB_G : 0);
507     else
508     cpu->cd.mips.coproc[0]->tlbs[entrynr].hi =
509     (vaddr & ENTRYHI_VPN2_MASK) |
510     (vaddr & ENTRYHI_R_MASK) |
511     (asid & ENTRYHI_ASID) |
512     (global? TLB_G : 0);
513     /* NOTE: The pagemask size is for a "dual" page: */
514     cpu->cd.mips.coproc[0]->tlbs[entrynr].mask =
515     (2*size - 1) & ~0x1fff;
516     cpu->cd.mips.coproc[0]->tlbs[entrynr].lo0 =
517     (((paddr0 >> 12) << ENTRYLO_PFN_SHIFT) &
518     ENTRYLO_PFN_MASK) |
519     (dirty0? ENTRYLO_D : 0) |
520     (valid0? ENTRYLO_V : 0) |
521     (global? ENTRYLO_G : 0) |
522     ((cachealgo0 << ENTRYLO_C_SHIFT) & ENTRYLO_C_MASK);
523     cpu->cd.mips.coproc[0]->tlbs[entrynr].lo1 =
524     (((paddr1 >> 12) << ENTRYLO_PFN_SHIFT) &
525     ENTRYLO_PFN_MASK) |
526     (dirty1? ENTRYLO_D : 0) |
527     (valid1? ENTRYLO_V : 0) |
528     (global? ENTRYLO_G : 0) |
529     ((cachealgo1 << ENTRYLO_C_SHIFT) & ENTRYLO_C_MASK);
530     /* TODO: R4100, 1KB pages etc */
531     }
532     }
533    
534    
535 dpavlin 10 #ifdef BINTRANS
536 dpavlin 2 /*
537     * old_update_translation_table():
538     */
539     static void old_update_translation_table(struct cpu *cpu, uint64_t vaddr_page,
540     unsigned char *host_page, int writeflag, uint64_t paddr_page)
541     {
542     int a, b;
543     struct vth32_table *tbl1;
544 dpavlin 10 void *p_r, *p_w;
545 dpavlin 2 uint32_t p_paddr;
546    
547     /* This table stuff only works for 32-bit mode: */
548     if (vaddr_page & 0x80000000ULL) {
549     if ((vaddr_page >> 32) != 0xffffffffULL)
550     return;
551     } else {
552     if ((vaddr_page >> 32) != 0)
553     return;
554     }
555    
556     a = (vaddr_page >> 22) & 0x3ff;
557     b = (vaddr_page >> 12) & 0x3ff;
558     /* printf("vaddr = %08x, a = %03x, b = %03x\n",
559     (int)vaddr_page,a, b); */
560     tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];
561     /* printf("tbl1 = %p\n", tbl1); */
562     if (tbl1 == cpu->cd.mips.vaddr_to_hostaddr_nulltable) {
563     /* Allocate a new table1: */
564     /* printf("ALLOCATING a new table1, 0x%08x - "
565     "0x%08x\n", a << 22, (a << 22) + 0x3fffff); */
566     if (cpu->cd.mips.next_free_vth_table == NULL) {
567     tbl1 = malloc(sizeof(struct vth32_table));
568     if (tbl1 == NULL) {
569     fprintf(stderr, "out of mem\n");
570     exit(1);
571     }
572     memset(tbl1, 0, sizeof(struct vth32_table));
573     } else {
574     tbl1 = cpu->cd.mips.next_free_vth_table;
575     cpu->cd.mips.next_free_vth_table =
576     tbl1->next_free;
577     tbl1->next_free = NULL;
578     }
579     cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a] = tbl1;
580     if (tbl1->refcount != 0) {
581     printf("INTERNAL ERROR in coproc.c\n");
582     exit(1);
583     }
584     }
585 dpavlin 10 p_r = tbl1->haddr_entry[b*2];
586     p_w = tbl1->haddr_entry[b*2+1];
587 dpavlin 2 p_paddr = tbl1->paddr_entry[b];
588 dpavlin 10 /* printf(" p_r=%p p_w=%p\n", p_r, p_w); */
589     if (p_r == NULL && p_paddr == 0 &&
590     (host_page != NULL || paddr_page != 0)) {
591 dpavlin 2 tbl1->refcount ++;
592     /* printf("ADDING %08x -> %p wf=%i (refcount is "
593     "now %i)\n", (int)vaddr_page, host_page,
594     writeflag, tbl1->refcount); */
595     }
596     if (writeflag == -1) {
597     /* Forced downgrade to read-only: */
598 dpavlin 10 tbl1->haddr_entry[b*2 + 1] = NULL;
599     } else if (writeflag==0 && p_w != NULL && host_page != NULL) {
600 dpavlin 2 /* Don't degrade a page from writable to readonly. */
601     } else {
602 dpavlin 10 if (host_page != NULL) {
603     tbl1->haddr_entry[b*2] = host_page;
604     if (writeflag)
605     tbl1->haddr_entry[b*2+1] = host_page;
606     else
607     tbl1->haddr_entry[b*2+1] = NULL;
608     } else {
609     tbl1->haddr_entry[b*2] = NULL;
610     tbl1->haddr_entry[b*2+1] = NULL;
611     }
612 dpavlin 2 tbl1->paddr_entry[b] = paddr_page;
613     }
614     tbl1->bintrans_chunks[b] = NULL;
615 dpavlin 10 }
616 dpavlin 2 #endif
617    
618    
619     /*
620     * update_translation_table():
621     */
622     void update_translation_table(struct cpu *cpu, uint64_t vaddr_page,
623     unsigned char *host_page, int writeflag, uint64_t paddr_page)
624     {
625     #ifdef BINTRANS
626     if (!cpu->machine->bintrans_enable)
627     return;
628    
629     if (writeflag > 0)
630     bintrans_invalidate(cpu, paddr_page);
631    
632     if (cpu->machine->old_bintrans_enable) {
633     old_update_translation_table(cpu, vaddr_page, host_page,
634     writeflag, paddr_page);
635     return;
636     }
637    
638     /* TODO */
639     /* printf("update_translation_table(): TODO\n"); */
640     #endif
641     }
642    
643    
644     #ifdef BINTRANS
645     /*
646     * invalidate_table_entry():
647     */
648     static void invalidate_table_entry(struct cpu *cpu, uint64_t vaddr)
649     {
650     int a, b;
651     struct vth32_table *tbl1;
652 dpavlin 10 void *p_r, *p_w;
653 dpavlin 2 uint32_t p_paddr;
654    
655     if (!cpu->machine->old_bintrans_enable) {
656     /* printf("invalidate_table_entry(): New: TODO\n"); */
657     return;
658     }
659    
660     /* This table stuff only works for 32-bit mode: */
661     if (vaddr & 0x80000000ULL) {
662     if ((vaddr >> 32) != 0xffffffffULL) {
663     fatal("invalidate_table_entry(): vaddr = 0x%016llx\n",
664     (long long)vaddr);
665     return;
666     }
667     } else {
668     if ((vaddr >> 32) != 0) {
669     fatal("invalidate_table_entry(): vaddr = 0x%016llx\n",
670     (long long)vaddr);
671     return;
672     }
673     }
674    
675     a = (vaddr >> 22) & 0x3ff;
676     b = (vaddr >> 12) & 0x3ff;
677    
678     /* printf("vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b); */
679    
680     tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];
681     /* printf("tbl1 = %p\n", tbl1); */
682 dpavlin 10 p_r = tbl1->haddr_entry[b*2];
683     p_w = tbl1->haddr_entry[b*2+1];
684 dpavlin 2 p_paddr = tbl1->paddr_entry[b];
685     tbl1->bintrans_chunks[b] = NULL;
686 dpavlin 10 /* printf("B: p_r=%p p_w=%p\n", p_r,p_w); */
687     if (p_r != NULL || p_paddr != 0) {
688 dpavlin 2 /* printf("Found a mapping, "
689     "vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b); */
690 dpavlin 10 tbl1->haddr_entry[b*2] = NULL;
691     tbl1->haddr_entry[b*2+1] = NULL;
692 dpavlin 2 tbl1->paddr_entry[b] = 0;
693     tbl1->refcount --;
694     if (tbl1->refcount == 0) {
695     cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a] =
696     cpu->cd.mips.vaddr_to_hostaddr_nulltable;
697     /* "free" tbl1: */
698     tbl1->next_free = cpu->cd.mips.next_free_vth_table;
699     cpu->cd.mips.next_free_vth_table = tbl1;
700     }
701     }
702     }
703    
704    
705     /*
706     * clear_all_chunks_from_all_tables():
707     */
708     void clear_all_chunks_from_all_tables(struct cpu *cpu)
709     {
710     int a, b;
711     struct vth32_table *tbl1;
712    
713     if (!cpu->machine->old_bintrans_enable) {
714     printf("clear_all_chunks_from_all_tables(): New: TODO\n");
715     return;
716     }
717    
718     for (a=0; a<0x400; a++) {
719     tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];
720     if (tbl1 != cpu->cd.mips.vaddr_to_hostaddr_nulltable) {
721 dpavlin 4 for (b=0; b<0x400; b++) {
722 dpavlin 10 tbl1->haddr_entry[b*2] = NULL;
723     tbl1->haddr_entry[b*2+1] = NULL;
724 dpavlin 4 tbl1->paddr_entry[b] = 0;
725 dpavlin 2 tbl1->bintrans_chunks[b] = NULL;
726 dpavlin 4 }
727 dpavlin 2 }
728     }
729     }
730     #endif
731    
732    
733     /*
734     * mips_invalidate_translation_caches_paddr():
735     *
736     * Invalidate based on physical address.
737     */
738     void mips_invalidate_translation_caches_paddr(struct cpu *cpu, uint64_t paddr)
739     {
740     #ifdef BINTRANS
741     paddr &= ~0xfff;
742    
743     if (cpu->machine->bintrans_enable) {
744     #if 1
745     int i;
746     uint64_t tlb_paddr0, tlb_paddr1;
747     uint64_t tlb_vaddr;
748     uint64_t p, p2;
749    
750     switch (cpu->cd.mips.cpu_type.mmu_model) {
751     case MMU3K:
752     for (i=0; i<64; i++) {
753     tlb_paddr0 = cpu->cd.mips.coproc[0]->
754     tlbs[i].lo0 & R2K3K_ENTRYLO_PFN_MASK;
755     tlb_vaddr = cpu->cd.mips.coproc[0]->
756     tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK;
757     tlb_vaddr = (int64_t)(int32_t)tlb_vaddr;
758     if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &
759     R2K3K_ENTRYLO_V) && tlb_paddr0 == paddr)
760     invalidate_table_entry(cpu, tlb_vaddr);
761     }
762     break;
763     default:
764     for (i=0; i<cpu->cd.mips.coproc[0]->nr_of_tlbs; i++) {
765     int psize = 12;
766     int or_pmask = 0x1fff;
767     int phys_shift = 12;
768    
769     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
770     or_pmask = 0x7ff;
771     phys_shift = 10;
772     }
773     switch (cpu->cd.mips.coproc[0]->
774     tlbs[i].mask | or_pmask) {
775     case 0x000007ff: psize = 10; break;
776     case 0x00001fff: psize = 12; break;
777     case 0x00007fff: psize = 14; break;
778     case 0x0001ffff: psize = 16; break;
779     case 0x0007ffff: psize = 18; break;
780     case 0x001fffff: psize = 20; break;
781     case 0x007fffff: psize = 22; break;
782     case 0x01ffffff: psize = 24; break;
783     case 0x07ffffff: psize = 26; break;
784     default:
785     printf("invalidate_translation_caches"
786     "_paddr(): bad pagemask?\n");
787     }
788     tlb_paddr0 = (cpu->cd.mips.coproc[0]->tlbs[i].
789     lo0 & ENTRYLO_PFN_MASK)>>ENTRYLO_PFN_SHIFT;
790     tlb_paddr1 = (cpu->cd.mips.coproc[0]->tlbs[i].
791     lo1 & ENTRYLO_PFN_MASK)>>ENTRYLO_PFN_SHIFT;
792     tlb_paddr0 <<= phys_shift;
793     tlb_paddr1 <<= phys_shift;
794     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
795     tlb_vaddr = cpu->cd.mips.coproc[0]->
796     tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;
797     if (tlb_vaddr & ((int64_t)1 << 43))
798     tlb_vaddr |=
799     0xfffff00000000000ULL;
800     } else {
801     tlb_vaddr = cpu->cd.mips.coproc[0]->
802     tlbs[i].hi & ENTRYHI_VPN2_MASK;
803     if (tlb_vaddr & ((int64_t)1 << 39))
804     tlb_vaddr |=
805     0xffffff0000000000ULL;
806     }
807     if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &
808     ENTRYLO_V) && paddr >= tlb_paddr0 &&
809     paddr < tlb_paddr0 + (1<<psize)) {
810     p2 = 1 << psize;
811     for (p=0; p<p2; p+=4096)
812     invalidate_table_entry(cpu,
813     tlb_vaddr + p);
814     }
815     if ((cpu->cd.mips.coproc[0]->tlbs[i].lo1 &
816     ENTRYLO_V) && paddr >= tlb_paddr1 &&
817     paddr < tlb_paddr1 + (1<<psize)) {
818     p2 = 1 << psize;
819     for (p=0; p<p2; p+=4096)
820     invalidate_table_entry(cpu,
821     tlb_vaddr + p +
822     (1 << psize));
823     }
824     }
825     }
826     #endif
827    
828     if (paddr < 0x20000000) {
829     invalidate_table_entry(cpu, 0xffffffff80000000ULL
830     + paddr);
831     invalidate_table_entry(cpu, 0xffffffffa0000000ULL
832     + paddr);
833     }
834     }
835    
836     #if 0
837     {
838     int i;
839    
840     /* TODO: Don't invalidate everything. */
841     for (i=0; i<N_BINTRANS_VADDR_TO_HOST; i++)
842     cpu->bintrans_data_hostpage[i] = NULL;
843     }
844     #endif
845    
846     #endif
847     }
848    
849    
850     /*
851     * invalidate_translation_caches():
852     *
853     * This is necessary for every change to the TLB, and when the ASID is changed,
854     * so that for example user-space addresses are not cached when they should
855     * not be.
856     */
857     static void invalidate_translation_caches(struct cpu *cpu,
858     int all, uint64_t vaddr, int kernelspace, int old_asid_to_invalidate)
859     {
860     int i;
861    
862     /* printf("inval(all=%i, kernel=%i, addr=%016llx)\n",
863     all, kernelspace, (long long)vaddr); */
864    
865     #ifdef BINTRANS
866     if (!cpu->machine->bintrans_enable)
867     goto nobintrans;
868    
869     if (all) {
870     int i;
871     uint64_t tlb_vaddr;
872     switch (cpu->cd.mips.cpu_type.mmu_model) {
873     case MMU3K:
874     for (i=0; i<64; i++) {
875     tlb_vaddr = cpu->cd.mips.coproc[0]->tlbs[i].hi
876     & R2K3K_ENTRYHI_VPN_MASK;
877     tlb_vaddr = (int64_t)(int32_t)tlb_vaddr;
878     if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &
879     R2K3K_ENTRYLO_V) && (tlb_vaddr &
880     0xc0000000ULL) != 0x80000000ULL) {
881     int asid = (cpu->cd.mips.coproc[0]->
882     tlbs[i].hi & R2K3K_ENTRYHI_ASID_MASK
883     ) >> R2K3K_ENTRYHI_ASID_SHIFT;
884     if (old_asid_to_invalidate < 0 ||
885     old_asid_to_invalidate == asid)
886     invalidate_table_entry(cpu,
887     tlb_vaddr);
888     }
889     }
890     break;
891     default:
892     for (i=0; i<cpu->cd.mips.coproc[0]->nr_of_tlbs; i++) {
893     int psize = 10, or_pmask = 0x1fff;
894     int phys_shift = 12;
895    
896     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
897     or_pmask = 0x7ff;
898     phys_shift = 10;
899     }
900    
901     switch (cpu->cd.mips.coproc[0]->tlbs[i].mask
902     | or_pmask) {
903     case 0x000007ff: psize = 10; break;
904     case 0x00001fff: psize = 12; break;
905     case 0x00007fff: psize = 14; break;
906     case 0x0001ffff: psize = 16; break;
907     case 0x0007ffff: psize = 18; break;
908     case 0x001fffff: psize = 20; break;
909     case 0x007fffff: psize = 22; break;
910     case 0x01ffffff: psize = 24; break;
911     case 0x07ffffff: psize = 26; break;
912     default:
913     printf("invalidate_translation_caches"
914     "(): bad pagemask?\n");
915     }
916    
917     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
918     tlb_vaddr = cpu->cd.mips.coproc[0]->
919     tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;
920     if (tlb_vaddr & ((int64_t)1 << 43))
921     tlb_vaddr |=
922     0xfffff00000000000ULL;
923     } else {
924     tlb_vaddr = cpu->cd.mips.coproc[0]->
925     tlbs[i].hi & ENTRYHI_VPN2_MASK;
926     if (tlb_vaddr & ((int64_t)1 << 39))
927     tlb_vaddr |=
928     0xffffff0000000000ULL;
929     }
930    
931     /* TODO: Check the ASID etc. */
932    
933     invalidate_table_entry(cpu, tlb_vaddr);
934     invalidate_table_entry(cpu, tlb_vaddr |
935     (1 << psize));
936     }
937     }
938     } else
939     invalidate_table_entry(cpu, vaddr);
940    
941     nobintrans:
942    
943     /* TODO: Don't invalidate everything. */
944     for (i=0; i<N_BINTRANS_VADDR_TO_HOST; i++)
945     cpu->cd.mips.bintrans_data_hostpage[i] = NULL;
946     #endif
947    
948     if (kernelspace)
949     all = 1;
950    
951     #ifdef USE_TINY_CACHE
952     {
953     vaddr >>= 12;
954    
955     /* Invalidate the tiny translation cache... */
956     if (!cpu->machine->bintrans_enable)
957     for (i=0; i<N_TRANSLATION_CACHE_INSTR; i++)
958     if (all || vaddr == (cpu->cd.mips.
959     translation_cache_instr[i].vaddr_pfn))
960     cpu->cd.mips.translation_cache_instr[i].wf = 0;
961    
962     if (!cpu->machine->bintrans_enable)
963     for (i=0; i<N_TRANSLATION_CACHE_DATA; i++)
964     if (all || vaddr == (cpu->cd.mips.
965     translation_cache_data[i].vaddr_pfn))
966     cpu->cd.mips.translation_cache_data[i].wf = 0;
967     }
968     #endif
969     }
970    
971    
972     /*
973     * coproc_register_read();
974     *
975     * Read a value from a MIPS coprocessor register.
976     */
977     void coproc_register_read(struct cpu *cpu,
978 dpavlin 10 struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int select)
979 dpavlin 2 {
980     int unimpl = 1;
981    
982     if (cp->coproc_nr==0 && reg_nr==COP0_INDEX) unimpl = 0;
983     if (cp->coproc_nr==0 && reg_nr==COP0_RANDOM) unimpl = 0;
984     if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYLO0) unimpl = 0;
985     if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYLO1) unimpl = 0;
986     if (cp->coproc_nr==0 && reg_nr==COP0_CONTEXT) unimpl = 0;
987     if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK) unimpl = 0;
988     if (cp->coproc_nr==0 && reg_nr==COP0_WIRED) unimpl = 0;
989     if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR) unimpl = 0;
990 dpavlin 4 if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) {
991     /*
992     * This speeds up delay-loops that just read the count
993     * register until it has reached a certain value. (Only for
994     * R4000 etc.)
995     *
996     * TODO: Maybe this should be optional?
997     */
998     if (cpu->cd.mips.cpu_type.exc_model != EXC3K) {
999     int increase = 500;
1000     int32_t x = cp->reg[COP0_COUNT];
1001     int32_t y = cp->reg[COP0_COMPARE];
1002     int32_t diff = x - y;
1003     if (diff < 0 && diff + increase >= 0
1004     && cpu->cd.mips.compare_register_set) {
1005     mips_cpu_interrupt(cpu, 7);
1006     cpu->cd.mips.compare_register_set = 0;
1007     }
1008     cp->reg[COP0_COUNT] = (int64_t)
1009     (int32_t)(cp->reg[COP0_COUNT] + increase);
1010     }
1011    
1012     unimpl = 0;
1013     }
1014 dpavlin 2 if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI) unimpl = 0;
1015     if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE) unimpl = 0;
1016     if (cp->coproc_nr==0 && reg_nr==COP0_STATUS) unimpl = 0;
1017     if (cp->coproc_nr==0 && reg_nr==COP0_CAUSE) unimpl = 0;
1018     if (cp->coproc_nr==0 && reg_nr==COP0_EPC) unimpl = 0;
1019     if (cp->coproc_nr==0 && reg_nr==COP0_PRID) unimpl = 0;
1020 dpavlin 10 if (cp->coproc_nr==0 && reg_nr==COP0_CONFIG) {
1021     if (select > 0) {
1022     switch (select) {
1023     case 1: *ptr = cpu->cd.mips.cop0_config_select1;
1024     break;
1025     default:fatal("coproc_register_read(): unimplemented"
1026     " config register select %i\n", select);
1027     exit(1);
1028     }
1029     return;
1030     }
1031     unimpl = 0;
1032     }
1033 dpavlin 2 if (cp->coproc_nr==0 && reg_nr==COP0_LLADDR) unimpl = 0;
1034     if (cp->coproc_nr==0 && reg_nr==COP0_WATCHLO) unimpl = 0;
1035     if (cp->coproc_nr==0 && reg_nr==COP0_WATCHHI) unimpl = 0;
1036     if (cp->coproc_nr==0 && reg_nr==COP0_XCONTEXT) unimpl = 0;
1037     if (cp->coproc_nr==0 && reg_nr==COP0_ERRCTL) unimpl = 0;
1038     if (cp->coproc_nr==0 && reg_nr==COP0_CACHEERR) unimpl = 0;
1039     if (cp->coproc_nr==0 && reg_nr==COP0_TAGDATA_LO) unimpl = 0;
1040     if (cp->coproc_nr==0 && reg_nr==COP0_TAGDATA_HI) unimpl = 0;
1041     if (cp->coproc_nr==0 && reg_nr==COP0_ERROREPC) unimpl = 0;
1042     if (cp->coproc_nr==0 && reg_nr==COP0_RESERV22) {
1043     /* Used by Linux on Linksys WRT54G */
1044     unimpl = 0;
1045     }
1046     if (cp->coproc_nr==0 && reg_nr==COP0_DEBUG) unimpl = 0;
1047     if (cp->coproc_nr==0 && reg_nr==COP0_PERFCNT) unimpl = 0;
1048     if (cp->coproc_nr==0 && reg_nr==COP0_DESAVE) unimpl = 0;
1049    
1050     if (cp->coproc_nr==1) unimpl = 0;
1051    
1052     if (unimpl) {
1053     fatal("cpu%i: warning: read from unimplemented coproc%i"
1054     " register %i (%s)\n", cpu->cpu_id, cp->coproc_nr, reg_nr,
1055     cp->coproc_nr==0? cop0_names[reg_nr] : "?");
1056    
1057     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0,
1058     cp->coproc_nr, 0, 0, 0);
1059     return;
1060     }
1061    
1062     *ptr = cp->reg[reg_nr];
1063     }
1064    
1065    
1066     /*
1067     * coproc_register_write();
1068     *
1069     * Write a value to a MIPS coprocessor register.
1070     */
1071     void coproc_register_write(struct cpu *cpu,
1072 dpavlin 10 struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int flag64,
1073     int select)
1074 dpavlin 2 {
1075     int unimpl = 1;
1076     int readonly = 0;
1077     uint64_t tmp = *ptr;
1078     uint64_t tmp2 = 0, old;
1079     int inval = 0, old_asid, oldmode;
1080    
1081     switch (cp->coproc_nr) {
1082     case 0:
1083     /* COPROC 0: */
1084     switch (reg_nr) {
1085     case COP0_INDEX:
1086     case COP0_RANDOM:
1087     unimpl = 0;
1088     break;
1089     case COP0_ENTRYLO0:
1090     unimpl = 0;
1091     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
1092     (tmp & 0xff)!=0) {
1093     /* char *symbol;
1094     uint64_t offset;
1095     symbol = get_symbol_name(
1096     cpu->cd.mips.pc_last, &offset);
1097     fatal("YO! pc = 0x%08llx <%s> "
1098     "lo=%016llx\n", (long long)
1099     cpu->cd.mips.pc_last, symbol? symbol :
1100     "no symbol", (long long)tmp); */
1101     tmp &= (R2K3K_ENTRYLO_PFN_MASK |
1102     R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |
1103     R2K3K_ENTRYLO_V | R2K3K_ENTRYLO_G);
1104     } else if (cpu->cd.mips.cpu_type.mmu_model == MMU4K) {
1105     tmp &= (ENTRYLO_PFN_MASK | ENTRYLO_C_MASK |
1106     ENTRYLO_D | ENTRYLO_V | ENTRYLO_G);
1107     }
1108     break;
1109     case COP0_BADVADDR:
1110     /* Hm. Irix writes to this register. (Why?) */
1111     unimpl = 0;
1112     break;
1113     case COP0_ENTRYLO1:
1114     unimpl = 0;
1115     if (cpu->cd.mips.cpu_type.mmu_model == MMU4K) {
1116     tmp &= (ENTRYLO_PFN_MASK | ENTRYLO_C_MASK |
1117     ENTRYLO_D | ENTRYLO_V | ENTRYLO_G);
1118     }
1119     break;
1120     case COP0_CONTEXT:
1121     old = cp->reg[COP0_CONTEXT];
1122     cp->reg[COP0_CONTEXT] = tmp;
1123     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1124     cp->reg[COP0_CONTEXT] &=
1125     ~R2K3K_CONTEXT_BADVPN_MASK;
1126     cp->reg[COP0_CONTEXT] |=
1127     (old & R2K3K_CONTEXT_BADVPN_MASK);
1128     } else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1129     cp->reg[COP0_CONTEXT] &=
1130     ~CONTEXT_BADVPN2_MASK_R4100;
1131     cp->reg[COP0_CONTEXT] |=
1132     (old & CONTEXT_BADVPN2_MASK_R4100);
1133     } else {
1134     cp->reg[COP0_CONTEXT] &=
1135     ~CONTEXT_BADVPN2_MASK;
1136     cp->reg[COP0_CONTEXT] |=
1137     (old & CONTEXT_BADVPN2_MASK);
1138     }
1139     return;
1140     case COP0_PAGEMASK:
1141     tmp2 = tmp >> PAGEMASK_SHIFT;
1142     if (tmp2 != 0x000 &&
1143     tmp2 != 0x003 &&
1144     tmp2 != 0x00f &&
1145     tmp2 != 0x03f &&
1146     tmp2 != 0x0ff &&
1147     tmp2 != 0x3ff &&
1148     tmp2 != 0xfff)
1149     fatal("cpu%i: trying to write an invalid"
1150     " pagemask 0x%08lx to COP0_PAGEMASK\n",
1151     cpu->cpu_id, (long)tmp);
1152     unimpl = 0;
1153     break;
1154     case COP0_WIRED:
1155     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1156     fatal("cpu%i: r2k/r3k wired register must "
1157     "always be 8\n", cpu->cpu_id);
1158     tmp = 8;
1159     }
1160     cp->reg[COP0_RANDOM] = cp->nr_of_tlbs-1;
1161     tmp &= INDEX_MASK;
1162     unimpl = 0;
1163     break;
1164     case COP0_COUNT:
1165     if (tmp != (int64_t)(int32_t)tmp)
1166     fatal("WARNING: trying to write a 64-bit value"
1167     " to the COUNT register!\n");
1168     tmp = (int64_t)(int32_t)tmp;
1169     unimpl = 0;
1170     break;
1171     case COP0_COMPARE:
1172     /* Clear the timer interrupt bit (bit 7): */
1173     cpu->cd.mips.compare_register_set = 1;
1174     mips_cpu_interrupt_ack(cpu, 7);
1175     if (tmp != (int64_t)(int32_t)tmp)
1176     fatal("WARNING: trying to write a 64-bit value"
1177     " to the COMPARE register!\n");
1178     tmp = (int64_t)(int32_t)tmp;
1179     unimpl = 0;
1180     break;
1181     case COP0_ENTRYHI:
1182     /*
1183     * Translation caches must be invalidated, because the
1184     * address space might change (if the ASID changes).
1185     */
1186     switch (cpu->cd.mips.cpu_type.mmu_model) {
1187     case MMU3K:
1188     old_asid = (cp->reg[COP0_ENTRYHI] &
1189     R2K3K_ENTRYHI_ASID_MASK) >>
1190     R2K3K_ENTRYHI_ASID_SHIFT;
1191     if ((cp->reg[COP0_ENTRYHI] &
1192     R2K3K_ENTRYHI_ASID_MASK) !=
1193     (tmp & R2K3K_ENTRYHI_ASID_MASK))
1194     inval = 1;
1195     break;
1196     default:
1197     old_asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
1198     if ((cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID) !=
1199     (tmp & ENTRYHI_ASID))
1200     inval = 1;
1201     break;
1202     }
1203     if (inval)
1204     invalidate_translation_caches(cpu, 1, 0, 0,
1205     old_asid);
1206     unimpl = 0;
1207     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
1208     (tmp & 0x3f)!=0) {
1209     /* char *symbol;
1210     uint64_t offset;
1211     symbol = get_symbol_name(cpu->
1212     cd.mips.pc_last, &offset);
1213     fatal("YO! pc = 0x%08llx <%s> "
1214     "hi=%016llx\n", (long long)cpu->
1215     cd.mips.pc_last, symbol? symbol :
1216     "no symbol", (long long)tmp); */
1217     tmp &= ~0x3f;
1218     }
1219     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1220     tmp &= (R2K3K_ENTRYHI_VPN_MASK |
1221     R2K3K_ENTRYHI_ASID_MASK);
1222     else if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
1223     tmp &= (ENTRYHI_R_MASK |
1224     ENTRYHI_VPN2_MASK_R10K | ENTRYHI_ASID);
1225     else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
1226     tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK |
1227     0x1800 | ENTRYHI_ASID);
1228     else
1229     tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK |
1230     ENTRYHI_ASID);
1231     break;
1232     case COP0_EPC:
1233     unimpl = 0;
1234     break;
1235     case COP0_PRID:
1236     readonly = 1;
1237     break;
1238     case COP0_CONFIG:
1239 dpavlin 10 if (select > 0) {
1240     switch (select) {
1241     case 1: cpu->cd.mips.cop0_config_select1 = tmp;
1242     break;
1243     default:fatal("coproc_register_write(): unimpl"
1244     "emented config register select "
1245     "%i\n", select);
1246     exit(1);
1247     }
1248     return;
1249     }
1250    
1251 dpavlin 2 /* fatal("COP0_CONFIG: modifying K0 bits: "
1252     "0x%08x => ", cp->reg[reg_nr]); */
1253     tmp = *ptr;
1254     tmp &= 0x3; /* only bits 2..0 can be written */
1255     cp->reg[reg_nr] &= ~(0x3); cp->reg[reg_nr] |= tmp;
1256     /* fatal("0x%08x\n", cp->reg[reg_nr]); */
1257     return;
1258     case COP0_STATUS:
1259     oldmode = cp->reg[COP0_STATUS];
1260     tmp &= ~(1 << 21); /* bit 21 is read-only */
1261 dpavlin 4 #if 0
1262     /* Why was this here? It should not be necessary. */
1263    
1264 dpavlin 2 /* Changing from kernel to user mode? Then
1265     invalidate some translation caches: */
1266     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1267     if (!(oldmode & MIPS1_SR_KU_CUR)
1268     && (tmp & MIPS1_SR_KU_CUR))
1269     invalidate_translation_caches(cpu,
1270     0, 0, 1, 0);
1271     } else {
1272     /* TODO: don't hardcode */
1273     if ((oldmode & 0xff) != (tmp & 0xff))
1274     invalidate_translation_caches(
1275     cpu, 0, 0, 1, 0);
1276     }
1277 dpavlin 4 #endif
1278    
1279     #ifdef BINTRANS
1280     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
1281     (oldmode & MIPS1_ISOL_CACHES) !=
1282     (tmp & MIPS1_ISOL_CACHES)) {
1283     /* R3000-style caches when isolated are
1284     treated in bintrans mode by changing
1285     the vaddr_to_hostaddr_table0 pointer: */
1286     if (tmp & MIPS1_ISOL_CACHES) {
1287     /* cpu->cd.mips.
1288     dont_run_next_bintrans = 1; */
1289     cpu->cd.mips.vaddr_to_hostaddr_table0 =
1290     tmp & MIPS1_SWAP_CACHES?
1291     cpu->cd.mips.
1292     vaddr_to_hostaddr_table0_cacheisol_i
1293     : cpu->cd.mips.
1294     vaddr_to_hostaddr_table0_cacheisol_d;
1295     } else {
1296     cpu->cd.mips.vaddr_to_hostaddr_table0 =
1297     cpu->cd.mips.
1298     vaddr_to_hostaddr_table0_kernel;
1299    
1300     /* TODO: cpu->cd.mips.
1301     vaddr_to_hostaddr_table0_user; */
1302     }
1303     }
1304     #endif
1305 dpavlin 2 unimpl = 0;
1306     break;
1307     case COP0_CAUSE:
1308     /* A write to the cause register only
1309     affects IM bits 0 and 1: */
1310     cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);
1311     cp->reg[reg_nr] |= (tmp & (0x3 << STATUS_IM_SHIFT));
1312     if (!(cp->reg[COP0_CAUSE] & STATUS_IM_MASK))
1313     cpu->cd.mips.cached_interrupt_is_possible = 0;
1314     else
1315     cpu->cd.mips.cached_interrupt_is_possible = 1;
1316     return;
1317     case COP0_FRAMEMASK:
1318     /* TODO: R10000 */
1319     unimpl = 0;
1320     break;
1321     case COP0_TAGDATA_LO:
1322     case COP0_TAGDATA_HI:
1323     /* TODO: R4300 and others? */
1324     unimpl = 0;
1325     break;
1326     case COP0_LLADDR:
1327     unimpl = 0;
1328     break;
1329     case COP0_WATCHLO:
1330     case COP0_WATCHHI:
1331     unimpl = 0;
1332     break;
1333     case COP0_XCONTEXT:
1334     /*
1335     * TODO: According to the R10000 manual, the R4400
1336     * shares the PTEbase portion of the context registers
1337     * (that is, xcontext and context). On R10000, they
1338     * are separate registers.
1339     */
1340     /* debug("[ xcontext 0x%016llx ]\n", tmp); */
1341     unimpl = 0;
1342     break;
1343    
1344     /* Most of these are actually TODOs: */
1345     case COP0_ERROREPC:
1346     case COP0_DEPC:
1347     case COP0_RESERV22: /* Used by Linux on Linksys WRT54G */
1348     case COP0_DESAVE:
1349     case COP0_PERFCNT:
1350     case COP0_ERRCTL: /* R10000 */
1351     unimpl = 0;
1352     break;
1353     }
1354     break;
1355    
1356     case 1:
1357     /* COPROC 1: */
1358     unimpl = 0;
1359     break;
1360     }
1361    
1362     if (unimpl) {
1363     fatal("cpu%i: warning: write to unimplemented coproc%i "
1364     "register %i (%s), data = 0x%016llx\n", cpu->cpu_id,
1365     cp->coproc_nr, reg_nr, cp->coproc_nr==0?
1366     cop0_names[reg_nr] : "?", (long long)tmp);
1367    
1368     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0,
1369     cp->coproc_nr, 0, 0, 0);
1370     return;
1371     }
1372    
1373     if (readonly) {
1374     fatal("cpu%i: warning: write to READONLY coproc%i register "
1375     "%i ignored\n", cpu->cpu_id, cp->coproc_nr, reg_nr);
1376     return;
1377     }
1378    
1379     cp->reg[reg_nr] = tmp;
1380    
1381     if (!flag64)
1382     cp->reg[reg_nr] = (int64_t)(int32_t)cp->reg[reg_nr];
1383     }
1384    
1385    
1386     /*
1387     * MIPS floating-point stuff:
1388     *
1389     * TODO: Move this to some other file?
1390     */
1391     #define FMT_S 16
1392     #define FMT_D 17
1393     #define FMT_W 20
1394     #define FMT_L 21
1395     #define FMT_PS 22
1396    
1397     #define FPU_OP_ADD 1
1398     #define FPU_OP_SUB 2
1399     #define FPU_OP_MUL 3
1400     #define FPU_OP_DIV 4
1401     #define FPU_OP_SQRT 5
1402     #define FPU_OP_MOV 6
1403     #define FPU_OP_CVT 7
1404     #define FPU_OP_C 8
1405     #define FPU_OP_ABS 9
1406     #define FPU_OP_NEG 10
1407     /* TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W,
1408     RSQRT */
1409    
1410    
1411     struct internal_float_value {
1412     double f;
1413     int nan;
1414     };
1415    
1416    
1417     /*
1418     * fpu_interpret_float_value():
1419     *
1420     * Interprets a float value from binary IEEE format into an
1421     * internal_float_value struct.
1422     */
1423     static void fpu_interpret_float_value(uint64_t reg,
1424     struct internal_float_value *fvp, int fmt)
1425     {
1426     int n_frac = 0, n_exp = 0;
1427     int i, nan, sign = 0, exponent;
1428     double fraction;
1429    
1430     memset(fvp, 0, sizeof(struct internal_float_value));
1431    
1432     /* n_frac and n_exp: */
1433     switch (fmt) {
1434     case FMT_S: n_frac = 23; n_exp = 8; break;
1435     case FMT_W: n_frac = 31; n_exp = 0; break;
1436     case FMT_D: n_frac = 52; n_exp = 11; break;
1437     case FMT_L: n_frac = 63; n_exp = 0; break;
1438     default:
1439     fatal("fpu_interpret_float_value(): "
1440     "unimplemented format %i\n", fmt);
1441     }
1442    
1443     /* exponent: */
1444     exponent = 0;
1445     switch (fmt) {
1446     case FMT_W:
1447     reg &= 0xffffffffULL;
1448     case FMT_L:
1449     break;
1450     case FMT_S:
1451     reg &= 0xffffffffULL;
1452     case FMT_D:
1453     exponent = (reg >> n_frac) & ((1 << n_exp) - 1);
1454     exponent -= (1 << (n_exp-1)) - 1;
1455     break;
1456     default:
1457     fatal("fpu_interpret_float_value(): unimplemented "
1458     "format %i\n", fmt);
1459     }
1460    
1461     /* nan: */
1462     nan = 0;
1463     switch (fmt) {
1464     case FMT_S:
1465     if (reg == 0x7fffffffULL || reg == 0x7fbfffffULL)
1466     nan = 1;
1467     break;
1468     case FMT_D:
1469     if (reg == 0x7fffffffffffffffULL ||
1470     reg == 0x7ff7ffffffffffffULL)
1471     nan = 1;
1472     break;
1473     }
1474    
1475     if (nan) {
1476     fvp->f = 1.0;
1477     goto no_reasonable_result;
1478     }
1479    
1480     /* fraction: */
1481     fraction = 0.0;
1482     switch (fmt) {
1483     case FMT_W:
1484     {
1485     int32_t r_int = reg;
1486     fraction = r_int;
1487     }
1488     break;
1489     case FMT_L:
1490     {
1491     int64_t r_int = reg;
1492     fraction = r_int;
1493     }
1494     break;
1495     case FMT_S:
1496     case FMT_D:
1497     /* sign: */
1498     sign = (reg >> 31) & 1;
1499     if (fmt == FMT_D)
1500     sign = (reg >> 63) & 1;
1501    
1502     fraction = 0.0;
1503     for (i=0; i<n_frac; i++) {
1504     int bit = (reg >> i) & 1;
1505     fraction /= 2.0;
1506     if (bit)
1507     fraction += 1.0;
1508     }
1509     /* Add implicit bit 0: */
1510     fraction = (fraction / 2.0) + 1.0;
1511     break;
1512     default:
1513     fatal("fpu_interpret_float_value(): "
1514     "unimplemented format %i\n", fmt);
1515     }
1516    
1517     /* form the value: */
1518     fvp->f = fraction;
1519    
1520     /* fatal("load reg=%016llx sign=%i exponent=%i fraction=%f ",
1521     (long long)reg, sign, exponent, fraction); */
1522    
1523     /* TODO: this is awful for exponents of large magnitude. */
1524     if (exponent > 0) {
1525     /*
1526     * NOTE / TODO:
1527     *
1528     * This is an ulgy workaround on Alpha, where it seems that
1529     * multiplying by 2, 1024 times causes a floating point
1530     * exception. (Triggered by running for example NetBSD/pmax
1531     * 2.0 on an Alpha.)
1532     */
1533     if (exponent == 1024)
1534     exponent = 1023;
1535    
1536     while (exponent-- > 0)
1537     fvp->f *= 2.0;
1538     } else if (exponent < 0) {
1539     while (exponent++ < 0)
1540     fvp->f /= 2.0;
1541     }
1542    
1543     if (sign)
1544     fvp->f = -fvp->f;
1545    
1546     no_reasonable_result:
1547     fvp->nan = nan;
1548    
1549     /* fatal("f = %f\n", fvp->f); */
1550     }
1551    
1552    
1553     /*
1554     * fpu_store_float_value():
1555     *
1556     * Stores a float value (actually a double) in fmt format.
1557     */
1558     static void fpu_store_float_value(struct mips_coproc *cp, int fd,
1559     double nf, int fmt, int nan)
1560     {
1561     int n_frac = 0, n_exp = 0, signofs=0;
1562     int i, exponent;
1563     uint64_t r = 0, r2;
1564     int64_t r3;
1565    
1566     /* n_frac and n_exp: */
1567     switch (fmt) {
1568     case FMT_S: n_frac = 23; n_exp = 8; signofs = 31; break;
1569     case FMT_W: n_frac = 31; n_exp = 0; signofs = 31; break;
1570     case FMT_D: n_frac = 52; n_exp = 11; signofs = 63; break;
1571     case FMT_L: n_frac = 63; n_exp = 0; signofs = 63; break;
1572     default:
1573     fatal("fpu_store_float_value(): unimplemented format"
1574     " %i\n", fmt);
1575     }
1576    
1577     if ((fmt == FMT_S || fmt == FMT_D) && nan)
1578     goto store_nan;
1579    
1580     /* fraction: */
1581     switch (fmt) {
1582     case FMT_W:
1583     case FMT_L:
1584     /*
1585     * This causes an implicit conversion of double to integer.
1586     * If nf < 0.0, then r2 will begin with a sequence of binary
1587     * 1's, which is ok.
1588     */
1589     r3 = nf;
1590     r2 = r3;
1591     r |= r2;
1592    
1593     if (fmt == FMT_W)
1594     r &= 0xffffffffULL;
1595     break;
1596     case FMT_S:
1597     case FMT_D:
1598     /* fatal("store f=%f ", nf); */
1599    
1600     /* sign bit: */
1601     if (nf < 0.0) {
1602     r |= ((uint64_t)1 << signofs);
1603     nf = -nf;
1604     }
1605    
1606     /*
1607     * How to convert back from double to exponent + fraction:
1608     * We want fraction to be 1.xxx, that is
1609     * 1.0 <= fraction < 2.0
1610     *
1611     * This method is very slow but should work:
1612     */
1613     exponent = 0;
1614     while (nf < 1.0 && exponent > -1023) {
1615     nf *= 2.0;
1616     exponent --;
1617     }
1618     while (nf >= 2.0 && exponent < 1023) {
1619     nf /= 2.0;
1620     exponent ++;
1621     }
1622    
1623     /* Here: 1.0 <= nf < 2.0 */
1624     /* fatal(" nf=%f", nf); */
1625     nf -= 1.0; /* remove implicit first bit */
1626     for (i=n_frac-1; i>=0; i--) {
1627     nf *= 2.0;
1628     if (nf >= 1.0) {
1629     r |= ((uint64_t)1 << i);
1630     nf -= 1.0;
1631     }
1632     /* printf("\n i=%2i r=%016llx\n", i, (long long)r); */
1633     }
1634    
1635     /* Insert the exponent into the resulting word: */
1636     /* (First bias, then make sure it's within range) */
1637     exponent += (((uint64_t)1 << (n_exp-1)) - 1);
1638     if (exponent < 0)
1639     exponent = 0;
1640     if (exponent >= ((int64_t)1 << n_exp))
1641     exponent = ((int64_t)1 << n_exp) - 1;
1642     r |= (uint64_t)exponent << n_frac;
1643    
1644     /* Special case for 0.0: */
1645     if (exponent == 0)
1646     r = 0;
1647    
1648     /* fatal(" exp=%i, r = %016llx\n", exponent, (long long)r); */
1649    
1650     break;
1651     default:
1652     /* TODO */
1653     fatal("fpu_store_float_value(): unimplemented format "
1654     "%i\n", fmt);
1655     }
1656    
1657     store_nan:
1658     if (nan) {
1659     if (fmt == FMT_S)
1660     r = 0x7fffffffULL;
1661     else if (fmt == FMT_D)
1662     r = 0x7fffffffffffffffULL;
1663     else
1664     r = 0x7fffffffULL;
1665     }
1666    
1667     /*
1668     * TODO: this is for 32-bit mode. It has to be updated later
1669     * for 64-bit coprocessor stuff.
1670     */
1671     if (fmt == FMT_D || fmt == FMT_L) {
1672     cp->reg[fd] = r & 0xffffffffULL;
1673     cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;
1674    
1675     if (cp->reg[fd] & 0x80000000ULL)
1676     cp->reg[fd] |= 0xffffffff00000000ULL;
1677     if (cp->reg[fd+1] & 0x80000000ULL)
1678     cp->reg[fd+1] |= 0xffffffff00000000ULL;
1679     } else {
1680     cp->reg[fd] = r & 0xffffffffULL;
1681    
1682     if (cp->reg[fd] & 0x80000000ULL)
1683     cp->reg[fd] |= 0xffffffff00000000ULL;
1684     }
1685     }
1686    
1687    
1688     /*
1689     * fpu_op():
1690     *
1691     * Perform a floating-point operation. For those of fs and ft
1692     * that are >= 0, those numbers are interpreted into local
1693     * variables.
1694     *
1695     * Only FPU_OP_C (compare) returns anything of interest, 1 for
1696     * true, 0 for false.
1697     */
1698     static int fpu_op(struct cpu *cpu, struct mips_coproc *cp, int op, int fmt,
1699     int ft, int fs, int fd, int cond, int output_fmt)
1700     {
1701     /* Potentially two input registers, fs and ft */
1702     struct internal_float_value float_value[2];
1703     int unordered, nan;
1704     uint64_t fs_v = 0;
1705     double nf;
1706    
1707     if (fs >= 0) {
1708     fs_v = cp->reg[fs];
1709     /* TODO: register-pair mode and plain
1710     register mode? "FR" bit? */
1711     if (fmt == FMT_D || fmt == FMT_L)
1712     fs_v = (fs_v & 0xffffffffULL) +
1713     (cp->reg[(fs + 1) & 31] << 32);
1714     fpu_interpret_float_value(fs_v, &float_value[0], fmt);
1715     }
1716     if (ft >= 0) {
1717     uint64_t v = cp->reg[ft];
1718     /* TODO: register-pair mode and
1719     plain register mode? "FR" bit? */
1720     if (fmt == FMT_D || fmt == FMT_L)
1721     v = (v & 0xffffffffULL) +
1722     (cp->reg[(ft + 1) & 31] << 32);
1723     fpu_interpret_float_value(v, &float_value[1], fmt);
1724     }
1725    
1726     switch (op) {
1727     case FPU_OP_ADD:
1728     nf = float_value[0].f + float_value[1].f;
1729     /* debug(" add: %f + %f = %f\n",
1730     float_value[0].f, float_value[1].f, nf); */
1731     fpu_store_float_value(cp, fd, nf, output_fmt,
1732     float_value[0].nan || float_value[1].nan);
1733     break;
1734     case FPU_OP_SUB:
1735     nf = float_value[0].f - float_value[1].f;
1736     /* debug(" sub: %f - %f = %f\n",
1737     float_value[0].f, float_value[1].f, nf); */
1738     fpu_store_float_value(cp, fd, nf, output_fmt,
1739     float_value[0].nan || float_value[1].nan);
1740     break;
1741     case FPU_OP_MUL:
1742     nf = float_value[0].f * float_value[1].f;
1743     /* debug(" mul: %f * %f = %f\n",
1744     float_value[0].f, float_value[1].f, nf); */
1745     fpu_store_float_value(cp, fd, nf, output_fmt,
1746     float_value[0].nan || float_value[1].nan);
1747     break;
1748     case FPU_OP_DIV:
1749     nan = float_value[0].nan || float_value[1].nan;
1750     if (fabs(float_value[1].f) > 0.00000000001)
1751     nf = float_value[0].f / float_value[1].f;
1752     else {
1753     fatal("DIV by zero !!!!\n");
1754     nf = 0.0; /* TODO */
1755     nan = 1;
1756     }
1757     /* debug(" div: %f / %f = %f\n",
1758     float_value[0].f, float_value[1].f, nf); */
1759     fpu_store_float_value(cp, fd, nf, output_fmt, nan);
1760     break;
1761     case FPU_OP_SQRT:
1762     nan = float_value[0].nan;
1763     if (float_value[0].f >= 0.0)
1764     nf = sqrt(float_value[0].f);
1765     else {
1766     fatal("SQRT by less than zero, %f !!!!\n",
1767     float_value[0].f);
1768     nf = 0.0; /* TODO */
1769     nan = 1;
1770     }
1771     /* debug(" sqrt: %f => %f\n", float_value[0].f, nf); */
1772     fpu_store_float_value(cp, fd, nf, output_fmt, nan);
1773     break;
1774     case FPU_OP_ABS:
1775     nf = fabs(float_value[0].f);
1776     /* debug(" abs: %f => %f\n", float_value[0].f, nf); */
1777     fpu_store_float_value(cp, fd, nf, output_fmt,
1778     float_value[0].nan);
1779     break;
1780     case FPU_OP_NEG:
1781     nf = - float_value[0].f;
1782     /* debug(" neg: %f => %f\n", float_value[0].f, nf); */
1783     fpu_store_float_value(cp, fd, nf, output_fmt,
1784     float_value[0].nan);
1785     break;
1786     case FPU_OP_CVT:
1787     nf = float_value[0].f;
1788     /* debug(" mov: %f => %f\n", float_value[0].f, nf); */
1789     fpu_store_float_value(cp, fd, nf, output_fmt,
1790     float_value[0].nan);
1791     break;
1792     case FPU_OP_MOV:
1793     /* Non-arithmetic move: */
1794     /*
1795     * TODO: this is for 32-bit mode. It has to be updated later
1796     * for 64-bit coprocessor stuff.
1797     */
1798     if (output_fmt == FMT_D || output_fmt == FMT_L) {
1799     cp->reg[fd] = fs_v & 0xffffffffULL;
1800     cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;
1801     if (cp->reg[fd] & 0x80000000ULL)
1802     cp->reg[fd] |= 0xffffffff00000000ULL;
1803     if (cp->reg[fd+1] & 0x80000000ULL)
1804     cp->reg[fd+1] |= 0xffffffff00000000ULL;
1805     } else {
1806     cp->reg[fd] = fs_v & 0xffffffffULL;
1807     if (cp->reg[fd] & 0x80000000ULL)
1808     cp->reg[fd] |= 0xffffffff00000000ULL;
1809     }
1810     break;
1811     case FPU_OP_C:
1812     /* debug(" c: cond=%i\n", cond); */
1813    
1814     unordered = 0;
1815     if (float_value[0].nan || float_value[1].nan)
1816     unordered = 1;
1817    
1818     switch (cond) {
1819     case 2: /* Equal */
1820     return (float_value[0].f == float_value[1].f);
1821     case 4: /* Ordered or Less than */
1822     return (float_value[0].f < float_value[1].f)
1823     || !unordered;
1824     case 5: /* Unordered or Less than */
1825     return (float_value[0].f < float_value[1].f)
1826     || unordered;
1827     case 6: /* Ordered or Less than or Equal */
1828     return (float_value[0].f <= float_value[1].f)
1829     || !unordered;
1830     case 7: /* Unordered or Less than or Equal */
1831     return (float_value[0].f <= float_value[1].f)
1832     || unordered;
1833     case 12:/* Less than */
1834     return (float_value[0].f < float_value[1].f);
1835     case 14:/* Less than or equal */
1836     return (float_value[0].f <= float_value[1].f);
1837    
1838     /* The following are not commonly used, so I'll move these out
1839     of the if-0 on a case-by-case basis. */
1840     #if 0
1841     case 0: return 0; /* False */
1842     case 1: return 0; /* Unordered */
1843     case 3: return (float_value[0].f == float_value[1].f);
1844     /* Unordered or Equal */
1845     case 8: return 0; /* Signaling false */
1846     case 9: return 0; /* Not Greater than or Less than or Equal */
1847     case 10:return (float_value[0].f == float_value[1].f); /* Signaling Equal */
1848     case 11:return (float_value[0].f == float_value[1].f); /* Not Greater
1849     than or Less than */
1850     case 13:return !(float_value[0].f >= float_value[1].f); /* Not greater
1851     than or equal */
1852     case 15:return !(float_value[0].f > float_value[1].f); /* Not greater than */
1853     #endif
1854    
1855     default:
1856     fatal("fpu_op(): unimplemented condition "
1857     "code %i. see cpu_mips_coproc.c\n", cond);
1858     }
1859     break;
1860     default:
1861     fatal("fpu_op(): unimplemented op %i\n", op);
1862     }
1863    
1864     return 0;
1865     }
1866    
1867    
1868     /*
1869     * fpu_function():
1870     *
1871     * Returns 1 if function was implemented, 0 otherwise.
1872     * Debug trace should be printed for known instructions.
1873     */
1874     static int fpu_function(struct cpu *cpu, struct mips_coproc *cp,
1875     uint32_t function, int unassemble_only)
1876     {
1877     int fd, fs, ft, fmt, cond, cc;
1878    
1879     fmt = (function >> 21) & 31;
1880     ft = (function >> 16) & 31;
1881     fs = (function >> 11) & 31;
1882     cc = (function >> 8) & 7;
1883     fd = (function >> 6) & 31;
1884     cond = (function >> 0) & 15;
1885    
1886    
1887     /* bc1f, bc1t, bc1fl, bc1tl: */
1888     if ((function & 0x03e00000) == 0x01000000) {
1889     int nd, tf, imm, cond_true;
1890     char *instr_mnem;
1891    
1892     /* cc are bits 20..18: */
1893     cc = (function >> 18) & 7;
1894     nd = (function >> 17) & 1;
1895     tf = (function >> 16) & 1;
1896     imm = function & 65535;
1897     if (imm >= 32768)
1898     imm -= 65536;
1899    
1900     instr_mnem = NULL;
1901     if (nd == 0 && tf == 0) instr_mnem = "bc1f";
1902     if (nd == 0 && tf == 1) instr_mnem = "bc1t";
1903     if (nd == 1 && tf == 0) instr_mnem = "bc1fl";
1904     if (nd == 1 && tf == 1) instr_mnem = "bc1tl";
1905    
1906     if (cpu->machine->instruction_trace || unassemble_only)
1907     debug("%s\t%i,0x%016llx\n", instr_mnem, cc,
1908     (long long) (cpu->pc + (imm << 2)));
1909     if (unassemble_only)
1910     return 1;
1911    
1912     if (cpu->cd.mips.delay_slot) {
1913     fatal("%s: jump inside a jump's delay slot, "
1914     "or similar. TODO\n", instr_mnem);
1915     cpu->running = 0;
1916     return 1;
1917     }
1918    
1919     /* Both the FCCR and FCSR contain condition code bits... */
1920     if (cc == 0)
1921     cond_true = (cp->fcr[FPU_FCSR] >> FCSR_FCC0_SHIFT) & 1;
1922     else
1923     cond_true = (cp->fcr[FPU_FCSR] >>
1924     (FCSR_FCC1_SHIFT + cc-1)) & 1;
1925    
1926     if (!tf)
1927     cond_true = !cond_true;
1928    
1929     if (cond_true) {
1930     cpu->cd.mips.delay_slot = TO_BE_DELAYED;
1931     cpu->cd.mips.delay_jmpaddr = cpu->pc + (imm << 2);
1932     } else {
1933     /* "likely": */
1934     if (nd) {
1935     /* nullify the delay slot */
1936     cpu->cd.mips.nullify_next = 1;
1937     }
1938     }
1939    
1940     return 1;
1941     }
1942    
1943     /* add.fmt: Floating-point add */
1944     if ((function & 0x0000003f) == 0x00000000) {
1945     if (cpu->machine->instruction_trace || unassemble_only)
1946     debug("add.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);
1947     if (unassemble_only)
1948     return 1;
1949    
1950     fpu_op(cpu, cp, FPU_OP_ADD, fmt, ft, fs, fd, -1, fmt);
1951     return 1;
1952     }
1953    
1954     /* sub.fmt: Floating-point subtract */
1955     if ((function & 0x0000003f) == 0x00000001) {
1956     if (cpu->machine->instruction_trace || unassemble_only)
1957     debug("sub.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);
1958     if (unassemble_only)
1959     return 1;
1960    
1961     fpu_op(cpu, cp, FPU_OP_SUB, fmt, ft, fs, fd, -1, fmt);
1962     return 1;
1963     }
1964    
1965     /* mul.fmt: Floating-point multiply */
1966     if ((function & 0x0000003f) == 0x00000002) {
1967     if (cpu->machine->instruction_trace || unassemble_only)
1968     debug("mul.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);
1969     if (unassemble_only)
1970     return 1;
1971    
1972     fpu_op(cpu, cp, FPU_OP_MUL, fmt, ft, fs, fd, -1, fmt);
1973     return 1;
1974     }
1975    
1976     /* div.fmt: Floating-point divide */
1977     if ((function & 0x0000003f) == 0x00000003) {
1978     if (cpu->machine->instruction_trace || unassemble_only)
1979     debug("div.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);
1980     if (unassemble_only)
1981     return 1;
1982    
1983     fpu_op(cpu, cp, FPU_OP_DIV, fmt, ft, fs, fd, -1, fmt);
1984     return 1;
1985     }
1986    
1987     /* sqrt.fmt: Floating-point square-root */
1988     if ((function & 0x001f003f) == 0x00000004) {
1989     if (cpu->machine->instruction_trace || unassemble_only)
1990     debug("sqrt.%i\tr%i,r%i\n", fmt, fd, fs);
1991     if (unassemble_only)
1992     return 1;
1993    
1994     fpu_op(cpu, cp, FPU_OP_SQRT, fmt, -1, fs, fd, -1, fmt);
1995     return 1;
1996     }
1997    
1998     /* abs.fmt: Floating-point absolute value */
1999     if ((function & 0x001f003f) == 0x00000005) {
2000     if (cpu->machine->instruction_trace || unassemble_only)
2001     debug("abs.%i\tr%i,r%i\n", fmt, fd, fs);
2002     if (unassemble_only)
2003     return 1;
2004    
2005     fpu_op(cpu, cp, FPU_OP_ABS, fmt, -1, fs, fd, -1, fmt);
2006     return 1;
2007     }
2008    
2009     /* mov.fmt: Floating-point (non-arithmetic) move */
2010     if ((function & 0x0000003f) == 0x00000006) {
2011     if (cpu->machine->instruction_trace || unassemble_only)
2012     debug("mov.%i\tr%i,r%i\n", fmt, fd, fs);
2013     if (unassemble_only)
2014     return 1;
2015    
2016     fpu_op(cpu, cp, FPU_OP_MOV, fmt, -1, fs, fd, -1, fmt);
2017     return 1;
2018     }
2019    
2020     /* neg.fmt: Floating-point negate */
2021     if ((function & 0x001f003f) == 0x00000007) {
2022     if (cpu->machine->instruction_trace || unassemble_only)
2023     debug("neg.%i\tr%i,r%i\n", fmt, fd, fs);
2024     if (unassemble_only)
2025     return 1;
2026    
2027     fpu_op(cpu, cp, FPU_OP_NEG, fmt, -1, fs, fd, -1, fmt);
2028     return 1;
2029     }
2030    
2031     /* trunc.l.fmt: Truncate */
2032     if ((function & 0x001f003f) == 0x00000009) {
2033     if (cpu->machine->instruction_trace || unassemble_only)
2034     debug("trunc.l.%i\tr%i,r%i\n", fmt, fd, fs);
2035     if (unassemble_only)
2036     return 1;
2037    
2038     /* TODO: not CVT? */
2039    
2040     fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_L);
2041     return 1;
2042     }
2043    
2044     /* trunc.w.fmt: Truncate */
2045     if ((function & 0x001f003f) == 0x0000000d) {
2046     if (cpu->machine->instruction_trace || unassemble_only)
2047     debug("trunc.w.%i\tr%i,r%i\n", fmt, fd, fs);
2048     if (unassemble_only)
2049     return 1;
2050    
2051     /* TODO: not CVT? */
2052    
2053     fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_W);
2054     return 1;
2055     }
2056    
2057     /* c.cond.fmt: Floating-point compare */
2058     if ((function & 0x000000f0) == 0x00000030) {
2059     int cond_true;
2060     int bit;
2061    
2062     if (cpu->machine->instruction_trace || unassemble_only)
2063     debug("c.%i.%i\tr%i,r%i,r%i\n", cond, fmt, cc, fs, ft);
2064     if (unassemble_only)
2065     return 1;
2066    
2067     cond_true = fpu_op(cpu, cp, FPU_OP_C, fmt,
2068     ft, fs, -1, cond, fmt);
2069    
2070     /*
2071     * Both the FCCR and FCSR contain condition code bits:
2072     * FCCR: bits 7..0
2073     * FCSR: bits 31..25 and 23
2074     */
2075     cp->fcr[FPU_FCCR] &= ~(1 << cc);
2076     if (cond_true)
2077     cp->fcr[FPU_FCCR] |= (1 << cc);
2078    
2079     if (cc == 0) {
2080     bit = 1 << FCSR_FCC0_SHIFT;
2081     cp->fcr[FPU_FCSR] &= ~bit;
2082     if (cond_true)
2083     cp->fcr[FPU_FCSR] |= bit;
2084     } else {
2085     bit = 1 << (FCSR_FCC1_SHIFT + cc-1);
2086     cp->fcr[FPU_FCSR] &= ~bit;
2087     if (cond_true)
2088     cp->fcr[FPU_FCSR] |= bit;
2089     }
2090    
2091     return 1;
2092     }
2093    
2094     /* cvt.s.fmt: Convert to single floating-point */
2095     if ((function & 0x001f003f) == 0x00000020) {
2096     if (cpu->machine->instruction_trace || unassemble_only)
2097     debug("cvt.s.%i\tr%i,r%i\n", fmt, fd, fs);
2098     if (unassemble_only)
2099     return 1;
2100    
2101     fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_S);
2102     return 1;
2103     }
2104    
2105     /* cvt.d.fmt: Convert to double floating-point */
2106     if ((function & 0x001f003f) == 0x00000021) {
2107     if (cpu->machine->instruction_trace || unassemble_only)
2108     debug("cvt.d.%i\tr%i,r%i\n", fmt, fd, fs);
2109     if (unassemble_only)
2110     return 1;
2111    
2112     fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_D);
2113     return 1;
2114     }
2115    
2116     /* cvt.w.fmt: Convert to word fixed-point */
2117     if ((function & 0x001f003f) == 0x00000024) {
2118     if (cpu->machine->instruction_trace || unassemble_only)
2119     debug("cvt.w.%i\tr%i,r%i\n", fmt, fd, fs);
2120     if (unassemble_only)
2121     return 1;
2122    
2123     fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_W);
2124     return 1;
2125     }
2126    
2127     return 0;
2128     }
2129    
2130    
2131     /*
2132     * coproc_tlbpr():
2133     *
2134     * 'tlbp' and 'tlbr'.
2135     */
2136     void coproc_tlbpr(struct cpu *cpu, int readflag)
2137     {
2138     struct mips_coproc *cp = cpu->cd.mips.coproc[0];
2139     int i, found, g_bit;
2140     uint64_t vpn2, xmask;
2141    
2142     /* Read: */
2143     if (readflag) {
2144     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
2145     i = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK) >>
2146     R2K3K_INDEX_SHIFT;
2147     if (i >= cp->nr_of_tlbs) {
2148     /* TODO: exception? */
2149     fatal("warning: tlbr from index %i (too "
2150     "high)\n", i);
2151     return;
2152     }
2153    
2154     /*
2155     * TODO: Hm. Earlier I had an & ~0x3f on the high
2156     * assignment and an & ~0xff on the lo0 assignment.
2157     * I wonder why.
2158     */
2159    
2160     cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi; /* & ~0x3f; */
2161     cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;/* & ~0xff; */
2162     } else {
2163     /* R4000: */
2164     i = cp->reg[COP0_INDEX] & INDEX_MASK;
2165     if (i >= cp->nr_of_tlbs) /* TODO: exception */
2166     return;
2167    
2168     cp->reg[COP0_PAGEMASK] = cp->tlbs[i].mask;
2169     cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi;
2170     cp->reg[COP0_ENTRYLO1] = cp->tlbs[i].lo1;
2171     cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;
2172    
2173     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
2174     /* R4100 don't have the G bit in entryhi */
2175     } else {
2176     /* R4000 etc: */
2177     cp->reg[COP0_ENTRYHI] &= ~TLB_G;
2178     g_bit = cp->tlbs[i].hi & TLB_G;
2179    
2180     cp->reg[COP0_ENTRYLO0] &= ~ENTRYLO_G;
2181     cp->reg[COP0_ENTRYLO1] &= ~ENTRYLO_G;
2182     if (g_bit) {
2183     cp->reg[COP0_ENTRYLO0] |= ENTRYLO_G;
2184     cp->reg[COP0_ENTRYLO1] |= ENTRYLO_G;
2185     }
2186     }
2187     }
2188    
2189     return;
2190     }
2191    
2192     /* Probe: */
2193     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
2194     vpn2 = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
2195     found = -1;
2196     for (i=0; i<cp->nr_of_tlbs; i++)
2197     if ( ((cp->tlbs[i].hi & R2K3K_ENTRYHI_ASID_MASK) ==
2198     (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK))
2199     || cp->tlbs[i].lo0 & R2K3K_ENTRYLO_G)
2200     if ((cp->tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK)
2201     == vpn2) {
2202     found = i;
2203     break;
2204     }
2205     } else {
2206     /* R4000 and R10000: */
2207     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
2208     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K;
2209     else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
2210     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800;
2211     else
2212     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK;
2213     vpn2 = cp->reg[COP0_ENTRYHI] & xmask;
2214     found = -1;
2215     for (i=0; i<cp->nr_of_tlbs; i++) {
2216     int gbit = cp->tlbs[i].hi & TLB_G;
2217     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
2218     gbit = (cp->tlbs[i].lo0 & ENTRYLO_G) &&
2219     (cp->tlbs[i].lo1 & ENTRYLO_G);
2220    
2221     if ( ((cp->tlbs[i].hi & ENTRYHI_ASID) ==
2222     (cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID)) || gbit) {
2223     uint64_t a = vpn2 & ~cp->tlbs[i].mask;
2224     uint64_t b = (cp->tlbs[i].hi & xmask) &
2225     ~cp->tlbs[i].mask;
2226     if (a == b) {
2227     found = i;
2228     break;
2229     }
2230     }
2231     }
2232     }
2233     if (found == -1)
2234     cp->reg[COP0_INDEX] = INDEX_P;
2235     else {
2236     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
2237     cp->reg[COP0_INDEX] = found << R2K3K_INDEX_SHIFT;
2238     else
2239     cp->reg[COP0_INDEX] = found;
2240     }
2241    
2242     /* Sign extend the index register: */
2243     if ((cp->reg[COP0_INDEX] >> 32) == 0 &&
2244     cp->reg[COP0_INDEX] & 0x80000000)
2245     cp->reg[COP0_INDEX] |=
2246     0xffffffff00000000ULL;
2247     }
2248    
2249    
2250     /*
2251     * coproc_tlbwri():
2252     *
2253     * 'tlbwr' and 'tlbwi'
2254     */
2255     void coproc_tlbwri(struct cpu *cpu, int randomflag)
2256     {
2257     struct mips_coproc *cp = cpu->cd.mips.coproc[0];
2258     int index, g_bit;
2259     uint64_t oldvaddr;
2260     int old_asid = -1;
2261    
2262     /*
2263     * ... and the last instruction page:
2264     *
2265     * Some thoughts about this: Code running in
2266     * the kernel's physical address space has the
2267     * same vaddr->paddr translation, so the last
2268     * virtual page invalidation only needs to
2269     * happen if we are for some extremely weird
2270     * reason NOT running in the kernel's physical
2271     * address space.
2272     *
2273     * (An even insaner (but probably useless)
2274     * optimization would be to only invalidate
2275     * the last virtual page stuff if the TLB
2276     * update actually affects the vaddr in
2277     * question.)
2278     */
2279    
2280     if (cpu->pc < (uint64_t)0xffffffff80000000ULL ||
2281     cpu->pc >= (uint64_t)0xffffffffc0000000ULL)
2282     cpu->cd.mips.pc_last_virtual_page =
2283     PC_LAST_PAGE_IMPOSSIBLE_VALUE;
2284    
2285     if (randomflag) {
2286     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
2287     index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
2288     >> R2K3K_RANDOM_SHIFT;
2289     else
2290     index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
2291     } else {
2292     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
2293     index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK)
2294     >> R2K3K_INDEX_SHIFT;
2295     else
2296     index = cp->reg[COP0_INDEX] & INDEX_MASK;
2297     }
2298    
2299     if (index >= cp->nr_of_tlbs) {
2300     fatal("warning: tlb index %i too high (max is %i)\n",
2301     index, cp->nr_of_tlbs - 1);
2302     /* TODO: cause an exception? */
2303     return;
2304     }
2305    
2306     #if 0
2307     /* Debug dump of the previous entry at that index: */
2308     debug(" old entry at index = %04x", index);
2309     debug(" mask = %016llx", (long long) cp->tlbs[index].mask);
2310     debug(" hi = %016llx", (long long) cp->tlbs[index].hi);
2311     debug(" lo0 = %016llx", (long long) cp->tlbs[index].lo0);
2312     debug(" lo1 = %016llx\n", (long long) cp->tlbs[index].lo1);
2313     #endif
2314    
2315     /* Translation caches must be invalidated: */
2316     switch (cpu->cd.mips.cpu_type.mmu_model) {
2317     case MMU3K:
2318     oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
2319     oldvaddr &= 0xffffffffULL;
2320     if (oldvaddr & 0x80000000ULL)
2321     oldvaddr |= 0xffffffff00000000ULL;
2322     old_asid = (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK)
2323     >> R2K3K_ENTRYHI_ASID_SHIFT;
2324    
2325     /* TODO: Bug? Why does this if need to be commented out? */
2326    
2327 dpavlin 4 /* if (cp->tlbs[index].lo0 & ENTRYLO_V) */
2328 dpavlin 2 invalidate_translation_caches(cpu, 0, oldvaddr, 0, 0);
2329     break;
2330     default:
2331     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
2332     oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
2333     /* 44 addressable bits: */
2334     if (oldvaddr & 0x80000000000ULL)
2335     oldvaddr |= 0xfffff00000000000ULL;
2336     } else {
2337     /* Assume MMU4K */
2338     oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
2339     /* 40 addressable bits: */
2340     if (oldvaddr & 0x8000000000ULL)
2341     oldvaddr |= 0xffffff0000000000ULL;
2342     }
2343    
2344     /*
2345     * Both pages:
2346     *
2347     * TODO: non-4KB page sizes!
2348     */
2349     invalidate_translation_caches(
2350     cpu, 0, oldvaddr & ~0x1fff, 0, 0);
2351     invalidate_translation_caches(
2352     cpu, 0, (oldvaddr & ~0x1fff) | 0x1000, 0, 0);
2353     }
2354    
2355    
2356 dpavlin 4 /*
2357     * Check for duplicate entries. (There should not be two mappings
2358     * from one virtual address to physical addresses.)
2359     *
2360     * TODO: Do this for MMU3K and R4100 too.
2361     *
2362     * TODO: Make this detection more robust.
2363     */
2364     if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&
2365     cpu->cd.mips.cpu_type.rev != MIPS_R4100) {
2366     uint64_t vaddr1, vaddr2;
2367     int i, asid;
2368    
2369     vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;
2370     asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
2371     /* Since this is just a warning, it's probably not necessary
2372     to use R4000 masks etc. */
2373    
2374     for (i=0; i<cp->nr_of_tlbs; i++) {
2375     if (i == index && !randomflag)
2376     continue;
2377    
2378     if (!(cp->tlbs[i].hi & TLB_G) &&
2379     (cp->tlbs[i].hi & ENTRYHI_ASID) != asid)
2380     continue;
2381    
2382     vaddr2 = cp->tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;
2383     if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 &
2384     ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V)))
2385 dpavlin 6 fatal("\n[ WARNING! tlbw%s to index 0x%02x "
2386     "vaddr=0x%llx (asid 0x%02x) is already in"
2387     " the TLB (entry 0x%02x) ! ]\n\n",
2388     randomflag? "r" : "i", index,
2389     (long long)vaddr1, asid, i);
2390 dpavlin 4 }
2391     }
2392    
2393    
2394 dpavlin 2 /* Write the new entry: */
2395    
2396     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
2397     uint64_t vaddr, paddr;
2398     int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;
2399     unsigned char *memblock = NULL;
2400    
2401     cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI];
2402     cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0];
2403    
2404     vaddr = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
2405     paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;
2406    
2407     /* TODO: This is ugly. */
2408     if (paddr < 0x10000000)
2409     memblock = memory_paddr_to_hostaddr(
2410     cpu->mem, paddr, 1);
2411    
2412     if (memblock != NULL &&
2413     cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {
2414     memblock += (paddr & ((1 << BITS_PER_PAGETABLE) - 1));
2415    
2416     /*
2417     * TODO: Hahaha, this is even uglier than the thing
2418     * above. Some OSes seem to map code pages read/write,
2419     * which causes the bintrans cache to be invalidated
2420     * even when it doesn't have to be.
2421     */
2422     /* if (vaddr < 0x10000000) */
2423     wf = 0;
2424    
2425     update_translation_table(cpu, vaddr, memblock,
2426     wf, paddr);
2427     }
2428     } else {
2429     /* R4000: */
2430     g_bit = (cp->reg[COP0_ENTRYLO0] &
2431     cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
2432     cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];
2433     cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI];
2434     cp->tlbs[index].lo1 = cp->reg[COP0_ENTRYLO1];
2435     cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0];
2436    
2437     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
2438     /* NOTE: The VR4131 (and possibly others) don't have
2439     a Global bit in entryhi */
2440     cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK];
2441     } else {
2442     cp->tlbs[index].lo0 &= ~ENTRYLO_G;
2443     cp->tlbs[index].lo1 &= ~ENTRYLO_G;
2444    
2445     cp->tlbs[index].hi &= ~TLB_G;
2446     if (g_bit)
2447     cp->tlbs[index].hi |= TLB_G;
2448     }
2449     }
2450    
2451     if (randomflag) {
2452     if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
2453     cp->reg[COP0_RANDOM] =
2454     ((random() % (cp->nr_of_tlbs - 8)) + 8)
2455     << R2K3K_RANDOM_SHIFT;
2456     } else {
2457     cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
2458     % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
2459     }
2460     }
2461     }
2462    
2463    
2464     /*
2465     * coproc_rfe():
2466     *
2467     * Return from exception. (R3000 etc.)
2468     */
2469     void coproc_rfe(struct cpu *cpu)
2470     {
2471     int oldmode;
2472    
2473     oldmode = cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_SR_KU_CUR;
2474    
2475     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =
2476     (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |
2477     ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2);
2478    
2479     /* Changing from kernel to user mode? Then this is necessary: */
2480     if (!oldmode &&
2481     (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &
2482     MIPS1_SR_KU_CUR))
2483     invalidate_translation_caches(cpu, 0, 0, 1, 0);
2484     }
2485    
2486    
2487     /*
2488     * coproc_eret():
2489     *
2490     * Return from exception. (R4000 etc.)
2491     */
2492     void coproc_eret(struct cpu *cpu)
2493     {
2494     int oldmode, newmode;
2495    
2496     /* Kernel mode flag: */
2497     oldmode = 0;
2498     if ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS3_SR_KSU_MASK)
2499     != MIPS3_SR_KSU_USER
2500     || (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & (STATUS_EXL |
2501     STATUS_ERL)) ||
2502     (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 1) == 0)
2503     oldmode = 1;
2504    
2505     if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {
2506     cpu->pc = cpu->cd.mips.pc_last =
2507     cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC];
2508     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
2509     } else {
2510     cpu->pc = cpu->cd.mips.pc_last =
2511     cpu->cd.mips.coproc[0]->reg[COP0_EPC];
2512     cpu->cd.mips.delay_slot = 0;
2513     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;
2514     }
2515    
2516     cpu->cd.mips.rmw = 0; /* the "LL bit" */
2517    
2518     /* New kernel mode flag: */
2519     newmode = 0;
2520     if ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS3_SR_KSU_MASK)
2521     != MIPS3_SR_KSU_USER
2522     || (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & (STATUS_EXL |
2523     STATUS_ERL)) ||
2524     (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 1) == 0)
2525     newmode = 1;
2526    
2527 dpavlin 4 #if 0
2528 dpavlin 2 /* Changing from kernel to user mode?
2529     Then this is necessary: TODO */
2530     if (oldmode && !newmode)
2531     invalidate_translation_caches(cpu, 0, 0, 1, 0);
2532 dpavlin 4 #endif
2533 dpavlin 2 }
2534    
2535    
2536     /*
2537     * coproc_function():
2538     *
2539     * Execute a coprocessor specific instruction. cp must be != NULL.
2540     * Debug trace should be printed for known instructions, if
2541     * unassemble_only is non-zero. (This will NOT execute the instruction.)
2542     *
2543     * TODO: This is a mess and should be restructured (again).
2544     */
2545     void coproc_function(struct cpu *cpu, struct mips_coproc *cp, int cpnr,
2546     uint32_t function, int unassemble_only, int running)
2547     {
2548     int co_bit, op, rt, rd, fs, copz;
2549     uint64_t tmpvalue;
2550    
2551     if (cp == NULL) {
2552     if (unassemble_only) {
2553     debug("cop%i\t0x%08x (coprocessor not available)\n",
2554     cpnr, (int)function);
2555     return;
2556     }
2557     fatal("[ pc=0x%016llx cop%i\t0x%08x (coprocessor not "
2558     "available)\n", (long long)cpu->pc, cpnr, (int)function);
2559     return;
2560     }
2561    
2562     #if 0
2563     /* No FPU? */
2564     if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {
2565     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);
2566     return;
2567     }
2568     #endif
2569    
2570     /* For quick reference: */
2571     copz = (function >> 21) & 31;
2572     rt = (function >> 16) & 31;
2573     rd = (function >> 11) & 31;
2574    
2575     if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MFCz << 21))
2576     || ((function & 0x03e007f8) == (COPz_DMFCz << 21)))) {
2577     if (unassemble_only) {
2578 dpavlin 10 debug("%s%i\t%s,%s",
2579 dpavlin 2 copz==COPz_DMFCz? "dmfc" : "mfc", cpnr,
2580     regnames[rt], cop0_names[rd]);
2581 dpavlin 10 if (function & 7)
2582     debug(",%i", (int)(function & 7));
2583     debug("\n");
2584 dpavlin 2 return;
2585     }
2586     coproc_register_read(cpu, cpu->cd.mips.coproc[cpnr],
2587 dpavlin 10 rd, &tmpvalue, function & 7);
2588 dpavlin 2 cpu->cd.mips.gpr[rt] = tmpvalue;
2589     if (copz == COPz_MFCz) {
2590     /* Sign-extend: */
2591     cpu->cd.mips.gpr[rt] &= 0xffffffffULL;
2592     if (cpu->cd.mips.gpr[rt] & 0x80000000ULL)
2593     cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL;
2594     }
2595     return;
2596     }
2597    
2598     if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MTCz << 21))
2599     || ((function & 0x03e007f8) == (COPz_DMTCz << 21)))) {
2600     if (unassemble_only) {
2601 dpavlin 10 debug("%s%i\t%s,%s",
2602 dpavlin 2 copz==COPz_DMTCz? "dmtc" : "mtc", cpnr,
2603     regnames[rt], cop0_names[rd]);
2604 dpavlin 10 if (function & 7)
2605     debug(",%i", (int)(function & 7));
2606     debug("\n");
2607 dpavlin 2 return;
2608     }
2609     tmpvalue = cpu->cd.mips.gpr[rt];
2610     if (copz == COPz_MTCz) {
2611     /* Sign-extend: */
2612     tmpvalue &= 0xffffffffULL;
2613     if (tmpvalue & 0x80000000ULL)
2614     tmpvalue |= 0xffffffff00000000ULL;
2615     }
2616     coproc_register_write(cpu, cpu->cd.mips.coproc[cpnr], rd,
2617 dpavlin 10 &tmpvalue, copz == COPz_DMTCz, function & 7);
2618 dpavlin 2 return;
2619     }
2620    
2621     if (cpnr <= 1 && (((function & 0x03e007ff) == (COPz_CFCz << 21))
2622     || ((function & 0x03e007ff) == (COPz_CTCz << 21)))) {
2623     switch (copz) {
2624     case COPz_CFCz: /* Copy from FPU control register */
2625     rt = (function >> 16) & 31;
2626     fs = (function >> 11) & 31;
2627     if (unassemble_only) {
2628     debug("cfc%i\t%s,r%i\n", cpnr,
2629     regnames[rt], fs);
2630     return;
2631     }
2632     cpu->cd.mips.gpr[rt] = cp->fcr[fs] & 0xffffffffULL;
2633     if (cpu->cd.mips.gpr[rt] & 0x80000000ULL)
2634     cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL;
2635     /* TODO: implement delay for gpr[rt]
2636     (for MIPS I,II,III only) */
2637     return;
2638     case COPz_CTCz: /* Copy to FPU control register */
2639     rt = (function >> 16) & 31;
2640     fs = (function >> 11) & 31;
2641     if (unassemble_only) {
2642     debug("ctc%i\t%s,r%i\n", cpnr,
2643     regnames[rt], fs);
2644     return;
2645     }
2646    
2647     switch (cpnr) {
2648     case 0: /* System coprocessor */
2649     fatal("[ warning: unimplemented ctc%i, "
2650     "0x%08x -> ctl reg %i ]\n", cpnr,
2651     (int)cpu->cd.mips.gpr[rt], fs);
2652     break;
2653     case 1: /* FPU */
2654     if (fs == 0)
2655     fatal("[ Attempt to write to FPU "
2656     "control register 0 (?) ]\n");
2657     else {
2658     uint64_t tmp = cpu->cd.mips.gpr[rt];
2659     cp->fcr[fs] = tmp;
2660    
2661     /* TODO: writing to control register 31
2662     should cause exceptions, depending
2663     on status bits! */
2664    
2665     switch (fs) {
2666     case FPU_FCCR:
2667     cp->fcr[FPU_FCSR] =
2668     (cp->fcr[FPU_FCSR] &
2669     0x017fffffULL) | ((tmp & 1)
2670     << FCSR_FCC0_SHIFT)
2671     | (((tmp & 0xfe) >> 1) <<
2672     FCSR_FCC1_SHIFT);
2673     break;
2674     case FPU_FCSR:
2675     cp->fcr[FPU_FCCR] =
2676     (cp->fcr[FPU_FCCR] &
2677     0xffffff00ULL) | ((tmp >>
2678     FCSR_FCC0_SHIFT) & 1) |
2679     (((tmp >> FCSR_FCC1_SHIFT)
2680     & 0x7f) << 1);
2681     break;
2682     default:
2683     ;
2684     }
2685     }
2686     break;
2687     }
2688    
2689     /* TODO: implement delay for gpr[rt]
2690     (for MIPS I,II,III only) */
2691     return;
2692     default:
2693     ;
2694     }
2695     }
2696    
2697     /* Math (Floating point) coprocessor calls: */
2698     if (cpnr==1) {
2699     if (fpu_function(cpu, cp, function, unassemble_only))
2700     return;
2701     }
2702    
2703     /* For AU1500 and probably others: deret */
2704     if (function == 0x0200001f) {
2705     if (unassemble_only) {
2706     debug("deret\n");
2707     return;
2708     }
2709    
2710     /*
2711     * According to the MIPS64 manual, deret loads PC from the
2712     * DEPC cop0 register, and jumps there immediately. No
2713     * delay slot.
2714     *
2715     * TODO: This instruction is only available if the processor
2716     * is in debug mode. (What does that mean?)
2717     * TODO: This instruction is undefined in a delay slot.
2718     */
2719    
2720     cpu->pc = cpu->cd.mips.pc_last = cp->reg[COP0_DEPC];
2721     cpu->cd.mips.delay_slot = 0;
2722     cp->reg[COP0_STATUS] &= ~STATUS_EXL;
2723    
2724     return;
2725     }
2726    
2727    
2728     /* Ugly R5900 hacks: */
2729     if ((function & 0xfffff) == 0x38) { /* ei */
2730     if (unassemble_only) {
2731     debug("ei\n");
2732     return;
2733     }
2734     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE;
2735     return;
2736     }
2737    
2738     if ((function & 0xfffff) == 0x39) { /* di */
2739     if (unassemble_only) {
2740     debug("di\n");
2741     return;
2742     }
2743     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE;
2744     return;
2745     }
2746    
2747     co_bit = (function >> 25) & 1;
2748    
2749     /* TLB operations and other things: */
2750     if (cp->coproc_nr == 0) {
2751     op = (function) & 0xff;
2752     switch (co_bit) {
2753     case 1:
2754     switch (op) {
2755     case COP0_TLBR: /* Read indexed TLB entry */
2756     if (unassemble_only) {
2757     debug("tlbr\n");
2758     return;
2759     }
2760     coproc_tlbpr(cpu, 1);
2761     return;
2762     case COP0_TLBWI: /* Write indexed */
2763     case COP0_TLBWR: /* Write random */
2764     if (unassemble_only) {
2765     if (op == COP0_TLBWI)
2766     debug("tlbwi");
2767     else
2768     debug("tlbwr");
2769     if (!running) {
2770     debug("\n");
2771     return;
2772     }
2773     debug("\tindex=%08llx",
2774     (long long)cp->reg[COP0_INDEX]);
2775     debug(", random=%08llx",
2776     (long long)cp->reg[COP0_RANDOM]);
2777     debug(", mask=%016llx",
2778     (long long)cp->reg[COP0_PAGEMASK]);
2779     debug(", hi=%016llx",
2780     (long long)cp->reg[COP0_ENTRYHI]);
2781     debug(", lo0=%016llx",
2782     (long long)cp->reg[COP0_ENTRYLO0]);
2783     debug(", lo1=%016llx\n",
2784     (long long)cp->reg[COP0_ENTRYLO1]);
2785     }
2786     coproc_tlbwri(cpu, op == COP0_TLBWR);
2787     return;
2788     case COP0_TLBP: /* Probe TLB for
2789     matching entry */
2790     if (unassemble_only) {
2791     debug("tlbp\n");
2792     return;
2793     }
2794     coproc_tlbpr(cpu, 0);
2795     return;
2796     case COP0_RFE: /* R2000/R3000 only:
2797     Return from Exception */
2798     if (unassemble_only) {
2799     debug("rfe\n");
2800     return;
2801     }
2802     coproc_rfe(cpu);
2803     return;
2804     case COP0_ERET: /* R4000: Return from exception */
2805     if (unassemble_only) {
2806     debug("eret\n");
2807     return;
2808     }
2809     coproc_eret(cpu);
2810     return;
2811     case COP0_STANDBY:
2812     if (unassemble_only) {
2813     debug("standby\n");
2814     return;
2815     }
2816     /* TODO: Hm. Do something here? */
2817     return;
2818     case COP0_SUSPEND:
2819     if (unassemble_only) {
2820     debug("suspend\n");
2821     return;
2822     }
2823     /* TODO: Hm. Do something here? */
2824     return;
2825     case COP0_HIBERNATE:
2826     if (unassemble_only) {
2827     debug("hibernate\n");
2828     return;
2829     }
2830     /* TODO: Hm. Do something here? */
2831     return;
2832     default:
2833     ;
2834     }
2835     default:
2836     ;
2837     }
2838     }
2839    
2840     /* TODO: coprocessor R2020 on DECstation? */
2841     if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x0100ffff) {
2842     if (unassemble_only) {
2843     debug("decstation_r2020_writeback\n");
2844     return;
2845     }
2846     /* TODO */
2847     return;
2848     }
2849    
2850     /* TODO: RM5200 idle (?) */
2851     if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x02000020) {
2852     if (unassemble_only) {
2853     debug("idle(?)\n"); /* TODO */
2854     return;
2855     }
2856    
2857     /* Idle? TODO */
2858     return;
2859     }
2860    
2861     if (unassemble_only) {
2862     debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);
2863     return;
2864     }
2865    
2866     fatal("cpu%i: UNIMPLEMENTED coproc%i function %08lx "
2867     "(pc = %016llx)\n", cpu->cpu_id, cp->coproc_nr, function,
2868     (long long)cpu->cd.mips.pc_last);
2869     #if 1
2870     single_step = 1;
2871     #else
2872     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cp->coproc_nr, 0, 0, 0);
2873     #endif
2874     }
2875    
2876     #endif /* ENABLE_MIPS */

  ViewVC Help
Powered by ViewVC 1.1.26