/[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 26 - (show annotations)
Mon Oct 8 16:20:10 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 63054 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1264 2006/06/25 11:08:04 debug Exp $
20060624	Replacing the error-prone machine type initialization stuff
		with something more reasonable.
		Finally removing the old "cpu_run" kludge; moving around stuff
		in machine.c and emul.c to better suit the dyntrans system.
		Various minor dyntrans cleanups (renaming translate_address to
		translate_v2p, and experimenting with template physpages).
20060625	Removing the speed hack which separated the vph entries into
		two halves (code vs data); things seem a lot more stable now.
		Minor performance hack: R2000/R3000 cache isolation now only
		clears address translations when going into isolation, not
		when going out of it.
		Fixing the MIPS interrupt problems by letting mtc0 immediately
		cause interrupts.

==============  RELEASE 0.4.0.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26