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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26