/[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 18 - (show annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 81301 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26