/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (show 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 /*
2 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_mips_coproc.c,v 1.33 2006/06/22 13:30:38 debug Exp $
29 *
30 * Emulation of MIPS coprocessors.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <math.h>
37
38 #include "cop0.h"
39 #include "cpu.h"
40 #include "cpu_mips.h"
41 #include "emul.h"
42 #include "float_emul.h"
43 #include "machine.h"
44 #include "memory.h"
45 #include "mips_cpu_types.h"
46 #include "misc.h"
47 #include "opcodes_mips.h"
48
49
50 #ifndef ENABLE_MIPS
51
52
53 struct mips_coproc *mips_coproc_new(struct cpu *cpu, int coproc_nr)
54 { return NULL; }
55
56 void mips_coproc_tlb_set_entry(struct cpu *cpu, int entrynr, int size,
57 uint64_t vaddr, uint64_t paddr0, uint64_t paddr1,
58 int valid0, int valid1, int dirty0, int dirty1, int global, int asid,
59 int cachealgo0, int cachealgo1) { }
60
61
62 #else /* ENABLE_MIPS */
63
64
65 extern volatile int single_step;
66
67 static char *cop0_names[] = COP0_NAMES;
68 static char *regnames[] = MIPS_REGISTER_NAMES;
69
70
71 /*
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 const int m16 = 0; /* TODO: MIPS16 support */
79 int IB, DB, SB, IC, DC, SC, IA, DA;
80
81 /* 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
126 return;
127 }
128
129 switch (cpu->cd.mips.cpu_type.rev) {
130 case MIPS_R2000:
131 case MIPS_R3000:
132 /* No config register. */
133 break;
134 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 default:fatal("Internal error: No initialization code for"
319 " config0? cpu rev = 0x%x", cpu->cd.mips.cpu_type.rev);
320 exit(1);
321 }
322 }
323
324
325 /*
326 * initialize_cop1():
327 *
328 * Helper function, called from mips_coproc_new().
329 */
330 static void initialize_cop1(struct cpu *cpu, struct mips_coproc *c)
331 {
332 int fpu_rev;
333 uint64_t other_stuff = 0;
334
335 switch (cpu->cd.mips.cpu_type.rev & 0xff) {
336 case MIPS_R2000: fpu_rev = MIPS_R2010; break;
337 case MIPS_R3000: fpu_rev = MIPS_R3010;
338 other_stuff |= 0x40; /* or 0x30? TODO */
339 break;
340 case MIPS_R6000: fpu_rev = MIPS_R6010; break;
341 case MIPS_R4000: fpu_rev = MIPS_R4010; break;
342 case MIPS_4Kc: /* TODO: Is this the same as 5Kc? */
343 case MIPS_5Kc: other_stuff = COP1_REVISION_DOUBLE
344 | COP1_REVISION_SINGLE;
345 case MIPS_R5000:
346 case MIPS_RM5200: fpu_rev = cpu->cd.mips.cpu_type.rev;
347 other_stuff |= 0x10;
348 /* or cpu->cd.mips.cpu_type.sub ? TODO */
349 break;
350 case MIPS_R10000: fpu_rev = MIPS_R10000; break;
351 case MIPS_R12000: fpu_rev = 0x9; break;
352 default: fpu_rev = MIPS_SOFT;
353 }
354
355 c->fcr[COP1_REVISION] = (fpu_rev << 8) | other_stuff;
356
357 #if 0
358 /* These are mentioned in the MIPS64 documentation: */
359 + (1 << 16) /* single */
360 + (1 << 17) /* double */
361 + (1 << 18) /* paired-single */
362 + (1 << 19) /* 3d */
363 #endif
364 }
365
366
367 /*
368 * mips_coproc_new():
369 *
370 * Create a new MIPS coprocessor object.
371 */
372 struct mips_coproc *mips_coproc_new(struct cpu *cpu, int coproc_nr)
373 {
374 struct mips_coproc *c;
375
376 c = malloc(sizeof(struct mips_coproc));
377 if (c == NULL) {
378 fprintf(stderr, "out of memory\n");
379 exit(1);
380 }
381
382 memset(c, 0, sizeof(struct mips_coproc));
383 c->coproc_nr = coproc_nr;
384
385 if (coproc_nr == 0) {
386 c->nr_of_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;
387 c->tlbs = zeroed_alloc(c->nr_of_tlbs * sizeof(struct mips_tlb));
388
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 /* 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 c->reg[COP0_PAGEMASK] = 0x1fff;
416
417 /* Note: .rev may contain the company ID as well! */
418 c->reg[COP0_PRID] =
419 (0x00 << 24) /* Company Options */
420 | (0x00 << 16) /* Company ID */
421 | (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 c->reg[COP0_STATUS] = (int32_t)c->reg[COP0_STATUS];
431 }
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 * 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 */
520 static void invalidate_asid(struct cpu *cpu, int asid)
521 {
522 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
526 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 }
535 } else {
536 /* TODO: Implement support for other. */
537 cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);
538 }
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 #if 0
562 /*
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 #endif
583 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 symbol = get_symbol_name(cpu->pc, &offset);
667 fatal("YO! pc = 0x%08llx <%s> "
668 "lo=%016llx\n", (long long)
669 cpu->pc, symbol? symbol :
670 "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 if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
736 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 if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
746 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 * Translation caches must be invalidated if the
754 * ASID changes:
755 */
756 switch (cpu->cd.mips.cpu_type.mmu_model) {
757 case MMU3K:
758 old_asid = cp->reg[COP0_ENTRYHI] &
759 R2K3K_ENTRYHI_ASID_MASK;
760 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
773 if (inval)
774 invalidate_asid(cpu, old_asid);
775
776 unimpl = 0;
777 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
778 (tmp & 0x3f)!=0) {
779 /* char *symbol;
780 uint64_t offset;
781 symbol = get_symbol_name(cpu->pc,
782 &offset);
783 fatal("YO! pc = 0x%08llx <%s> "
784 "hi=%016llx\n", (long long)cpu->pc,
785 symbol? symbol :
786 "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 /*
832 * TODO: Perhaps this can be solved some other
833 * way, like in the old bintrans system?
834 */
835 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
836 (oldmode & MIPS1_ISOL_CACHES) !=
837 (tmp & MIPS1_ISOL_CACHES)) {
838 cpu->invalidate_translation_caches(
839 cpu, 0, INVALIDATE_ALL);
840
841 /* 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 }
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 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 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
941 static char *ccname[16] = {
942 "f", "un", "eq", "ueq", "olt", "ult", "ole", "ule",
943 "sf", "ngle", "seq", "ngl", "lt", "nge", "le", "ngt" };
944
945 #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 /* TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W, RSQRT */
956
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 int ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
967 uint64_t r = ieee_store_float_value(nf, ieee_fmt, nan);
968
969 /*
970 * TODO: This is for 32-bit mode. It has to be updated later
971 * for 64-bit coprocessor functionality!
972 */
973 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) {
974 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 * Perform a floating-point operation. For those of fs and ft that are >= 0,
994 * those numbers are interpreted into local variables.
995 *
996 * Only FPU_OP_C (compare) returns anything of interest, 1 for true, 0 for
997 * false.
998 */
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 struct ieee_float_value float_value[2];
1004 int unordered, nan, ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1005 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 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1013 fs_v = (fs_v & 0xffffffffULL) +
1014 (cp->reg[(fs + 1) & 31] << 32);
1015 ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);
1016 }
1017 if (ft >= 0) {
1018 uint64_t v = cp->reg[ft];
1019 /* TODO: register-pair mode and
1020 plain register mode? "FR" bit? */
1021 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1022 v = (v & 0xffffffffULL) +
1023 (cp->reg[(ft + 1) & 31] << 32);
1024 ieee_interpret_float_value(v, &float_value[1], ieee_fmt);
1025 }
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 if (output_fmt == COP1_FMT_D || output_fmt == COP1_FMT_L) {
1100 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 if (cpu->delay_slot) {
1214 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 cond_true = (cp->fcr[MIPS_FPU_FCSR] >>
1223 MIPS_FCSR_FCC0_SHIFT) & 1;
1224 else
1225 cond_true = (cp->fcr[MIPS_FPU_FCSR] >>
1226 (MIPS_FCSR_FCC1_SHIFT + cc-1)) & 1;
1227
1228 if (!tf)
1229 cond_true = !cond_true;
1230
1231 if (cond_true) {
1232 cpu->delay_slot = TO_BE_DELAYED;
1233 cpu->delay_jmpaddr = cpu->pc + (imm << 2);
1234 } 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 debug("add.%s\tr%i,r%i,r%i\n",
1249 fmtname[fmt], fd, fs, ft);
1250 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 debug("sub.%s\tr%i,r%i,r%i\n",
1261 fmtname[fmt], fd, fs, ft);
1262 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 debug("mul.%s\tr%i,r%i,r%i\n",
1273 fmtname[fmt], fd, fs, ft);
1274 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 debug("div.%s\tr%i,r%i,r%i\n",
1285 fmtname[fmt], fd, fs, ft);
1286 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 debug("sqrt.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1297 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 debug("abs.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1308 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 debug("mov.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1319 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 debug("neg.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1330 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 debug("trunc.l.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1341 if (unassemble_only)
1342 return 1;
1343
1344 /* TODO: not CVT? */
1345
1346 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_L);
1347 return 1;
1348 }
1349
1350 /* trunc.w.fmt: Truncate */
1351 if ((function & 0x001f003f) == 0x0000000d) {
1352 if (cpu->machine->instruction_trace || unassemble_only)
1353 debug("trunc.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1354 if (unassemble_only)
1355 return 1;
1356
1357 /* TODO: not CVT? */
1358
1359 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W);
1360 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 debug("c.%s.%s\tcc%i,r%i,r%i\n", ccname[cond],
1370 fmtname[fmt], cc, fs, ft);
1371 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 cp->fcr[MIPS_FPU_FCCR] &= ~(1 << cc);
1383 if (cond_true)
1384 cp->fcr[MIPS_FPU_FCCR] |= (1 << cc);
1385
1386 if (cc == 0) {
1387 bit = 1 << MIPS_FCSR_FCC0_SHIFT;
1388 cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1389 if (cond_true)
1390 cp->fcr[MIPS_FPU_FCSR] |= bit;
1391 } else {
1392 bit = 1 << (MIPS_FCSR_FCC1_SHIFT + cc-1);
1393 cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1394 if (cond_true)
1395 cp->fcr[MIPS_FPU_FCSR] |= bit;
1396 }
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 debug("cvt.s.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1405 if (unassemble_only)
1406 return 1;
1407
1408 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_S);
1409 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 debug("cvt.d.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1416 if (unassemble_only)
1417 return 1;
1418
1419 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_D);
1420 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 debug("cvt.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1427 if (unassemble_only)
1428 return 1;
1429
1430 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W);
1431 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 * MIPS TLB write random (tlbwr) and write indexed (tlbwi) instructions.
1561 */
1562 void coproc_tlbwri(struct cpu *cpu, int randomflag)
1563 {
1564 struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1565 int index, g_bit, old_asid = -1;
1566 uint64_t oldvaddr;
1567
1568 if (randomflag) {
1569 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 index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
1574 >> R2K3K_RANDOM_SHIFT;
1575 } else {
1576 cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1577 % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
1578 index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
1579 }
1580 } 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
1596 #if 0
1597 /* Debug dump of the previous entry at that index: */
1598 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 #endif
1617
1618 /*
1619 * Any virtual address translation for the old TLB entry must be
1620 * invalidated first:
1621 */
1622
1623 switch (cpu->cd.mips.cpu_type.mmu_model) {
1624
1625 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 cpu->invalidate_translation_caches(cpu, oldvaddr,
1634 INVALIDATE_VADDR);
1635 break;
1636
1637 default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1638 oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
1639 /* 44 addressable bits: */
1640 if (oldvaddr & 0x80000000000ULL)
1641 oldvaddr |= 0xfffff00000000000ULL;
1642 } else if (cpu->is_32bit) {
1643 /* MIPS32 etc.: */
1644 oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1645 oldvaddr = (int32_t)oldvaddr;
1646 } 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 #if 1
1655 cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);
1656 #else
1657 /*
1658 * TODO: non-4KB page sizes!
1659 */
1660 cpu->invalidate_translation_caches(cpu, oldvaddr,
1661 INVALIDATE_VADDR);
1662 cpu->invalidate_translation_caches(cpu, oldvaddr | 0x1000,
1663 INVALIDATE_VADDR);
1664 #endif
1665 }
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 int i;
1680 unsigned int asid;
1681
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 uint32_t vaddr, paddr;
1711 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 memblock = memory_paddr_to_hostaddr(cpu->mem, paddr, 0);
1721
1722 /* 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 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 #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 } else {
1788 /* Assume MMU4K */
1789 oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1790 /* 40 addressable bits: */
1791 if (oldvaddr & 0x8000000000ULL)
1792 oldvaddr |= 0xffffff0000000000ULL;
1793 }
1794
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 }
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 cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC];
1831 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
1832 } else {
1833 cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC];
1834 cpu->delay_slot = 0;
1835 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 debug("r%i", rd);
1888 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 debug("r%i", rd);
1914 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 cpu->cd.mips.gpr[rt] = (int32_t)cp->fcr[fs];
1943 /* 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 case MIPS_FPU_FCCR:
1975 cp->fcr[MIPS_FPU_FCSR] =
1976 (cp->fcr[MIPS_FPU_FCSR] &
1977 0x017fffffULL) | ((tmp & 1)
1978 << MIPS_FCSR_FCC0_SHIFT)
1979 | (((tmp & 0xfe) >> 1) <<
1980 MIPS_FCSR_FCC1_SHIFT);
1981 break;
1982 case MIPS_FPU_FCSR:
1983 cp->fcr[MIPS_FPU_FCCR] =
1984 (cp->fcr[MIPS_FPU_FCCR] &
1985 0xffffff00ULL) | ((tmp >>
1986 MIPS_FCSR_FCC0_SHIFT) & 1) |
1987 (((tmp >>
1988 MIPS_FCSR_FCC1_SHIFT)
1989 & 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 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 return;
2023 }
2024
2025 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 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 return;
2075 }
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 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 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 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 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