/[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

Annotation of /trunk/src/cpu_mips_coproc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 6 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 dpavlin 2 /*
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 dpavlin 12 * $Id: cpu_mips_coproc.c,v 1.27 2005/08/14 15:47:36 debug Exp $
29 dpavlin 2 *
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 dpavlin 12 int cpu_type, IB, DB, SB, IC, DC, SC, IA, DA;
92 dpavlin 2
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 dpavlin 10 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 dpavlin 2 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 dpavlin 10 /* According to the MIPS64 (5K) User's Manual: */
308 dpavlin 2 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 dpavlin 10 | ((cpu->byte_order == EMUL_BIG_ENDIAN? 1 : 0) << 15)
315 dpavlin 2 /* endian mode */
316 dpavlin 10 | ((cpu_type == MIPS_5Kc? 2 : 0) << 13)
317     /* 0=MIPS32, 1=64S, 2=64 */
318 dpavlin 2 | ( 0 << 10) /* Architecture revision */
319     | ( 1 << 7) /* MMU type: 1=TLB, 3=FMT */
320     | ( 2 << 0) /* kseg0 cache coherency algorithm */
321     ;
322 dpavlin 12 /* Config select 1: caches etc. TODO: Don't use
323     cpu->machine for this stuff! */
324 dpavlin 10 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 dpavlin 12 IA = cpu->cd.mips.cpu_type.piways - 1;
333     DA = cpu->cd.mips.cpu_type.pdways - 1;
334 dpavlin 10 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 dpavlin 12 | (IA << 16) /* IA: I-cache assoc. (ways-1) */
339 dpavlin 10 | (DC << 13) /* DS: D-cache sets per way */
340     | (DB << 10) /* DL: D-cache line-size */
341 dpavlin 12 | (DA << 7) /* DA: D-cache assoc. (ways-1) */
342 dpavlin 10 | (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 dpavlin 2 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 dpavlin 12 int a, b, index;
545 dpavlin 2 struct vth32_table *tbl1;
546 dpavlin 10 void *p_r, *p_w;
547 dpavlin 2 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 dpavlin 12 index = (vaddr_page >> 12) & 0xfffff;
561    
562 dpavlin 2 /* printf("vaddr = %08x, a = %03x, b = %03x\n",
563     (int)vaddr_page,a, b); */
564 dpavlin 12
565 dpavlin 2 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 dpavlin 12 cpu->cd.mips.next_free_vth_table = tbl1->next_free;
581 dpavlin 2 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 dpavlin 10 p_r = tbl1->haddr_entry[b*2];
590     p_w = tbl1->haddr_entry[b*2+1];
591 dpavlin 2 p_paddr = tbl1->paddr_entry[b];
592 dpavlin 10 /* 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 dpavlin 2 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 dpavlin 10 tbl1->haddr_entry[b*2 + 1] = NULL;
603 dpavlin 12 if (cpu->cd.mips.host_store ==
604     cpu->cd.mips.host_store_orig)
605     cpu->cd.mips.host_store[index] = NULL;
606 dpavlin 10 } else if (writeflag==0 && p_w != NULL && host_page != NULL) {
607 dpavlin 2 /* Don't degrade a page from writable to readonly. */
608     } else {
609 dpavlin 10 if (host_page != NULL) {
610     tbl1->haddr_entry[b*2] = host_page;
611 dpavlin 12 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 dpavlin 10 tbl1->haddr_entry[b*2+1] = host_page;
616 dpavlin 12 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 dpavlin 10 tbl1->haddr_entry[b*2+1] = NULL;
622 dpavlin 12 if (cpu->cd.mips.host_store ==
623     cpu->cd.mips.host_store_orig)
624     cpu->cd.mips.host_store[index] = NULL;
625     }
626 dpavlin 10 } else {
627     tbl1->haddr_entry[b*2] = NULL;
628     tbl1->haddr_entry[b*2+1] = NULL;
629 dpavlin 12 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 dpavlin 10 }
635 dpavlin 2 tbl1->paddr_entry[b] = paddr_page;
636     }
637     tbl1->bintrans_chunks[b] = NULL;
638 dpavlin 10 }
639 dpavlin 2
640    
641     /*
642 dpavlin 12 * mips_update_translation_table():
643 dpavlin 2 */
644 dpavlin 12 void mips_update_translation_table(struct cpu *cpu, uint64_t vaddr_page,
645 dpavlin 2 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 dpavlin 12 int a, b, index;
670 dpavlin 2 struct vth32_table *tbl1;
671 dpavlin 10 void *p_r, *p_w;
672 dpavlin 2 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 dpavlin 12 index = (vaddr >> 12) & 0xfffff;
697 dpavlin 2
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 dpavlin 10 p_r = tbl1->haddr_entry[b*2];
703     p_w = tbl1->haddr_entry[b*2+1];
704 dpavlin 2 p_paddr = tbl1->paddr_entry[b];
705     tbl1->bintrans_chunks[b] = NULL;
706 dpavlin 10 /* printf("B: p_r=%p p_w=%p\n", p_r,p_w); */
707 dpavlin 12 cpu->cd.mips.host_load_orig[index] = NULL;
708     cpu->cd.mips.host_store_orig[index] = NULL;
709 dpavlin 10 if (p_r != NULL || p_paddr != 0) {
710 dpavlin 2 /* printf("Found a mapping, "
711     "vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b); */
712 dpavlin 10 tbl1->haddr_entry[b*2] = NULL;
713     tbl1->haddr_entry[b*2+1] = NULL;
714 dpavlin 2 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 dpavlin 4 for (b=0; b<0x400; b++) {
744 dpavlin 12 int index;
745    
746 dpavlin 10 tbl1->haddr_entry[b*2] = NULL;
747     tbl1->haddr_entry[b*2+1] = NULL;
748 dpavlin 4 tbl1->paddr_entry[b] = 0;
749 dpavlin 2 tbl1->bintrans_chunks[b] = NULL;
750 dpavlin 12
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 dpavlin 4 }
758 dpavlin 2 }
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 dpavlin 10 struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int select)
1004 dpavlin 2 {
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 dpavlin 4 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 dpavlin 2 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 dpavlin 10 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 dpavlin 2 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 dpavlin 10 struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int flag64,
1098     int select)
1099 dpavlin 2 {
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 dpavlin 10 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 dpavlin 2 /* 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 dpavlin 4 #if 0
1287     /* Why was this here? It should not be necessary. */
1288    
1289 dpavlin 2 /* 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 dpavlin 4 #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 dpavlin 12 /* 2-level table: */
1312 dpavlin 4 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 dpavlin 12
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 dpavlin 4 } else {
1324 dpavlin 12 /* 2-level table: */
1325 dpavlin 4 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 dpavlin 12
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 dpavlin 4 }
1338     }
1339 dpavlin 2 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 dpavlin 4 /* if (cp->tlbs[index].lo0 & ENTRYLO_V) */
2362 dpavlin 2 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 dpavlin 4 /*
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 dpavlin 6 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 dpavlin 4 }
2425     }
2426    
2427    
2428 dpavlin 2 /* 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 dpavlin 12 cpu->update_translation_table(cpu, vaddr, memblock,
2460 dpavlin 2 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 dpavlin 4 #if 0
2562 dpavlin 2 /* 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 dpavlin 4 #endif
2567 dpavlin 2 }
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 dpavlin 10 debug("%s%i\t%s,%s",
2613 dpavlin 2 copz==COPz_DMFCz? "dmfc" : "mfc", cpnr,
2614     regnames[rt], cop0_names[rd]);
2615 dpavlin 10 if (function & 7)
2616     debug(",%i", (int)(function & 7));
2617     debug("\n");
2618 dpavlin 2 return;
2619     }
2620     coproc_register_read(cpu, cpu->cd.mips.coproc[cpnr],
2621 dpavlin 10 rd, &tmpvalue, function & 7);
2622 dpavlin 2 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 dpavlin 10 debug("%s%i\t%s,%s",
2636 dpavlin 2 copz==COPz_DMTCz? "dmtc" : "mtc", cpnr,
2637     regnames[rt], cop0_names[rd]);
2638 dpavlin 10 if (function & 7)
2639     debug(",%i", (int)(function & 7));
2640     debug("\n");
2641 dpavlin 2 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 dpavlin 10 &tmpvalue, copz == COPz_DMTCz, function & 7);
2652 dpavlin 2 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