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

Annotation of /trunk/src/cpus/cpu_mips_coproc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 14 - (hide annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 81301 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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

  ViewVC Help
Powered by ViewVC 1.1.26