/[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 20 - (hide annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 76566 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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 dpavlin 20 * $Id: cpu_mips_coproc.c,v 1.8 2005/11/23 02:17:41 debug Exp $
29 dpavlin 14 *
30     * Emulation of MIPS coprocessors.
31     */
32    
33     #include <stdio.h>
34     #include <stdlib.h>
35     #include <string.h>
36     #include <math.h>
37    
38     #include "bintrans.h"
39     #include "cop0.h"
40     #include "cpu.h"
41     #include "cpu_mips.h"
42     #include "emul.h"
43 dpavlin 20 #include "float_emul.h"
44 dpavlin 14 #include "machine.h"
45     #include "memory.h"
46     #include "mips_cpu_types.h"
47     #include "misc.h"
48     #include "opcodes_mips.h"
49    
50    
51     #ifndef ENABLE_MIPS
52    
53    
54     struct mips_coproc *mips_coproc_new(struct cpu *cpu, int coproc_nr)
55     { return NULL; }
56    
57     void mips_coproc_tlb_set_entry(struct cpu *cpu, int entrynr, int size,
58     uint64_t vaddr, uint64_t paddr0, uint64_t paddr1,
59     int valid0, int valid1, int dirty0, int dirty1, int global, int asid,
60     int cachealgo0, int cachealgo1) { }
61    
62    
63     #else /* ENABLE_MIPS */
64    
65    
66     extern volatile int single_step;
67    
68     static char *cop0_names[] = COP0_NAMES;
69     static char *regnames[] = MIPS_REGISTER_NAMES;
70    
71    
72     /* FPU control registers: */
73     #define FPU_FCIR 0
74     #define FPU_FCCR 25
75     #define FPU_FCSR 31
76     #define FCSR_FCC0_SHIFT 23
77     #define FCSR_FCC1_SHIFT 25
78    
79    
80     /*
81     * initialize_cop0_config():
82     *
83     * Helper function, called from mips_coproc_new().
84     */
85     static void initialize_cop0_config(struct cpu *cpu, struct mips_coproc *c)
86     {
87     #ifdef ENABLE_MIPS16
88     const int m16 = 1;
89     #else
90     const int m16 = 0;
91     #endif
92     int cpu_type, IB, DB, SB, IC, DC, SC, IA, DA;
93    
94     /* Default values: */
95     c->reg[COP0_CONFIG] =
96     ( 0 << 31) /* config1 present */
97 dpavlin 18 | (0x00 << 16) /* implementation dependent */
98 dpavlin 14 | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
99     /* endian mode */
100     | ( 2 << 13) /* 0 = MIPS32,
101     1 = MIPS64 with 32-bit segments,
102     2 = MIPS64 with all segments,
103     3 = reserved */
104     | ( 0 << 10) /* architecture revision level,
105     0 = "Revision 1", other
106     values are reserved */
107     | ( 1 << 7) /* MMU type: 0 = none,
108     1 = Standard TLB,
109     2 = Standard BAT,
110     3 = fixed mapping, 4-7=reserved */
111     | ( 0 << 0) /* kseg0 coherency algorithm
112     (TODO) */
113     ;
114    
115     cpu_type = cpu->cd.mips.cpu_type.rev & 0xff;
116    
117     /* AU1x00 are treated as 4Kc (MIPS32 cores): */
118     if ((cpu->cd.mips.cpu_type.rev & 0xffff) == 0x0301)
119     cpu_type = MIPS_4Kc;
120    
121     switch (cpu_type) {
122     case MIPS_R4000: /* according to the R4000 manual */
123     case MIPS_R4600:
124     IB = cpu->machine->cache_picache_linesize - 4;
125     IB = IB < 0? 0 : (IB > 1? 1 : IB);
126     DB = cpu->machine->cache_pdcache_linesize - 4;
127     DB = DB < 0? 0 : (DB > 1? 1 : DB);
128     SB = cpu->machine->cache_secondary_linesize - 4;
129     SB = SB < 0? 0 : (SB > 3? 3 : SB);
130     IC = cpu->machine->cache_picache - 12;
131     IC = IC < 0? 0 : (IC > 7? 7 : IC);
132     DC = cpu->machine->cache_pdcache - 12;
133     DC = DC < 0? 0 : (DC > 7? 7 : DC);
134     SC = cpu->machine->cache_secondary? 0 : 1;
135     c->reg[COP0_CONFIG] =
136     ( 0 << 31) /* Master/Checker present bit */
137     | (0x00 << 28) /* EC: system clock divisor,
138     0x00 = '2' */
139     | (0x00 << 24) /* EP */
140     | ( SB << 22) /* SB */
141     | (0x00 << 21) /* SS: 0 = mixed i/d scache */
142     | (0x00 << 20) /* SW */
143     | (0x00 << 18) /* EW: 0=64-bit */
144     | ( SC << 17) /* SC: 0=secondary cache present,
145     1=non-present */
146     | (0x00 << 16) /* SM: (todo) */
147     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
148     /* endian mode */
149     | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */
150     | (0x00 << 13) /* EB: (todo) */
151     | (0x00 << 12) /* 0 (resered) */
152     | ( IC << 9) /* IC: I-cache = 2^(12+IC) bytes
153     (1 = 8KB, 4=64K) */
154     | ( DC << 6) /* DC: D-cache = 2^(12+DC) bytes
155     (1 = 8KB, 4=64K) */
156     | ( IB << 5) /* IB: I-cache line size (0=16,
157     1=32) */
158     | ( DB << 4) /* DB: D-cache line size (0=16,
159     1=32) */
160     | ( 0 << 3) /* CU: todo */
161     | ( 0 << 0) /* kseg0 coherency algorithm
162     (TODO) */
163     ;
164     break;
165     case MIPS_R4100: /* According to the VR4131 manual: */
166     IB = cpu->machine->cache_picache_linesize - 4;
167     IB = IB < 0? 0 : (IB > 1? 1 : IB);
168     DB = cpu->machine->cache_pdcache_linesize - 4;
169     DB = DB < 0? 0 : (DB > 1? 1 : DB);
170     IC = cpu->machine->cache_picache - 10;
171     IC = IC < 0? 0 : (IC > 7? 7 : IC);
172     DC = cpu->machine->cache_pdcache - 10;
173     DC = DC < 0? 0 : (DC > 7? 7 : DC);
174     c->reg[COP0_CONFIG] =
175     ( 0 << 31) /* IS: Instruction Streaming bit */
176     | (0x01 << 28) /* EC: system clock divisor,
177     0x01 = 2 */
178     | (0x00 << 24) /* EP */
179     | (0x00 << 23) /* AD: Accelerate data mode
180     (0=VR4000-compatible) */
181     | ( m16 << 20) /* M16: MIPS16 support */
182     | ( 1 << 17) /* '1' */
183     | (0x00 << 16) /* BP: 'Branch forecast'
184     (0 = enabled) */
185     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
186     /* endian mode */
187     | ( 2 << 13) /* '2' hardcoded on VR4131 */
188     | ( 1 << 12) /* CS: Cache size mode
189     (1 on VR4131) */
190     | ( IC << 9) /* IC: I-cache = 2^(10+IC) bytes
191     (0 = 1KB, 4=16K) */
192     | ( DC << 6) /* DC: D-cache = 2^(10+DC) bytes
193     (0 = 1KB, 4=16K) */
194     | ( IB << 5) /* IB: I-cache line size (0=16,
195     1=32) */
196     | ( DB << 4) /* DB: D-cache line size (0=16,
197     1=32) */
198     | ( 0 << 0) /* kseg0 coherency algorithm (TODO) */
199     ;
200     break;
201     case MIPS_R5000:
202     case MIPS_RM5200: /* rm5200 is just a wild guess */
203     /* These are just guesses: (the comments are wrong) */
204     c->reg[COP0_CONFIG] =
205     ( 0 << 31) /* Master/Checker present bit */
206     | (0x00 << 28) /* EC: system clock divisor,
207     0x00 = '2' */
208     | (0x00 << 24) /* EP */
209     | (0x00 << 22) /* SB */
210     | (0x00 << 21) /* SS */
211     | (0x00 << 20) /* SW */
212     | (0x00 << 18) /* EW: 0=64-bit */
213     | (0x01 << 17) /* SC: 0=secondary cache present,
214     1=non-present */
215     | (0x00 << 16) /* SM: (todo) */
216     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
217     /* endian mode */
218     | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */
219     | (0x00 << 13) /* EB: (todo) */
220     | (0x00 << 12) /* 0 (resered) */
221     | ( 3 << 9) /* IC: I-cache = 2^(12+IC) bytes
222     (1 = 8KB, 4=64K) */
223     | ( 3 << 6) /* DC: D-cache = 2^(12+DC) bytes
224     (1 = 8KB, 4=64K) */
225     | ( 1 << 5) /* IB: I-cache line size (0=16,
226     1=32) */
227     | ( 1 << 4) /* DB: D-cache line size (0=16,
228     1=32) */
229     | ( 0 << 3) /* CU: todo */
230     | ( 2 << 0) /* kseg0 coherency algorithm
231     (TODO) */
232     ;
233     break;
234     case MIPS_R10000:
235     case MIPS_R12000:
236     case MIPS_R14000:
237     IC = cpu->machine->cache_picache - 12;
238     IC = IC < 0? 0 : (IC > 7? 7 : IC);
239     DC = cpu->machine->cache_pdcache - 12;
240     DC = DC < 0? 0 : (DC > 7? 7 : DC);
241     SC = cpu->machine->cache_secondary - 19;
242     SC = SC < 0? 0 : (SC > 7? 7 : SC);
243     /* According to the R10000 User's Manual: */
244     c->reg[COP0_CONFIG] =
245     ( IC << 29) /* Primary instruction cache size
246     (3 = 32KB) */
247     | ( DC << 26) /* Primary data cache size (3 =
248     32KB) */
249     | ( 0 << 19) /* SCClkDiv */
250     | ( SC << 16) /* SCSize, secondary cache size.
251     0 = 512KB. powers of two */
252     | ( 0 << 15) /* MemEnd */
253     | ( 0 << 14) /* SCCorEn */
254     | ( 1 << 13) /* SCBlkSize. 0=16 words,
255     1=32 words */
256     | ( 0 << 9) /* SysClkDiv */
257     | ( 0 << 7) /* PrcReqMax */
258     | ( 0 << 6) /* PrcElmReq */
259     | ( 0 << 5) /* CohPrcReqTar */
260     | ( 0 << 3) /* Device number */
261     | ( 2 << 0) /* Cache coherency algorithm for
262     kseg0 */
263     ;
264     break;
265     case MIPS_R5900:
266     /*
267     * R5900 is supposed to have the following (according
268     * to NetBSD/playstation2):
269     * cpu0: 16KB/64B 2-way set-associative L1 Instruction
270     * cache, 48 TLB entries
271     * cpu0: 8KB/64B 2-way set-associative write-back L1
272     * Data cache
273     * The following settings are just guesses:
274     * (comments are incorrect)
275     */
276     c->reg[COP0_CONFIG] =
277     ( 0 << 31) /* Master/Checker present bit */
278     | (0x00 << 28) /* EC: system clock divisor,
279     0x00 = '2' */
280     | (0x00 << 24) /* EP */
281     | (0x00 << 22) /* SB */
282     | (0x00 << 21) /* SS */
283     | (0x00 << 20) /* SW */
284     | (0x00 << 18) /* EW: 0=64-bit */
285     | (0x01 << 17) /* SC: 0=secondary cache present,
286     1=non-present */
287     | (0x00 << 16) /* SM: (todo) */
288     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
289     /* endian mode */
290     | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */
291     | (0x00 << 13) /* EB: (todo) */
292     | (0x00 << 12) /* 0 (resered) */
293     | ( 3 << 9) /* IC: I-cache = 2^(12+IC) bytes
294     (1 = 8KB, 4=64K) */
295     | ( 3 << 6) /* DC: D-cache = 2^(12+DC) bytes
296     (1 = 8KB, 4=64K) */
297     | ( 1 << 5) /* IB: I-cache line size (0=16,
298     1=32) */
299     | ( 1 << 4) /* DB: D-cache line size (0=16,
300     1=32) */
301     | ( 0 << 3) /* CU: todo */
302     | ( 0 << 0) /* kseg0 coherency algorithm
303     (TODO) */
304     ;
305     break;
306     case MIPS_4Kc:
307     case MIPS_5Kc:
308     /* According to the MIPS64 (5K) User's Manual: */
309     c->reg[COP0_CONFIG] =
310     ( (uint32_t)1 << 31)/* Config 1 present bit */
311     | ( 0 << 20) /* ISD: instruction scheduling
312     disable (=1) */
313     | ( 0 << 17) /* DID: dual issue disable */
314     | ( 0 << 16) /* BM: burst mode */
315     | ((cpu->byte_order == EMUL_BIG_ENDIAN? 1 : 0) << 15)
316     /* endian mode */
317     | ((cpu_type == MIPS_5Kc? 2 : 0) << 13)
318     /* 0=MIPS32, 1=64S, 2=64 */
319     | ( 0 << 10) /* Architecture revision */
320     | ( 1 << 7) /* MMU type: 1=TLB, 3=FMT */
321     | ( 2 << 0) /* kseg0 cache coherency algorithm */
322     ;
323     /* Config select 1: caches etc. TODO: Don't use
324     cpu->machine for this stuff! */
325     IB = cpu->machine->cache_picache_linesize - 1;
326     IB = IB < 0? 0 : (IB > 7? 7 : IB);
327     DB = cpu->machine->cache_pdcache_linesize - 1;
328     DB = DB < 0? 0 : (DB > 7? 7 : DB);
329     IC = cpu->machine->cache_picache -
330     cpu->machine->cache_picache_linesize - 7;
331     DC = cpu->machine->cache_pdcache -
332     cpu->machine->cache_pdcache_linesize - 7;
333     IA = cpu->cd.mips.cpu_type.piways - 1;
334     DA = cpu->cd.mips.cpu_type.pdways - 1;
335     cpu->cd.mips.cop0_config_select1 =
336     ((cpu->cd.mips.cpu_type.nr_of_tlb_entries - 1) << 25)
337     | (IC << 22) /* IS: I-cache sets per way */
338     | (IB << 19) /* IL: I-cache line-size */
339     | (IA << 16) /* IA: I-cache assoc. (ways-1) */
340     | (DC << 13) /* DS: D-cache sets per way */
341     | (DB << 10) /* DL: D-cache line-size */
342     | (DA << 7) /* DA: D-cache assoc. (ways-1) */
343     | (16 * 0) /* Existance of PerformanceCounters */
344     | ( 8 * 0) /* Existance of Watch Registers */
345     | ( 4 * m16) /* Existance of MIPS16 */
346     | ( 2 * 0) /* Existance of EJTAG */
347     | ( 1 * 1) /* Existance of FPU */
348     ;
349     break;
350     default:
351     ;
352     }
353     }
354    
355    
356     /*
357     * initialize_cop1():
358     *
359     * Helper function, called from mips_coproc_new().
360     */
361     static void initialize_cop1(struct cpu *cpu, struct mips_coproc *c)
362     {
363     int fpu_rev;
364     uint64_t other_stuff = 0;
365    
366     switch (cpu->cd.mips.cpu_type.rev & 0xff) {
367     case MIPS_R2000: fpu_rev = MIPS_R2010; break;
368     case MIPS_R3000: fpu_rev = MIPS_R3010;
369     other_stuff |= 0x40; /* or 0x30? TODO */
370     break;
371     case MIPS_R6000: fpu_rev = MIPS_R6010; break;
372     case MIPS_R4000: fpu_rev = MIPS_R4010; break;
373     case MIPS_4Kc: /* TODO: Is this the same as 5Kc? */
374     case MIPS_5Kc: other_stuff = COP1_REVISION_DOUBLE
375     | COP1_REVISION_SINGLE;
376     case MIPS_R5000:
377     case MIPS_RM5200: fpu_rev = cpu->cd.mips.cpu_type.rev;
378     other_stuff |= 0x10;
379     /* or cpu->cd.mips.cpu_type.sub ? TODO */
380     break;
381     case MIPS_R10000: fpu_rev = MIPS_R10000; break;
382     case MIPS_R12000: fpu_rev = 0x9; break;
383     default: fpu_rev = MIPS_SOFT;
384     }
385    
386     c->fcr[COP1_REVISION] = (fpu_rev << 8) | other_stuff;
387    
388     #if 0
389     /* These are mentioned in the MIPS64 documentation: */
390     + (1 << 16) /* single */
391     + (1 << 17) /* double */
392     + (1 << 18) /* paired-single */
393     + (1 << 19) /* 3d */
394     #endif
395     }
396    
397    
398     /*
399     * mips_coproc_new():
400     *
401     * Create a new MIPS coprocessor object.
402     */
403     struct mips_coproc *mips_coproc_new(struct cpu *cpu, int coproc_nr)
404     {
405     struct mips_coproc *c;
406    
407     c = malloc(sizeof(struct mips_coproc));
408     if (c == NULL) {
409     fprintf(stderr, "out of memory\n");
410     exit(1);
411     }
412    
413     memset(c, 0, sizeof(struct mips_coproc));
414     c->coproc_nr = coproc_nr;
415    
416     if (coproc_nr == 0) {
417     c->nr_of_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;
418 dpavlin 20 c->tlbs = zeroed_alloc(c->nr_of_tlbs * sizeof(struct mips_tlb));
419 dpavlin 14
420     /*
421     * Start with nothing in the status register. This makes sure
422     * that we are running in kernel mode with all interrupts
423     * disabled.
424     */
425     c->reg[COP0_STATUS] = 0;
426    
427     /* For userland emulation, enable all four coprocessors: */
428     if (cpu->machine->userland_emul)
429     c->reg[COP0_STATUS] |=
430     ((uint32_t)0xf << STATUS_CU_SHIFT);
431    
432     /* Hm. Enable coprocessors 0 and 1 even if we're not just
433     emulating userland? TODO: Think about this. */
434     /* if (cpu->machine->prom_emulation) */
435     c->reg[COP0_STATUS] |=
436     ((uint32_t)0x3 << STATUS_CU_SHIFT);
437    
438     if (!cpu->machine->prom_emulation)
439     c->reg[COP0_STATUS] |= STATUS_BEV;
440    
441     /* Default pagesize = 4 KB. */
442     c->reg[COP0_PAGEMASK] = 0x1fff;
443    
444     /* Note: .rev may contain the company ID as well! */
445     c->reg[COP0_PRID] =
446     (0x00 << 24) /* Company Options */
447     | (0x00 << 16) /* Company ID */
448     | (cpu->cd.mips.cpu_type.rev << 8) /* Processor ID */
449     | (cpu->cd.mips.cpu_type.sub) /* Revision */
450     ;
451    
452     c->reg[COP0_WIRED] = 0;
453    
454     initialize_cop0_config(cpu, c);
455    
456     /* Make sure the status register is sign-extended nicely: */
457     c->reg[COP0_STATUS] = (int64_t)(int32_t)c->reg[COP0_STATUS];
458     }
459    
460     if (coproc_nr == 1)
461     initialize_cop1(cpu, c);
462    
463     return c;
464     }
465    
466    
467     /*
468     * mips_coproc_tlb_set_entry():
469     *
470     * Used by machine setup code, if a specific machine emulation starts up
471     * with hardcoded virtual to physical mappings.
472     */
473     void mips_coproc_tlb_set_entry(struct cpu *cpu, int entrynr, int size,
474     uint64_t vaddr, uint64_t paddr0, uint64_t paddr1,
475     int valid0, int valid1, int dirty0, int dirty1, int global, int asid,
476     int cachealgo0, int cachealgo1)
477     {
478     if (entrynr < 0 || entrynr >= cpu->cd.mips.coproc[0]->nr_of_tlbs) {
479     printf("mips_coproc_tlb_set_entry(): invalid entry nr: %i\n",
480     entrynr);
481     exit(1);
482     }
483    
484     switch (cpu->cd.mips.cpu_type.mmu_model) {
485     case MMU3K:
486     if (size != 4096) {
487     printf("mips_coproc_tlb_set_entry(): invalid pagesize "
488     "(%i) for MMU3K\n", size);
489     exit(1);
490     }
491     cpu->cd.mips.coproc[0]->tlbs[entrynr].hi =
492     (vaddr & R2K3K_ENTRYHI_VPN_MASK) |
493     ((asid << R2K3K_ENTRYHI_ASID_SHIFT) &
494     R2K3K_ENTRYHI_ASID_MASK);
495     cpu->cd.mips.coproc[0]->tlbs[entrynr].lo0 =
496     (paddr0 & R2K3K_ENTRYLO_PFN_MASK) |
497     (cachealgo0? R2K3K_ENTRYLO_N : 0) |
498     (dirty0? R2K3K_ENTRYLO_D : 0) |
499     (valid0? R2K3K_ENTRYLO_V : 0) |
500     (global? R2K3K_ENTRYLO_G : 0);
501     break;
502     default:
503     /* MMU4K and MMU10K, etc: */
504     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
505     cpu->cd.mips.coproc[0]->tlbs[entrynr].hi =
506     (vaddr & ENTRYHI_VPN2_MASK_R10K) |
507     (vaddr & ENTRYHI_R_MASK) |
508     (asid & ENTRYHI_ASID) |
509     (global? TLB_G : 0);
510     else
511     cpu->cd.mips.coproc[0]->tlbs[entrynr].hi =
512     (vaddr & ENTRYHI_VPN2_MASK) |
513     (vaddr & ENTRYHI_R_MASK) |
514     (asid & ENTRYHI_ASID) |
515     (global? TLB_G : 0);
516     /* NOTE: The pagemask size is for a "dual" page: */
517     cpu->cd.mips.coproc[0]->tlbs[entrynr].mask =
518     (2*size - 1) & ~0x1fff;
519     cpu->cd.mips.coproc[0]->tlbs[entrynr].lo0 =
520     (((paddr0 >> 12) << ENTRYLO_PFN_SHIFT) &
521     ENTRYLO_PFN_MASK) |
522     (dirty0? ENTRYLO_D : 0) |
523     (valid0? ENTRYLO_V : 0) |
524     (global? ENTRYLO_G : 0) |
525     ((cachealgo0 << ENTRYLO_C_SHIFT) & ENTRYLO_C_MASK);
526     cpu->cd.mips.coproc[0]->tlbs[entrynr].lo1 =
527     (((paddr1 >> 12) << ENTRYLO_PFN_SHIFT) &
528     ENTRYLO_PFN_MASK) |
529     (dirty1? ENTRYLO_D : 0) |
530     (valid1? ENTRYLO_V : 0) |
531     (global? ENTRYLO_G : 0) |
532     ((cachealgo1 << ENTRYLO_C_SHIFT) & ENTRYLO_C_MASK);
533     /* TODO: R4100, 1KB pages etc */
534     }
535     }
536    
537    
538     /*
539     * old_update_translation_table():
540     */
541     static void old_update_translation_table(struct cpu *cpu, uint64_t vaddr_page,
542     unsigned char *host_page, int writeflag, uint64_t paddr_page)
543     {
544     int a, b, index;
545     struct vth32_table *tbl1;
546     void *p_r, *p_w;
547     uint32_t p_paddr;
548    
549     /* This table stuff only works for 32-bit mode: */
550     if (vaddr_page & 0x80000000ULL) {
551     if ((vaddr_page >> 32) != 0xffffffffULL)
552     return;
553     } else {
554     if ((vaddr_page >> 32) != 0)
555     return;
556     }
557    
558     a = (vaddr_page >> 22) & 0x3ff;
559     b = (vaddr_page >> 12) & 0x3ff;
560     index = (vaddr_page >> 12) & 0xfffff;
561    
562     /* printf("vaddr = %08x, a = %03x, b = %03x\n",
563     (int)vaddr_page,a, b); */
564    
565     tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];
566     /* printf("tbl1 = %p\n", tbl1); */
567     if (tbl1 == cpu->cd.mips.vaddr_to_hostaddr_nulltable) {
568     /* Allocate a new table1: */
569     /* printf("ALLOCATING a new table1, 0x%08x - "
570     "0x%08x\n", a << 22, (a << 22) + 0x3fffff); */
571     if (cpu->cd.mips.next_free_vth_table == NULL) {
572     tbl1 = malloc(sizeof(struct vth32_table));
573     if (tbl1 == NULL) {
574     fprintf(stderr, "out of mem\n");
575     exit(1);
576     }
577     memset(tbl1, 0, sizeof(struct vth32_table));
578     } else {
579     tbl1 = cpu->cd.mips.next_free_vth_table;
580     cpu->cd.mips.next_free_vth_table = tbl1->next_free;
581     tbl1->next_free = NULL;
582     }
583     cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a] = tbl1;
584     if (tbl1->refcount != 0) {
585     printf("INTERNAL ERROR in coproc.c\n");
586     exit(1);
587     }
588     }
589     p_r = tbl1->haddr_entry[b*2];
590     p_w = tbl1->haddr_entry[b*2+1];
591     p_paddr = tbl1->paddr_entry[b];
592     /* printf(" p_r=%p p_w=%p\n", p_r, p_w); */
593     if (p_r == NULL && p_paddr == 0 &&
594     (host_page != NULL || paddr_page != 0)) {
595     tbl1->refcount ++;
596     /* printf("ADDING %08x -> %p wf=%i (refcount is "
597     "now %i)\n", (int)vaddr_page, host_page,
598     writeflag, tbl1->refcount); */
599     }
600     if (writeflag == -1) {
601     /* Forced downgrade to read-only: */
602     tbl1->haddr_entry[b*2 + 1] = NULL;
603     if (cpu->cd.mips.host_store ==
604     cpu->cd.mips.host_store_orig)
605     cpu->cd.mips.host_store[index] = NULL;
606     } else if (writeflag==0 && p_w != NULL && host_page != NULL) {
607     /* Don't degrade a page from writable to readonly. */
608     } else {
609     if (host_page != NULL) {
610     tbl1->haddr_entry[b*2] = host_page;
611     if (cpu->cd.mips.host_load ==
612     cpu->cd.mips.host_load_orig)
613     cpu->cd.mips.host_load[index] = host_page;
614     if (writeflag) {
615     tbl1->haddr_entry[b*2+1] = host_page;
616     if (cpu->cd.mips.host_store ==
617     cpu->cd.mips.host_store_orig)
618     cpu->cd.mips.host_store[index] =
619     host_page;
620     } else {
621     tbl1->haddr_entry[b*2+1] = NULL;
622     if (cpu->cd.mips.host_store ==
623     cpu->cd.mips.host_store_orig)
624     cpu->cd.mips.host_store[index] = NULL;
625     }
626     } else {
627     tbl1->haddr_entry[b*2] = NULL;
628     tbl1->haddr_entry[b*2+1] = NULL;
629     if (cpu->cd.mips.host_store ==
630     cpu->cd.mips.host_store_orig) {
631     cpu->cd.mips.host_load[index] = NULL;
632     cpu->cd.mips.host_store[index] = NULL;
633     }
634     }
635     tbl1->paddr_entry[b] = paddr_page;
636     }
637     tbl1->bintrans_chunks[b] = NULL;
638     }
639    
640    
641     /*
642     * mips_update_translation_table():
643     */
644     void mips_update_translation_table(struct cpu *cpu, uint64_t vaddr_page,
645     unsigned char *host_page, int writeflag, uint64_t paddr_page)
646     {
647     if (!cpu->machine->bintrans_enable)
648     return;
649    
650     if (writeflag > 0)
651     bintrans_invalidate(cpu, paddr_page);
652    
653     if (cpu->machine->old_bintrans_enable) {
654     old_update_translation_table(cpu, vaddr_page, host_page,
655     writeflag, paddr_page);
656     return;
657     }
658    
659     /* TODO */
660     /* printf("update_translation_table(): TODO\n"); */
661     }
662    
663    
664     /*
665     * invalidate_table_entry():
666     */
667     static void invalidate_table_entry(struct cpu *cpu, uint64_t vaddr)
668     {
669     int a, b, index;
670     struct vth32_table *tbl1;
671     void *p_r, *p_w;
672     uint32_t p_paddr;
673    
674     if (!cpu->machine->old_bintrans_enable) {
675     /* printf("invalidate_table_entry(): New: TODO\n"); */
676     return;
677     }
678    
679     /* This table stuff only works for 32-bit mode: */
680     if (vaddr & 0x80000000ULL) {
681     if ((vaddr >> 32) != 0xffffffffULL) {
682     fatal("invalidate_table_entry(): vaddr = 0x%016llx\n",
683     (long long)vaddr);
684     return;
685     }
686     } else {
687     if ((vaddr >> 32) != 0) {
688     fatal("invalidate_table_entry(): vaddr = 0x%016llx\n",
689     (long long)vaddr);
690     return;
691     }
692     }
693    
694     a = (vaddr >> 22) & 0x3ff;
695     b = (vaddr >> 12) & 0x3ff;
696     index = (vaddr >> 12) & 0xfffff;
697    
698     /* printf("vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b); */
699    
700     tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];
701     /* printf("tbl1 = %p\n", tbl1); */
702     p_r = tbl1->haddr_entry[b*2];
703     p_w = tbl1->haddr_entry[b*2+1];
704     p_paddr = tbl1->paddr_entry[b];
705     tbl1->bintrans_chunks[b] = NULL;
706     /* printf("B: p_r=%p p_w=%p\n", p_r,p_w); */
707     cpu->cd.mips.host_load_orig[index] = NULL;
708     cpu->cd.mips.host_store_orig[index] = NULL;
709     if (p_r != NULL || p_paddr != 0) {
710     /* printf("Found a mapping, "
711     "vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b); */
712     tbl1->haddr_entry[b*2] = NULL;
713     tbl1->haddr_entry[b*2+1] = NULL;
714     tbl1->paddr_entry[b] = 0;
715     tbl1->refcount --;
716     if (tbl1->refcount == 0) {
717     cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a] =
718     cpu->cd.mips.vaddr_to_hostaddr_nulltable;
719     /* "free" tbl1: */
720     tbl1->next_free = cpu->cd.mips.next_free_vth_table;
721     cpu->cd.mips.next_free_vth_table = tbl1;
722     }
723     }
724     }
725    
726    
727     /*
728     * clear_all_chunks_from_all_tables():
729     */
730     void clear_all_chunks_from_all_tables(struct cpu *cpu)
731     {
732     int a, b;
733     struct vth32_table *tbl1;
734    
735     if (!cpu->machine->old_bintrans_enable) {
736     printf("clear_all_chunks_from_all_tables(): New: TODO\n");
737     return;
738     }
739    
740     for (a=0; a<0x400; a++) {
741     tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];
742     if (tbl1 != cpu->cd.mips.vaddr_to_hostaddr_nulltable) {
743     for (b=0; b<0x400; b++) {
744     int index;
745    
746     tbl1->haddr_entry[b*2] = NULL;
747     tbl1->haddr_entry[b*2+1] = NULL;
748     tbl1->paddr_entry[b] = 0;
749     tbl1->bintrans_chunks[b] = NULL;
750    
751     if (cpu->cd.mips.host_store ==
752     cpu->cd.mips.host_store_orig) {
753     index = (a << 10) + b;
754     cpu->cd.mips.host_load[index] = NULL;
755     cpu->cd.mips.host_store[index] = NULL;
756     }
757     }
758     }
759     }
760     }
761    
762    
763     /*
764     * mips_invalidate_translation_caches_paddr():
765     *
766     * Invalidate based on physical address.
767     */
768     void mips_invalidate_translation_caches_paddr(struct cpu *cpu,
769     uint64_t paddr, int flags)
770     {
771     paddr &= ~0xfff;
772    
773     if (cpu->machine->bintrans_enable) {
774     #if 1
775     int i;
776     uint64_t tlb_paddr0, tlb_paddr1;
777     uint64_t tlb_vaddr;
778     uint64_t p, p2;
779    
780     switch (cpu->cd.mips.cpu_type.mmu_model) {
781     case MMU3K:
782     for (i=0; i<64; i++) {
783     tlb_paddr0 = cpu->cd.mips.coproc[0]->
784     tlbs[i].lo0 & R2K3K_ENTRYLO_PFN_MASK;
785     tlb_vaddr = cpu->cd.mips.coproc[0]->
786     tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK;
787     tlb_vaddr = (int64_t)(int32_t)tlb_vaddr;
788     if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &
789     R2K3K_ENTRYLO_V) && tlb_paddr0 == paddr)
790     invalidate_table_entry(cpu, tlb_vaddr);
791     }
792     break;
793     default:
794     for (i=0; i<cpu->cd.mips.coproc[0]->nr_of_tlbs; i++) {
795     int psize = 12;
796     int or_pmask = 0x1fff;
797     int phys_shift = 12;
798 dpavlin 20 int tmp_pmask = cpu->cd.mips.coproc[0]->
799     tlbs[i].mask | or_pmask;
800 dpavlin 14
801     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
802     or_pmask = 0x7ff;
803     phys_shift = 10;
804     }
805 dpavlin 20 switch (tmp_pmask) {
806 dpavlin 14 case 0x000007ff: psize = 10; break;
807     case 0x00001fff: psize = 12; break;
808     case 0x00007fff: psize = 14; break;
809     case 0x0001ffff: psize = 16; break;
810     case 0x0007ffff: psize = 18; break;
811     case 0x001fffff: psize = 20; break;
812     case 0x007fffff: psize = 22; break;
813     case 0x01ffffff: psize = 24; break;
814     case 0x07ffffff: psize = 26; break;
815     default:
816     printf("invalidate_translation_caches"
817 dpavlin 20 "_paddr(): bad pagemask: 0x%x\n",
818     (int)tmp_pmask);
819 dpavlin 14 }
820     tlb_paddr0 = (cpu->cd.mips.coproc[0]->tlbs[i].
821     lo0 & ENTRYLO_PFN_MASK)>>ENTRYLO_PFN_SHIFT;
822     tlb_paddr1 = (cpu->cd.mips.coproc[0]->tlbs[i].
823     lo1 & ENTRYLO_PFN_MASK)>>ENTRYLO_PFN_SHIFT;
824     tlb_paddr0 <<= phys_shift;
825     tlb_paddr1 <<= phys_shift;
826     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
827     tlb_vaddr = cpu->cd.mips.coproc[0]->
828     tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;
829     if (tlb_vaddr & ((int64_t)1 << 43))
830     tlb_vaddr |=
831     0xfffff00000000000ULL;
832     } else {
833     tlb_vaddr = cpu->cd.mips.coproc[0]->
834     tlbs[i].hi & ENTRYHI_VPN2_MASK;
835     if (tlb_vaddr & ((int64_t)1 << 39))
836     tlb_vaddr |=
837     0xffffff0000000000ULL;
838     }
839     if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &
840     ENTRYLO_V) && paddr >= tlb_paddr0 &&
841     paddr < tlb_paddr0 + (1<<psize)) {
842     p2 = 1 << psize;
843     for (p=0; p<p2; p+=4096)
844     invalidate_table_entry(cpu,
845     tlb_vaddr + p);
846     }
847     if ((cpu->cd.mips.coproc[0]->tlbs[i].lo1 &
848     ENTRYLO_V) && paddr >= tlb_paddr1 &&
849     paddr < tlb_paddr1 + (1<<psize)) {
850     p2 = 1 << psize;
851     for (p=0; p<p2; p+=4096)
852     invalidate_table_entry(cpu,
853     tlb_vaddr + p +
854     (1 << psize));
855     }
856     }
857     }
858     #endif
859    
860     if (paddr < 0x20000000) {
861     invalidate_table_entry(cpu, 0xffffffff80000000ULL
862     + paddr);
863     invalidate_table_entry(cpu, 0xffffffffa0000000ULL
864     + paddr);
865     }
866     }
867    
868     #if 0
869     {
870     int i;
871    
872     /* TODO: Don't invalidate everything. */
873     for (i=0; i<N_BINTRANS_VADDR_TO_HOST; i++)
874     cpu->bintrans_data_hostpage[i] = NULL;
875     }
876     #endif
877     }
878    
879    
880     /*
881     * invalidate_translation_caches():
882     *
883     * This is necessary for every change to the TLB, and when the ASID is changed,
884     * so that for example user-space addresses are not cached when they should
885     * not be.
886     */
887     static void invalidate_translation_caches(struct cpu *cpu,
888     int all, uint64_t vaddr, int kernelspace, int old_asid_to_invalidate)
889     {
890     int i;
891    
892     /* printf("inval(all=%i, kernel=%i, addr=%016llx)\n",
893     all, kernelspace, (long long)vaddr); */
894    
895     if (!cpu->machine->bintrans_enable)
896     goto nobintrans;
897    
898     if (all) {
899     int i;
900     uint64_t tlb_vaddr;
901     switch (cpu->cd.mips.cpu_type.mmu_model) {
902     case MMU3K:
903     for (i=0; i<64; i++) {
904     tlb_vaddr = cpu->cd.mips.coproc[0]->tlbs[i].hi
905     & R2K3K_ENTRYHI_VPN_MASK;
906     tlb_vaddr = (int64_t)(int32_t)tlb_vaddr;
907     if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &
908     R2K3K_ENTRYLO_V) && (tlb_vaddr &
909     0xc0000000ULL) != 0x80000000ULL) {
910     int asid = (cpu->cd.mips.coproc[0]->
911     tlbs[i].hi & R2K3K_ENTRYHI_ASID_MASK
912     ) >> R2K3K_ENTRYHI_ASID_SHIFT;
913     if (old_asid_to_invalidate < 0 ||
914     old_asid_to_invalidate == asid)
915     invalidate_table_entry(cpu,
916     tlb_vaddr);
917     }
918     }
919     break;
920     default:
921     for (i=0; i<cpu->cd.mips.coproc[0]->nr_of_tlbs; i++) {
922     int psize = 10, or_pmask = 0x1fff;
923     int phys_shift = 12;
924    
925     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
926     or_pmask = 0x7ff;
927     phys_shift = 10;
928     }
929    
930     switch (cpu->cd.mips.coproc[0]->tlbs[i].mask
931     | or_pmask) {
932     case 0x000007ff: psize = 10; break;
933     case 0x00001fff: psize = 12; break;
934     case 0x00007fff: psize = 14; break;
935     case 0x0001ffff: psize = 16; break;
936     case 0x0007ffff: psize = 18; break;
937     case 0x001fffff: psize = 20; break;
938     case 0x007fffff: psize = 22; break;
939     case 0x01ffffff: psize = 24; break;
940     case 0x07ffffff: psize = 26; break;
941     default:
942     printf("invalidate_translation_caches"
943     "(): bad pagemask?\n");
944     }
945    
946     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
947     tlb_vaddr = cpu->cd.mips.coproc[0]->
948     tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;
949     if (tlb_vaddr & ((int64_t)1 << 43))
950     tlb_vaddr |=
951     0xfffff00000000000ULL;
952     } else {
953     tlb_vaddr = cpu->cd.mips.coproc[0]->
954     tlbs[i].hi & ENTRYHI_VPN2_MASK;
955     if (tlb_vaddr & ((int64_t)1 << 39))
956     tlb_vaddr |=
957     0xffffff0000000000ULL;
958     }
959    
960     /* TODO: Check the ASID etc. */
961    
962     invalidate_table_entry(cpu, tlb_vaddr);
963     invalidate_table_entry(cpu, tlb_vaddr |
964     (1 << psize));
965     }
966     }
967     } else
968     invalidate_table_entry(cpu, vaddr);
969    
970     nobintrans:
971    
972     /* TODO: Don't invalidate everything. */
973     for (i=0; i<N_BINTRANS_VADDR_TO_HOST; i++)
974     cpu->cd.mips.bintrans_data_hostpage[i] = NULL;
975    
976     if (kernelspace)
977     all = 1;
978    
979     #ifdef USE_TINY_CACHE
980     {
981     vaddr >>= 12;
982    
983     /* Invalidate the tiny translation cache... */
984     if (!cpu->machine->bintrans_enable)
985     for (i=0; i<N_TRANSLATION_CACHE_INSTR; i++)
986     if (all || vaddr == (cpu->cd.mips.
987     translation_cache_instr[i].vaddr_pfn))
988     cpu->cd.mips.translation_cache_instr[i].wf = 0;
989    
990     if (!cpu->machine->bintrans_enable)
991     for (i=0; i<N_TRANSLATION_CACHE_DATA; i++)
992     if (all || vaddr == (cpu->cd.mips.
993     translation_cache_data[i].vaddr_pfn))
994     cpu->cd.mips.translation_cache_data[i].wf = 0;
995     }
996     #endif
997     }
998    
999    
1000     /*
1001     * coproc_register_read();
1002     *
1003     * Read a value from a MIPS coprocessor register.
1004     */
1005     void coproc_register_read(struct cpu *cpu,
1006     struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int select)
1007     {
1008     int unimpl = 1;
1009    
1010     if (cp->coproc_nr==0 && reg_nr==COP0_INDEX) unimpl = 0;
1011     if (cp->coproc_nr==0 && reg_nr==COP0_RANDOM) unimpl = 0;
1012     if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYLO0) unimpl = 0;
1013     if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYLO1) unimpl = 0;
1014     if (cp->coproc_nr==0 && reg_nr==COP0_CONTEXT) unimpl = 0;
1015     if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK) unimpl = 0;
1016     if (cp->coproc_nr==0 && reg_nr==COP0_WIRED) unimpl = 0;
1017     if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR) unimpl = 0;
1018     if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) {
1019 dpavlin 20 #if 0
1020 dpavlin 14 /*
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 dpavlin 20 #endif
1041 dpavlin 14 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 dpavlin 20 static int mips_fmt_to_ieee_fmt[32] = {
1430     0, 0, 0, 0, 0, 0, 0, 0,
1431     0, 0, 0, 0, 0, 0, 0, 0,
1432     IEEE_FMT_S, IEEE_FMT_D, 0, 0,
1433     IEEE_FMT_W, IEEE_FMT_L, /* PS (Paired Single) */ 0, 0,
1434     0, 0, 0, 0, 0, 0, 0, 0 };
1435    
1436     /* MIPS floating point types: */
1437 dpavlin 14 #define FMT_S 16
1438     #define FMT_D 17
1439     #define FMT_W 20
1440     #define FMT_L 21
1441     #define FMT_PS 22
1442    
1443     #define FPU_OP_ADD 1
1444     #define FPU_OP_SUB 2
1445     #define FPU_OP_MUL 3
1446     #define FPU_OP_DIV 4
1447     #define FPU_OP_SQRT 5
1448     #define FPU_OP_MOV 6
1449     #define FPU_OP_CVT 7
1450     #define FPU_OP_C 8
1451     #define FPU_OP_ABS 9
1452     #define FPU_OP_NEG 10
1453 dpavlin 20 /* TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W, RSQRT */
1454 dpavlin 14
1455    
1456     /*
1457     * fpu_store_float_value():
1458     *
1459     * Stores a float value (actually a double) in fmt format.
1460     */
1461     static void fpu_store_float_value(struct mips_coproc *cp, int fd,
1462     double nf, int fmt, int nan)
1463     {
1464 dpavlin 20 int ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1465     uint64_t r = ieee_store_float_value(nf, ieee_fmt, nan);
1466 dpavlin 14
1467     /*
1468 dpavlin 20 * TODO: This is for 32-bit mode. It has to be updated later
1469     * for 64-bit coprocessor functionality!
1470 dpavlin 14 */
1471     if (fmt == FMT_D || fmt == FMT_L) {
1472     cp->reg[fd] = r & 0xffffffffULL;
1473     cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;
1474    
1475     if (cp->reg[fd] & 0x80000000ULL)
1476     cp->reg[fd] |= 0xffffffff00000000ULL;
1477     if (cp->reg[fd+1] & 0x80000000ULL)
1478     cp->reg[fd+1] |= 0xffffffff00000000ULL;
1479     } else {
1480     cp->reg[fd] = r & 0xffffffffULL;
1481    
1482     if (cp->reg[fd] & 0x80000000ULL)
1483     cp->reg[fd] |= 0xffffffff00000000ULL;
1484     }
1485     }
1486    
1487    
1488     /*
1489     * fpu_op():
1490     *
1491 dpavlin 20 * Perform a floating-point operation. For those of fs and ft that are >= 0,
1492     * those numbers are interpreted into local variables.
1493 dpavlin 14 *
1494 dpavlin 20 * Only FPU_OP_C (compare) returns anything of interest, 1 for true, 0 for
1495     * false.
1496 dpavlin 14 */
1497     static int fpu_op(struct cpu *cpu, struct mips_coproc *cp, int op, int fmt,
1498     int ft, int fs, int fd, int cond, int output_fmt)
1499     {
1500     /* Potentially two input registers, fs and ft */
1501 dpavlin 20 struct ieee_float_value float_value[2];
1502     int unordered, nan, ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1503 dpavlin 14 uint64_t fs_v = 0;
1504     double nf;
1505    
1506     if (fs >= 0) {
1507     fs_v = cp->reg[fs];
1508     /* TODO: register-pair mode and plain
1509     register mode? "FR" bit? */
1510     if (fmt == FMT_D || fmt == FMT_L)
1511     fs_v = (fs_v & 0xffffffffULL) +
1512     (cp->reg[(fs + 1) & 31] << 32);
1513 dpavlin 20 ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);
1514 dpavlin 14 }
1515     if (ft >= 0) {
1516     uint64_t v = cp->reg[ft];
1517     /* TODO: register-pair mode and
1518     plain register mode? "FR" bit? */
1519     if (fmt == FMT_D || fmt == FMT_L)
1520     v = (v & 0xffffffffULL) +
1521     (cp->reg[(ft + 1) & 31] << 32);
1522 dpavlin 20 ieee_interpret_float_value(v, &float_value[1], ieee_fmt);
1523 dpavlin 14 }
1524    
1525     switch (op) {
1526     case FPU_OP_ADD:
1527     nf = float_value[0].f + float_value[1].f;
1528     /* debug(" add: %f + %f = %f\n",
1529     float_value[0].f, float_value[1].f, nf); */
1530     fpu_store_float_value(cp, fd, nf, output_fmt,
1531     float_value[0].nan || float_value[1].nan);
1532     break;
1533     case FPU_OP_SUB:
1534     nf = float_value[0].f - float_value[1].f;
1535     /* debug(" sub: %f - %f = %f\n",
1536     float_value[0].f, float_value[1].f, nf); */
1537     fpu_store_float_value(cp, fd, nf, output_fmt,
1538     float_value[0].nan || float_value[1].nan);
1539     break;
1540     case FPU_OP_MUL:
1541     nf = float_value[0].f * float_value[1].f;
1542     /* debug(" mul: %f * %f = %f\n",
1543     float_value[0].f, float_value[1].f, nf); */
1544     fpu_store_float_value(cp, fd, nf, output_fmt,
1545     float_value[0].nan || float_value[1].nan);
1546     break;
1547     case FPU_OP_DIV:
1548     nan = float_value[0].nan || float_value[1].nan;
1549     if (fabs(float_value[1].f) > 0.00000000001)
1550     nf = float_value[0].f / float_value[1].f;
1551     else {
1552     fatal("DIV by zero !!!!\n");
1553     nf = 0.0; /* TODO */
1554     nan = 1;
1555     }
1556     /* debug(" div: %f / %f = %f\n",
1557     float_value[0].f, float_value[1].f, nf); */
1558     fpu_store_float_value(cp, fd, nf, output_fmt, nan);
1559     break;
1560     case FPU_OP_SQRT:
1561     nan = float_value[0].nan;
1562     if (float_value[0].f >= 0.0)
1563     nf = sqrt(float_value[0].f);
1564     else {
1565     fatal("SQRT by less than zero, %f !!!!\n",
1566     float_value[0].f);
1567     nf = 0.0; /* TODO */
1568     nan = 1;
1569     }
1570     /* debug(" sqrt: %f => %f\n", float_value[0].f, nf); */
1571     fpu_store_float_value(cp, fd, nf, output_fmt, nan);
1572     break;
1573     case FPU_OP_ABS:
1574     nf = fabs(float_value[0].f);
1575     /* debug(" abs: %f => %f\n", float_value[0].f, nf); */
1576     fpu_store_float_value(cp, fd, nf, output_fmt,
1577     float_value[0].nan);
1578     break;
1579     case FPU_OP_NEG:
1580     nf = - float_value[0].f;
1581     /* debug(" neg: %f => %f\n", float_value[0].f, nf); */
1582     fpu_store_float_value(cp, fd, nf, output_fmt,
1583     float_value[0].nan);
1584     break;
1585     case FPU_OP_CVT:
1586     nf = float_value[0].f;
1587     /* debug(" mov: %f => %f\n", float_value[0].f, nf); */
1588     fpu_store_float_value(cp, fd, nf, output_fmt,
1589     float_value[0].nan);
1590     break;
1591     case FPU_OP_MOV:
1592     /* Non-arithmetic move: */
1593     /*
1594     * TODO: this is for 32-bit mode. It has to be updated later
1595     * for 64-bit coprocessor stuff.
1596     */
1597     if (output_fmt == FMT_D || output_fmt == FMT_L) {
1598     cp->reg[fd] = fs_v & 0xffffffffULL;
1599     cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;
1600     if (cp->reg[fd] & 0x80000000ULL)
1601     cp->reg[fd] |= 0xffffffff00000000ULL;
1602     if (cp->reg[fd+1] & 0x80000000ULL)
1603     cp->reg[fd+1] |= 0xffffffff00000000ULL;
1604     } else {
1605     cp->reg[fd] = fs_v & 0xffffffffULL;
1606     if (cp->reg[fd] & 0x80000000ULL)
1607     cp->reg[fd] |= 0xffffffff00000000ULL;
1608     }
1609     break;
1610     case FPU_OP_C:
1611     /* debug(" c: cond=%i\n", cond); */
1612    
1613     unordered = 0;
1614     if (float_value[0].nan || float_value[1].nan)
1615     unordered = 1;
1616    
1617     switch (cond) {
1618     case 2: /* Equal */
1619     return (float_value[0].f == float_value[1].f);
1620     case 4: /* Ordered or Less than */
1621     return (float_value[0].f < float_value[1].f)
1622     || !unordered;
1623     case 5: /* Unordered or Less than */
1624     return (float_value[0].f < float_value[1].f)
1625     || unordered;
1626     case 6: /* Ordered or Less than or Equal */
1627     return (float_value[0].f <= float_value[1].f)
1628     || !unordered;
1629     case 7: /* Unordered or Less than or Equal */
1630     return (float_value[0].f <= float_value[1].f)
1631     || unordered;
1632     case 12:/* Less than */
1633     return (float_value[0].f < float_value[1].f);
1634     case 14:/* Less than or equal */
1635     return (float_value[0].f <= float_value[1].f);
1636    
1637     /* The following are not commonly used, so I'll move these out
1638     of the if-0 on a case-by-case basis. */
1639     #if 0
1640     case 0: return 0; /* False */
1641     case 1: return 0; /* Unordered */
1642     case 3: return (float_value[0].f == float_value[1].f);
1643     /* Unordered or Equal */
1644     case 8: return 0; /* Signaling false */
1645     case 9: return 0; /* Not Greater than or Less than or Equal */
1646     case 10:return (float_value[0].f == float_value[1].f); /* Signaling Equal */
1647     case 11:return (float_value[0].f == float_value[1].f); /* Not Greater
1648     than or Less than */
1649     case 13:return !(float_value[0].f >= float_value[1].f); /* Not greater
1650     than or equal */
1651     case 15:return !(float_value[0].f > float_value[1].f); /* Not greater than */
1652     #endif
1653    
1654     default:
1655     fatal("fpu_op(): unimplemented condition "
1656     "code %i. see cpu_mips_coproc.c\n", cond);
1657     }
1658     break;
1659     default:
1660     fatal("fpu_op(): unimplemented op %i\n", op);
1661     }
1662    
1663     return 0;
1664     }
1665    
1666    
1667     /*
1668     * fpu_function():
1669     *
1670     * Returns 1 if function was implemented, 0 otherwise.
1671     * Debug trace should be printed for known instructions.
1672     */
1673     static int fpu_function(struct cpu *cpu, struct mips_coproc *cp,
1674     uint32_t function, int unassemble_only)
1675     {
1676     int fd, fs, ft, fmt, cond, cc;
1677    
1678     fmt = (function >> 21) & 31;
1679     ft = (function >> 16) & 31;
1680     fs = (function >> 11) & 31;
1681     cc = (function >> 8) & 7;
1682     fd = (function >> 6) & 31;
1683     cond = (function >> 0) & 15;
1684    
1685    
1686     /* bc1f, bc1t, bc1fl, bc1tl: */
1687     if ((function & 0x03e00000) == 0x01000000) {
1688     int nd, tf, imm, cond_true;
1689     char *instr_mnem;
1690    
1691     /* cc are bits 20..18: */
1692     cc = (function >> 18) & 7;
1693     nd = (function >> 17) & 1;
1694     tf = (function >> 16) & 1;
1695     imm = function & 65535;
1696     if (imm >= 32768)
1697     imm -= 65536;
1698    
1699     instr_mnem = NULL;
1700     if (nd == 0 && tf == 0) instr_mnem = "bc1f";
1701     if (nd == 0 && tf == 1) instr_mnem = "bc1t";
1702     if (nd == 1 && tf == 0) instr_mnem = "bc1fl";
1703     if (nd == 1 && tf == 1) instr_mnem = "bc1tl";
1704    
1705     if (cpu->machine->instruction_trace || unassemble_only)
1706     debug("%s\t%i,0x%016llx\n", instr_mnem, cc,
1707     (long long) (cpu->pc + (imm << 2)));
1708     if (unassemble_only)
1709     return 1;
1710    
1711     if (cpu->cd.mips.delay_slot) {
1712     fatal("%s: jump inside a jump's delay slot, "
1713     "or similar. TODO\n", instr_mnem);
1714     cpu->running = 0;
1715     return 1;
1716     }
1717    
1718     /* Both the FCCR and FCSR contain condition code bits... */
1719     if (cc == 0)
1720     cond_true = (cp->fcr[FPU_FCSR] >> FCSR_FCC0_SHIFT) & 1;
1721     else
1722     cond_true = (cp->fcr[FPU_FCSR] >>
1723     (FCSR_FCC1_SHIFT + cc-1)) & 1;
1724    
1725     if (!tf)
1726     cond_true = !cond_true;
1727    
1728     if (cond_true) {
1729     cpu->cd.mips.delay_slot = TO_BE_DELAYED;
1730     cpu->cd.mips.delay_jmpaddr = cpu->pc + (imm << 2);
1731     } else {
1732     /* "likely": */
1733     if (nd) {
1734     /* nullify the delay slot */
1735     cpu->cd.mips.nullify_next = 1;
1736     }
1737     }
1738    
1739     return 1;
1740     }
1741    
1742     /* add.fmt: Floating-point add */
1743     if ((function & 0x0000003f) == 0x00000000) {
1744     if (cpu->machine->instruction_trace || unassemble_only)
1745     debug("add.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);
1746     if (unassemble_only)
1747     return 1;
1748    
1749     fpu_op(cpu, cp, FPU_OP_ADD, fmt, ft, fs, fd, -1, fmt);
1750     return 1;
1751     }
1752    
1753     /* sub.fmt: Floating-point subtract */
1754     if ((function & 0x0000003f) == 0x00000001) {
1755     if (cpu->machine->instruction_trace || unassemble_only)
1756     debug("sub.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);
1757     if (unassemble_only)
1758     return 1;
1759    
1760     fpu_op(cpu, cp, FPU_OP_SUB, fmt, ft, fs, fd, -1, fmt);
1761     return 1;
1762     }
1763    
1764     /* mul.fmt: Floating-point multiply */
1765     if ((function & 0x0000003f) == 0x00000002) {
1766     if (cpu->machine->instruction_trace || unassemble_only)
1767     debug("mul.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);
1768     if (unassemble_only)
1769     return 1;
1770    
1771     fpu_op(cpu, cp, FPU_OP_MUL, fmt, ft, fs, fd, -1, fmt);
1772     return 1;
1773     }
1774    
1775     /* div.fmt: Floating-point divide */
1776     if ((function & 0x0000003f) == 0x00000003) {
1777     if (cpu->machine->instruction_trace || unassemble_only)
1778     debug("div.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);
1779     if (unassemble_only)
1780     return 1;
1781    
1782     fpu_op(cpu, cp, FPU_OP_DIV, fmt, ft, fs, fd, -1, fmt);
1783     return 1;
1784     }
1785    
1786     /* sqrt.fmt: Floating-point square-root */
1787     if ((function & 0x001f003f) == 0x00000004) {
1788     if (cpu->machine->instruction_trace || unassemble_only)
1789     debug("sqrt.%i\tr%i,r%i\n", fmt, fd, fs);
1790     if (unassemble_only)
1791     return 1;
1792    
1793     fpu_op(cpu, cp, FPU_OP_SQRT, fmt, -1, fs, fd, -1, fmt);
1794     return 1;
1795     }
1796    
1797     /* abs.fmt: Floating-point absolute value */
1798     if ((function & 0x001f003f) == 0x00000005) {
1799     if (cpu->machine->instruction_trace || unassemble_only)
1800     debug("abs.%i\tr%i,r%i\n", fmt, fd, fs);
1801     if (unassemble_only)
1802     return 1;
1803    
1804     fpu_op(cpu, cp, FPU_OP_ABS, fmt, -1, fs, fd, -1, fmt);
1805     return 1;
1806     }
1807    
1808     /* mov.fmt: Floating-point (non-arithmetic) move */
1809     if ((function & 0x0000003f) == 0x00000006) {
1810     if (cpu->machine->instruction_trace || unassemble_only)
1811     debug("mov.%i\tr%i,r%i\n", fmt, fd, fs);
1812     if (unassemble_only)
1813     return 1;
1814    
1815     fpu_op(cpu, cp, FPU_OP_MOV, fmt, -1, fs, fd, -1, fmt);
1816     return 1;
1817     }
1818    
1819     /* neg.fmt: Floating-point negate */
1820     if ((function & 0x001f003f) == 0x00000007) {
1821     if (cpu->machine->instruction_trace || unassemble_only)
1822     debug("neg.%i\tr%i,r%i\n", fmt, fd, fs);
1823     if (unassemble_only)
1824     return 1;
1825    
1826     fpu_op(cpu, cp, FPU_OP_NEG, fmt, -1, fs, fd, -1, fmt);
1827     return 1;
1828     }
1829    
1830     /* trunc.l.fmt: Truncate */
1831     if ((function & 0x001f003f) == 0x00000009) {
1832     if (cpu->machine->instruction_trace || unassemble_only)
1833     debug("trunc.l.%i\tr%i,r%i\n", fmt, fd, fs);
1834     if (unassemble_only)
1835     return 1;
1836    
1837     /* TODO: not CVT? */
1838    
1839     fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_L);
1840     return 1;
1841     }
1842    
1843     /* trunc.w.fmt: Truncate */
1844     if ((function & 0x001f003f) == 0x0000000d) {
1845     if (cpu->machine->instruction_trace || unassemble_only)
1846     debug("trunc.w.%i\tr%i,r%i\n", fmt, fd, fs);
1847     if (unassemble_only)
1848     return 1;
1849    
1850     /* TODO: not CVT? */
1851    
1852     fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_W);
1853     return 1;
1854     }
1855    
1856     /* c.cond.fmt: Floating-point compare */
1857     if ((function & 0x000000f0) == 0x00000030) {
1858     int cond_true;
1859     int bit;
1860    
1861     if (cpu->machine->instruction_trace || unassemble_only)
1862     debug("c.%i.%i\tr%i,r%i,r%i\n", cond, fmt, cc, fs, ft);
1863     if (unassemble_only)
1864     return 1;
1865    
1866     cond_true = fpu_op(cpu, cp, FPU_OP_C, fmt,
1867     ft, fs, -1, cond, fmt);
1868    
1869     /*
1870     * Both the FCCR and FCSR contain condition code bits:
1871     * FCCR: bits 7..0
1872     * FCSR: bits 31..25 and 23
1873     */
1874     cp->fcr[FPU_FCCR] &= ~(1 << cc);
1875     if (cond_true)
1876     cp->fcr[FPU_FCCR] |= (1 << cc);
1877    
1878     if (cc == 0) {
1879     bit = 1 << FCSR_FCC0_SHIFT;
1880     cp->fcr[FPU_FCSR] &= ~bit;
1881     if (cond_true)
1882     cp->fcr[FPU_FCSR] |= bit;
1883     } else {
1884     bit = 1 << (FCSR_FCC1_SHIFT + cc-1);
1885     cp->fcr[FPU_FCSR] &= ~bit;
1886     if (cond_true)
1887     cp->fcr[FPU_FCSR] |= bit;
1888     }
1889    
1890     return 1;
1891     }
1892    
1893     /* cvt.s.fmt: Convert to single floating-point */
1894     if ((function & 0x001f003f) == 0x00000020) {
1895     if (cpu->machine->instruction_trace || unassemble_only)
1896     debug("cvt.s.%i\tr%i,r%i\n", fmt, fd, fs);
1897     if (unassemble_only)
1898     return 1;
1899    
1900     fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_S);
1901     return 1;
1902     }
1903    
1904     /* cvt.d.fmt: Convert to double floating-point */
1905     if ((function & 0x001f003f) == 0x00000021) {
1906     if (cpu->machine->instruction_trace || unassemble_only)
1907     debug("cvt.d.%i\tr%i,r%i\n", fmt, fd, fs);
1908     if (unassemble_only)
1909     return 1;
1910    
1911     fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_D);
1912     return 1;
1913     }
1914    
1915     /* cvt.w.fmt: Convert to word fixed-point */
1916     if ((function & 0x001f003f) == 0x00000024) {
1917     if (cpu->machine->instruction_trace || unassemble_only)
1918     debug("cvt.w.%i\tr%i,r%i\n", fmt, fd, fs);
1919     if (unassemble_only)
1920     return 1;
1921    
1922     fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_W);
1923     return 1;
1924     }
1925    
1926     return 0;
1927     }
1928    
1929    
1930     /*
1931     * coproc_tlbpr():
1932     *
1933     * 'tlbp' and 'tlbr'.
1934     */
1935     void coproc_tlbpr(struct cpu *cpu, int readflag)
1936     {
1937     struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1938     int i, found, g_bit;
1939     uint64_t vpn2, xmask;
1940    
1941     /* Read: */
1942     if (readflag) {
1943     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1944     i = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK) >>
1945     R2K3K_INDEX_SHIFT;
1946     if (i >= cp->nr_of_tlbs) {
1947     /* TODO: exception? */
1948     fatal("warning: tlbr from index %i (too "
1949     "high)\n", i);
1950     return;
1951     }
1952    
1953     /*
1954     * TODO: Hm. Earlier I had an & ~0x3f on the high
1955     * assignment and an & ~0xff on the lo0 assignment.
1956     * I wonder why.
1957     */
1958    
1959     cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi; /* & ~0x3f; */
1960     cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;/* & ~0xff; */
1961     } else {
1962     /* R4000: */
1963     i = cp->reg[COP0_INDEX] & INDEX_MASK;
1964     if (i >= cp->nr_of_tlbs) /* TODO: exception */
1965     return;
1966    
1967     cp->reg[COP0_PAGEMASK] = cp->tlbs[i].mask;
1968     cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi;
1969     cp->reg[COP0_ENTRYLO1] = cp->tlbs[i].lo1;
1970     cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;
1971    
1972     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1973     /* R4100 don't have the G bit in entryhi */
1974     } else {
1975     /* R4000 etc: */
1976     cp->reg[COP0_ENTRYHI] &= ~TLB_G;
1977     g_bit = cp->tlbs[i].hi & TLB_G;
1978    
1979     cp->reg[COP0_ENTRYLO0] &= ~ENTRYLO_G;
1980     cp->reg[COP0_ENTRYLO1] &= ~ENTRYLO_G;
1981     if (g_bit) {
1982     cp->reg[COP0_ENTRYLO0] |= ENTRYLO_G;
1983     cp->reg[COP0_ENTRYLO1] |= ENTRYLO_G;
1984     }
1985     }
1986     }
1987    
1988     return;
1989     }
1990    
1991     /* Probe: */
1992     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1993     vpn2 = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1994     found = -1;
1995     for (i=0; i<cp->nr_of_tlbs; i++)
1996     if ( ((cp->tlbs[i].hi & R2K3K_ENTRYHI_ASID_MASK) ==
1997     (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK))
1998     || cp->tlbs[i].lo0 & R2K3K_ENTRYLO_G)
1999     if ((cp->tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK)
2000     == vpn2) {
2001     found = i;
2002     break;
2003     }
2004     } else {
2005     /* R4000 and R10000: */
2006     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
2007     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K;
2008     else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
2009     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800;
2010     else
2011     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK;
2012     vpn2 = cp->reg[COP0_ENTRYHI] & xmask;
2013     found = -1;
2014     for (i=0; i<cp->nr_of_tlbs; i++) {
2015     int gbit = cp->tlbs[i].hi & TLB_G;
2016     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
2017     gbit = (cp->tlbs[i].lo0 & ENTRYLO_G) &&
2018     (cp->tlbs[i].lo1 & ENTRYLO_G);
2019    
2020     if ( ((cp->tlbs[i].hi & ENTRYHI_ASID) ==
2021     (cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID)) || gbit) {
2022     uint64_t a = vpn2 & ~cp->tlbs[i].mask;
2023     uint64_t b = (cp->tlbs[i].hi & xmask) &
2024     ~cp->tlbs[i].mask;
2025     if (a == b) {
2026     found = i;
2027     break;
2028     }
2029     }
2030     }
2031     }
2032     if (found == -1)
2033     cp->reg[COP0_INDEX] = INDEX_P;
2034     else {
2035     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
2036     cp->reg[COP0_INDEX] = found << R2K3K_INDEX_SHIFT;
2037     else
2038     cp->reg[COP0_INDEX] = found;
2039     }
2040    
2041     /* Sign extend the index register: */
2042     if ((cp->reg[COP0_INDEX] >> 32) == 0 &&
2043     cp->reg[COP0_INDEX] & 0x80000000)
2044     cp->reg[COP0_INDEX] |=
2045     0xffffffff00000000ULL;
2046     }
2047    
2048    
2049     /*
2050     * coproc_tlbwri():
2051     *
2052     * 'tlbwr' and 'tlbwi'
2053     */
2054     void coproc_tlbwri(struct cpu *cpu, int randomflag)
2055     {
2056     struct mips_coproc *cp = cpu->cd.mips.coproc[0];
2057     int index, g_bit;
2058     uint64_t oldvaddr;
2059     int old_asid = -1;
2060    
2061     /*
2062     * ... and the last instruction page:
2063     *
2064     * Some thoughts about this: Code running in
2065     * the kernel's physical address space has the
2066     * same vaddr->paddr translation, so the last
2067     * virtual page invalidation only needs to
2068     * happen if we are for some extremely weird
2069     * reason NOT running in the kernel's physical
2070     * address space.
2071     *
2072     * (An even insaner (but probably useless)
2073     * optimization would be to only invalidate
2074     * the last virtual page stuff if the TLB
2075     * update actually affects the vaddr in
2076     * question.)
2077     */
2078    
2079     if (cpu->pc < (uint64_t)0xffffffff80000000ULL ||
2080     cpu->pc >= (uint64_t)0xffffffffc0000000ULL)
2081     cpu->cd.mips.pc_last_virtual_page =
2082     PC_LAST_PAGE_IMPOSSIBLE_VALUE;
2083    
2084     if (randomflag) {
2085     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
2086     index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
2087     >> R2K3K_RANDOM_SHIFT;
2088     else
2089     index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
2090     } else {
2091     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
2092     index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK)
2093     >> R2K3K_INDEX_SHIFT;
2094     else
2095     index = cp->reg[COP0_INDEX] & INDEX_MASK;
2096     }
2097    
2098     if (index >= cp->nr_of_tlbs) {
2099     fatal("warning: tlb index %i too high (max is %i)\n",
2100     index, cp->nr_of_tlbs - 1);
2101     /* TODO: cause an exception? */
2102     return;
2103     }
2104    
2105     #if 0
2106     /* Debug dump of the previous entry at that index: */
2107     debug(" old entry at index = %04x", index);
2108     debug(" mask = %016llx", (long long) cp->tlbs[index].mask);
2109     debug(" hi = %016llx", (long long) cp->tlbs[index].hi);
2110     debug(" lo0 = %016llx", (long long) cp->tlbs[index].lo0);
2111     debug(" lo1 = %016llx\n", (long long) cp->tlbs[index].lo1);
2112     #endif
2113    
2114     /* Translation caches must be invalidated: */
2115     switch (cpu->cd.mips.cpu_type.mmu_model) {
2116     case MMU3K:
2117     oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
2118     oldvaddr &= 0xffffffffULL;
2119     if (oldvaddr & 0x80000000ULL)
2120     oldvaddr |= 0xffffffff00000000ULL;
2121     old_asid = (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK)
2122     >> R2K3K_ENTRYHI_ASID_SHIFT;
2123    
2124     /* TODO: Bug? Why does this if need to be commented out? */
2125    
2126     /* if (cp->tlbs[index].lo0 & ENTRYLO_V) */
2127     invalidate_translation_caches(cpu, 0, oldvaddr, 0, 0);
2128     break;
2129     default:
2130     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
2131     oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
2132     /* 44 addressable bits: */
2133     if (oldvaddr & 0x80000000000ULL)
2134     oldvaddr |= 0xfffff00000000000ULL;
2135     } else {
2136     /* Assume MMU4K */
2137     oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
2138     /* 40 addressable bits: */
2139     if (oldvaddr & 0x8000000000ULL)
2140     oldvaddr |= 0xffffff0000000000ULL;
2141     }
2142    
2143     /*
2144     * Both pages:
2145     *
2146     * TODO: non-4KB page sizes!
2147     */
2148     invalidate_translation_caches(
2149     cpu, 0, oldvaddr & ~0x1fff, 0, 0);
2150     invalidate_translation_caches(
2151     cpu, 0, (oldvaddr & ~0x1fff) | 0x1000, 0, 0);
2152     }
2153    
2154    
2155     /*
2156     * Check for duplicate entries. (There should not be two mappings
2157     * from one virtual address to physical addresses.)
2158     *
2159     * TODO: Do this for MMU3K and R4100 too.
2160     *
2161     * TODO: Make this detection more robust.
2162     */
2163     if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&
2164     cpu->cd.mips.cpu_type.rev != MIPS_R4100) {
2165     uint64_t vaddr1, vaddr2;
2166     int i, asid;
2167    
2168     vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;
2169     asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
2170     /* Since this is just a warning, it's probably not necessary
2171     to use R4000 masks etc. */
2172    
2173     for (i=0; i<cp->nr_of_tlbs; i++) {
2174     if (i == index && !randomflag)
2175     continue;
2176    
2177     if (!(cp->tlbs[i].hi & TLB_G) &&
2178     (cp->tlbs[i].hi & ENTRYHI_ASID) != asid)
2179     continue;
2180    
2181     vaddr2 = cp->tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;
2182     if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 &
2183     ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V)))
2184     fatal("\n[ WARNING! tlbw%s to index 0x%02x "
2185     "vaddr=0x%llx (asid 0x%02x) is already in"
2186     " the TLB (entry 0x%02x) ! ]\n\n",
2187     randomflag? "r" : "i", index,
2188     (long long)vaddr1, asid, i);
2189     }
2190     }
2191    
2192    
2193     /* Write the new entry: */
2194    
2195     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
2196     uint64_t vaddr, paddr;
2197     int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;
2198     unsigned char *memblock = NULL;
2199    
2200     cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI];
2201     cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0];
2202    
2203     vaddr = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
2204     paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;
2205    
2206     /* TODO: This is ugly. */
2207     if (paddr < 0x10000000)
2208     memblock = memory_paddr_to_hostaddr(
2209     cpu->mem, paddr, 1);
2210    
2211     if (memblock != NULL &&
2212     cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {
2213     memblock += (paddr & ((1 << BITS_PER_PAGETABLE) - 1));
2214    
2215     /*
2216     * TODO: Hahaha, this is even uglier than the thing
2217     * above. Some OSes seem to map code pages read/write,
2218     * which causes the bintrans cache to be invalidated
2219     * even when it doesn't have to be.
2220     */
2221     /* if (vaddr < 0x10000000) */
2222     wf = 0;
2223    
2224     cpu->update_translation_table(cpu, vaddr, memblock,
2225     wf, paddr);
2226     }
2227     } else {
2228     /* R4000: */
2229     g_bit = (cp->reg[COP0_ENTRYLO0] &
2230     cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
2231     cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];
2232     cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI];
2233     cp->tlbs[index].lo1 = cp->reg[COP0_ENTRYLO1];
2234     cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0];
2235    
2236     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
2237     /* NOTE: The VR4131 (and possibly others) don't have
2238     a Global bit in entryhi */
2239     cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK];
2240     } else {
2241     cp->tlbs[index].lo0 &= ~ENTRYLO_G;
2242     cp->tlbs[index].lo1 &= ~ENTRYLO_G;
2243    
2244     cp->tlbs[index].hi &= ~TLB_G;
2245     if (g_bit)
2246     cp->tlbs[index].hi |= TLB_G;
2247     }
2248     }
2249    
2250     if (randomflag) {
2251     if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
2252     cp->reg[COP0_RANDOM] =
2253     ((random() % (cp->nr_of_tlbs - 8)) + 8)
2254     << R2K3K_RANDOM_SHIFT;
2255     } else {
2256     cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
2257     % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
2258     }
2259     }
2260     }
2261    
2262    
2263     /*
2264     * coproc_rfe():
2265     *
2266     * Return from exception. (R3000 etc.)
2267     */
2268     void coproc_rfe(struct cpu *cpu)
2269     {
2270     int oldmode;
2271    
2272     oldmode = cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_SR_KU_CUR;
2273    
2274     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =
2275     (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |
2276     ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2);
2277    
2278     /* Changing from kernel to user mode? Then this is necessary: */
2279     if (!oldmode &&
2280     (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &
2281     MIPS1_SR_KU_CUR))
2282     invalidate_translation_caches(cpu, 0, 0, 1, 0);
2283     }
2284    
2285    
2286     /*
2287     * coproc_eret():
2288     *
2289     * Return from exception. (R4000 etc.)
2290     */
2291     void coproc_eret(struct cpu *cpu)
2292     {
2293     int oldmode, newmode;
2294    
2295     /* Kernel mode flag: */
2296     oldmode = 0;
2297     if ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS3_SR_KSU_MASK)
2298     != MIPS3_SR_KSU_USER
2299     || (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & (STATUS_EXL |
2300     STATUS_ERL)) ||
2301     (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 1) == 0)
2302     oldmode = 1;
2303    
2304     if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {
2305     cpu->pc = cpu->cd.mips.pc_last =
2306     cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC];
2307     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
2308     } else {
2309     cpu->pc = cpu->cd.mips.pc_last =
2310     cpu->cd.mips.coproc[0]->reg[COP0_EPC];
2311     cpu->cd.mips.delay_slot = 0;
2312     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;
2313     }
2314    
2315     cpu->cd.mips.rmw = 0; /* the "LL bit" */
2316    
2317     /* New kernel mode flag: */
2318     newmode = 0;
2319     if ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS3_SR_KSU_MASK)
2320     != MIPS3_SR_KSU_USER
2321     || (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & (STATUS_EXL |
2322     STATUS_ERL)) ||
2323     (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 1) == 0)
2324     newmode = 1;
2325    
2326     #if 0
2327     /* Changing from kernel to user mode?
2328     Then this is necessary: TODO */
2329     if (oldmode && !newmode)
2330     invalidate_translation_caches(cpu, 0, 0, 1, 0);
2331     #endif
2332     }
2333    
2334    
2335     /*
2336     * coproc_function():
2337     *
2338     * Execute a coprocessor specific instruction. cp must be != NULL.
2339     * Debug trace should be printed for known instructions, if
2340     * unassemble_only is non-zero. (This will NOT execute the instruction.)
2341     *
2342     * TODO: This is a mess and should be restructured (again).
2343     */
2344     void coproc_function(struct cpu *cpu, struct mips_coproc *cp, int cpnr,
2345     uint32_t function, int unassemble_only, int running)
2346     {
2347     int co_bit, op, rt, rd, fs, copz;
2348     uint64_t tmpvalue;
2349    
2350     if (cp == NULL) {
2351     if (unassemble_only) {
2352     debug("cop%i\t0x%08x (coprocessor not available)\n",
2353     cpnr, (int)function);
2354     return;
2355     }
2356     fatal("[ pc=0x%016llx cop%i\t0x%08x (coprocessor not "
2357     "available)\n", (long long)cpu->pc, cpnr, (int)function);
2358     return;
2359     }
2360    
2361     #if 0
2362     /* No FPU? */
2363     if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {
2364     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);
2365     return;
2366     }
2367     #endif
2368    
2369     /* For quick reference: */
2370     copz = (function >> 21) & 31;
2371     rt = (function >> 16) & 31;
2372     rd = (function >> 11) & 31;
2373    
2374     if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MFCz << 21))
2375     || ((function & 0x03e007f8) == (COPz_DMFCz << 21)))) {
2376     if (unassemble_only) {
2377     debug("%s%i\t%s,", copz==COPz_DMFCz? "dmfc" : "mfc",
2378     cpnr, regnames[rt]);
2379     if (cpnr == 0)
2380     debug("%s", cop0_names[rd]);
2381     else
2382     debug("cpreg%i", rd);
2383     if (function & 7)
2384     debug(",%i", (int)(function & 7));
2385     debug("\n");
2386     return;
2387     }
2388     coproc_register_read(cpu, cpu->cd.mips.coproc[cpnr],
2389     rd, &tmpvalue, function & 7);
2390     cpu->cd.mips.gpr[rt] = tmpvalue;
2391     if (copz == COPz_MFCz) {
2392     /* Sign-extend: */
2393     cpu->cd.mips.gpr[rt] &= 0xffffffffULL;
2394     if (cpu->cd.mips.gpr[rt] & 0x80000000ULL)
2395     cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL;
2396     }
2397     return;
2398     }
2399    
2400     if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MTCz << 21))
2401     || ((function & 0x03e007f8) == (COPz_DMTCz << 21)))) {
2402     if (unassemble_only) {
2403     debug("%s%i\t%s,", copz==COPz_DMTCz? "dmtc" : "mtc",
2404     cpnr, regnames[rt]);
2405     if (cpnr == 0)
2406     debug("%s", cop0_names[rd]);
2407     else
2408     debug("cpreg%i", rd);
2409     if (function & 7)
2410     debug(",%i", (int)(function & 7));
2411     debug("\n");
2412     return;
2413     }
2414     tmpvalue = cpu->cd.mips.gpr[rt];
2415     if (copz == COPz_MTCz) {
2416     /* Sign-extend: */
2417     tmpvalue &= 0xffffffffULL;
2418     if (tmpvalue & 0x80000000ULL)
2419     tmpvalue |= 0xffffffff00000000ULL;
2420     }
2421     coproc_register_write(cpu, cpu->cd.mips.coproc[cpnr], rd,
2422     &tmpvalue, copz == COPz_DMTCz, function & 7);
2423     return;
2424     }
2425    
2426     if (cpnr <= 1 && (((function & 0x03e007ff) == (COPz_CFCz << 21))
2427     || ((function & 0x03e007ff) == (COPz_CTCz << 21)))) {
2428     switch (copz) {
2429     case COPz_CFCz: /* Copy from FPU control register */
2430     rt = (function >> 16) & 31;
2431     fs = (function >> 11) & 31;
2432     if (unassemble_only) {
2433     debug("cfc%i\t%s,r%i\n", cpnr,
2434     regnames[rt], fs);
2435     return;
2436     }
2437     cpu->cd.mips.gpr[rt] = cp->fcr[fs] & 0xffffffffULL;
2438     if (cpu->cd.mips.gpr[rt] & 0x80000000ULL)
2439     cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL;
2440     /* TODO: implement delay for gpr[rt]
2441     (for MIPS I,II,III only) */
2442     return;
2443     case COPz_CTCz: /* Copy to FPU control register */
2444     rt = (function >> 16) & 31;
2445     fs = (function >> 11) & 31;
2446     if (unassemble_only) {
2447     debug("ctc%i\t%s,r%i\n", cpnr,
2448     regnames[rt], fs);
2449     return;
2450     }
2451    
2452     switch (cpnr) {
2453     case 0: /* System coprocessor */
2454     fatal("[ warning: unimplemented ctc%i, "
2455     "0x%08x -> ctl reg %i ]\n", cpnr,
2456     (int)cpu->cd.mips.gpr[rt], fs);
2457     break;
2458     case 1: /* FPU */
2459     if (fs == 0)
2460     fatal("[ Attempt to write to FPU "
2461     "control register 0 (?) ]\n");
2462     else {
2463     uint64_t tmp = cpu->cd.mips.gpr[rt];
2464     cp->fcr[fs] = tmp;
2465    
2466     /* TODO: writing to control register 31
2467     should cause exceptions, depending
2468     on status bits! */
2469    
2470     switch (fs) {
2471     case FPU_FCCR:
2472     cp->fcr[FPU_FCSR] =
2473     (cp->fcr[FPU_FCSR] &
2474     0x017fffffULL) | ((tmp & 1)
2475     << FCSR_FCC0_SHIFT)
2476     | (((tmp & 0xfe) >> 1) <<
2477     FCSR_FCC1_SHIFT);
2478     break;
2479     case FPU_FCSR:
2480     cp->fcr[FPU_FCCR] =
2481     (cp->fcr[FPU_FCCR] &
2482     0xffffff00ULL) | ((tmp >>
2483     FCSR_FCC0_SHIFT) & 1) |
2484     (((tmp >> FCSR_FCC1_SHIFT)
2485     & 0x7f) << 1);
2486     break;
2487     default:
2488     ;
2489     }
2490     }
2491     break;
2492     }
2493    
2494     /* TODO: implement delay for gpr[rt]
2495     (for MIPS I,II,III only) */
2496     return;
2497     default:
2498     ;
2499     }
2500     }
2501    
2502     /* Math (Floating point) coprocessor calls: */
2503     if (cpnr==1) {
2504     if (fpu_function(cpu, cp, function, unassemble_only))
2505     return;
2506     }
2507    
2508     /* For AU1500 and probably others: deret */
2509     if (function == 0x0200001f) {
2510     if (unassemble_only) {
2511     debug("deret\n");
2512     return;
2513     }
2514    
2515     /*
2516     * According to the MIPS64 manual, deret loads PC from the
2517     * DEPC cop0 register, and jumps there immediately. No
2518     * delay slot.
2519     *
2520     * TODO: This instruction is only available if the processor
2521     * is in debug mode. (What does that mean?)
2522     * TODO: This instruction is undefined in a delay slot.
2523     */
2524    
2525     cpu->pc = cpu->cd.mips.pc_last = cp->reg[COP0_DEPC];
2526     cpu->cd.mips.delay_slot = 0;
2527     cp->reg[COP0_STATUS] &= ~STATUS_EXL;
2528    
2529     return;
2530     }
2531    
2532    
2533     /* Ugly R5900 hacks: */
2534     if ((function & 0xfffff) == 0x38) { /* ei */
2535     if (unassemble_only) {
2536     debug("ei\n");
2537     return;
2538     }
2539     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE;
2540     return;
2541     }
2542    
2543     if ((function & 0xfffff) == 0x39) { /* di */
2544     if (unassemble_only) {
2545     debug("di\n");
2546     return;
2547     }
2548     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE;
2549     return;
2550     }
2551    
2552     co_bit = (function >> 25) & 1;
2553    
2554     /* TLB operations and other things: */
2555     if (cp->coproc_nr == 0) {
2556     op = (function) & 0xff;
2557     switch (co_bit) {
2558     case 1:
2559     switch (op) {
2560     case COP0_TLBR: /* Read indexed TLB entry */
2561     if (unassemble_only) {
2562     debug("tlbr\n");
2563     return;
2564     }
2565     coproc_tlbpr(cpu, 1);
2566     return;
2567     case COP0_TLBWI: /* Write indexed */
2568     case COP0_TLBWR: /* Write random */
2569     if (unassemble_only) {
2570     if (op == COP0_TLBWI)
2571     debug("tlbwi");
2572     else
2573     debug("tlbwr");
2574     if (!running) {
2575     debug("\n");
2576     return;
2577     }
2578     debug("\tindex=%08llx",
2579     (long long)cp->reg[COP0_INDEX]);
2580     debug(", random=%08llx",
2581     (long long)cp->reg[COP0_RANDOM]);
2582     debug(", mask=%016llx",
2583     (long long)cp->reg[COP0_PAGEMASK]);
2584     debug(", hi=%016llx",
2585     (long long)cp->reg[COP0_ENTRYHI]);
2586     debug(", lo0=%016llx",
2587     (long long)cp->reg[COP0_ENTRYLO0]);
2588     debug(", lo1=%016llx\n",
2589     (long long)cp->reg[COP0_ENTRYLO1]);
2590     }
2591     coproc_tlbwri(cpu, op == COP0_TLBWR);
2592     return;
2593     case COP0_TLBP: /* Probe TLB for
2594     matching entry */
2595     if (unassemble_only) {
2596     debug("tlbp\n");
2597     return;
2598     }
2599     coproc_tlbpr(cpu, 0);
2600     return;
2601     case COP0_RFE: /* R2000/R3000 only:
2602     Return from Exception */
2603     if (unassemble_only) {
2604     debug("rfe\n");
2605     return;
2606     }
2607     coproc_rfe(cpu);
2608     return;
2609     case COP0_ERET: /* R4000: Return from exception */
2610     if (unassemble_only) {
2611     debug("eret\n");
2612     return;
2613     }
2614     coproc_eret(cpu);
2615     return;
2616     case COP0_STANDBY:
2617     if (unassemble_only) {
2618     debug("standby\n");
2619     return;
2620     }
2621     /* TODO: Hm. Do something here? */
2622     return;
2623     case COP0_SUSPEND:
2624     if (unassemble_only) {
2625     debug("suspend\n");
2626     return;
2627     }
2628     /* TODO: Hm. Do something here? */
2629     return;
2630     case COP0_HIBERNATE:
2631     if (unassemble_only) {
2632     debug("hibernate\n");
2633     return;
2634     }
2635     /* TODO: Hm. Do something here? */
2636     return;
2637     default:
2638     ;
2639     }
2640     default:
2641     ;
2642     }
2643     }
2644    
2645     /* TODO: coprocessor R2020 on DECstation? */
2646     if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x0100ffff) {
2647     if (unassemble_only) {
2648     debug("decstation_r2020_writeback\n");
2649     return;
2650     }
2651     /* TODO */
2652     return;
2653     }
2654    
2655     /* TODO: RM5200 idle (?) */
2656     if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x02000020) {
2657     if (unassemble_only) {
2658     debug("idle(?)\n"); /* TODO */
2659     return;
2660     }
2661    
2662     /* Idle? TODO */
2663     return;
2664     }
2665    
2666     if (unassemble_only) {
2667     debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);
2668     return;
2669     }
2670    
2671     fatal("cpu%i: UNIMPLEMENTED coproc%i function %08lx "
2672     "(pc = %016llx)\n", cpu->cpu_id, cp->coproc_nr, function,
2673     (long long)cpu->cd.mips.pc_last);
2674     #if 1
2675     single_step = 1;
2676     #else
2677     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cp->coproc_nr, 0, 0, 0);
2678     #endif
2679     }
2680    
2681     #endif /* ENABLE_MIPS */

  ViewVC Help
Powered by ViewVC 1.1.26