/[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 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 65259 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26