/[gxemul]/trunk/src/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/cpu_mips_coproc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (show annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 79765 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 0.3.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26