/[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 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 76719 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26