/[gxemul]/trunk/src/cpu_mips_coproc.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/cpu_mips_coproc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 81092 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.905 2005/08/16 09:16:24 debug Exp $
20050628	Continuing the work on the ARM translation engine. end_of_page
		works. Experimenting with load/store translation caches
		(virtual -> physical -> host).
20050629	More ARM stuff (memory access translation cache, mostly). This
		might break a lot of stuff elsewhere, probably some MIPS-
		related translation things.
20050630	Many load/stores are now automatically generated and included
		into cpu_arm_instr.c; 1024 functions in total (!).
		Fixes based on feedback from Alec Voropay: only print 8 hex
		digits instead of 16 in some cases when emulating 32-bit
		machines; similar 8 vs 16 digit fix for breakpoint addresses;
		4Kc has 16 TLB entries, not 48; the MIPS config select1
		register is now printed with "reg ,0".
		Also changing many other occurances of 16 vs 8 digit output.
		Adding cache associativity fields to mips_cpu_types.h; updating
		some other cache fields; making the output of
		mips_cpu_dumpinfo() look nicer.
		Generalizing the bintrans stuff for device accesses to also
		work with the new translation system. (This might also break
		some MIPS things.)
		Adding multi-load/store instructions to the ARM disassembler
		and the translator, and some optimizations of various kinds.
20050701	Adding a simple dev_disk (it can read/write sectors from
		disk images).
20050712	Adding dev_ether (a simple ethernet send/receive device).
		Debugger command "ninstrs" for toggling show_nr_of_instructions
		during runtime.
		Removing the framebuffer logo.
20050713	Continuing on dev_ether.
		Adding a dummy cpu_alpha (again).
20050714	More work on cpu_alpha.
20050715	More work on cpu_alpha. Many instructions work, enough to run
		a simple framebuffer fill test (similar to the ARM test).
20050716	More Alpha stuff.
20050717	Minor updates (Alpha stuff).
20050718	Minor updates (Alpha stuff).
20050719	Generalizing some Alpha instructions.
20050720	More Alpha-related updates.
20050721	Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha.
20050722	Alpha-related updates: userland stuff (Hello World using
		write() compiled statically for FreeBSD/Alpha runs fine), and
		more instructions are now implemented.
20050723	Fixing ldq_u and stq_u.
		Adding more instructions (conditional moves, masks, extracts,
		shifts).
20050724	More FreeBSD/Alpha userland stuff, and adding some more
		instructions (inserts).
20050725	Continuing on the Alpha stuff. (Adding dummy ldt/stt.)
		Adding a -A command line option to turn off alignment checks
		in some cases (for translated code).
		Trying to remove the old bintrans code which updated the pc
		and nr_of_executed_instructions for every instruction.
20050726	Making another attempt att removing the pc/nr of instructions
		code. This time it worked, huge performance increase for
		artificial test code, but performance loss for real-world
		code :-( so I'm scrapping that code for now.
		Tiny performance increase on Alpha (by using ret instead of
		jmp, to play nice with the Alpha's branch prediction) for the
		old MIPS bintrans backend.
20050727	Various minor fixes and cleanups.
20050728	Switching from a 2-level virtual to host/physical translation
		system for ARM emulation, to a 1-level translation.
		Trying to switch from 2-level to 1-level for the MIPS bintrans
		system as well (Alpha only, so far), but there is at least one
		problem: caches and/or how they work with device mappings.
20050730	Doing the 2-level to 1-level conversion for the i386 backend.
		The cache/device bug is still there for R2K/3K :(
		Various other minor updates (Malta etc).
		The mc146818 clock now updates the UIP bit in a way which works
		better with Linux for at least sgimips and Malta emulation.
		Beginning the work on refactoring the dyntrans system.
20050731	Continuing the dyntrans refactoring.
		Fixing a small but serious host alignment bug in memory_rw.
		Adding support for big-endian load/stores to the i386 bintrans
		backend.
		Another minor i386 bintrans backend update: stores from the
		zero register are now one (or two) loads shorter.
		The slt and sltu instructions were incorrectly implemented for
		the i386 backend; only using them for 32-bit mode for now.
20050801	Continuing the dyntrans refactoring.
		Cleanup of the ns16550 serial controller (removing unnecessary
		code).
		Bugfix (memory corruption bug) in dev_gt, and a patch/hack from
		Alec Voropay for Linux/Malta.
20050802	More cleanup/refactoring of the dyntrans subsystem: adding
		phys_page pointers to the lookup tables, for quick jumps
		between translated pages.
		Better fix for the ns16550 device (but still no real FIFO
		functionality).
		Converting cpu_ppc to the new dyntrans system. This means that
		I will have to start from scratch with implementing each
		instruction, and figure out how to implement dual 64/32-bit
		modes etc.
		Removing the URISC CPU family, because it was useless.
20050803	When selecting a machine type, the main type can now be omitted
		if the subtype name is unique. (I.e. -E can be omitted.)
		Fixing a dyntrans/device update bug. (Writes to offset 0 of
		a device could sometimes go unnoticed.)
		Adding an experimental "instruction combination" hack for
		ARM for memset-like byte fill loops.
20050804	Minor progress on cpu_alpha and related things.
		Finally fixing the MIPS dmult/dmultu bugs.
		Fixing some minor TODOs.
20050805	Generalizing the 8259 PIC. It now also works with Cobalt
		and evbmips emulation, in addition to the x86 hack.
		Finally converting the ns16550 device to use devinit.
		Continuing the work on the dyntrans system. Thinking about
		how to add breakpoints.
20050806	More dyntrans updates. Breakpoints seem to work now.
20050807	Minor updates: cpu_alpha and related things; removing
		dev_malta (as it isn't used any more).
		Dyntrans: working on general "show trace tree" support.
		The trace tree stuff now works with both the old MIPS code and
		with newer dyntrans modes. :)
		Continuing on Alpha-related stuff (trying to get *BSD to boot
		a bit further, adding more instructions, etc).
20050808	Adding a dummy IA64 cpu family, and continuing the refactoring
		of the dyntrans system.
		Removing the regression test stuff, because it was more or
		less useless.
		Adding loadlinked/storeconditional type instructions to the
		Alpha emulation. (Needed for Linux/alpha. Not very well tested
		yet.)
20050809	The function call trace tree now prints a per-function nr of
		arguments. (Semi-meaningless, since that data isn't read yet
		from the ELFs; some hardcoded symbols such as memcpy() and
		strlen() work fine, though.)
		More dyntrans refactoring; taking out more of the things that
		are common to all cpu families.
20050810	Working on adding support for "dual mode" for PPC dyntrans
		(i.e. both 64-bit and 32-bit modes).
		(Re)adding some simple PPC instructions.
20050811	Adding a dummy M68K cpu family. The dyntrans system isn't ready
		for variable-length ISAs yet, so it's completely bogus so far.
		Re-adding more PPC instructions.
		Adding a hack to src/file.c which allows OpenBSD/mac68k a.out
		kernels to be loaded.
		Beginning to add PPC loads/stores. So far they only work in
		32-bit mode.
20050812	The configure file option "add_remote" now accepts symbolic
		host names, in addition to numeric IPv4 addresses.
		Re-adding more PPC instructions.
20050814	Continuing to port back more PPC instructions.
		Found and fixed the cache/device write-update bug for 32-bit
		MIPS bintrans. :-)
		Triggered a really weird and annoying bug in Compaq's C
		compiler; ccc sometimes outputs code which loads from an
		address _before_ checking whether the pointer was NULL or not.
		(I'm not sure how to handle this problem.)
20050815	Removing all of the old x86 instruction execution code; adding
		a new (dummy) dyntrans module for x86.
		Taking the first steps to extend the dyntrans system to support
		variable-length instructions.
		Slowly preparing for the next release.
20050816	Adding a dummy SPARC cpu module.
		Minor updates (documentation etc) for the release.

==============  RELEASE 0.3.5  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26