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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (show annotations)
Mon Oct 8 16:18:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 77645 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.772 2005/06/04 12:02:16 debug Exp $
20050428	Disabling the "-fmove-all-movables" option in the configure
		script, because it causes the compile to fail on OpenBSD/sgi.
20050502	Minor updates.
20050503	Removing the WRT54G mode (it was bogus anyway), and adding a
		comment about Windows NT for MIPS in doc/experiments.html.
		Minor updates to the x86 instruction decoding.
20050504	Adding some more x86 instructions.
		Adding support for reading files from ISO9660 CDROMs (including
		gzipped files). It's an ugly hack, but it seems to work.
		Various other minor updates (dev_vga.c, pc_bios.c etc).
20050505	Some more x86-related updates.
		Beginning (what I hope will be) a major code cleanup phase.
		"bootris" (an x86 bootsector) runs :-)
20050506	Adding some more x86 instructions.
20050507	tmpnam => mkstemp.
		Working on a hack to allow VGA charcells to be shown even when
		not running with X11.
		Adding more x86 instructions.
20050508	x86 32-bit SIB addressing fix, and more instructions.
20050509	Adding more x86 instructions.
20050510	Minor documentation updates, and other updates (x86 stuff etc.)
20050511	More x86-related updates.
20050513	Various updates, mostly x86-related. (Trying to fix flag 
		calculation, factoring out the ugly shift/rotate code, and
		some other things.)
20050514	Adding support for loading some old i386 a.out executables.
		Finally beginning the cleanup of machine/PROM/bios dependant
		info.
		Some minor documentation updates.
		Trying to clean up ARCBIOS stuff a little.
20050515	Trying to make it possible to actually use more than one disk
		type per machine (floppy, ide, scsi).
		Trying to clean up the kbd vs PROM console stuff. (For PC and
		ARC emulation modes, mostly.)
		Beginning to add an 8259 interrupt controller, and connecting
		it to the x86 emulation.
20050516	The first x86 interrupts seem to work (keyboard stuff).
		Adding a 8253/8254 programmable interval timer skeleton.
		FreeDOS now reaches a command prompt and can be interacted
		with.
20050517	After some bugfixes, MS-DOS also (sometimes) reaches a
		command prompt now.
		Trying to fix the pckbc to work with MS-DOS' keyb.com, but no
		success yet.
20050518	Adding a simple 32-bit x86 MMU skeleton.
20050519	Some more work on the x86 stuff. (Beginning the work on paging,
		and various other fixes).
20050520	More updates. Working on dev_vga (4-bit graphics modes), adding
		40 columns support to the PC bios emulation.
		Trying to add support for resizing windows when switching
		between graphics modes.
20050521	Many more x86-related updates.
20050522	Correcting the initial stack pointer's sign-extension for
		ARCBIOS emulation (thanks to Alec Voropay for noticing the
		error).
		Continuing on the cleanup (ARCBIOS etc).
		dev_vga updates.
20050523	More x86 updates: trying to add some support for protected mode
		interrupts (via gate descriptors) and many other fixes.
		More ARCBIOS cleanup.
		Adding a device flag which indicates that reads cause no
		side-effects. (Useful for the "dump" command in the debugger,
		and other things.)
		Adding support for directly starting up x86 ELFs, skipping the
		bootloader stage. (Most ELFs, however, are not suitable for
		this.)
20050524	Adding simple 32-bit x86 TSS task switching, but no privilege
		level support yet.
		More work on dev_vga. A small "Copper bars" demo works. :-)
		Adding support for Trap Flag (single-step exceptions), at least
		in real mode, and various other x86-related fixes.
20050525	Adding a new disk image prefix (gH;S;) which can be used to
		override the default nr of heads and sectors per track.
20050527	Various bug fixes, more work on the x86 mode (stack change on
		interrupts between different priv.levels), and some minor
		documentation updates.
20050528	Various fixes (x86 stuff).
20050529	More x86 fixes. An OpenBSD/i386 bootfloppy reaches userland
		and can be interacted with (although there are problems with
		key repetition). NetBSD/i386 triggers a serious CISC-related
		problem: instruction fetches across page boundaries, where
		the later part isn't actually part of the instruction.
20050530	Various minor updates. (Documentation updates, etc.)
20050531	Adding some experimental code (experiments/new_test_*) which
		could be useful for dynamic (but not binary) translation in
		the future.
20050602	Adding a dummy ARM skeleton.
		Fixing the pckbc key repetition problem (by adding release
		scancodes for all keypresses).
20050603	Minor updates for the next release.
20050604	Release testing. Minor updates.

==============  RELEASE 0.3.3  ==============

20050604	There'll probably be a 0.3.3.1 release soon, with some very
		very tiny updates.


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

  ViewVC Help
Powered by ViewVC 1.1.26