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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Mon Oct 8 16:17:52 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 74915 byte(s)
0.3.1
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.11 2005/03/15 06:52:14 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->bintrans_chunks[b] = NULL;
689 }
690 }
691 }
692 #endif
693
694
695 /*
696 * mips_invalidate_translation_caches_paddr():
697 *
698 * Invalidate based on physical address.
699 */
700 void mips_invalidate_translation_caches_paddr(struct cpu *cpu, uint64_t paddr)
701 {
702 #ifdef BINTRANS
703 paddr &= ~0xfff;
704
705 if (cpu->machine->bintrans_enable) {
706 #if 1
707 int i;
708 uint64_t tlb_paddr0, tlb_paddr1;
709 uint64_t tlb_vaddr;
710 uint64_t p, p2;
711
712 switch (cpu->cd.mips.cpu_type.mmu_model) {
713 case MMU3K:
714 for (i=0; i<64; i++) {
715 tlb_paddr0 = cpu->cd.mips.coproc[0]->
716 tlbs[i].lo0 & R2K3K_ENTRYLO_PFN_MASK;
717 tlb_vaddr = cpu->cd.mips.coproc[0]->
718 tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK;
719 tlb_vaddr = (int64_t)(int32_t)tlb_vaddr;
720 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &
721 R2K3K_ENTRYLO_V) && tlb_paddr0 == paddr)
722 invalidate_table_entry(cpu, tlb_vaddr);
723 }
724 break;
725 default:
726 for (i=0; i<cpu->cd.mips.coproc[0]->nr_of_tlbs; i++) {
727 int psize = 12;
728 int or_pmask = 0x1fff;
729 int phys_shift = 12;
730
731 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
732 or_pmask = 0x7ff;
733 phys_shift = 10;
734 }
735 switch (cpu->cd.mips.coproc[0]->
736 tlbs[i].mask | or_pmask) {
737 case 0x000007ff: psize = 10; break;
738 case 0x00001fff: psize = 12; break;
739 case 0x00007fff: psize = 14; break;
740 case 0x0001ffff: psize = 16; break;
741 case 0x0007ffff: psize = 18; break;
742 case 0x001fffff: psize = 20; break;
743 case 0x007fffff: psize = 22; break;
744 case 0x01ffffff: psize = 24; break;
745 case 0x07ffffff: psize = 26; break;
746 default:
747 printf("invalidate_translation_caches"
748 "_paddr(): bad pagemask?\n");
749 }
750 tlb_paddr0 = (cpu->cd.mips.coproc[0]->tlbs[i].
751 lo0 & ENTRYLO_PFN_MASK)>>ENTRYLO_PFN_SHIFT;
752 tlb_paddr1 = (cpu->cd.mips.coproc[0]->tlbs[i].
753 lo1 & ENTRYLO_PFN_MASK)>>ENTRYLO_PFN_SHIFT;
754 tlb_paddr0 <<= phys_shift;
755 tlb_paddr1 <<= phys_shift;
756 if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
757 tlb_vaddr = cpu->cd.mips.coproc[0]->
758 tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;
759 if (tlb_vaddr & ((int64_t)1 << 43))
760 tlb_vaddr |=
761 0xfffff00000000000ULL;
762 } else {
763 tlb_vaddr = cpu->cd.mips.coproc[0]->
764 tlbs[i].hi & ENTRYHI_VPN2_MASK;
765 if (tlb_vaddr & ((int64_t)1 << 39))
766 tlb_vaddr |=
767 0xffffff0000000000ULL;
768 }
769 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &
770 ENTRYLO_V) && paddr >= tlb_paddr0 &&
771 paddr < tlb_paddr0 + (1<<psize)) {
772 p2 = 1 << psize;
773 for (p=0; p<p2; p+=4096)
774 invalidate_table_entry(cpu,
775 tlb_vaddr + p);
776 }
777 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo1 &
778 ENTRYLO_V) && paddr >= tlb_paddr1 &&
779 paddr < tlb_paddr1 + (1<<psize)) {
780 p2 = 1 << psize;
781 for (p=0; p<p2; p+=4096)
782 invalidate_table_entry(cpu,
783 tlb_vaddr + p +
784 (1 << psize));
785 }
786 }
787 }
788 #endif
789
790 if (paddr < 0x20000000) {
791 invalidate_table_entry(cpu, 0xffffffff80000000ULL
792 + paddr);
793 invalidate_table_entry(cpu, 0xffffffffa0000000ULL
794 + paddr);
795 }
796 }
797
798 #if 0
799 {
800 int i;
801
802 /* TODO: Don't invalidate everything. */
803 for (i=0; i<N_BINTRANS_VADDR_TO_HOST; i++)
804 cpu->bintrans_data_hostpage[i] = NULL;
805 }
806 #endif
807
808 #endif
809 }
810
811
812 /*
813 * invalidate_translation_caches():
814 *
815 * This is necessary for every change to the TLB, and when the ASID is changed,
816 * so that for example user-space addresses are not cached when they should
817 * not be.
818 */
819 static void invalidate_translation_caches(struct cpu *cpu,
820 int all, uint64_t vaddr, int kernelspace, int old_asid_to_invalidate)
821 {
822 int i;
823
824 /* printf("inval(all=%i, kernel=%i, addr=%016llx)\n",
825 all, kernelspace, (long long)vaddr); */
826
827 #ifdef BINTRANS
828 if (!cpu->machine->bintrans_enable)
829 goto nobintrans;
830
831 if (all) {
832 int i;
833 uint64_t tlb_vaddr;
834 switch (cpu->cd.mips.cpu_type.mmu_model) {
835 case MMU3K:
836 for (i=0; i<64; i++) {
837 tlb_vaddr = cpu->cd.mips.coproc[0]->tlbs[i].hi
838 & R2K3K_ENTRYHI_VPN_MASK;
839 tlb_vaddr = (int64_t)(int32_t)tlb_vaddr;
840 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &
841 R2K3K_ENTRYLO_V) && (tlb_vaddr &
842 0xc0000000ULL) != 0x80000000ULL) {
843 int asid = (cpu->cd.mips.coproc[0]->
844 tlbs[i].hi & R2K3K_ENTRYHI_ASID_MASK
845 ) >> R2K3K_ENTRYHI_ASID_SHIFT;
846 if (old_asid_to_invalidate < 0 ||
847 old_asid_to_invalidate == asid)
848 invalidate_table_entry(cpu,
849 tlb_vaddr);
850 }
851 }
852 break;
853 default:
854 for (i=0; i<cpu->cd.mips.coproc[0]->nr_of_tlbs; i++) {
855 int psize = 10, or_pmask = 0x1fff;
856 int phys_shift = 12;
857
858 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
859 or_pmask = 0x7ff;
860 phys_shift = 10;
861 }
862
863 switch (cpu->cd.mips.coproc[0]->tlbs[i].mask
864 | or_pmask) {
865 case 0x000007ff: psize = 10; break;
866 case 0x00001fff: psize = 12; break;
867 case 0x00007fff: psize = 14; break;
868 case 0x0001ffff: psize = 16; break;
869 case 0x0007ffff: psize = 18; break;
870 case 0x001fffff: psize = 20; break;
871 case 0x007fffff: psize = 22; break;
872 case 0x01ffffff: psize = 24; break;
873 case 0x07ffffff: psize = 26; break;
874 default:
875 printf("invalidate_translation_caches"
876 "(): bad pagemask?\n");
877 }
878
879 if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
880 tlb_vaddr = cpu->cd.mips.coproc[0]->
881 tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;
882 if (tlb_vaddr & ((int64_t)1 << 43))
883 tlb_vaddr |=
884 0xfffff00000000000ULL;
885 } else {
886 tlb_vaddr = cpu->cd.mips.coproc[0]->
887 tlbs[i].hi & ENTRYHI_VPN2_MASK;
888 if (tlb_vaddr & ((int64_t)1 << 39))
889 tlb_vaddr |=
890 0xffffff0000000000ULL;
891 }
892
893 /* TODO: Check the ASID etc. */
894
895 invalidate_table_entry(cpu, tlb_vaddr);
896 invalidate_table_entry(cpu, tlb_vaddr |
897 (1 << psize));
898 }
899 }
900 } else
901 invalidate_table_entry(cpu, vaddr);
902
903 nobintrans:
904
905 /* TODO: Don't invalidate everything. */
906 for (i=0; i<N_BINTRANS_VADDR_TO_HOST; i++)
907 cpu->cd.mips.bintrans_data_hostpage[i] = NULL;
908 #endif
909
910 if (kernelspace)
911 all = 1;
912
913 #ifdef USE_TINY_CACHE
914 {
915 vaddr >>= 12;
916
917 /* Invalidate the tiny translation cache... */
918 if (!cpu->machine->bintrans_enable)
919 for (i=0; i<N_TRANSLATION_CACHE_INSTR; i++)
920 if (all || vaddr == (cpu->cd.mips.
921 translation_cache_instr[i].vaddr_pfn))
922 cpu->cd.mips.translation_cache_instr[i].wf = 0;
923
924 if (!cpu->machine->bintrans_enable)
925 for (i=0; i<N_TRANSLATION_CACHE_DATA; i++)
926 if (all || vaddr == (cpu->cd.mips.
927 translation_cache_data[i].vaddr_pfn))
928 cpu->cd.mips.translation_cache_data[i].wf = 0;
929 }
930 #endif
931 }
932
933
934 /*
935 * coproc_register_read();
936 *
937 * Read a value from a MIPS coprocessor register.
938 */
939 void coproc_register_read(struct cpu *cpu,
940 struct mips_coproc *cp, int reg_nr, uint64_t *ptr)
941 {
942 int unimpl = 1;
943
944 if (cp->coproc_nr==0 && reg_nr==COP0_INDEX) unimpl = 0;
945 if (cp->coproc_nr==0 && reg_nr==COP0_RANDOM) unimpl = 0;
946 if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYLO0) unimpl = 0;
947 if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYLO1) unimpl = 0;
948 if (cp->coproc_nr==0 && reg_nr==COP0_CONTEXT) unimpl = 0;
949 if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK) unimpl = 0;
950 if (cp->coproc_nr==0 && reg_nr==COP0_WIRED) unimpl = 0;
951 if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR) unimpl = 0;
952 if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) unimpl = 0;
953 if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI) unimpl = 0;
954 if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE) unimpl = 0;
955 if (cp->coproc_nr==0 && reg_nr==COP0_STATUS) unimpl = 0;
956 if (cp->coproc_nr==0 && reg_nr==COP0_CAUSE) unimpl = 0;
957 if (cp->coproc_nr==0 && reg_nr==COP0_EPC) unimpl = 0;
958 if (cp->coproc_nr==0 && reg_nr==COP0_PRID) unimpl = 0;
959 if (cp->coproc_nr==0 && reg_nr==COP0_CONFIG) unimpl = 0;
960 if (cp->coproc_nr==0 && reg_nr==COP0_LLADDR) unimpl = 0;
961 if (cp->coproc_nr==0 && reg_nr==COP0_WATCHLO) unimpl = 0;
962 if (cp->coproc_nr==0 && reg_nr==COP0_WATCHHI) unimpl = 0;
963 if (cp->coproc_nr==0 && reg_nr==COP0_XCONTEXT) unimpl = 0;
964 if (cp->coproc_nr==0 && reg_nr==COP0_ERRCTL) unimpl = 0;
965 if (cp->coproc_nr==0 && reg_nr==COP0_CACHEERR) unimpl = 0;
966 if (cp->coproc_nr==0 && reg_nr==COP0_TAGDATA_LO) unimpl = 0;
967 if (cp->coproc_nr==0 && reg_nr==COP0_TAGDATA_HI) unimpl = 0;
968 if (cp->coproc_nr==0 && reg_nr==COP0_ERROREPC) unimpl = 0;
969 if (cp->coproc_nr==0 && reg_nr==COP0_RESERV22) {
970 /* Used by Linux on Linksys WRT54G */
971 unimpl = 0;
972 }
973 if (cp->coproc_nr==0 && reg_nr==COP0_DEBUG) unimpl = 0;
974 if (cp->coproc_nr==0 && reg_nr==COP0_PERFCNT) unimpl = 0;
975 if (cp->coproc_nr==0 && reg_nr==COP0_DESAVE) unimpl = 0;
976
977 if (cp->coproc_nr==1) unimpl = 0;
978
979 if (unimpl) {
980 fatal("cpu%i: warning: read from unimplemented coproc%i"
981 " register %i (%s)\n", cpu->cpu_id, cp->coproc_nr, reg_nr,
982 cp->coproc_nr==0? cop0_names[reg_nr] : "?");
983
984 mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0,
985 cp->coproc_nr, 0, 0, 0);
986 return;
987 }
988
989 *ptr = cp->reg[reg_nr];
990 }
991
992
993 /*
994 * coproc_register_write();
995 *
996 * Write a value to a MIPS coprocessor register.
997 */
998 void coproc_register_write(struct cpu *cpu,
999 struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int flag64)
1000 {
1001 int unimpl = 1;
1002 int readonly = 0;
1003 uint64_t tmp = *ptr;
1004 uint64_t tmp2 = 0, old;
1005 int inval = 0, old_asid, oldmode;
1006
1007 switch (cp->coproc_nr) {
1008 case 0:
1009 /* COPROC 0: */
1010 switch (reg_nr) {
1011 case COP0_INDEX:
1012 case COP0_RANDOM:
1013 unimpl = 0;
1014 break;
1015 case COP0_ENTRYLO0:
1016 unimpl = 0;
1017 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
1018 (tmp & 0xff)!=0) {
1019 /* char *symbol;
1020 uint64_t offset;
1021 symbol = get_symbol_name(
1022 cpu->cd.mips.pc_last, &offset);
1023 fatal("YO! pc = 0x%08llx <%s> "
1024 "lo=%016llx\n", (long long)
1025 cpu->cd.mips.pc_last, symbol? symbol :
1026 "no symbol", (long long)tmp); */
1027 tmp &= (R2K3K_ENTRYLO_PFN_MASK |
1028 R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |
1029 R2K3K_ENTRYLO_V | R2K3K_ENTRYLO_G);
1030 } else if (cpu->cd.mips.cpu_type.mmu_model == MMU4K) {
1031 tmp &= (ENTRYLO_PFN_MASK | ENTRYLO_C_MASK |
1032 ENTRYLO_D | ENTRYLO_V | ENTRYLO_G);
1033 }
1034 break;
1035 case COP0_BADVADDR:
1036 /* Hm. Irix writes to this register. (Why?) */
1037 unimpl = 0;
1038 break;
1039 case COP0_ENTRYLO1:
1040 unimpl = 0;
1041 if (cpu->cd.mips.cpu_type.mmu_model == MMU4K) {
1042 tmp &= (ENTRYLO_PFN_MASK | ENTRYLO_C_MASK |
1043 ENTRYLO_D | ENTRYLO_V | ENTRYLO_G);
1044 }
1045 break;
1046 case COP0_CONTEXT:
1047 old = cp->reg[COP0_CONTEXT];
1048 cp->reg[COP0_CONTEXT] = tmp;
1049 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1050 cp->reg[COP0_CONTEXT] &=
1051 ~R2K3K_CONTEXT_BADVPN_MASK;
1052 cp->reg[COP0_CONTEXT] |=
1053 (old & R2K3K_CONTEXT_BADVPN_MASK);
1054 } else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1055 cp->reg[COP0_CONTEXT] &=
1056 ~CONTEXT_BADVPN2_MASK_R4100;
1057 cp->reg[COP0_CONTEXT] |=
1058 (old & CONTEXT_BADVPN2_MASK_R4100);
1059 } else {
1060 cp->reg[COP0_CONTEXT] &=
1061 ~CONTEXT_BADVPN2_MASK;
1062 cp->reg[COP0_CONTEXT] |=
1063 (old & CONTEXT_BADVPN2_MASK);
1064 }
1065 return;
1066 case COP0_PAGEMASK:
1067 tmp2 = tmp >> PAGEMASK_SHIFT;
1068 if (tmp2 != 0x000 &&
1069 tmp2 != 0x003 &&
1070 tmp2 != 0x00f &&
1071 tmp2 != 0x03f &&
1072 tmp2 != 0x0ff &&
1073 tmp2 != 0x3ff &&
1074 tmp2 != 0xfff)
1075 fatal("cpu%i: trying to write an invalid"
1076 " pagemask 0x%08lx to COP0_PAGEMASK\n",
1077 cpu->cpu_id, (long)tmp);
1078 unimpl = 0;
1079 break;
1080 case COP0_WIRED:
1081 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1082 fatal("cpu%i: r2k/r3k wired register must "
1083 "always be 8\n", cpu->cpu_id);
1084 tmp = 8;
1085 }
1086 cp->reg[COP0_RANDOM] = cp->nr_of_tlbs-1;
1087 tmp &= INDEX_MASK;
1088 unimpl = 0;
1089 break;
1090 case COP0_COUNT:
1091 if (tmp != (int64_t)(int32_t)tmp)
1092 fatal("WARNING: trying to write a 64-bit value"
1093 " to the COUNT register!\n");
1094 tmp = (int64_t)(int32_t)tmp;
1095 unimpl = 0;
1096 break;
1097 case COP0_COMPARE:
1098 /* Clear the timer interrupt bit (bit 7): */
1099 cpu->cd.mips.compare_register_set = 1;
1100 mips_cpu_interrupt_ack(cpu, 7);
1101 if (tmp != (int64_t)(int32_t)tmp)
1102 fatal("WARNING: trying to write a 64-bit value"
1103 " to the COMPARE register!\n");
1104 tmp = (int64_t)(int32_t)tmp;
1105 unimpl = 0;
1106 break;
1107 case COP0_ENTRYHI:
1108 /*
1109 * Translation caches must be invalidated, because the
1110 * address space might change (if the ASID changes).
1111 */
1112 switch (cpu->cd.mips.cpu_type.mmu_model) {
1113 case MMU3K:
1114 old_asid = (cp->reg[COP0_ENTRYHI] &
1115 R2K3K_ENTRYHI_ASID_MASK) >>
1116 R2K3K_ENTRYHI_ASID_SHIFT;
1117 if ((cp->reg[COP0_ENTRYHI] &
1118 R2K3K_ENTRYHI_ASID_MASK) !=
1119 (tmp & R2K3K_ENTRYHI_ASID_MASK))
1120 inval = 1;
1121 break;
1122 default:
1123 old_asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
1124 if ((cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID) !=
1125 (tmp & ENTRYHI_ASID))
1126 inval = 1;
1127 break;
1128 }
1129 if (inval)
1130 invalidate_translation_caches(cpu, 1, 0, 0,
1131 old_asid);
1132 unimpl = 0;
1133 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
1134 (tmp & 0x3f)!=0) {
1135 /* char *symbol;
1136 uint64_t offset;
1137 symbol = get_symbol_name(cpu->
1138 cd.mips.pc_last, &offset);
1139 fatal("YO! pc = 0x%08llx <%s> "
1140 "hi=%016llx\n", (long long)cpu->
1141 cd.mips.pc_last, symbol? symbol :
1142 "no symbol", (long long)tmp); */
1143 tmp &= ~0x3f;
1144 }
1145 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1146 tmp &= (R2K3K_ENTRYHI_VPN_MASK |
1147 R2K3K_ENTRYHI_ASID_MASK);
1148 else if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
1149 tmp &= (ENTRYHI_R_MASK |
1150 ENTRYHI_VPN2_MASK_R10K | ENTRYHI_ASID);
1151 else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
1152 tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK |
1153 0x1800 | ENTRYHI_ASID);
1154 else
1155 tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK |
1156 ENTRYHI_ASID);
1157 break;
1158 case COP0_EPC:
1159 unimpl = 0;
1160 break;
1161 case COP0_PRID:
1162 readonly = 1;
1163 break;
1164 case COP0_CONFIG:
1165 /* fatal("COP0_CONFIG: modifying K0 bits: "
1166 "0x%08x => ", cp->reg[reg_nr]); */
1167 tmp = *ptr;
1168 tmp &= 0x3; /* only bits 2..0 can be written */
1169 cp->reg[reg_nr] &= ~(0x3); cp->reg[reg_nr] |= tmp;
1170 /* fatal("0x%08x\n", cp->reg[reg_nr]); */
1171 return;
1172 case COP0_STATUS:
1173 oldmode = cp->reg[COP0_STATUS];
1174 tmp &= ~(1 << 21); /* bit 21 is read-only */
1175 /* Changing from kernel to user mode? Then
1176 invalidate some translation caches: */
1177 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1178 if (!(oldmode & MIPS1_SR_KU_CUR)
1179 && (tmp & MIPS1_SR_KU_CUR))
1180 invalidate_translation_caches(cpu,
1181 0, 0, 1, 0);
1182 } else {
1183 /* TODO: don't hardcode */
1184 if ((oldmode & 0xff) != (tmp & 0xff))
1185 invalidate_translation_caches(
1186 cpu, 0, 0, 1, 0);
1187 }
1188 unimpl = 0;
1189 break;
1190 case COP0_CAUSE:
1191 /* A write to the cause register only
1192 affects IM bits 0 and 1: */
1193 cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);
1194 cp->reg[reg_nr] |= (tmp & (0x3 << STATUS_IM_SHIFT));
1195 if (!(cp->reg[COP0_CAUSE] & STATUS_IM_MASK))
1196 cpu->cd.mips.cached_interrupt_is_possible = 0;
1197 else
1198 cpu->cd.mips.cached_interrupt_is_possible = 1;
1199 return;
1200 case COP0_FRAMEMASK:
1201 /* TODO: R10000 */
1202 unimpl = 0;
1203 break;
1204 case COP0_TAGDATA_LO:
1205 case COP0_TAGDATA_HI:
1206 /* TODO: R4300 and others? */
1207 unimpl = 0;
1208 break;
1209 case COP0_LLADDR:
1210 unimpl = 0;
1211 break;
1212 case COP0_WATCHLO:
1213 case COP0_WATCHHI:
1214 unimpl = 0;
1215 break;
1216 case COP0_XCONTEXT:
1217 /*
1218 * TODO: According to the R10000 manual, the R4400
1219 * shares the PTEbase portion of the context registers
1220 * (that is, xcontext and context). On R10000, they
1221 * are separate registers.
1222 */
1223 /* debug("[ xcontext 0x%016llx ]\n", tmp); */
1224 unimpl = 0;
1225 break;
1226
1227 /* Most of these are actually TODOs: */
1228 case COP0_ERROREPC:
1229 case COP0_DEPC:
1230 case COP0_RESERV22: /* Used by Linux on Linksys WRT54G */
1231 case COP0_DESAVE:
1232 case COP0_PERFCNT:
1233 case COP0_ERRCTL: /* R10000 */
1234 unimpl = 0;
1235 break;
1236 }
1237 break;
1238
1239 case 1:
1240 /* COPROC 1: */
1241 unimpl = 0;
1242 break;
1243 }
1244
1245 if (unimpl) {
1246 fatal("cpu%i: warning: write to unimplemented coproc%i "
1247 "register %i (%s), data = 0x%016llx\n", cpu->cpu_id,
1248 cp->coproc_nr, reg_nr, cp->coproc_nr==0?
1249 cop0_names[reg_nr] : "?", (long long)tmp);
1250
1251 mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0,
1252 cp->coproc_nr, 0, 0, 0);
1253 return;
1254 }
1255
1256 if (readonly) {
1257 fatal("cpu%i: warning: write to READONLY coproc%i register "
1258 "%i ignored\n", cpu->cpu_id, cp->coproc_nr, reg_nr);
1259 return;
1260 }
1261
1262 cp->reg[reg_nr] = tmp;
1263
1264 if (!flag64)
1265 cp->reg[reg_nr] = (int64_t)(int32_t)cp->reg[reg_nr];
1266 }
1267
1268
1269 /*
1270 * MIPS floating-point stuff:
1271 *
1272 * TODO: Move this to some other file?
1273 */
1274 #define FMT_S 16
1275 #define FMT_D 17
1276 #define FMT_W 20
1277 #define FMT_L 21
1278 #define FMT_PS 22
1279
1280 #define FPU_OP_ADD 1
1281 #define FPU_OP_SUB 2
1282 #define FPU_OP_MUL 3
1283 #define FPU_OP_DIV 4
1284 #define FPU_OP_SQRT 5
1285 #define FPU_OP_MOV 6
1286 #define FPU_OP_CVT 7
1287 #define FPU_OP_C 8
1288 #define FPU_OP_ABS 9
1289 #define FPU_OP_NEG 10
1290 /* TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W,
1291 RSQRT */
1292
1293
1294 struct internal_float_value {
1295 double f;
1296 int nan;
1297 };
1298
1299
1300 /*
1301 * fpu_interpret_float_value():
1302 *
1303 * Interprets a float value from binary IEEE format into an
1304 * internal_float_value struct.
1305 */
1306 static void fpu_interpret_float_value(uint64_t reg,
1307 struct internal_float_value *fvp, int fmt)
1308 {
1309 int n_frac = 0, n_exp = 0;
1310 int i, nan, sign = 0, exponent;
1311 double fraction;
1312
1313 memset(fvp, 0, sizeof(struct internal_float_value));
1314
1315 /* n_frac and n_exp: */
1316 switch (fmt) {
1317 case FMT_S: n_frac = 23; n_exp = 8; break;
1318 case FMT_W: n_frac = 31; n_exp = 0; break;
1319 case FMT_D: n_frac = 52; n_exp = 11; break;
1320 case FMT_L: n_frac = 63; n_exp = 0; break;
1321 default:
1322 fatal("fpu_interpret_float_value(): "
1323 "unimplemented format %i\n", fmt);
1324 }
1325
1326 /* exponent: */
1327 exponent = 0;
1328 switch (fmt) {
1329 case FMT_W:
1330 reg &= 0xffffffffULL;
1331 case FMT_L:
1332 break;
1333 case FMT_S:
1334 reg &= 0xffffffffULL;
1335 case FMT_D:
1336 exponent = (reg >> n_frac) & ((1 << n_exp) - 1);
1337 exponent -= (1 << (n_exp-1)) - 1;
1338 break;
1339 default:
1340 fatal("fpu_interpret_float_value(): unimplemented "
1341 "format %i\n", fmt);
1342 }
1343
1344 /* nan: */
1345 nan = 0;
1346 switch (fmt) {
1347 case FMT_S:
1348 if (reg == 0x7fffffffULL || reg == 0x7fbfffffULL)
1349 nan = 1;
1350 break;
1351 case FMT_D:
1352 if (reg == 0x7fffffffffffffffULL ||
1353 reg == 0x7ff7ffffffffffffULL)
1354 nan = 1;
1355 break;
1356 }
1357
1358 if (nan) {
1359 fvp->f = 1.0;
1360 goto no_reasonable_result;
1361 }
1362
1363 /* fraction: */
1364 fraction = 0.0;
1365 switch (fmt) {
1366 case FMT_W:
1367 {
1368 int32_t r_int = reg;
1369 fraction = r_int;
1370 }
1371 break;
1372 case FMT_L:
1373 {
1374 int64_t r_int = reg;
1375 fraction = r_int;
1376 }
1377 break;
1378 case FMT_S:
1379 case FMT_D:
1380 /* sign: */
1381 sign = (reg >> 31) & 1;
1382 if (fmt == FMT_D)
1383 sign = (reg >> 63) & 1;
1384
1385 fraction = 0.0;
1386 for (i=0; i<n_frac; i++) {
1387 int bit = (reg >> i) & 1;
1388 fraction /= 2.0;
1389 if (bit)
1390 fraction += 1.0;
1391 }
1392 /* Add implicit bit 0: */
1393 fraction = (fraction / 2.0) + 1.0;
1394 break;
1395 default:
1396 fatal("fpu_interpret_float_value(): "
1397 "unimplemented format %i\n", fmt);
1398 }
1399
1400 /* form the value: */
1401 fvp->f = fraction;
1402
1403 /* fatal("load reg=%016llx sign=%i exponent=%i fraction=%f ",
1404 (long long)reg, sign, exponent, fraction); */
1405
1406 /* TODO: this is awful for exponents of large magnitude. */
1407 if (exponent > 0) {
1408 /*
1409 * NOTE / TODO:
1410 *
1411 * This is an ulgy workaround on Alpha, where it seems that
1412 * multiplying by 2, 1024 times causes a floating point
1413 * exception. (Triggered by running for example NetBSD/pmax
1414 * 2.0 on an Alpha.)
1415 */
1416 if (exponent == 1024)
1417 exponent = 1023;
1418
1419 while (exponent-- > 0)
1420 fvp->f *= 2.0;
1421 } else if (exponent < 0) {
1422 while (exponent++ < 0)
1423 fvp->f /= 2.0;
1424 }
1425
1426 if (sign)
1427 fvp->f = -fvp->f;
1428
1429 no_reasonable_result:
1430 fvp->nan = nan;
1431
1432 /* fatal("f = %f\n", fvp->f); */
1433 }
1434
1435
1436 /*
1437 * fpu_store_float_value():
1438 *
1439 * Stores a float value (actually a double) in fmt format.
1440 */
1441 static void fpu_store_float_value(struct mips_coproc *cp, int fd,
1442 double nf, int fmt, int nan)
1443 {
1444 int n_frac = 0, n_exp = 0, signofs=0;
1445 int i, exponent;
1446 uint64_t r = 0, r2;
1447 int64_t r3;
1448
1449 /* n_frac and n_exp: */
1450 switch (fmt) {
1451 case FMT_S: n_frac = 23; n_exp = 8; signofs = 31; break;
1452 case FMT_W: n_frac = 31; n_exp = 0; signofs = 31; break;
1453 case FMT_D: n_frac = 52; n_exp = 11; signofs = 63; break;
1454 case FMT_L: n_frac = 63; n_exp = 0; signofs = 63; break;
1455 default:
1456 fatal("fpu_store_float_value(): unimplemented format"
1457 " %i\n", fmt);
1458 }
1459
1460 if ((fmt == FMT_S || fmt == FMT_D) && nan)
1461 goto store_nan;
1462
1463 /* fraction: */
1464 switch (fmt) {
1465 case FMT_W:
1466 case FMT_L:
1467 /*
1468 * This causes an implicit conversion of double to integer.
1469 * If nf < 0.0, then r2 will begin with a sequence of binary
1470 * 1's, which is ok.
1471 */
1472 r3 = nf;
1473 r2 = r3;
1474 r |= r2;
1475
1476 if (fmt == FMT_W)
1477 r &= 0xffffffffULL;
1478 break;
1479 case FMT_S:
1480 case FMT_D:
1481 /* fatal("store f=%f ", nf); */
1482
1483 /* sign bit: */
1484 if (nf < 0.0) {
1485 r |= ((uint64_t)1 << signofs);
1486 nf = -nf;
1487 }
1488
1489 /*
1490 * How to convert back from double to exponent + fraction:
1491 * We want fraction to be 1.xxx, that is
1492 * 1.0 <= fraction < 2.0
1493 *
1494 * This method is very slow but should work:
1495 */
1496 exponent = 0;
1497 while (nf < 1.0 && exponent > -1023) {
1498 nf *= 2.0;
1499 exponent --;
1500 }
1501 while (nf >= 2.0 && exponent < 1023) {
1502 nf /= 2.0;
1503 exponent ++;
1504 }
1505
1506 /* Here: 1.0 <= nf < 2.0 */
1507 /* fatal(" nf=%f", nf); */
1508 nf -= 1.0; /* remove implicit first bit */
1509 for (i=n_frac-1; i>=0; i--) {
1510 nf *= 2.0;
1511 if (nf >= 1.0) {
1512 r |= ((uint64_t)1 << i);
1513 nf -= 1.0;
1514 }
1515 /* printf("\n i=%2i r=%016llx\n", i, (long long)r); */
1516 }
1517
1518 /* Insert the exponent into the resulting word: */
1519 /* (First bias, then make sure it's within range) */
1520 exponent += (((uint64_t)1 << (n_exp-1)) - 1);
1521 if (exponent < 0)
1522 exponent = 0;
1523 if (exponent >= ((int64_t)1 << n_exp))
1524 exponent = ((int64_t)1 << n_exp) - 1;
1525 r |= (uint64_t)exponent << n_frac;
1526
1527 /* Special case for 0.0: */
1528 if (exponent == 0)
1529 r = 0;
1530
1531 /* fatal(" exp=%i, r = %016llx\n", exponent, (long long)r); */
1532
1533 break;
1534 default:
1535 /* TODO */
1536 fatal("fpu_store_float_value(): unimplemented format "
1537 "%i\n", fmt);
1538 }
1539
1540 store_nan:
1541 if (nan) {
1542 if (fmt == FMT_S)
1543 r = 0x7fffffffULL;
1544 else if (fmt == FMT_D)
1545 r = 0x7fffffffffffffffULL;
1546 else
1547 r = 0x7fffffffULL;
1548 }
1549
1550 /*
1551 * TODO: this is for 32-bit mode. It has to be updated later
1552 * for 64-bit coprocessor stuff.
1553 */
1554 if (fmt == FMT_D || fmt == FMT_L) {
1555 cp->reg[fd] = r & 0xffffffffULL;
1556 cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;
1557
1558 if (cp->reg[fd] & 0x80000000ULL)
1559 cp->reg[fd] |= 0xffffffff00000000ULL;
1560 if (cp->reg[fd+1] & 0x80000000ULL)
1561 cp->reg[fd+1] |= 0xffffffff00000000ULL;
1562 } else {
1563 cp->reg[fd] = r & 0xffffffffULL;
1564
1565 if (cp->reg[fd] & 0x80000000ULL)
1566 cp->reg[fd] |= 0xffffffff00000000ULL;
1567 }
1568 }
1569
1570
1571 /*
1572 * fpu_op():
1573 *
1574 * Perform a floating-point operation. For those of fs and ft
1575 * that are >= 0, those numbers are interpreted into local
1576 * variables.
1577 *
1578 * Only FPU_OP_C (compare) returns anything of interest, 1 for
1579 * true, 0 for false.
1580 */
1581 static int fpu_op(struct cpu *cpu, struct mips_coproc *cp, int op, int fmt,
1582 int ft, int fs, int fd, int cond, int output_fmt)
1583 {
1584 /* Potentially two input registers, fs and ft */
1585 struct internal_float_value float_value[2];
1586 int unordered, nan;
1587 uint64_t fs_v = 0;
1588 double nf;
1589
1590 if (fs >= 0) {
1591 fs_v = cp->reg[fs];
1592 /* TODO: register-pair mode and plain
1593 register mode? "FR" bit? */
1594 if (fmt == FMT_D || fmt == FMT_L)
1595 fs_v = (fs_v & 0xffffffffULL) +
1596 (cp->reg[(fs + 1) & 31] << 32);
1597 fpu_interpret_float_value(fs_v, &float_value[0], fmt);
1598 }
1599 if (ft >= 0) {
1600 uint64_t v = cp->reg[ft];
1601 /* TODO: register-pair mode and
1602 plain register mode? "FR" bit? */
1603 if (fmt == FMT_D || fmt == FMT_L)
1604 v = (v & 0xffffffffULL) +
1605 (cp->reg[(ft + 1) & 31] << 32);
1606 fpu_interpret_float_value(v, &float_value[1], fmt);
1607 }
1608
1609 switch (op) {
1610 case FPU_OP_ADD:
1611 nf = float_value[0].f + float_value[1].f;
1612 /* debug(" add: %f + %f = %f\n",
1613 float_value[0].f, float_value[1].f, nf); */
1614 fpu_store_float_value(cp, fd, nf, output_fmt,
1615 float_value[0].nan || float_value[1].nan);
1616 break;
1617 case FPU_OP_SUB:
1618 nf = float_value[0].f - float_value[1].f;
1619 /* debug(" sub: %f - %f = %f\n",
1620 float_value[0].f, float_value[1].f, nf); */
1621 fpu_store_float_value(cp, fd, nf, output_fmt,
1622 float_value[0].nan || float_value[1].nan);
1623 break;
1624 case FPU_OP_MUL:
1625 nf = float_value[0].f * float_value[1].f;
1626 /* debug(" mul: %f * %f = %f\n",
1627 float_value[0].f, float_value[1].f, nf); */
1628 fpu_store_float_value(cp, fd, nf, output_fmt,
1629 float_value[0].nan || float_value[1].nan);
1630 break;
1631 case FPU_OP_DIV:
1632 nan = float_value[0].nan || float_value[1].nan;
1633 if (fabs(float_value[1].f) > 0.00000000001)
1634 nf = float_value[0].f / float_value[1].f;
1635 else {
1636 fatal("DIV by zero !!!!\n");
1637 nf = 0.0; /* TODO */
1638 nan = 1;
1639 }
1640 /* debug(" div: %f / %f = %f\n",
1641 float_value[0].f, float_value[1].f, nf); */
1642 fpu_store_float_value(cp, fd, nf, output_fmt, nan);
1643 break;
1644 case FPU_OP_SQRT:
1645 nan = float_value[0].nan;
1646 if (float_value[0].f >= 0.0)
1647 nf = sqrt(float_value[0].f);
1648 else {
1649 fatal("SQRT by less than zero, %f !!!!\n",
1650 float_value[0].f);
1651 nf = 0.0; /* TODO */
1652 nan = 1;
1653 }
1654 /* debug(" sqrt: %f => %f\n", float_value[0].f, nf); */
1655 fpu_store_float_value(cp, fd, nf, output_fmt, nan);
1656 break;
1657 case FPU_OP_ABS:
1658 nf = fabs(float_value[0].f);
1659 /* debug(" abs: %f => %f\n", float_value[0].f, nf); */
1660 fpu_store_float_value(cp, fd, nf, output_fmt,
1661 float_value[0].nan);
1662 break;
1663 case FPU_OP_NEG:
1664 nf = - float_value[0].f;
1665 /* debug(" neg: %f => %f\n", float_value[0].f, nf); */
1666 fpu_store_float_value(cp, fd, nf, output_fmt,
1667 float_value[0].nan);
1668 break;
1669 case FPU_OP_CVT:
1670 nf = float_value[0].f;
1671 /* debug(" mov: %f => %f\n", float_value[0].f, nf); */
1672 fpu_store_float_value(cp, fd, nf, output_fmt,
1673 float_value[0].nan);
1674 break;
1675 case FPU_OP_MOV:
1676 /* Non-arithmetic move: */
1677 /*
1678 * TODO: this is for 32-bit mode. It has to be updated later
1679 * for 64-bit coprocessor stuff.
1680 */
1681 if (output_fmt == FMT_D || output_fmt == FMT_L) {
1682 cp->reg[fd] = fs_v & 0xffffffffULL;
1683 cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;
1684 if (cp->reg[fd] & 0x80000000ULL)
1685 cp->reg[fd] |= 0xffffffff00000000ULL;
1686 if (cp->reg[fd+1] & 0x80000000ULL)
1687 cp->reg[fd+1] |= 0xffffffff00000000ULL;
1688 } else {
1689 cp->reg[fd] = fs_v & 0xffffffffULL;
1690 if (cp->reg[fd] & 0x80000000ULL)
1691 cp->reg[fd] |= 0xffffffff00000000ULL;
1692 }
1693 break;
1694 case FPU_OP_C:
1695 /* debug(" c: cond=%i\n", cond); */
1696
1697 unordered = 0;
1698 if (float_value[0].nan || float_value[1].nan)
1699 unordered = 1;
1700
1701 switch (cond) {
1702 case 2: /* Equal */
1703 return (float_value[0].f == float_value[1].f);
1704 case 4: /* Ordered or Less than */
1705 return (float_value[0].f < float_value[1].f)
1706 || !unordered;
1707 case 5: /* Unordered or Less than */
1708 return (float_value[0].f < float_value[1].f)
1709 || unordered;
1710 case 6: /* Ordered or Less than or Equal */
1711 return (float_value[0].f <= float_value[1].f)
1712 || !unordered;
1713 case 7: /* Unordered or Less than or Equal */
1714 return (float_value[0].f <= float_value[1].f)
1715 || unordered;
1716 case 12:/* Less than */
1717 return (float_value[0].f < float_value[1].f);
1718 case 14:/* Less than or equal */
1719 return (float_value[0].f <= float_value[1].f);
1720
1721 /* The following are not commonly used, so I'll move these out
1722 of the if-0 on a case-by-case basis. */
1723 #if 0
1724 case 0: return 0; /* False */
1725 case 1: return 0; /* Unordered */
1726 case 3: return (float_value[0].f == float_value[1].f);
1727 /* Unordered or Equal */
1728 case 8: return 0; /* Signaling false */
1729 case 9: return 0; /* Not Greater than or Less than or Equal */
1730 case 10:return (float_value[0].f == float_value[1].f); /* Signaling Equal */
1731 case 11:return (float_value[0].f == float_value[1].f); /* Not Greater
1732 than or Less than */
1733 case 13:return !(float_value[0].f >= float_value[1].f); /* Not greater
1734 than or equal */
1735 case 15:return !(float_value[0].f > float_value[1].f); /* Not greater than */
1736 #endif
1737
1738 default:
1739 fatal("fpu_op(): unimplemented condition "
1740 "code %i. see cpu_mips_coproc.c\n", cond);
1741 }
1742 break;
1743 default:
1744 fatal("fpu_op(): unimplemented op %i\n", op);
1745 }
1746
1747 return 0;
1748 }
1749
1750
1751 /*
1752 * fpu_function():
1753 *
1754 * Returns 1 if function was implemented, 0 otherwise.
1755 * Debug trace should be printed for known instructions.
1756 */
1757 static int fpu_function(struct cpu *cpu, struct mips_coproc *cp,
1758 uint32_t function, int unassemble_only)
1759 {
1760 int fd, fs, ft, fmt, cond, cc;
1761
1762 fmt = (function >> 21) & 31;
1763 ft = (function >> 16) & 31;
1764 fs = (function >> 11) & 31;
1765 cc = (function >> 8) & 7;
1766 fd = (function >> 6) & 31;
1767 cond = (function >> 0) & 15;
1768
1769
1770 /* bc1f, bc1t, bc1fl, bc1tl: */
1771 if ((function & 0x03e00000) == 0x01000000) {
1772 int nd, tf, imm, cond_true;
1773 char *instr_mnem;
1774
1775 /* cc are bits 20..18: */
1776 cc = (function >> 18) & 7;
1777 nd = (function >> 17) & 1;
1778 tf = (function >> 16) & 1;
1779 imm = function & 65535;
1780 if (imm >= 32768)
1781 imm -= 65536;
1782
1783 instr_mnem = NULL;
1784 if (nd == 0 && tf == 0) instr_mnem = "bc1f";
1785 if (nd == 0 && tf == 1) instr_mnem = "bc1t";
1786 if (nd == 1 && tf == 0) instr_mnem = "bc1fl";
1787 if (nd == 1 && tf == 1) instr_mnem = "bc1tl";
1788
1789 if (cpu->machine->instruction_trace || unassemble_only)
1790 debug("%s\t%i,0x%016llx\n", instr_mnem, cc,
1791 (long long) (cpu->pc + (imm << 2)));
1792 if (unassemble_only)
1793 return 1;
1794
1795 if (cpu->cd.mips.delay_slot) {
1796 fatal("%s: jump inside a jump's delay slot, "
1797 "or similar. TODO\n", instr_mnem);
1798 cpu->running = 0;
1799 return 1;
1800 }
1801
1802 /* Both the FCCR and FCSR contain condition code bits... */
1803 if (cc == 0)
1804 cond_true = (cp->fcr[FPU_FCSR] >> FCSR_FCC0_SHIFT) & 1;
1805 else
1806 cond_true = (cp->fcr[FPU_FCSR] >>
1807 (FCSR_FCC1_SHIFT + cc-1)) & 1;
1808
1809 if (!tf)
1810 cond_true = !cond_true;
1811
1812 if (cond_true) {
1813 cpu->cd.mips.delay_slot = TO_BE_DELAYED;
1814 cpu->cd.mips.delay_jmpaddr = cpu->pc + (imm << 2);
1815 } else {
1816 /* "likely": */
1817 if (nd) {
1818 /* nullify the delay slot */
1819 cpu->cd.mips.nullify_next = 1;
1820 }
1821 }
1822
1823 return 1;
1824 }
1825
1826 /* add.fmt: Floating-point add */
1827 if ((function & 0x0000003f) == 0x00000000) {
1828 if (cpu->machine->instruction_trace || unassemble_only)
1829 debug("add.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);
1830 if (unassemble_only)
1831 return 1;
1832
1833 fpu_op(cpu, cp, FPU_OP_ADD, fmt, ft, fs, fd, -1, fmt);
1834 return 1;
1835 }
1836
1837 /* sub.fmt: Floating-point subtract */
1838 if ((function & 0x0000003f) == 0x00000001) {
1839 if (cpu->machine->instruction_trace || unassemble_only)
1840 debug("sub.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);
1841 if (unassemble_only)
1842 return 1;
1843
1844 fpu_op(cpu, cp, FPU_OP_SUB, fmt, ft, fs, fd, -1, fmt);
1845 return 1;
1846 }
1847
1848 /* mul.fmt: Floating-point multiply */
1849 if ((function & 0x0000003f) == 0x00000002) {
1850 if (cpu->machine->instruction_trace || unassemble_only)
1851 debug("mul.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);
1852 if (unassemble_only)
1853 return 1;
1854
1855 fpu_op(cpu, cp, FPU_OP_MUL, fmt, ft, fs, fd, -1, fmt);
1856 return 1;
1857 }
1858
1859 /* div.fmt: Floating-point divide */
1860 if ((function & 0x0000003f) == 0x00000003) {
1861 if (cpu->machine->instruction_trace || unassemble_only)
1862 debug("div.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);
1863 if (unassemble_only)
1864 return 1;
1865
1866 fpu_op(cpu, cp, FPU_OP_DIV, fmt, ft, fs, fd, -1, fmt);
1867 return 1;
1868 }
1869
1870 /* sqrt.fmt: Floating-point square-root */
1871 if ((function & 0x001f003f) == 0x00000004) {
1872 if (cpu->machine->instruction_trace || unassemble_only)
1873 debug("sqrt.%i\tr%i,r%i\n", fmt, fd, fs);
1874 if (unassemble_only)
1875 return 1;
1876
1877 fpu_op(cpu, cp, FPU_OP_SQRT, fmt, -1, fs, fd, -1, fmt);
1878 return 1;
1879 }
1880
1881 /* abs.fmt: Floating-point absolute value */
1882 if ((function & 0x001f003f) == 0x00000005) {
1883 if (cpu->machine->instruction_trace || unassemble_only)
1884 debug("abs.%i\tr%i,r%i\n", fmt, fd, fs);
1885 if (unassemble_only)
1886 return 1;
1887
1888 fpu_op(cpu, cp, FPU_OP_ABS, fmt, -1, fs, fd, -1, fmt);
1889 return 1;
1890 }
1891
1892 /* mov.fmt: Floating-point (non-arithmetic) move */
1893 if ((function & 0x0000003f) == 0x00000006) {
1894 if (cpu->machine->instruction_trace || unassemble_only)
1895 debug("mov.%i\tr%i,r%i\n", fmt, fd, fs);
1896 if (unassemble_only)
1897 return 1;
1898
1899 fpu_op(cpu, cp, FPU_OP_MOV, fmt, -1, fs, fd, -1, fmt);
1900 return 1;
1901 }
1902
1903 /* neg.fmt: Floating-point negate */
1904 if ((function & 0x001f003f) == 0x00000007) {
1905 if (cpu->machine->instruction_trace || unassemble_only)
1906 debug("neg.%i\tr%i,r%i\n", fmt, fd, fs);
1907 if (unassemble_only)
1908 return 1;
1909
1910 fpu_op(cpu, cp, FPU_OP_NEG, fmt, -1, fs, fd, -1, fmt);
1911 return 1;
1912 }
1913
1914 /* trunc.l.fmt: Truncate */
1915 if ((function & 0x001f003f) == 0x00000009) {
1916 if (cpu->machine->instruction_trace || unassemble_only)
1917 debug("trunc.l.%i\tr%i,r%i\n", fmt, fd, fs);
1918 if (unassemble_only)
1919 return 1;
1920
1921 /* TODO: not CVT? */
1922
1923 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_L);
1924 return 1;
1925 }
1926
1927 /* trunc.w.fmt: Truncate */
1928 if ((function & 0x001f003f) == 0x0000000d) {
1929 if (cpu->machine->instruction_trace || unassemble_only)
1930 debug("trunc.w.%i\tr%i,r%i\n", fmt, fd, fs);
1931 if (unassemble_only)
1932 return 1;
1933
1934 /* TODO: not CVT? */
1935
1936 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_W);
1937 return 1;
1938 }
1939
1940 /* c.cond.fmt: Floating-point compare */
1941 if ((function & 0x000000f0) == 0x00000030) {
1942 int cond_true;
1943 int bit;
1944
1945 if (cpu->machine->instruction_trace || unassemble_only)
1946 debug("c.%i.%i\tr%i,r%i,r%i\n", cond, fmt, cc, fs, ft);
1947 if (unassemble_only)
1948 return 1;
1949
1950 cond_true = fpu_op(cpu, cp, FPU_OP_C, fmt,
1951 ft, fs, -1, cond, fmt);
1952
1953 /*
1954 * Both the FCCR and FCSR contain condition code bits:
1955 * FCCR: bits 7..0
1956 * FCSR: bits 31..25 and 23
1957 */
1958 cp->fcr[FPU_FCCR] &= ~(1 << cc);
1959 if (cond_true)
1960 cp->fcr[FPU_FCCR] |= (1 << cc);
1961
1962 if (cc == 0) {
1963 bit = 1 << FCSR_FCC0_SHIFT;
1964 cp->fcr[FPU_FCSR] &= ~bit;
1965 if (cond_true)
1966 cp->fcr[FPU_FCSR] |= bit;
1967 } else {
1968 bit = 1 << (FCSR_FCC1_SHIFT + cc-1);
1969 cp->fcr[FPU_FCSR] &= ~bit;
1970 if (cond_true)
1971 cp->fcr[FPU_FCSR] |= bit;
1972 }
1973
1974 return 1;
1975 }
1976
1977 /* cvt.s.fmt: Convert to single floating-point */
1978 if ((function & 0x001f003f) == 0x00000020) {
1979 if (cpu->machine->instruction_trace || unassemble_only)
1980 debug("cvt.s.%i\tr%i,r%i\n", fmt, fd, fs);
1981 if (unassemble_only)
1982 return 1;
1983
1984 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_S);
1985 return 1;
1986 }
1987
1988 /* cvt.d.fmt: Convert to double floating-point */
1989 if ((function & 0x001f003f) == 0x00000021) {
1990 if (cpu->machine->instruction_trace || unassemble_only)
1991 debug("cvt.d.%i\tr%i,r%i\n", fmt, fd, fs);
1992 if (unassemble_only)
1993 return 1;
1994
1995 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_D);
1996 return 1;
1997 }
1998
1999 /* cvt.w.fmt: Convert to word fixed-point */
2000 if ((function & 0x001f003f) == 0x00000024) {
2001 if (cpu->machine->instruction_trace || unassemble_only)
2002 debug("cvt.w.%i\tr%i,r%i\n", fmt, fd, fs);
2003 if (unassemble_only)
2004 return 1;
2005
2006 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_W);
2007 return 1;
2008 }
2009
2010 return 0;
2011 }
2012
2013
2014 /*
2015 * coproc_tlbpr():
2016 *
2017 * 'tlbp' and 'tlbr'.
2018 */
2019 void coproc_tlbpr(struct cpu *cpu, int readflag)
2020 {
2021 struct mips_coproc *cp = cpu->cd.mips.coproc[0];
2022 int i, found, g_bit;
2023 uint64_t vpn2, xmask;
2024
2025 /* Read: */
2026 if (readflag) {
2027 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
2028 i = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK) >>
2029 R2K3K_INDEX_SHIFT;
2030 if (i >= cp->nr_of_tlbs) {
2031 /* TODO: exception? */
2032 fatal("warning: tlbr from index %i (too "
2033 "high)\n", i);
2034 return;
2035 }
2036
2037 /*
2038 * TODO: Hm. Earlier I had an & ~0x3f on the high
2039 * assignment and an & ~0xff on the lo0 assignment.
2040 * I wonder why.
2041 */
2042
2043 cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi; /* & ~0x3f; */
2044 cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;/* & ~0xff; */
2045 } else {
2046 /* R4000: */
2047 i = cp->reg[COP0_INDEX] & INDEX_MASK;
2048 if (i >= cp->nr_of_tlbs) /* TODO: exception */
2049 return;
2050
2051 cp->reg[COP0_PAGEMASK] = cp->tlbs[i].mask;
2052 cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi;
2053 cp->reg[COP0_ENTRYLO1] = cp->tlbs[i].lo1;
2054 cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;
2055
2056 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
2057 /* R4100 don't have the G bit in entryhi */
2058 } else {
2059 /* R4000 etc: */
2060 cp->reg[COP0_ENTRYHI] &= ~TLB_G;
2061 g_bit = cp->tlbs[i].hi & TLB_G;
2062
2063 cp->reg[COP0_ENTRYLO0] &= ~ENTRYLO_G;
2064 cp->reg[COP0_ENTRYLO1] &= ~ENTRYLO_G;
2065 if (g_bit) {
2066 cp->reg[COP0_ENTRYLO0] |= ENTRYLO_G;
2067 cp->reg[COP0_ENTRYLO1] |= ENTRYLO_G;
2068 }
2069 }
2070 }
2071
2072 return;
2073 }
2074
2075 /* Probe: */
2076 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
2077 vpn2 = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
2078 found = -1;
2079 for (i=0; i<cp->nr_of_tlbs; i++)
2080 if ( ((cp->tlbs[i].hi & R2K3K_ENTRYHI_ASID_MASK) ==
2081 (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK))
2082 || cp->tlbs[i].lo0 & R2K3K_ENTRYLO_G)
2083 if ((cp->tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK)
2084 == vpn2) {
2085 found = i;
2086 break;
2087 }
2088 } else {
2089 /* R4000 and R10000: */
2090 if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
2091 xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K;
2092 else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
2093 xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800;
2094 else
2095 xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK;
2096 vpn2 = cp->reg[COP0_ENTRYHI] & xmask;
2097 found = -1;
2098 for (i=0; i<cp->nr_of_tlbs; i++) {
2099 int gbit = cp->tlbs[i].hi & TLB_G;
2100 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
2101 gbit = (cp->tlbs[i].lo0 & ENTRYLO_G) &&
2102 (cp->tlbs[i].lo1 & ENTRYLO_G);
2103
2104 if ( ((cp->tlbs[i].hi & ENTRYHI_ASID) ==
2105 (cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID)) || gbit) {
2106 uint64_t a = vpn2 & ~cp->tlbs[i].mask;
2107 uint64_t b = (cp->tlbs[i].hi & xmask) &
2108 ~cp->tlbs[i].mask;
2109 if (a == b) {
2110 found = i;
2111 break;
2112 }
2113 }
2114 }
2115 }
2116 if (found == -1)
2117 cp->reg[COP0_INDEX] = INDEX_P;
2118 else {
2119 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
2120 cp->reg[COP0_INDEX] = found << R2K3K_INDEX_SHIFT;
2121 else
2122 cp->reg[COP0_INDEX] = found;
2123 }
2124
2125 /* Sign extend the index register: */
2126 if ((cp->reg[COP0_INDEX] >> 32) == 0 &&
2127 cp->reg[COP0_INDEX] & 0x80000000)
2128 cp->reg[COP0_INDEX] |=
2129 0xffffffff00000000ULL;
2130 }
2131
2132
2133 /*
2134 * coproc_tlbwri():
2135 *
2136 * 'tlbwr' and 'tlbwi'
2137 */
2138 void coproc_tlbwri(struct cpu *cpu, int randomflag)
2139 {
2140 struct mips_coproc *cp = cpu->cd.mips.coproc[0];
2141 int index, g_bit;
2142 uint64_t oldvaddr;
2143 int old_asid = -1;
2144
2145 /*
2146 * ... and the last instruction page:
2147 *
2148 * Some thoughts about this: Code running in
2149 * the kernel's physical address space has the
2150 * same vaddr->paddr translation, so the last
2151 * virtual page invalidation only needs to
2152 * happen if we are for some extremely weird
2153 * reason NOT running in the kernel's physical
2154 * address space.
2155 *
2156 * (An even insaner (but probably useless)
2157 * optimization would be to only invalidate
2158 * the last virtual page stuff if the TLB
2159 * update actually affects the vaddr in
2160 * question.)
2161 */
2162
2163 if (cpu->pc < (uint64_t)0xffffffff80000000ULL ||
2164 cpu->pc >= (uint64_t)0xffffffffc0000000ULL)
2165 cpu->cd.mips.pc_last_virtual_page =
2166 PC_LAST_PAGE_IMPOSSIBLE_VALUE;
2167
2168 if (randomflag) {
2169 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
2170 index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
2171 >> R2K3K_RANDOM_SHIFT;
2172 else
2173 index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
2174 } else {
2175 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
2176 index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK)
2177 >> R2K3K_INDEX_SHIFT;
2178 else
2179 index = cp->reg[COP0_INDEX] & INDEX_MASK;
2180 }
2181
2182 if (index >= cp->nr_of_tlbs) {
2183 fatal("warning: tlb index %i too high (max is %i)\n",
2184 index, cp->nr_of_tlbs - 1);
2185 /* TODO: cause an exception? */
2186 return;
2187 }
2188
2189 #if 0
2190 /* Debug dump of the previous entry at that index: */
2191 debug(" old entry at index = %04x", index);
2192 debug(" mask = %016llx", (long long) cp->tlbs[index].mask);
2193 debug(" hi = %016llx", (long long) cp->tlbs[index].hi);
2194 debug(" lo0 = %016llx", (long long) cp->tlbs[index].lo0);
2195 debug(" lo1 = %016llx\n", (long long) cp->tlbs[index].lo1);
2196 #endif
2197
2198 /* Translation caches must be invalidated: */
2199 switch (cpu->cd.mips.cpu_type.mmu_model) {
2200 case MMU3K:
2201 oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
2202 oldvaddr &= 0xffffffffULL;
2203 if (oldvaddr & 0x80000000ULL)
2204 oldvaddr |= 0xffffffff00000000ULL;
2205 old_asid = (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK)
2206 >> R2K3K_ENTRYHI_ASID_SHIFT;
2207
2208 /* TODO: Bug? Why does this if need to be commented out? */
2209
2210 /* if (cp->tlbs[index].lo0 & ENTRYLO_V) */
2211 invalidate_translation_caches(cpu, 0, oldvaddr, 0, 0);
2212 break;
2213 default:
2214 if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
2215 oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
2216 /* 44 addressable bits: */
2217 if (oldvaddr & 0x80000000000ULL)
2218 oldvaddr |= 0xfffff00000000000ULL;
2219 } else {
2220 /* Assume MMU4K */
2221 oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
2222 /* 40 addressable bits: */
2223 if (oldvaddr & 0x8000000000ULL)
2224 oldvaddr |= 0xffffff0000000000ULL;
2225 }
2226
2227 /*
2228 * Both pages:
2229 *
2230 * TODO: non-4KB page sizes!
2231 */
2232 invalidate_translation_caches(
2233 cpu, 0, oldvaddr & ~0x1fff, 0, 0);
2234 invalidate_translation_caches(
2235 cpu, 0, (oldvaddr & ~0x1fff) | 0x1000, 0, 0);
2236 }
2237
2238
2239 /* Write the new entry: */
2240
2241 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
2242 uint64_t vaddr, paddr;
2243 int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;
2244 unsigned char *memblock = NULL;
2245
2246 cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI];
2247 cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0];
2248
2249 vaddr = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
2250 paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;
2251
2252 /* TODO: This is ugly. */
2253 if (paddr < 0x10000000)
2254 memblock = memory_paddr_to_hostaddr(
2255 cpu->mem, paddr, 1);
2256
2257 if (memblock != NULL &&
2258 cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {
2259 memblock += (paddr & ((1 << BITS_PER_PAGETABLE) - 1));
2260
2261 /*
2262 * TODO: Hahaha, this is even uglier than the thing
2263 * above. Some OSes seem to map code pages read/write,
2264 * which causes the bintrans cache to be invalidated
2265 * even when it doesn't have to be.
2266 */
2267 /* if (vaddr < 0x10000000) */
2268 wf = 0;
2269
2270 update_translation_table(cpu, vaddr, memblock,
2271 wf, paddr);
2272 }
2273 } else {
2274 /* R4000: */
2275 g_bit = (cp->reg[COP0_ENTRYLO0] &
2276 cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
2277 cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];
2278 cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI];
2279 cp->tlbs[index].lo1 = cp->reg[COP0_ENTRYLO1];
2280 cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0];
2281
2282 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
2283 /* NOTE: The VR4131 (and possibly others) don't have
2284 a Global bit in entryhi */
2285 cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK];
2286 } else {
2287 cp->tlbs[index].lo0 &= ~ENTRYLO_G;
2288 cp->tlbs[index].lo1 &= ~ENTRYLO_G;
2289
2290 cp->tlbs[index].hi &= ~TLB_G;
2291 if (g_bit)
2292 cp->tlbs[index].hi |= TLB_G;
2293 }
2294 }
2295
2296 if (randomflag) {
2297 if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
2298 cp->reg[COP0_RANDOM] =
2299 ((random() % (cp->nr_of_tlbs - 8)) + 8)
2300 << R2K3K_RANDOM_SHIFT;
2301 } else {
2302 cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
2303 % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
2304 }
2305 }
2306 }
2307
2308
2309 /*
2310 * coproc_rfe():
2311 *
2312 * Return from exception. (R3000 etc.)
2313 */
2314 void coproc_rfe(struct cpu *cpu)
2315 {
2316 int oldmode;
2317
2318 oldmode = cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_SR_KU_CUR;
2319
2320 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =
2321 (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |
2322 ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2);
2323
2324 /* Changing from kernel to user mode? Then this is necessary: */
2325 if (!oldmode &&
2326 (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &
2327 MIPS1_SR_KU_CUR))
2328 invalidate_translation_caches(cpu, 0, 0, 1, 0);
2329 }
2330
2331
2332 /*
2333 * coproc_eret():
2334 *
2335 * Return from exception. (R4000 etc.)
2336 */
2337 void coproc_eret(struct cpu *cpu)
2338 {
2339 int oldmode, newmode;
2340
2341 /* Kernel mode flag: */
2342 oldmode = 0;
2343 if ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS3_SR_KSU_MASK)
2344 != MIPS3_SR_KSU_USER
2345 || (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & (STATUS_EXL |
2346 STATUS_ERL)) ||
2347 (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 1) == 0)
2348 oldmode = 1;
2349
2350 if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {
2351 cpu->pc = cpu->cd.mips.pc_last =
2352 cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC];
2353 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
2354 } else {
2355 cpu->pc = cpu->cd.mips.pc_last =
2356 cpu->cd.mips.coproc[0]->reg[COP0_EPC];
2357 cpu->cd.mips.delay_slot = 0;
2358 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;
2359 }
2360
2361 cpu->cd.mips.rmw = 0; /* the "LL bit" */
2362
2363 /* New kernel mode flag: */
2364 newmode = 0;
2365 if ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS3_SR_KSU_MASK)
2366 != MIPS3_SR_KSU_USER
2367 || (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & (STATUS_EXL |
2368 STATUS_ERL)) ||
2369 (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 1) == 0)
2370 newmode = 1;
2371
2372 /* Changing from kernel to user mode?
2373 Then this is necessary: TODO */
2374 if (oldmode && !newmode)
2375 invalidate_translation_caches(cpu, 0, 0, 1, 0);
2376 }
2377
2378
2379 /*
2380 * coproc_function():
2381 *
2382 * Execute a coprocessor specific instruction. cp must be != NULL.
2383 * Debug trace should be printed for known instructions, if
2384 * unassemble_only is non-zero. (This will NOT execute the instruction.)
2385 *
2386 * TODO: This is a mess and should be restructured (again).
2387 */
2388 void coproc_function(struct cpu *cpu, struct mips_coproc *cp, int cpnr,
2389 uint32_t function, int unassemble_only, int running)
2390 {
2391 int co_bit, op, rt, rd, fs, copz;
2392 uint64_t tmpvalue;
2393
2394 if (cp == NULL) {
2395 if (unassemble_only) {
2396 debug("cop%i\t0x%08x (coprocessor not available)\n",
2397 cpnr, (int)function);
2398 return;
2399 }
2400 fatal("[ pc=0x%016llx cop%i\t0x%08x (coprocessor not "
2401 "available)\n", (long long)cpu->pc, cpnr, (int)function);
2402 return;
2403 }
2404
2405 #if 0
2406 /* No FPU? */
2407 if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {
2408 mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);
2409 return;
2410 }
2411 #endif
2412
2413 /* For quick reference: */
2414 copz = (function >> 21) & 31;
2415 rt = (function >> 16) & 31;
2416 rd = (function >> 11) & 31;
2417
2418 if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MFCz << 21))
2419 || ((function & 0x03e007f8) == (COPz_DMFCz << 21)))) {
2420 if (unassemble_only) {
2421 debug("%s%i\t%s,%s\n",
2422 copz==COPz_DMFCz? "dmfc" : "mfc", cpnr,
2423 regnames[rt], cop0_names[rd]);
2424 return;
2425 }
2426 coproc_register_read(cpu, cpu->cd.mips.coproc[cpnr],
2427 rd, &tmpvalue);
2428 cpu->cd.mips.gpr[rt] = tmpvalue;
2429 if (copz == COPz_MFCz) {
2430 /* Sign-extend: */
2431 cpu->cd.mips.gpr[rt] &= 0xffffffffULL;
2432 if (cpu->cd.mips.gpr[rt] & 0x80000000ULL)
2433 cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL;
2434 }
2435 return;
2436 }
2437
2438 if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MTCz << 21))
2439 || ((function & 0x03e007f8) == (COPz_DMTCz << 21)))) {
2440 if (unassemble_only) {
2441 debug("%s%i\t%s,%s\n",
2442 copz==COPz_DMTCz? "dmtc" : "mtc", cpnr,
2443 regnames[rt], cop0_names[rd]);
2444 return;
2445 }
2446 tmpvalue = cpu->cd.mips.gpr[rt];
2447 if (copz == COPz_MTCz) {
2448 /* Sign-extend: */
2449 tmpvalue &= 0xffffffffULL;
2450 if (tmpvalue & 0x80000000ULL)
2451 tmpvalue |= 0xffffffff00000000ULL;
2452 }
2453 coproc_register_write(cpu, cpu->cd.mips.coproc[cpnr], rd,
2454 &tmpvalue, copz == COPz_DMTCz);
2455 return;
2456 }
2457
2458 if (cpnr <= 1 && (((function & 0x03e007ff) == (COPz_CFCz << 21))
2459 || ((function & 0x03e007ff) == (COPz_CTCz << 21)))) {
2460 switch (copz) {
2461 case COPz_CFCz: /* Copy from FPU control register */
2462 rt = (function >> 16) & 31;
2463 fs = (function >> 11) & 31;
2464 if (unassemble_only) {
2465 debug("cfc%i\t%s,r%i\n", cpnr,
2466 regnames[rt], fs);
2467 return;
2468 }
2469 cpu->cd.mips.gpr[rt] = cp->fcr[fs] & 0xffffffffULL;
2470 if (cpu->cd.mips.gpr[rt] & 0x80000000ULL)
2471 cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL;
2472 /* TODO: implement delay for gpr[rt]
2473 (for MIPS I,II,III only) */
2474 return;
2475 case COPz_CTCz: /* Copy to FPU control register */
2476 rt = (function >> 16) & 31;
2477 fs = (function >> 11) & 31;
2478 if (unassemble_only) {
2479 debug("ctc%i\t%s,r%i\n", cpnr,
2480 regnames[rt], fs);
2481 return;
2482 }
2483
2484 switch (cpnr) {
2485 case 0: /* System coprocessor */
2486 fatal("[ warning: unimplemented ctc%i, "
2487 "0x%08x -> ctl reg %i ]\n", cpnr,
2488 (int)cpu->cd.mips.gpr[rt], fs);
2489 break;
2490 case 1: /* FPU */
2491 if (fs == 0)
2492 fatal("[ Attempt to write to FPU "
2493 "control register 0 (?) ]\n");
2494 else {
2495 uint64_t tmp = cpu->cd.mips.gpr[rt];
2496 cp->fcr[fs] = tmp;
2497
2498 /* TODO: writing to control register 31
2499 should cause exceptions, depending
2500 on status bits! */
2501
2502 switch (fs) {
2503 case FPU_FCCR:
2504 cp->fcr[FPU_FCSR] =
2505 (cp->fcr[FPU_FCSR] &
2506 0x017fffffULL) | ((tmp & 1)
2507 << FCSR_FCC0_SHIFT)
2508 | (((tmp & 0xfe) >> 1) <<
2509 FCSR_FCC1_SHIFT);
2510 break;
2511 case FPU_FCSR:
2512 cp->fcr[FPU_FCCR] =
2513 (cp->fcr[FPU_FCCR] &
2514 0xffffff00ULL) | ((tmp >>
2515 FCSR_FCC0_SHIFT) & 1) |
2516 (((tmp >> FCSR_FCC1_SHIFT)
2517 & 0x7f) << 1);
2518 break;
2519 default:
2520 ;
2521 }
2522 }
2523 break;
2524 }
2525
2526 /* TODO: implement delay for gpr[rt]
2527 (for MIPS I,II,III only) */
2528 return;
2529 default:
2530 ;
2531 }
2532 }
2533
2534 /* Math (Floating point) coprocessor calls: */
2535 if (cpnr==1) {
2536 if (fpu_function(cpu, cp, function, unassemble_only))
2537 return;
2538 }
2539
2540 /* For AU1500 and probably others: deret */
2541 if (function == 0x0200001f) {
2542 if (unassemble_only) {
2543 debug("deret\n");
2544 return;
2545 }
2546
2547 /*
2548 * According to the MIPS64 manual, deret loads PC from the
2549 * DEPC cop0 register, and jumps there immediately. No
2550 * delay slot.
2551 *
2552 * TODO: This instruction is only available if the processor
2553 * is in debug mode. (What does that mean?)
2554 * TODO: This instruction is undefined in a delay slot.
2555 */
2556
2557 cpu->pc = cpu->cd.mips.pc_last = cp->reg[COP0_DEPC];
2558 cpu->cd.mips.delay_slot = 0;
2559 cp->reg[COP0_STATUS] &= ~STATUS_EXL;
2560
2561 return;
2562 }
2563
2564
2565 /* Ugly R5900 hacks: */
2566 if ((function & 0xfffff) == 0x38) { /* ei */
2567 if (unassemble_only) {
2568 debug("ei\n");
2569 return;
2570 }
2571 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE;
2572 return;
2573 }
2574
2575 if ((function & 0xfffff) == 0x39) { /* di */
2576 if (unassemble_only) {
2577 debug("di\n");
2578 return;
2579 }
2580 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE;
2581 return;
2582 }
2583
2584 co_bit = (function >> 25) & 1;
2585
2586 /* TLB operations and other things: */
2587 if (cp->coproc_nr == 0) {
2588 op = (function) & 0xff;
2589 switch (co_bit) {
2590 case 1:
2591 switch (op) {
2592 case COP0_TLBR: /* Read indexed TLB entry */
2593 if (unassemble_only) {
2594 debug("tlbr\n");
2595 return;
2596 }
2597 coproc_tlbpr(cpu, 1);
2598 return;
2599 case COP0_TLBWI: /* Write indexed */
2600 case COP0_TLBWR: /* Write random */
2601 if (unassemble_only) {
2602 if (op == COP0_TLBWI)
2603 debug("tlbwi");
2604 else
2605 debug("tlbwr");
2606 if (!running) {
2607 debug("\n");
2608 return;
2609 }
2610 debug("\tindex=%08llx",
2611 (long long)cp->reg[COP0_INDEX]);
2612 debug(", random=%08llx",
2613 (long long)cp->reg[COP0_RANDOM]);
2614 debug(", mask=%016llx",
2615 (long long)cp->reg[COP0_PAGEMASK]);
2616 debug(", hi=%016llx",
2617 (long long)cp->reg[COP0_ENTRYHI]);
2618 debug(", lo0=%016llx",
2619 (long long)cp->reg[COP0_ENTRYLO0]);
2620 debug(", lo1=%016llx\n",
2621 (long long)cp->reg[COP0_ENTRYLO1]);
2622 }
2623 coproc_tlbwri(cpu, op == COP0_TLBWR);
2624 return;
2625 case COP0_TLBP: /* Probe TLB for
2626 matching entry */
2627 if (unassemble_only) {
2628 debug("tlbp\n");
2629 return;
2630 }
2631 coproc_tlbpr(cpu, 0);
2632 return;
2633 case COP0_RFE: /* R2000/R3000 only:
2634 Return from Exception */
2635 if (unassemble_only) {
2636 debug("rfe\n");
2637 return;
2638 }
2639 coproc_rfe(cpu);
2640 return;
2641 case COP0_ERET: /* R4000: Return from exception */
2642 if (unassemble_only) {
2643 debug("eret\n");
2644 return;
2645 }
2646 coproc_eret(cpu);
2647 return;
2648 case COP0_STANDBY:
2649 if (unassemble_only) {
2650 debug("standby\n");
2651 return;
2652 }
2653 /* TODO: Hm. Do something here? */
2654 return;
2655 case COP0_SUSPEND:
2656 if (unassemble_only) {
2657 debug("suspend\n");
2658 return;
2659 }
2660 /* TODO: Hm. Do something here? */
2661 return;
2662 case COP0_HIBERNATE:
2663 if (unassemble_only) {
2664 debug("hibernate\n");
2665 return;
2666 }
2667 /* TODO: Hm. Do something here? */
2668 return;
2669 default:
2670 ;
2671 }
2672 default:
2673 ;
2674 }
2675 }
2676
2677 /* TODO: coprocessor R2020 on DECstation? */
2678 if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x0100ffff) {
2679 if (unassemble_only) {
2680 debug("decstation_r2020_writeback\n");
2681 return;
2682 }
2683 /* TODO */
2684 return;
2685 }
2686
2687 /* TODO: RM5200 idle (?) */
2688 if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x02000020) {
2689 if (unassemble_only) {
2690 debug("idle(?)\n"); /* TODO */
2691 return;
2692 }
2693
2694 /* Idle? TODO */
2695 return;
2696 }
2697
2698 if (unassemble_only) {
2699 debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);
2700 return;
2701 }
2702
2703 fatal("cpu%i: UNIMPLEMENTED coproc%i function %08lx "
2704 "(pc = %016llx)\n", cpu->cpu_id, cp->coproc_nr, function,
2705 (long long)cpu->cd.mips.pc_last);
2706 #if 1
2707 single_step = 1;
2708 #else
2709 mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cp->coproc_nr, 0, 0, 0);
2710 #endif
2711 }
2712
2713 #endif /* ENABLE_MIPS */

  ViewVC Help
Powered by ViewVC 1.1.26