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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26