/[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 24 - (hide annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 63456 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26