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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (show annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 76566 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26