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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5 - (show annotations)
Mon Oct 8 16:18:06 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 77564 byte(s)
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