/[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 4 - (show annotations)
Mon Oct 8 16:18:00 2007 UTC (13 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 77564 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

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

  ViewVC Help
Powered by ViewVC 1.1.26