/[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 4 - (hide annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 77564 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26