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

Annotation of /trunk/src/cpus/cpu_mips_coproc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 65259 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


1 dpavlin 14 /*
2 dpavlin 34 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 42 * $Id: cpu_mips_coproc.c,v 1.69 2007/06/15 18:07:08 debug Exp $
29 dpavlin 14 *
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 "cop0.h"
39     #include "cpu.h"
40     #include "cpu_mips.h"
41     #include "emul.h"
42 dpavlin 20 #include "float_emul.h"
43 dpavlin 14 #include "machine.h"
44     #include "memory.h"
45     #include "mips_cpu_types.h"
46     #include "misc.h"
47     #include "opcodes_mips.h"
48 dpavlin 32 #include "timer.h"
49 dpavlin 14
50    
51     extern volatile int single_step;
52    
53     static char *cop0_names[] = COP0_NAMES;
54     static char *regnames[] = MIPS_REGISTER_NAMES;
55    
56    
57     /*
58     * initialize_cop0_config():
59     *
60     * Helper function, called from mips_coproc_new().
61     */
62     static void initialize_cop0_config(struct cpu *cpu, struct mips_coproc *c)
63     {
64 dpavlin 24 const int m16 = 0; /* TODO: MIPS16 support */
65     int IB, DB, SB, IC, DC, SC, IA, DA;
66 dpavlin 14
67 dpavlin 24 /* Generic case for MIPS32/64: */
68     if (cpu->cd.mips.cpu_type.isa_level == 32 ||
69     cpu->cd.mips.cpu_type.isa_level == 64) {
70     /* According to the MIPS64 (5K) User's Manual: */
71     c->reg[COP0_CONFIG] =
72     ( (uint32_t)1 << 31)/* Config 1 present bit */
73     | ( 0 << 20) /* ISD: instruction scheduling
74     disable (=1) */
75     | ( 0 << 17) /* DID: dual issue disable */
76     | ( 0 << 16) /* BM: burst mode */
77     | ((cpu->byte_order == EMUL_BIG_ENDIAN? 1 : 0) << 15)
78     /* endian mode */
79     | ((cpu->cd.mips.cpu_type.isa_level == 64? 2 : 0) << 13)
80     /* 0=MIPS32, 1=64S, 2=64 */
81     | ( 0 << 10) /* Architecture revision */
82     | ( 1 << 7) /* MMU type: 1=TLB, 3=FMT */
83     | ( 2 << 0) /* kseg0 cache coherency algorithm */
84     ;
85     /* Config select 1: caches etc. TODO: Don't use
86     cpu->machine for this stuff! */
87 dpavlin 42 IB = cpu->cd.mips.cache_picache_linesize - 1;
88 dpavlin 24 IB = IB < 0? 0 : (IB > 7? 7 : IB);
89 dpavlin 42 DB = cpu->cd.mips.cache_pdcache_linesize - 1;
90 dpavlin 24 DB = DB < 0? 0 : (DB > 7? 7 : DB);
91 dpavlin 42 IC = cpu->cd.mips.cache_picache -
92     cpu->cd.mips.cache_picache_linesize - 7;
93     DC = cpu->cd.mips.cache_pdcache -
94     cpu->cd.mips.cache_pdcache_linesize - 7;
95 dpavlin 24 IA = cpu->cd.mips.cpu_type.piways - 1;
96     DA = cpu->cd.mips.cpu_type.pdways - 1;
97     cpu->cd.mips.cop0_config_select1 =
98     ((cpu->cd.mips.cpu_type.nr_of_tlb_entries - 1) << 25)
99     | (IC << 22) /* IS: I-cache sets per way */
100     | (IB << 19) /* IL: I-cache line-size */
101     | (IA << 16) /* IA: I-cache assoc. (ways-1) */
102     | (DC << 13) /* DS: D-cache sets per way */
103     | (DB << 10) /* DL: D-cache line-size */
104     | (DA << 7) /* DA: D-cache assoc. (ways-1) */
105     | (16 * 0) /* Existance of PerformanceCounters */
106     | ( 8 * 0) /* Existance of Watch Registers */
107     | ( 4 * m16) /* Existance of MIPS16 */
108     | ( 2 * 0) /* Existance of EJTAG */
109     | ( 1 * 1) /* Existance of FPU */
110     ;
111 dpavlin 14
112 dpavlin 24 return;
113     }
114 dpavlin 14
115 dpavlin 24 switch (cpu->cd.mips.cpu_type.rev) {
116     case MIPS_R2000:
117     case MIPS_R3000:
118     /* No config register. */
119     break;
120 dpavlin 14 case MIPS_R4000: /* according to the R4000 manual */
121     case MIPS_R4600:
122 dpavlin 42 IB = cpu->cd.mips.cache_picache_linesize - 4;
123 dpavlin 14 IB = IB < 0? 0 : (IB > 1? 1 : IB);
124 dpavlin 42 DB = cpu->cd.mips.cache_pdcache_linesize - 4;
125 dpavlin 14 DB = DB < 0? 0 : (DB > 1? 1 : DB);
126 dpavlin 42 SB = cpu->cd.mips.cache_secondary_linesize - 4;
127 dpavlin 14 SB = SB < 0? 0 : (SB > 3? 3 : SB);
128 dpavlin 42 IC = cpu->cd.mips.cache_picache - 12;
129 dpavlin 14 IC = IC < 0? 0 : (IC > 7? 7 : IC);
130 dpavlin 42 DC = cpu->cd.mips.cache_pdcache - 12;
131 dpavlin 14 DC = DC < 0? 0 : (DC > 7? 7 : DC);
132 dpavlin 42 SC = cpu->cd.mips.cache_secondary? 0 : 1;
133 dpavlin 14 c->reg[COP0_CONFIG] =
134     ( 0 << 31) /* Master/Checker present bit */
135     | (0x00 << 28) /* EC: system clock divisor,
136     0x00 = '2' */
137     | (0x00 << 24) /* EP */
138     | ( SB << 22) /* SB */
139     | (0x00 << 21) /* SS: 0 = mixed i/d scache */
140     | (0x00 << 20) /* SW */
141     | (0x00 << 18) /* EW: 0=64-bit */
142     | ( SC << 17) /* SC: 0=secondary cache present,
143     1=non-present */
144     | (0x00 << 16) /* SM: (todo) */
145     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
146     /* endian mode */
147     | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */
148     | (0x00 << 13) /* EB: (todo) */
149     | (0x00 << 12) /* 0 (resered) */
150     | ( IC << 9) /* IC: I-cache = 2^(12+IC) bytes
151     (1 = 8KB, 4=64K) */
152     | ( DC << 6) /* DC: D-cache = 2^(12+DC) bytes
153     (1 = 8KB, 4=64K) */
154     | ( IB << 5) /* IB: I-cache line size (0=16,
155     1=32) */
156     | ( DB << 4) /* DB: D-cache line size (0=16,
157     1=32) */
158     | ( 0 << 3) /* CU: todo */
159     | ( 0 << 0) /* kseg0 coherency algorithm
160     (TODO) */
161     ;
162     break;
163     case MIPS_R4100: /* According to the VR4131 manual: */
164 dpavlin 42 IB = cpu->cd.mips.cache_picache_linesize - 4;
165 dpavlin 14 IB = IB < 0? 0 : (IB > 1? 1 : IB);
166 dpavlin 42 DB = cpu->cd.mips.cache_pdcache_linesize - 4;
167 dpavlin 14 DB = DB < 0? 0 : (DB > 1? 1 : DB);
168 dpavlin 42 IC = cpu->cd.mips.cache_picache - 10;
169 dpavlin 14 IC = IC < 0? 0 : (IC > 7? 7 : IC);
170 dpavlin 42 DC = cpu->cd.mips.cache_pdcache - 10;
171 dpavlin 14 DC = DC < 0? 0 : (DC > 7? 7 : DC);
172     c->reg[COP0_CONFIG] =
173     ( 0 << 31) /* IS: Instruction Streaming bit */
174     | (0x01 << 28) /* EC: system clock divisor,
175     0x01 = 2 */
176     | (0x00 << 24) /* EP */
177     | (0x00 << 23) /* AD: Accelerate data mode
178     (0=VR4000-compatible) */
179     | ( m16 << 20) /* M16: MIPS16 support */
180     | ( 1 << 17) /* '1' */
181     | (0x00 << 16) /* BP: 'Branch forecast'
182     (0 = enabled) */
183     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
184     /* endian mode */
185     | ( 2 << 13) /* '2' hardcoded on VR4131 */
186     | ( 1 << 12) /* CS: Cache size mode
187     (1 on VR4131) */
188     | ( IC << 9) /* IC: I-cache = 2^(10+IC) bytes
189     (0 = 1KB, 4=16K) */
190     | ( DC << 6) /* DC: D-cache = 2^(10+DC) bytes
191     (0 = 1KB, 4=16K) */
192     | ( IB << 5) /* IB: I-cache line size (0=16,
193     1=32) */
194     | ( DB << 4) /* DB: D-cache line size (0=16,
195     1=32) */
196     | ( 0 << 0) /* kseg0 coherency algorithm (TODO) */
197     ;
198     break;
199     case MIPS_R5000:
200     case MIPS_RM5200: /* rm5200 is just a wild guess */
201     /* These are just guesses: (the comments are wrong) */
202     c->reg[COP0_CONFIG] =
203     ( 0 << 31) /* Master/Checker present bit */
204     | (0x00 << 28) /* EC: system clock divisor,
205     0x00 = '2' */
206     | (0x00 << 24) /* EP */
207     | (0x00 << 22) /* SB */
208     | (0x00 << 21) /* SS */
209     | (0x00 << 20) /* SW */
210     | (0x00 << 18) /* EW: 0=64-bit */
211     | (0x01 << 17) /* SC: 0=secondary cache present,
212     1=non-present */
213     | (0x00 << 16) /* SM: (todo) */
214     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
215     /* endian mode */
216     | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */
217     | (0x00 << 13) /* EB: (todo) */
218     | (0x00 << 12) /* 0 (resered) */
219     | ( 3 << 9) /* IC: I-cache = 2^(12+IC) bytes
220     (1 = 8KB, 4=64K) */
221     | ( 3 << 6) /* DC: D-cache = 2^(12+DC) bytes
222     (1 = 8KB, 4=64K) */
223     | ( 1 << 5) /* IB: I-cache line size (0=16,
224     1=32) */
225     | ( 1 << 4) /* DB: D-cache line size (0=16,
226     1=32) */
227     | ( 0 << 3) /* CU: todo */
228     | ( 2 << 0) /* kseg0 coherency algorithm
229     (TODO) */
230     ;
231     break;
232     case MIPS_R10000:
233     case MIPS_R12000:
234     case MIPS_R14000:
235 dpavlin 42 IC = cpu->cd.mips.cache_picache - 12;
236 dpavlin 14 IC = IC < 0? 0 : (IC > 7? 7 : IC);
237 dpavlin 42 DC = cpu->cd.mips.cache_pdcache - 12;
238 dpavlin 14 DC = DC < 0? 0 : (DC > 7? 7 : DC);
239 dpavlin 42 SC = cpu->cd.mips.cache_secondary - 19;
240 dpavlin 14 SC = SC < 0? 0 : (SC > 7? 7 : SC);
241     /* According to the R10000 User's Manual: */
242     c->reg[COP0_CONFIG] =
243     ( IC << 29) /* Primary instruction cache size
244     (3 = 32KB) */
245     | ( DC << 26) /* Primary data cache size (3 =
246     32KB) */
247     | ( 0 << 19) /* SCClkDiv */
248     | ( SC << 16) /* SCSize, secondary cache size.
249     0 = 512KB. powers of two */
250     | ( 0 << 15) /* MemEnd */
251     | ( 0 << 14) /* SCCorEn */
252     | ( 1 << 13) /* SCBlkSize. 0=16 words,
253     1=32 words */
254     | ( 0 << 9) /* SysClkDiv */
255     | ( 0 << 7) /* PrcReqMax */
256     | ( 0 << 6) /* PrcElmReq */
257     | ( 0 << 5) /* CohPrcReqTar */
258     | ( 0 << 3) /* Device number */
259     | ( 2 << 0) /* Cache coherency algorithm for
260     kseg0 */
261     ;
262     break;
263     case MIPS_R5900:
264     /*
265     * R5900 is supposed to have the following (according
266     * to NetBSD/playstation2):
267     * cpu0: 16KB/64B 2-way set-associative L1 Instruction
268     * cache, 48 TLB entries
269     * cpu0: 8KB/64B 2-way set-associative write-back L1
270     * Data cache
271     * The following settings are just guesses:
272     * (comments are incorrect)
273     */
274     c->reg[COP0_CONFIG] =
275     ( 0 << 31) /* Master/Checker present bit */
276     | (0x00 << 28) /* EC: system clock divisor,
277     0x00 = '2' */
278     | (0x00 << 24) /* EP */
279     | (0x00 << 22) /* SB */
280     | (0x00 << 21) /* SS */
281     | (0x00 << 20) /* SW */
282     | (0x00 << 18) /* EW: 0=64-bit */
283     | (0x01 << 17) /* SC: 0=secondary cache present,
284     1=non-present */
285     | (0x00 << 16) /* SM: (todo) */
286     | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)
287     /* endian mode */
288     | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */
289     | (0x00 << 13) /* EB: (todo) */
290     | (0x00 << 12) /* 0 (resered) */
291     | ( 3 << 9) /* IC: I-cache = 2^(12+IC) bytes
292     (1 = 8KB, 4=64K) */
293     | ( 3 << 6) /* DC: D-cache = 2^(12+DC) bytes
294     (1 = 8KB, 4=64K) */
295     | ( 1 << 5) /* IB: I-cache line size (0=16,
296     1=32) */
297     | ( 1 << 4) /* DB: D-cache line size (0=16,
298     1=32) */
299     | ( 0 << 3) /* CU: todo */
300     | ( 0 << 0) /* kseg0 coherency algorithm
301     (TODO) */
302     ;
303     break;
304 dpavlin 24 default:fatal("Internal error: No initialization code for"
305     " config0? cpu rev = 0x%x", cpu->cd.mips.cpu_type.rev);
306     exit(1);
307 dpavlin 14 }
308     }
309    
310    
311     /*
312     * initialize_cop1():
313     *
314     * Helper function, called from mips_coproc_new().
315     */
316     static void initialize_cop1(struct cpu *cpu, struct mips_coproc *c)
317     {
318     int fpu_rev;
319     uint64_t other_stuff = 0;
320    
321     switch (cpu->cd.mips.cpu_type.rev & 0xff) {
322     case MIPS_R2000: fpu_rev = MIPS_R2010; break;
323     case MIPS_R3000: fpu_rev = MIPS_R3010;
324     other_stuff |= 0x40; /* or 0x30? TODO */
325     break;
326     case MIPS_R6000: fpu_rev = MIPS_R6010; break;
327     case MIPS_R4000: fpu_rev = MIPS_R4010; break;
328     case MIPS_4Kc: /* TODO: Is this the same as 5Kc? */
329     case MIPS_5Kc: other_stuff = COP1_REVISION_DOUBLE
330     | COP1_REVISION_SINGLE;
331     case MIPS_R5000:
332     case MIPS_RM5200: fpu_rev = cpu->cd.mips.cpu_type.rev;
333     other_stuff |= 0x10;
334     /* or cpu->cd.mips.cpu_type.sub ? TODO */
335     break;
336     case MIPS_R10000: fpu_rev = MIPS_R10000; break;
337     case MIPS_R12000: fpu_rev = 0x9; break;
338     default: fpu_rev = MIPS_SOFT;
339     }
340    
341     c->fcr[COP1_REVISION] = (fpu_rev << 8) | other_stuff;
342    
343     #if 0
344     /* These are mentioned in the MIPS64 documentation: */
345     + (1 << 16) /* single */
346     + (1 << 17) /* double */
347     + (1 << 18) /* paired-single */
348     + (1 << 19) /* 3d */
349     #endif
350     }
351    
352    
353     /*
354     * mips_coproc_new():
355     *
356     * Create a new MIPS coprocessor object.
357     */
358     struct mips_coproc *mips_coproc_new(struct cpu *cpu, int coproc_nr)
359     {
360     struct mips_coproc *c;
361    
362 dpavlin 42 CHECK_ALLOCATION(c = malloc(sizeof(struct mips_coproc)));
363     memset(c, 0, sizeof(struct mips_coproc));
364 dpavlin 14
365     c->coproc_nr = coproc_nr;
366    
367     if (coproc_nr == 0) {
368     c->nr_of_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;
369 dpavlin 20 c->tlbs = zeroed_alloc(c->nr_of_tlbs * sizeof(struct mips_tlb));
370 dpavlin 14
371     /*
372     * Start with nothing in the status register. This makes sure
373     * that we are running in kernel mode with all interrupts
374     * disabled.
375     */
376     c->reg[COP0_STATUS] = 0;
377    
378     /* For userland emulation, enable all four coprocessors: */
379     if (cpu->machine->userland_emul)
380     c->reg[COP0_STATUS] |=
381     ((uint32_t)0xf << STATUS_CU_SHIFT);
382    
383     /* Hm. Enable coprocessors 0 and 1 even if we're not just
384     emulating userland? TODO: Think about this. */
385     /* if (cpu->machine->prom_emulation) */
386     c->reg[COP0_STATUS] |=
387     ((uint32_t)0x3 << STATUS_CU_SHIFT);
388    
389     if (!cpu->machine->prom_emulation)
390     c->reg[COP0_STATUS] |= STATUS_BEV;
391    
392 dpavlin 24 /* Ugly hack for R5900/TX79/C790: */
393     if (cpu->cd.mips.cpu_type.rev == MIPS_R5900)
394     c->reg[COP0_STATUS] |= R5900_STATUS_EIE;
395    
396     /* Default pagesize = 4 KB (i.e. dualpage = 8KB) */
397 dpavlin 14 c->reg[COP0_PAGEMASK] = 0x1fff;
398    
399     /* Note: .rev may contain the company ID as well! */
400     c->reg[COP0_PRID] =
401 dpavlin 24 (0x00 << 24) /* Company Options */
402     | (0x00 << 16) /* Company ID */
403 dpavlin 14 | (cpu->cd.mips.cpu_type.rev << 8) /* Processor ID */
404     | (cpu->cd.mips.cpu_type.sub) /* Revision */
405     ;
406    
407     c->reg[COP0_WIRED] = 0;
408    
409     initialize_cop0_config(cpu, c);
410    
411     /* Make sure the status register is sign-extended nicely: */
412 dpavlin 24 c->reg[COP0_STATUS] = (int32_t)c->reg[COP0_STATUS];
413 dpavlin 14 }
414    
415     if (coproc_nr == 1)
416     initialize_cop1(cpu, c);
417    
418     return c;
419     }
420    
421    
422     /*
423 dpavlin 32 * mips_timer_tick():
424     */
425     static void mips_timer_tick(struct timer *timer, void *extra)
426     {
427     struct cpu *cpu = (struct cpu *) extra;
428    
429     cpu->cd.mips.compare_interrupts_pending ++;
430    
431     if ((int32_t) (cpu->cd.mips.coproc[0]->reg[COP0_COUNT] -
432     cpu->cd.mips.coproc[0]->reg[COP0_COMPARE]) < 0) {
433     cpu->cd.mips.coproc[0]->reg[COP0_COUNT] =
434     cpu->cd.mips.coproc[0]->reg[COP0_COMPARE];
435     }
436     }
437    
438    
439     /*
440 dpavlin 14 * mips_coproc_tlb_set_entry():
441     *
442     * Used by machine setup code, if a specific machine emulation starts up
443     * with hardcoded virtual to physical mappings.
444     */
445     void mips_coproc_tlb_set_entry(struct cpu *cpu, int entrynr, int size,
446     uint64_t vaddr, uint64_t paddr0, uint64_t paddr1,
447     int valid0, int valid1, int dirty0, int dirty1, int global, int asid,
448     int cachealgo0, int cachealgo1)
449     {
450     if (entrynr < 0 || entrynr >= cpu->cd.mips.coproc[0]->nr_of_tlbs) {
451     printf("mips_coproc_tlb_set_entry(): invalid entry nr: %i\n",
452     entrynr);
453     exit(1);
454     }
455    
456     switch (cpu->cd.mips.cpu_type.mmu_model) {
457     case MMU3K:
458     if (size != 4096) {
459     printf("mips_coproc_tlb_set_entry(): invalid pagesize "
460     "(%i) for MMU3K\n", size);
461     exit(1);
462     }
463     cpu->cd.mips.coproc[0]->tlbs[entrynr].hi =
464     (vaddr & R2K3K_ENTRYHI_VPN_MASK) |
465     ((asid << R2K3K_ENTRYHI_ASID_SHIFT) &
466     R2K3K_ENTRYHI_ASID_MASK);
467     cpu->cd.mips.coproc[0]->tlbs[entrynr].lo0 =
468     (paddr0 & R2K3K_ENTRYLO_PFN_MASK) |
469     (cachealgo0? R2K3K_ENTRYLO_N : 0) |
470     (dirty0? R2K3K_ENTRYLO_D : 0) |
471     (valid0? R2K3K_ENTRYLO_V : 0) |
472     (global? R2K3K_ENTRYLO_G : 0);
473     break;
474     default:
475     /* MMU4K and MMU10K, etc: */
476     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
477     cpu->cd.mips.coproc[0]->tlbs[entrynr].hi =
478     (vaddr & ENTRYHI_VPN2_MASK_R10K) |
479     (vaddr & ENTRYHI_R_MASK) |
480     (asid & ENTRYHI_ASID) |
481     (global? TLB_G : 0);
482     else
483     cpu->cd.mips.coproc[0]->tlbs[entrynr].hi =
484     (vaddr & ENTRYHI_VPN2_MASK) |
485     (vaddr & ENTRYHI_R_MASK) |
486     (asid & ENTRYHI_ASID) |
487     (global? TLB_G : 0);
488     /* NOTE: The pagemask size is for a "dual" page: */
489     cpu->cd.mips.coproc[0]->tlbs[entrynr].mask =
490     (2*size - 1) & ~0x1fff;
491     cpu->cd.mips.coproc[0]->tlbs[entrynr].lo0 =
492     (((paddr0 >> 12) << ENTRYLO_PFN_SHIFT) &
493     ENTRYLO_PFN_MASK) |
494     (dirty0? ENTRYLO_D : 0) |
495     (valid0? ENTRYLO_V : 0) |
496     (global? ENTRYLO_G : 0) |
497     ((cachealgo0 << ENTRYLO_C_SHIFT) & ENTRYLO_C_MASK);
498     cpu->cd.mips.coproc[0]->tlbs[entrynr].lo1 =
499     (((paddr1 >> 12) << ENTRYLO_PFN_SHIFT) &
500     ENTRYLO_PFN_MASK) |
501     (dirty1? ENTRYLO_D : 0) |
502     (valid1? ENTRYLO_V : 0) |
503     (global? ENTRYLO_G : 0) |
504     ((cachealgo1 << ENTRYLO_C_SHIFT) & ENTRYLO_C_MASK);
505     /* TODO: R4100, 1KB pages etc */
506     }
507     }
508    
509    
510     /*
511 dpavlin 24 * invalidate_asid():
512     *
513     * Go through all entries in the TLB. If an entry has a matching asid, is
514     * valid, and is not global (i.e. the ASID matters), then its virtual address
515     * translation is invalidated.
516     *
517     * Note: In the R3000 case, the asid argument is shifted 6 bits.
518 dpavlin 14 */
519 dpavlin 40 static void invalidate_asid(struct cpu *cpu, unsigned int asid)
520 dpavlin 14 {
521 dpavlin 24 struct mips_coproc *cp = cpu->cd.mips.coproc[0];
522 dpavlin 40 unsigned int i, ntlbs = cp->nr_of_tlbs;
523 dpavlin 24 struct mips_tlb *tlb = cp->tlbs;
524 dpavlin 14
525 dpavlin 24 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
526     for (i=0; i<ntlbs; i++)
527     if ((tlb[i].hi & R2K3K_ENTRYHI_ASID_MASK) == asid
528     && (tlb[i].lo0 & R2K3K_ENTRYLO_V)
529     && !(tlb[i].lo0 & R2K3K_ENTRYLO_G)) {
530     cpu->invalidate_translation_caches(cpu,
531     tlb[i].hi & R2K3K_ENTRYHI_VPN_MASK,
532     INVALIDATE_VADDR);
533 dpavlin 14 }
534     } else {
535 dpavlin 28 int non4kpages = 0;
536     uint64_t topbit = 1, fillmask = 0xffffff0000000000ULL;
537    
538 dpavlin 30 if (cpu->is_32bit) {
539     topbit = 0x80000000;
540     fillmask = 0xffffffff00000000ULL;
541     } else if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
542 dpavlin 28 topbit <<= 43;
543     fillmask <<= 4;
544     } else {
545     topbit <<= 39;
546     }
547    
548     for (i=0; i<ntlbs; i++) {
549     if (tlb[i].mask != 0 && tlb[i].mask != 0x1800) {
550     non4kpages = 1;
551     continue;
552     }
553    
554     if ((tlb[i].hi & ENTRYHI_ASID) == asid &&
555     !(tlb[i].hi & TLB_G)) {
556     uint64_t vaddr0, vaddr1;
557     vaddr0 = cp->tlbs[i].hi & ~fillmask;
558     if (vaddr0 & topbit)
559     vaddr0 |= fillmask;
560     vaddr1 = vaddr0 | 0x1000; /* TODO: mask */
561    
562     if (tlb[i].lo0 & ENTRYLO_V)
563     cpu->invalidate_translation_caches(cpu,
564     vaddr0, INVALIDATE_VADDR);
565     if (tlb[i].lo1 & ENTRYLO_V)
566     cpu->invalidate_translation_caches(cpu,
567     vaddr1, INVALIDATE_VADDR);
568     }
569     }
570    
571     if (non4kpages) {
572     cpu->invalidate_translation_caches(cpu,
573     0, INVALIDATE_ALL);
574     }
575 dpavlin 14 }
576     }
577    
578    
579     /*
580     * coproc_register_read();
581     *
582     * Read a value from a MIPS coprocessor register.
583     */
584     void coproc_register_read(struct cpu *cpu,
585     struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int select)
586     {
587     int unimpl = 1;
588    
589     if (cp->coproc_nr==0 && reg_nr==COP0_INDEX) unimpl = 0;
590     if (cp->coproc_nr==0 && reg_nr==COP0_RANDOM) unimpl = 0;
591     if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYLO0) unimpl = 0;
592     if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYLO1) unimpl = 0;
593     if (cp->coproc_nr==0 && reg_nr==COP0_CONTEXT) unimpl = 0;
594     if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK) unimpl = 0;
595     if (cp->coproc_nr==0 && reg_nr==COP0_WIRED) unimpl = 0;
596     if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR) unimpl = 0;
597 dpavlin 32 if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) {
598     /* TODO: Increase count in a more meaningful way! */
599     cp->reg[COP0_COUNT] = (int32_t) (cp->reg[COP0_COUNT] + 1);
600     unimpl = 0;
601     }
602 dpavlin 14 if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI) unimpl = 0;
603     if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE) unimpl = 0;
604     if (cp->coproc_nr==0 && reg_nr==COP0_STATUS) unimpl = 0;
605     if (cp->coproc_nr==0 && reg_nr==COP0_CAUSE) unimpl = 0;
606     if (cp->coproc_nr==0 && reg_nr==COP0_EPC) unimpl = 0;
607     if (cp->coproc_nr==0 && reg_nr==COP0_PRID) unimpl = 0;
608     if (cp->coproc_nr==0 && reg_nr==COP0_CONFIG) {
609     if (select > 0) {
610     switch (select) {
611     case 1: *ptr = cpu->cd.mips.cop0_config_select1;
612     break;
613     default:fatal("coproc_register_read(): unimplemented"
614     " config register select %i\n", select);
615     exit(1);
616     }
617     return;
618     }
619     unimpl = 0;
620     }
621     if (cp->coproc_nr==0 && reg_nr==COP0_LLADDR) unimpl = 0;
622     if (cp->coproc_nr==0 && reg_nr==COP0_WATCHLO) unimpl = 0;
623     if (cp->coproc_nr==0 && reg_nr==COP0_WATCHHI) unimpl = 0;
624     if (cp->coproc_nr==0 && reg_nr==COP0_XCONTEXT) unimpl = 0;
625     if (cp->coproc_nr==0 && reg_nr==COP0_ERRCTL) unimpl = 0;
626     if (cp->coproc_nr==0 && reg_nr==COP0_CACHEERR) unimpl = 0;
627     if (cp->coproc_nr==0 && reg_nr==COP0_TAGDATA_LO) unimpl = 0;
628     if (cp->coproc_nr==0 && reg_nr==COP0_TAGDATA_HI) unimpl = 0;
629     if (cp->coproc_nr==0 && reg_nr==COP0_ERROREPC) unimpl = 0;
630     if (cp->coproc_nr==0 && reg_nr==COP0_RESERV22) {
631     /* Used by Linux on Linksys WRT54G */
632     unimpl = 0;
633     }
634     if (cp->coproc_nr==0 && reg_nr==COP0_DEBUG) unimpl = 0;
635     if (cp->coproc_nr==0 && reg_nr==COP0_PERFCNT) unimpl = 0;
636     if (cp->coproc_nr==0 && reg_nr==COP0_DESAVE) unimpl = 0;
637    
638     if (cp->coproc_nr==1) unimpl = 0;
639    
640     if (unimpl) {
641     fatal("cpu%i: warning: read from unimplemented coproc%i"
642     " register %i (%s)\n", cpu->cpu_id, cp->coproc_nr, reg_nr,
643     cp->coproc_nr==0? cop0_names[reg_nr] : "?");
644    
645     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0,
646     cp->coproc_nr, 0, 0, 0);
647     return;
648     }
649    
650     *ptr = cp->reg[reg_nr];
651     }
652    
653    
654     /*
655     * coproc_register_write();
656     *
657     * Write a value to a MIPS coprocessor register.
658     */
659     void coproc_register_write(struct cpu *cpu,
660     struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int flag64,
661     int select)
662     {
663     int unimpl = 1;
664     int readonly = 0;
665     uint64_t tmp = *ptr;
666     uint64_t tmp2 = 0, old;
667 dpavlin 40 int inval = 0;
668     unsigned int old_asid;
669     uint64_t oldmode;
670 dpavlin 14
671     switch (cp->coproc_nr) {
672     case 0:
673     /* COPROC 0: */
674     switch (reg_nr) {
675     case COP0_INDEX:
676     case COP0_RANDOM:
677     unimpl = 0;
678     break;
679     case COP0_ENTRYLO0:
680     unimpl = 0;
681     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
682     (tmp & 0xff)!=0) {
683     /* char *symbol;
684     uint64_t offset;
685 dpavlin 24 symbol = get_symbol_name(cpu->pc, &offset);
686 dpavlin 14 fatal("YO! pc = 0x%08llx <%s> "
687     "lo=%016llx\n", (long long)
688 dpavlin 24 cpu->pc, symbol? symbol :
689 dpavlin 14 "no symbol", (long long)tmp); */
690     tmp &= (R2K3K_ENTRYLO_PFN_MASK |
691     R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |
692     R2K3K_ENTRYLO_V | R2K3K_ENTRYLO_G);
693     } else if (cpu->cd.mips.cpu_type.mmu_model == MMU4K) {
694     tmp &= (ENTRYLO_PFN_MASK | ENTRYLO_C_MASK |
695     ENTRYLO_D | ENTRYLO_V | ENTRYLO_G);
696     }
697     break;
698     case COP0_BADVADDR:
699     /* Hm. Irix writes to this register. (Why?) */
700     unimpl = 0;
701     break;
702     case COP0_ENTRYLO1:
703     unimpl = 0;
704     if (cpu->cd.mips.cpu_type.mmu_model == MMU4K) {
705     tmp &= (ENTRYLO_PFN_MASK | ENTRYLO_C_MASK |
706     ENTRYLO_D | ENTRYLO_V | ENTRYLO_G);
707     }
708     break;
709     case COP0_CONTEXT:
710     old = cp->reg[COP0_CONTEXT];
711     cp->reg[COP0_CONTEXT] = tmp;
712     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
713     cp->reg[COP0_CONTEXT] &=
714     ~R2K3K_CONTEXT_BADVPN_MASK;
715     cp->reg[COP0_CONTEXT] |=
716     (old & R2K3K_CONTEXT_BADVPN_MASK);
717     } else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
718     cp->reg[COP0_CONTEXT] &=
719     ~CONTEXT_BADVPN2_MASK_R4100;
720     cp->reg[COP0_CONTEXT] |=
721     (old & CONTEXT_BADVPN2_MASK_R4100);
722     } else {
723     cp->reg[COP0_CONTEXT] &=
724     ~CONTEXT_BADVPN2_MASK;
725     cp->reg[COP0_CONTEXT] |=
726     (old & CONTEXT_BADVPN2_MASK);
727     }
728     return;
729     case COP0_PAGEMASK:
730     tmp2 = tmp >> PAGEMASK_SHIFT;
731     if (tmp2 != 0x000 &&
732     tmp2 != 0x003 &&
733     tmp2 != 0x00f &&
734     tmp2 != 0x03f &&
735     tmp2 != 0x0ff &&
736     tmp2 != 0x3ff &&
737     tmp2 != 0xfff)
738     fatal("cpu%i: trying to write an invalid"
739     " pagemask 0x%08lx to COP0_PAGEMASK\n",
740     cpu->cpu_id, (long)tmp);
741     unimpl = 0;
742     break;
743     case COP0_WIRED:
744     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
745     fatal("cpu%i: r2k/r3k wired register must "
746     "always be 8\n", cpu->cpu_id);
747     tmp = 8;
748     }
749     cp->reg[COP0_RANDOM] = cp->nr_of_tlbs-1;
750     tmp &= INDEX_MASK;
751     unimpl = 0;
752     break;
753     case COP0_COUNT:
754 dpavlin 22 if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
755 dpavlin 14 fatal("WARNING: trying to write a 64-bit value"
756     " to the COUNT register!\n");
757     tmp = (int64_t)(int32_t)tmp;
758     unimpl = 0;
759     break;
760     case COP0_COMPARE:
761 dpavlin 32 if (cpu->machine->emulated_hz > 0) {
762     int32_t compare_diff = tmp -
763     cp->reg[COP0_COMPARE];
764     double hz;
765    
766     if (compare_diff < 0)
767     hz = tmp - cp->reg[COP0_COUNT];
768    
769     if (compare_diff == 0)
770     hz = 0;
771     else
772     hz = (double)cpu->machine->emulated_hz
773     / (double)compare_diff;
774     /*
775     * TODO: DON'T HARDCODE THIS!
776     */
777     hz = 100.0;
778    
779     /* Initialize or re-set the periodic timer: */
780     if (hz > 0) {
781     if (cpu->cd.mips.timer == NULL)
782     cpu->cd.mips.timer = timer_add(
783     hz, mips_timer_tick, cpu);
784     else
785     timer_update_frequency(
786     cpu->cd.mips.timer, hz);
787     }
788     }
789    
790     /* Ack the periodic timer, if it was asserted: */
791     if (cp->reg[COP0_CAUSE] & 0x8000 &&
792     cpu->cd.mips.compare_interrupts_pending > 0)
793     cpu->cd.mips.compare_interrupts_pending --;
794    
795     /* Clear the timer interrupt assertion (bit 7): */
796 dpavlin 34 cp->reg[COP0_CAUSE] &= ~0x8000;
797 dpavlin 32
798 dpavlin 22 if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
799 dpavlin 14 fatal("WARNING: trying to write a 64-bit value"
800     " to the COMPARE register!\n");
801 dpavlin 32
802 dpavlin 14 tmp = (int64_t)(int32_t)tmp;
803 dpavlin 32 cpu->cd.mips.compare_register_set = 1;
804 dpavlin 14 unimpl = 0;
805     break;
806     case COP0_ENTRYHI:
807     /*
808 dpavlin 24 * Translation caches must be invalidated if the
809     * ASID changes:
810 dpavlin 14 */
811     switch (cpu->cd.mips.cpu_type.mmu_model) {
812     case MMU3K:
813 dpavlin 24 old_asid = cp->reg[COP0_ENTRYHI] &
814     R2K3K_ENTRYHI_ASID_MASK;
815 dpavlin 14 if ((cp->reg[COP0_ENTRYHI] &
816     R2K3K_ENTRYHI_ASID_MASK) !=
817     (tmp & R2K3K_ENTRYHI_ASID_MASK))
818     inval = 1;
819     break;
820     default:
821     old_asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
822     if ((cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID) !=
823     (tmp & ENTRYHI_ASID))
824     inval = 1;
825     break;
826     }
827 dpavlin 24
828 dpavlin 14 if (inval)
829 dpavlin 24 invalidate_asid(cpu, old_asid);
830    
831 dpavlin 14 unimpl = 0;
832     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
833     (tmp & 0x3f)!=0) {
834     /* char *symbol;
835     uint64_t offset;
836 dpavlin 24 symbol = get_symbol_name(cpu->pc,
837     &offset);
838 dpavlin 14 fatal("YO! pc = 0x%08llx <%s> "
839 dpavlin 24 "hi=%016llx\n", (long long)cpu->pc,
840     symbol? symbol :
841 dpavlin 14 "no symbol", (long long)tmp); */
842     tmp &= ~0x3f;
843     }
844     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
845     tmp &= (R2K3K_ENTRYHI_VPN_MASK |
846     R2K3K_ENTRYHI_ASID_MASK);
847     else if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
848     tmp &= (ENTRYHI_R_MASK |
849     ENTRYHI_VPN2_MASK_R10K | ENTRYHI_ASID);
850     else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
851     tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK |
852     0x1800 | ENTRYHI_ASID);
853     else
854     tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK |
855     ENTRYHI_ASID);
856     break;
857     case COP0_EPC:
858     unimpl = 0;
859     break;
860     case COP0_PRID:
861     readonly = 1;
862     break;
863     case COP0_CONFIG:
864     if (select > 0) {
865     switch (select) {
866     case 1: cpu->cd.mips.cop0_config_select1 = tmp;
867     break;
868     default:fatal("coproc_register_write(): unimpl"
869     "emented config register select "
870     "%i\n", select);
871     exit(1);
872     }
873     return;
874     }
875    
876     /* fatal("COP0_CONFIG: modifying K0 bits: "
877     "0x%08x => ", cp->reg[reg_nr]); */
878     tmp = *ptr;
879     tmp &= 0x3; /* only bits 2..0 can be written */
880     cp->reg[reg_nr] &= ~(0x3); cp->reg[reg_nr] |= tmp;
881     /* fatal("0x%08x\n", cp->reg[reg_nr]); */
882     return;
883     case COP0_STATUS:
884     oldmode = cp->reg[COP0_STATUS];
885     tmp &= ~(1 << 21); /* bit 21 is read-only */
886 dpavlin 26
887 dpavlin 24 /*
888 dpavlin 26 * When isolating caches, invalidate all translations.
889     * During the isolation, a special hack in memory_rw.c
890     * prevents translation tables from being updated, so
891     * the translation caches don't have to be invalidated
892     * when switching back to normal mode.
893 dpavlin 24 */
894 dpavlin 14 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
895 dpavlin 24 (oldmode & MIPS1_ISOL_CACHES) !=
896 dpavlin 14 (tmp & MIPS1_ISOL_CACHES)) {
897 dpavlin 26 /* Invalidate everything if we are switching
898     to isolated mode: */
899     if (tmp & MIPS1_ISOL_CACHES) {
900     cpu->invalidate_translation_caches(
901     cpu, 0, INVALIDATE_ALL);
902     }
903 dpavlin 14 }
904     unimpl = 0;
905     break;
906     case COP0_CAUSE:
907     /* A write to the cause register only
908     affects IM bits 0 and 1: */
909     cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);
910     cp->reg[reg_nr] |= (tmp & (0x3 << STATUS_IM_SHIFT));
911     return;
912     case COP0_FRAMEMASK:
913     /* TODO: R10000 */
914     unimpl = 0;
915     break;
916     case COP0_TAGDATA_LO:
917     case COP0_TAGDATA_HI:
918     /* TODO: R4300 and others? */
919     unimpl = 0;
920     break;
921     case COP0_LLADDR:
922     unimpl = 0;
923     break;
924     case COP0_WATCHLO:
925     case COP0_WATCHHI:
926     unimpl = 0;
927     break;
928     case COP0_XCONTEXT:
929     /*
930     * TODO: According to the R10000 manual, the R4400
931     * shares the PTEbase portion of the context registers
932     * (that is, xcontext and context). On R10000, they
933     * are separate registers.
934     */
935     /* debug("[ xcontext 0x%016llx ]\n", tmp); */
936     unimpl = 0;
937     break;
938    
939     /* Most of these are actually TODOs: */
940     case COP0_ERROREPC:
941     case COP0_DEPC:
942     case COP0_RESERV22: /* Used by Linux on Linksys WRT54G */
943     case COP0_DESAVE:
944     case COP0_PERFCNT:
945     case COP0_ERRCTL: /* R10000 */
946     unimpl = 0;
947     break;
948     }
949     break;
950    
951     case 1:
952     /* COPROC 1: */
953     unimpl = 0;
954     break;
955     }
956    
957     if (unimpl) {
958     fatal("cpu%i: warning: write to unimplemented coproc%i "
959     "register %i (%s), data = 0x%016llx\n", cpu->cpu_id,
960     cp->coproc_nr, reg_nr, cp->coproc_nr==0?
961     cop0_names[reg_nr] : "?", (long long)tmp);
962    
963 dpavlin 42 /* mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0,
964 dpavlin 14 cp->coproc_nr, 0, 0, 0);
965 dpavlin 42 return; */
966 dpavlin 14 }
967    
968     if (readonly) {
969     fatal("cpu%i: warning: write to READONLY coproc%i register "
970     "%i ignored\n", cpu->cpu_id, cp->coproc_nr, reg_nr);
971     return;
972     }
973    
974     cp->reg[reg_nr] = tmp;
975    
976     if (!flag64)
977     cp->reg[reg_nr] = (int64_t)(int32_t)cp->reg[reg_nr];
978     }
979    
980    
981     /*
982     * MIPS floating-point stuff:
983     *
984     * TODO: Move this to some other file?
985     */
986 dpavlin 20 static int mips_fmt_to_ieee_fmt[32] = {
987     0, 0, 0, 0, 0, 0, 0, 0,
988     0, 0, 0, 0, 0, 0, 0, 0,
989     IEEE_FMT_S, IEEE_FMT_D, 0, 0,
990     IEEE_FMT_W, IEEE_FMT_L, /* PS (Paired Single) */ 0, 0,
991     0, 0, 0, 0, 0, 0, 0, 0 };
992    
993 dpavlin 24 static char *fmtname[32] = {
994     "0", "1", "2", "3", "4", "5", "6", "7",
995     "8", "9", "10", "11", "12", "13", "14", "15",
996     "s", "d", "18", "19", "w", "l", "ps", "23",
997     "24", "25", "26", "27", "28", "29", "30", "31" };
998 dpavlin 14
999 dpavlin 24 static char *ccname[16] = {
1000     "f", "un", "eq", "ueq", "olt", "ult", "ole", "ule",
1001     "sf", "ngle", "seq", "ngl", "lt", "nge", "le", "ngt" };
1002    
1003 dpavlin 14 #define FPU_OP_ADD 1
1004     #define FPU_OP_SUB 2
1005     #define FPU_OP_MUL 3
1006     #define FPU_OP_DIV 4
1007     #define FPU_OP_SQRT 5
1008     #define FPU_OP_MOV 6
1009     #define FPU_OP_CVT 7
1010     #define FPU_OP_C 8
1011     #define FPU_OP_ABS 9
1012     #define FPU_OP_NEG 10
1013 dpavlin 20 /* TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W, RSQRT */
1014 dpavlin 14
1015    
1016     /*
1017     * fpu_store_float_value():
1018     *
1019     * Stores a float value (actually a double) in fmt format.
1020     */
1021     static void fpu_store_float_value(struct mips_coproc *cp, int fd,
1022     double nf, int fmt, int nan)
1023     {
1024 dpavlin 20 int ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1025     uint64_t r = ieee_store_float_value(nf, ieee_fmt, nan);
1026 dpavlin 14
1027     /*
1028 dpavlin 20 * TODO: This is for 32-bit mode. It has to be updated later
1029     * for 64-bit coprocessor functionality!
1030 dpavlin 14 */
1031 dpavlin 24 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) {
1032 dpavlin 14 cp->reg[fd] = r & 0xffffffffULL;
1033     cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;
1034    
1035     if (cp->reg[fd] & 0x80000000ULL)
1036     cp->reg[fd] |= 0xffffffff00000000ULL;
1037     if (cp->reg[fd+1] & 0x80000000ULL)
1038     cp->reg[fd+1] |= 0xffffffff00000000ULL;
1039     } else {
1040     cp->reg[fd] = r & 0xffffffffULL;
1041    
1042     if (cp->reg[fd] & 0x80000000ULL)
1043     cp->reg[fd] |= 0xffffffff00000000ULL;
1044     }
1045     }
1046    
1047    
1048     /*
1049     * fpu_op():
1050     *
1051 dpavlin 20 * Perform a floating-point operation. For those of fs and ft that are >= 0,
1052     * those numbers are interpreted into local variables.
1053 dpavlin 14 *
1054 dpavlin 20 * Only FPU_OP_C (compare) returns anything of interest, 1 for true, 0 for
1055     * false.
1056 dpavlin 14 */
1057     static int fpu_op(struct cpu *cpu, struct mips_coproc *cp, int op, int fmt,
1058     int ft, int fs, int fd, int cond, int output_fmt)
1059     {
1060     /* Potentially two input registers, fs and ft */
1061 dpavlin 20 struct ieee_float_value float_value[2];
1062     int unordered, nan, ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1063 dpavlin 14 uint64_t fs_v = 0;
1064     double nf;
1065    
1066     if (fs >= 0) {
1067     fs_v = cp->reg[fs];
1068     /* TODO: register-pair mode and plain
1069     register mode? "FR" bit? */
1070 dpavlin 24 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1071 dpavlin 14 fs_v = (fs_v & 0xffffffffULL) +
1072     (cp->reg[(fs + 1) & 31] << 32);
1073 dpavlin 20 ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);
1074 dpavlin 14 }
1075     if (ft >= 0) {
1076     uint64_t v = cp->reg[ft];
1077     /* TODO: register-pair mode and
1078     plain register mode? "FR" bit? */
1079 dpavlin 24 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1080 dpavlin 14 v = (v & 0xffffffffULL) +
1081     (cp->reg[(ft + 1) & 31] << 32);
1082 dpavlin 20 ieee_interpret_float_value(v, &float_value[1], ieee_fmt);
1083 dpavlin 14 }
1084    
1085     switch (op) {
1086     case FPU_OP_ADD:
1087     nf = float_value[0].f + float_value[1].f;
1088     /* debug(" add: %f + %f = %f\n",
1089     float_value[0].f, float_value[1].f, nf); */
1090     fpu_store_float_value(cp, fd, nf, output_fmt,
1091     float_value[0].nan || float_value[1].nan);
1092     break;
1093     case FPU_OP_SUB:
1094     nf = float_value[0].f - float_value[1].f;
1095     /* debug(" sub: %f - %f = %f\n",
1096     float_value[0].f, float_value[1].f, nf); */
1097     fpu_store_float_value(cp, fd, nf, output_fmt,
1098     float_value[0].nan || float_value[1].nan);
1099     break;
1100     case FPU_OP_MUL:
1101     nf = float_value[0].f * float_value[1].f;
1102     /* debug(" mul: %f * %f = %f\n",
1103     float_value[0].f, float_value[1].f, nf); */
1104     fpu_store_float_value(cp, fd, nf, output_fmt,
1105     float_value[0].nan || float_value[1].nan);
1106     break;
1107     case FPU_OP_DIV:
1108     nan = float_value[0].nan || float_value[1].nan;
1109     if (fabs(float_value[1].f) > 0.00000000001)
1110     nf = float_value[0].f / float_value[1].f;
1111     else {
1112     fatal("DIV by zero !!!!\n");
1113     nf = 0.0; /* TODO */
1114     nan = 1;
1115     }
1116     /* debug(" div: %f / %f = %f\n",
1117     float_value[0].f, float_value[1].f, nf); */
1118     fpu_store_float_value(cp, fd, nf, output_fmt, nan);
1119     break;
1120     case FPU_OP_SQRT:
1121     nan = float_value[0].nan;
1122     if (float_value[0].f >= 0.0)
1123     nf = sqrt(float_value[0].f);
1124     else {
1125     fatal("SQRT by less than zero, %f !!!!\n",
1126     float_value[0].f);
1127     nf = 0.0; /* TODO */
1128     nan = 1;
1129     }
1130     /* debug(" sqrt: %f => %f\n", float_value[0].f, nf); */
1131     fpu_store_float_value(cp, fd, nf, output_fmt, nan);
1132     break;
1133     case FPU_OP_ABS:
1134     nf = fabs(float_value[0].f);
1135     /* debug(" abs: %f => %f\n", float_value[0].f, nf); */
1136     fpu_store_float_value(cp, fd, nf, output_fmt,
1137     float_value[0].nan);
1138     break;
1139     case FPU_OP_NEG:
1140     nf = - float_value[0].f;
1141     /* debug(" neg: %f => %f\n", float_value[0].f, nf); */
1142     fpu_store_float_value(cp, fd, nf, output_fmt,
1143     float_value[0].nan);
1144     break;
1145     case FPU_OP_CVT:
1146     nf = float_value[0].f;
1147     /* debug(" mov: %f => %f\n", float_value[0].f, nf); */
1148     fpu_store_float_value(cp, fd, nf, output_fmt,
1149     float_value[0].nan);
1150     break;
1151     case FPU_OP_MOV:
1152     /* Non-arithmetic move: */
1153     /*
1154     * TODO: this is for 32-bit mode. It has to be updated later
1155     * for 64-bit coprocessor stuff.
1156     */
1157 dpavlin 24 if (output_fmt == COP1_FMT_D || output_fmt == COP1_FMT_L) {
1158 dpavlin 14 cp->reg[fd] = fs_v & 0xffffffffULL;
1159     cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;
1160     if (cp->reg[fd] & 0x80000000ULL)
1161     cp->reg[fd] |= 0xffffffff00000000ULL;
1162     if (cp->reg[fd+1] & 0x80000000ULL)
1163     cp->reg[fd+1] |= 0xffffffff00000000ULL;
1164     } else {
1165     cp->reg[fd] = fs_v & 0xffffffffULL;
1166     if (cp->reg[fd] & 0x80000000ULL)
1167     cp->reg[fd] |= 0xffffffff00000000ULL;
1168     }
1169     break;
1170     case FPU_OP_C:
1171     /* debug(" c: cond=%i\n", cond); */
1172    
1173     unordered = 0;
1174     if (float_value[0].nan || float_value[1].nan)
1175     unordered = 1;
1176    
1177     switch (cond) {
1178     case 2: /* Equal */
1179     return (float_value[0].f == float_value[1].f);
1180     case 4: /* Ordered or Less than */
1181     return (float_value[0].f < float_value[1].f)
1182     || !unordered;
1183     case 5: /* Unordered or Less than */
1184     return (float_value[0].f < float_value[1].f)
1185     || unordered;
1186     case 6: /* Ordered or Less than or Equal */
1187     return (float_value[0].f <= float_value[1].f)
1188     || !unordered;
1189     case 7: /* Unordered or Less than or Equal */
1190     return (float_value[0].f <= float_value[1].f)
1191     || unordered;
1192     case 12:/* Less than */
1193     return (float_value[0].f < float_value[1].f);
1194     case 14:/* Less than or equal */
1195     return (float_value[0].f <= float_value[1].f);
1196    
1197     /* The following are not commonly used, so I'll move these out
1198     of the if-0 on a case-by-case basis. */
1199     #if 0
1200     case 0: return 0; /* False */
1201     case 1: return 0; /* Unordered */
1202     case 3: return (float_value[0].f == float_value[1].f);
1203     /* Unordered or Equal */
1204     case 8: return 0; /* Signaling false */
1205     case 9: return 0; /* Not Greater than or Less than or Equal */
1206     case 10:return (float_value[0].f == float_value[1].f); /* Signaling Equal */
1207     case 11:return (float_value[0].f == float_value[1].f); /* Not Greater
1208     than or Less than */
1209     case 13:return !(float_value[0].f >= float_value[1].f); /* Not greater
1210     than or equal */
1211     case 15:return !(float_value[0].f > float_value[1].f); /* Not greater than */
1212     #endif
1213    
1214     default:
1215     fatal("fpu_op(): unimplemented condition "
1216     "code %i. see cpu_mips_coproc.c\n", cond);
1217     }
1218     break;
1219     default:
1220     fatal("fpu_op(): unimplemented op %i\n", op);
1221     }
1222    
1223     return 0;
1224     }
1225    
1226    
1227     /*
1228     * fpu_function():
1229     *
1230     * Returns 1 if function was implemented, 0 otherwise.
1231     * Debug trace should be printed for known instructions.
1232     */
1233     static int fpu_function(struct cpu *cpu, struct mips_coproc *cp,
1234     uint32_t function, int unassemble_only)
1235     {
1236     int fd, fs, ft, fmt, cond, cc;
1237    
1238     fmt = (function >> 21) & 31;
1239     ft = (function >> 16) & 31;
1240     fs = (function >> 11) & 31;
1241     cc = (function >> 8) & 7;
1242     fd = (function >> 6) & 31;
1243     cond = (function >> 0) & 15;
1244    
1245    
1246     /* bc1f, bc1t, bc1fl, bc1tl: */
1247     if ((function & 0x03e00000) == 0x01000000) {
1248 dpavlin 30 int nd, tf, imm;
1249 dpavlin 14 char *instr_mnem;
1250    
1251     /* cc are bits 20..18: */
1252     cc = (function >> 18) & 7;
1253     nd = (function >> 17) & 1;
1254     tf = (function >> 16) & 1;
1255     imm = function & 65535;
1256     if (imm >= 32768)
1257     imm -= 65536;
1258    
1259     instr_mnem = NULL;
1260     if (nd == 0 && tf == 0) instr_mnem = "bc1f";
1261     if (nd == 0 && tf == 1) instr_mnem = "bc1t";
1262     if (nd == 1 && tf == 0) instr_mnem = "bc1fl";
1263     if (nd == 1 && tf == 1) instr_mnem = "bc1tl";
1264    
1265     if (cpu->machine->instruction_trace || unassemble_only)
1266     debug("%s\t%i,0x%016llx\n", instr_mnem, cc,
1267     (long long) (cpu->pc + (imm << 2)));
1268     if (unassemble_only)
1269     return 1;
1270    
1271 dpavlin 30 fatal("INTERNAL ERROR: MIPS coprocessor branches should not"
1272     " be implemented in cpu_mips_coproc.c, but in"
1273     " cpu_mips_instr.c!\n");
1274     exit(1);
1275 dpavlin 14 }
1276    
1277     /* add.fmt: Floating-point add */
1278     if ((function & 0x0000003f) == 0x00000000) {
1279     if (cpu->machine->instruction_trace || unassemble_only)
1280 dpavlin 24 debug("add.%s\tr%i,r%i,r%i\n",
1281     fmtname[fmt], fd, fs, ft);
1282 dpavlin 14 if (unassemble_only)
1283     return 1;
1284    
1285     fpu_op(cpu, cp, FPU_OP_ADD, fmt, ft, fs, fd, -1, fmt);
1286     return 1;
1287     }
1288    
1289     /* sub.fmt: Floating-point subtract */
1290     if ((function & 0x0000003f) == 0x00000001) {
1291     if (cpu->machine->instruction_trace || unassemble_only)
1292 dpavlin 24 debug("sub.%s\tr%i,r%i,r%i\n",
1293     fmtname[fmt], fd, fs, ft);
1294 dpavlin 14 if (unassemble_only)
1295     return 1;
1296    
1297     fpu_op(cpu, cp, FPU_OP_SUB, fmt, ft, fs, fd, -1, fmt);
1298     return 1;
1299     }
1300    
1301     /* mul.fmt: Floating-point multiply */
1302     if ((function & 0x0000003f) == 0x00000002) {
1303     if (cpu->machine->instruction_trace || unassemble_only)
1304 dpavlin 24 debug("mul.%s\tr%i,r%i,r%i\n",
1305     fmtname[fmt], fd, fs, ft);
1306 dpavlin 14 if (unassemble_only)
1307     return 1;
1308    
1309     fpu_op(cpu, cp, FPU_OP_MUL, fmt, ft, fs, fd, -1, fmt);
1310     return 1;
1311     }
1312    
1313     /* div.fmt: Floating-point divide */
1314     if ((function & 0x0000003f) == 0x00000003) {
1315     if (cpu->machine->instruction_trace || unassemble_only)
1316 dpavlin 24 debug("div.%s\tr%i,r%i,r%i\n",
1317     fmtname[fmt], fd, fs, ft);
1318 dpavlin 14 if (unassemble_only)
1319     return 1;
1320    
1321     fpu_op(cpu, cp, FPU_OP_DIV, fmt, ft, fs, fd, -1, fmt);
1322     return 1;
1323     }
1324    
1325     /* sqrt.fmt: Floating-point square-root */
1326     if ((function & 0x001f003f) == 0x00000004) {
1327     if (cpu->machine->instruction_trace || unassemble_only)
1328 dpavlin 24 debug("sqrt.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1329 dpavlin 14 if (unassemble_only)
1330     return 1;
1331    
1332     fpu_op(cpu, cp, FPU_OP_SQRT, fmt, -1, fs, fd, -1, fmt);
1333     return 1;
1334     }
1335    
1336     /* abs.fmt: Floating-point absolute value */
1337     if ((function & 0x001f003f) == 0x00000005) {
1338     if (cpu->machine->instruction_trace || unassemble_only)
1339 dpavlin 24 debug("abs.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1340 dpavlin 14 if (unassemble_only)
1341     return 1;
1342    
1343     fpu_op(cpu, cp, FPU_OP_ABS, fmt, -1, fs, fd, -1, fmt);
1344     return 1;
1345     }
1346    
1347     /* mov.fmt: Floating-point (non-arithmetic) move */
1348     if ((function & 0x0000003f) == 0x00000006) {
1349     if (cpu->machine->instruction_trace || unassemble_only)
1350 dpavlin 24 debug("mov.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1351 dpavlin 14 if (unassemble_only)
1352     return 1;
1353    
1354     fpu_op(cpu, cp, FPU_OP_MOV, fmt, -1, fs, fd, -1, fmt);
1355     return 1;
1356     }
1357    
1358     /* neg.fmt: Floating-point negate */
1359     if ((function & 0x001f003f) == 0x00000007) {
1360     if (cpu->machine->instruction_trace || unassemble_only)
1361 dpavlin 24 debug("neg.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1362 dpavlin 14 if (unassemble_only)
1363     return 1;
1364    
1365     fpu_op(cpu, cp, FPU_OP_NEG, fmt, -1, fs, fd, -1, fmt);
1366     return 1;
1367     }
1368    
1369     /* trunc.l.fmt: Truncate */
1370     if ((function & 0x001f003f) == 0x00000009) {
1371     if (cpu->machine->instruction_trace || unassemble_only)
1372 dpavlin 24 debug("trunc.l.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1373 dpavlin 14 if (unassemble_only)
1374     return 1;
1375    
1376     /* TODO: not CVT? */
1377    
1378 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_L);
1379 dpavlin 14 return 1;
1380     }
1381    
1382     /* trunc.w.fmt: Truncate */
1383     if ((function & 0x001f003f) == 0x0000000d) {
1384     if (cpu->machine->instruction_trace || unassemble_only)
1385 dpavlin 24 debug("trunc.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1386 dpavlin 14 if (unassemble_only)
1387     return 1;
1388    
1389     /* TODO: not CVT? */
1390    
1391 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W);
1392 dpavlin 14 return 1;
1393     }
1394    
1395     /* c.cond.fmt: Floating-point compare */
1396     if ((function & 0x000000f0) == 0x00000030) {
1397     int cond_true;
1398     int bit;
1399    
1400     if (cpu->machine->instruction_trace || unassemble_only)
1401 dpavlin 24 debug("c.%s.%s\tcc%i,r%i,r%i\n", ccname[cond],
1402     fmtname[fmt], cc, fs, ft);
1403 dpavlin 14 if (unassemble_only)
1404     return 1;
1405    
1406     cond_true = fpu_op(cpu, cp, FPU_OP_C, fmt,
1407     ft, fs, -1, cond, fmt);
1408    
1409     /*
1410     * Both the FCCR and FCSR contain condition code bits:
1411     * FCCR: bits 7..0
1412     * FCSR: bits 31..25 and 23
1413     */
1414 dpavlin 24 cp->fcr[MIPS_FPU_FCCR] &= ~(1 << cc);
1415 dpavlin 14 if (cond_true)
1416 dpavlin 24 cp->fcr[MIPS_FPU_FCCR] |= (1 << cc);
1417 dpavlin 14
1418     if (cc == 0) {
1419 dpavlin 24 bit = 1 << MIPS_FCSR_FCC0_SHIFT;
1420     cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1421 dpavlin 14 if (cond_true)
1422 dpavlin 24 cp->fcr[MIPS_FPU_FCSR] |= bit;
1423 dpavlin 14 } else {
1424 dpavlin 24 bit = 1 << (MIPS_FCSR_FCC1_SHIFT + cc-1);
1425     cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1426 dpavlin 14 if (cond_true)
1427 dpavlin 24 cp->fcr[MIPS_FPU_FCSR] |= bit;
1428 dpavlin 14 }
1429    
1430     return 1;
1431     }
1432    
1433     /* cvt.s.fmt: Convert to single floating-point */
1434     if ((function & 0x001f003f) == 0x00000020) {
1435     if (cpu->machine->instruction_trace || unassemble_only)
1436 dpavlin 24 debug("cvt.s.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1437 dpavlin 14 if (unassemble_only)
1438     return 1;
1439    
1440 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_S);
1441 dpavlin 14 return 1;
1442     }
1443    
1444     /* cvt.d.fmt: Convert to double floating-point */
1445     if ((function & 0x001f003f) == 0x00000021) {
1446     if (cpu->machine->instruction_trace || unassemble_only)
1447 dpavlin 24 debug("cvt.d.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1448 dpavlin 14 if (unassemble_only)
1449     return 1;
1450    
1451 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_D);
1452 dpavlin 14 return 1;
1453     }
1454    
1455     /* cvt.w.fmt: Convert to word fixed-point */
1456     if ((function & 0x001f003f) == 0x00000024) {
1457     if (cpu->machine->instruction_trace || unassemble_only)
1458 dpavlin 24 debug("cvt.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1459 dpavlin 14 if (unassemble_only)
1460     return 1;
1461    
1462 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W);
1463 dpavlin 14 return 1;
1464     }
1465    
1466     return 0;
1467     }
1468    
1469    
1470     /*
1471     * coproc_tlbpr():
1472     *
1473     * 'tlbp' and 'tlbr'.
1474     */
1475     void coproc_tlbpr(struct cpu *cpu, int readflag)
1476     {
1477     struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1478     int i, found, g_bit;
1479     uint64_t vpn2, xmask;
1480    
1481     /* Read: */
1482     if (readflag) {
1483     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1484     i = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK) >>
1485     R2K3K_INDEX_SHIFT;
1486     if (i >= cp->nr_of_tlbs) {
1487     /* TODO: exception? */
1488 dpavlin 30 fatal("[ warning: tlbr from index %i (too "
1489     "high) ]\n", i);
1490 dpavlin 14 return;
1491     }
1492    
1493 dpavlin 30 cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi;
1494     cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;
1495 dpavlin 14 } else {
1496     /* R4000: */
1497     i = cp->reg[COP0_INDEX] & INDEX_MASK;
1498     if (i >= cp->nr_of_tlbs) /* TODO: exception */
1499     return;
1500    
1501     cp->reg[COP0_PAGEMASK] = cp->tlbs[i].mask;
1502     cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi;
1503     cp->reg[COP0_ENTRYLO1] = cp->tlbs[i].lo1;
1504     cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;
1505    
1506     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1507     /* R4100 don't have the G bit in entryhi */
1508     } else {
1509     /* R4000 etc: */
1510     cp->reg[COP0_ENTRYHI] &= ~TLB_G;
1511     g_bit = cp->tlbs[i].hi & TLB_G;
1512    
1513     cp->reg[COP0_ENTRYLO0] &= ~ENTRYLO_G;
1514     cp->reg[COP0_ENTRYLO1] &= ~ENTRYLO_G;
1515     if (g_bit) {
1516     cp->reg[COP0_ENTRYLO0] |= ENTRYLO_G;
1517     cp->reg[COP0_ENTRYLO1] |= ENTRYLO_G;
1518     }
1519     }
1520     }
1521    
1522     return;
1523     }
1524    
1525     /* Probe: */
1526     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1527     vpn2 = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1528     found = -1;
1529     for (i=0; i<cp->nr_of_tlbs; i++)
1530     if ( ((cp->tlbs[i].hi & R2K3K_ENTRYHI_ASID_MASK) ==
1531     (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK))
1532     || cp->tlbs[i].lo0 & R2K3K_ENTRYLO_G)
1533     if ((cp->tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK)
1534     == vpn2) {
1535     found = i;
1536     break;
1537     }
1538     } else {
1539     /* R4000 and R10000: */
1540     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
1541     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K;
1542     else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
1543     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800;
1544     else
1545     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK;
1546     vpn2 = cp->reg[COP0_ENTRYHI] & xmask;
1547     found = -1;
1548     for (i=0; i<cp->nr_of_tlbs; i++) {
1549     int gbit = cp->tlbs[i].hi & TLB_G;
1550     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
1551     gbit = (cp->tlbs[i].lo0 & ENTRYLO_G) &&
1552     (cp->tlbs[i].lo1 & ENTRYLO_G);
1553    
1554     if ( ((cp->tlbs[i].hi & ENTRYHI_ASID) ==
1555     (cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID)) || gbit) {
1556     uint64_t a = vpn2 & ~cp->tlbs[i].mask;
1557     uint64_t b = (cp->tlbs[i].hi & xmask) &
1558     ~cp->tlbs[i].mask;
1559     if (a == b) {
1560     found = i;
1561     break;
1562     }
1563     }
1564     }
1565     }
1566     if (found == -1)
1567     cp->reg[COP0_INDEX] = INDEX_P;
1568     else {
1569     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1570     cp->reg[COP0_INDEX] = found << R2K3K_INDEX_SHIFT;
1571     else
1572     cp->reg[COP0_INDEX] = found;
1573     }
1574    
1575     /* Sign extend the index register: */
1576     if ((cp->reg[COP0_INDEX] >> 32) == 0 &&
1577     cp->reg[COP0_INDEX] & 0x80000000)
1578     cp->reg[COP0_INDEX] |=
1579     0xffffffff00000000ULL;
1580     }
1581    
1582    
1583     /*
1584     * coproc_tlbwri():
1585     *
1586 dpavlin 24 * MIPS TLB write random (tlbwr) and write indexed (tlbwi) instructions.
1587 dpavlin 14 */
1588     void coproc_tlbwri(struct cpu *cpu, int randomflag)
1589     {
1590     struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1591 dpavlin 28 int index, g_bit;
1592 dpavlin 14 uint64_t oldvaddr;
1593    
1594     if (randomflag) {
1595 dpavlin 24 if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
1596 dpavlin 28 index = ((cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
1597     >> R2K3K_RANDOM_SHIFT) - 1;
1598     /* R3000 always has 8 wired entries: */
1599     if (index < 8)
1600     index = cp->nr_of_tlbs - 1;
1601     cp->reg[COP0_RANDOM] = index << R2K3K_RANDOM_SHIFT;
1602 dpavlin 24 } else {
1603     cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1604     % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
1605 dpavlin 14 index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
1606 dpavlin 24 }
1607 dpavlin 14 } else {
1608     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1609     index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK)
1610     >> R2K3K_INDEX_SHIFT;
1611     else
1612     index = cp->reg[COP0_INDEX] & INDEX_MASK;
1613     }
1614    
1615     if (index >= cp->nr_of_tlbs) {
1616     fatal("warning: tlb index %i too high (max is %i)\n",
1617     index, cp->nr_of_tlbs - 1);
1618     /* TODO: cause an exception? */
1619     return;
1620     }
1621    
1622 dpavlin 24
1623 dpavlin 14 #if 0
1624     /* Debug dump of the previous entry at that index: */
1625 dpavlin 24 fatal("{ old TLB entry at index %02x:", index);
1626     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1627     fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1628     fatal(" lo=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1629     } else {
1630     if (cpu->is_32bit) {
1631     fatal(" mask=%08"PRIx32,(uint32_t)cp->tlbs[index].mask);
1632     fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1633     fatal(" lo0=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1634     fatal(" lo1=%08"PRIx32, (uint32_t)cp->tlbs[index].lo1);
1635     } else {
1636     fatal(" mask=%016"PRIx64, cp->tlbs[index].mask);
1637     fatal(" hi=%016"PRIx64, cp->tlbs[index].hi);
1638     fatal(" lo0=%016"PRIx64, cp->tlbs[index].lo0);
1639     fatal(" lo1=%016"PRIx64, cp->tlbs[index].lo1);
1640     }
1641     }
1642     fatal(" }\n");
1643 dpavlin 14 #endif
1644    
1645 dpavlin 24 /*
1646     * Any virtual address translation for the old TLB entry must be
1647     * invalidated first:
1648 dpavlin 28 *
1649     * (Only Valid entries need to be invalidated, and only those that
1650     * are either Global, or have the same ASID as the new entry will
1651     * have. No other address translations should be active anyway.)
1652 dpavlin 24 */
1653    
1654 dpavlin 14 switch (cpu->cd.mips.cpu_type.mmu_model) {
1655 dpavlin 24
1656 dpavlin 14 case MMU3K:
1657     oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
1658 dpavlin 28 oldvaddr = (int32_t) oldvaddr;
1659 dpavlin 14
1660 dpavlin 28 if (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_V &&
1661     (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_G ||
1662     (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK) ==
1663     (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK) ))
1664     cpu->invalidate_translation_caches(cpu, oldvaddr,
1665     INVALIDATE_VADDR);
1666 dpavlin 32
1667 dpavlin 24 break;
1668 dpavlin 14
1669 dpavlin 24 default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1670 dpavlin 32 oldvaddr = cp->tlbs[index].hi &
1671     (ENTRYHI_VPN2_MASK_R10K | ENTRYHI_R_MASK);
1672 dpavlin 14 /* 44 addressable bits: */
1673     if (oldvaddr & 0x80000000000ULL)
1674 dpavlin 32 oldvaddr |= 0x3ffff00000000000ULL;
1675 dpavlin 24 } else if (cpu->is_32bit) {
1676     /* MIPS32 etc.: */
1677     oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1678     oldvaddr = (int32_t)oldvaddr;
1679 dpavlin 14 } else {
1680     /* Assume MMU4K */
1681 dpavlin 32 oldvaddr = cp->tlbs[index].hi &
1682     (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK);
1683 dpavlin 14 /* 40 addressable bits: */
1684     if (oldvaddr & 0x8000000000ULL)
1685 dpavlin 32 oldvaddr |= 0x3fffff0000000000ULL;
1686 dpavlin 14 }
1687    
1688     /*
1689     * TODO: non-4KB page sizes!
1690     */
1691 dpavlin 28 if (cp->tlbs[index].lo0 & ENTRYLO_V)
1692     cpu->invalidate_translation_caches(cpu, oldvaddr,
1693     INVALIDATE_VADDR);
1694     if (cp->tlbs[index].lo1 & ENTRYLO_V)
1695     cpu->invalidate_translation_caches(cpu, oldvaddr|0x1000,
1696     INVALIDATE_VADDR);
1697 dpavlin 14 }
1698    
1699 dpavlin 28 #if 0
1700 dpavlin 14 /*
1701     * Check for duplicate entries. (There should not be two mappings
1702     * from one virtual address to physical addresses.)
1703     *
1704     * TODO: Do this for MMU3K and R4100 too.
1705     *
1706     * TODO: Make this detection more robust.
1707     */
1708     if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&
1709     cpu->cd.mips.cpu_type.rev != MIPS_R4100) {
1710     uint64_t vaddr1, vaddr2;
1711 dpavlin 22 int i;
1712     unsigned int asid;
1713 dpavlin 14
1714 dpavlin 32 vaddr1 = cp->reg[COP0_ENTRYHI] &
1715     (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1716 dpavlin 14 asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
1717     /* Since this is just a warning, it's probably not necessary
1718     to use R4000 masks etc. */
1719    
1720     for (i=0; i<cp->nr_of_tlbs; i++) {
1721     if (i == index && !randomflag)
1722     continue;
1723    
1724     if (!(cp->tlbs[i].hi & TLB_G) &&
1725     (cp->tlbs[i].hi & ENTRYHI_ASID) != asid)
1726     continue;
1727    
1728 dpavlin 32 vaddr2 = cp->tlbs[i].hi &
1729     (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1730 dpavlin 14 if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 &
1731     ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V)))
1732     fatal("\n[ WARNING! tlbw%s to index 0x%02x "
1733     "vaddr=0x%llx (asid 0x%02x) is already in"
1734     " the TLB (entry 0x%02x) ! ]\n\n",
1735     randomflag? "r" : "i", index,
1736     (long long)vaddr1, asid, i);
1737     }
1738     }
1739 dpavlin 28 #endif
1740 dpavlin 14
1741     /* Write the new entry: */
1742    
1743     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1744 dpavlin 24 uint32_t vaddr, paddr;
1745 dpavlin 14 int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;
1746     unsigned char *memblock = NULL;
1747    
1748     cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI];
1749     cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0];
1750    
1751     vaddr = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1752     paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;
1753    
1754 dpavlin 24 memblock = memory_paddr_to_hostaddr(cpu->mem, paddr, 0);
1755 dpavlin 14
1756 dpavlin 24 /* Invalidate any code translation, if we are writing
1757     a Dirty page to the TLB: */
1758     if (wf) {
1759     cpu->invalidate_code_translation(cpu, paddr,
1760     INVALIDATE_PADDR);
1761     }
1762    
1763 dpavlin 32 /* Set new last_written_tlb_index hint: */
1764     cpu->cd.mips.last_written_tlb_index = index;
1765    
1766 dpavlin 28 if (cp->reg[COP0_STATUS] & MIPS1_ISOL_CACHES) {
1767     fatal("Wow! Interesting case; tlbw* while caches"
1768     " are isolated. TODO\n");
1769     /* Don't update the translation table in this
1770     case... */
1771     exit(1);
1772     }
1773    
1774 dpavlin 24 /* If we have a memblock (host page) for the physical
1775     page, then add a translation for it immediately: */
1776 dpavlin 14 if (memblock != NULL &&
1777 dpavlin 28 cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V)
1778 dpavlin 14 cpu->update_translation_table(cpu, vaddr, memblock,
1779     wf, paddr);
1780     } else {
1781 dpavlin 28 /* R4000 etc.: */
1782     unsigned char *memblock = NULL;
1783     int pfn_shift = 12, vpn_shift = 12;
1784     int wf0, wf1, mask;
1785     uint64_t vaddr0, vaddr1, paddr0, paddr1, ptmp;
1786 dpavlin 40 uint64_t psize;
1787 dpavlin 28
1788 dpavlin 14 cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];
1789     cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI];
1790     cp->tlbs[index].lo1 = cp->reg[COP0_ENTRYLO1];
1791     cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0];
1792    
1793 dpavlin 28 wf0 = cp->tlbs[index].lo0 & ENTRYLO_D;
1794     wf1 = cp->tlbs[index].lo1 & ENTRYLO_D;
1795    
1796     mask = cp->reg[COP0_PAGEMASK];
1797 dpavlin 14 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1798 dpavlin 28 pfn_shift = 10;
1799     mask |= 0x07ff;
1800 dpavlin 14 } else {
1801 dpavlin 28 mask |= 0x1fff;
1802 dpavlin 14 }
1803 dpavlin 28 switch (mask) {
1804     case 0x00007ff:
1805     if (cp->tlbs[index].lo0 & ENTRYLO_V ||
1806     cp->tlbs[index].lo1 & ENTRYLO_V) {
1807     fatal("1KB pages don't work with dyntrans.\n");
1808     exit(1);
1809     }
1810     vpn_shift = 10;
1811     break;
1812     case 0x0001fff: break;
1813     case 0x0007fff: vpn_shift = 14; break;
1814     case 0x001ffff: vpn_shift = 16; break;
1815     case 0x007ffff: vpn_shift = 18; break;
1816     case 0x01fffff: vpn_shift = 20; break;
1817     case 0x07fffff: vpn_shift = 22; break;
1818     case 0x1ffffff: vpn_shift = 24; break;
1819     case 0x7ffffff: vpn_shift = 26; break;
1820     default:fatal("Unimplemented MASK = 0x%016x\n", mask);
1821 dpavlin 26 exit(1);
1822     }
1823 dpavlin 24
1824 dpavlin 28 paddr0 = ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)
1825 dpavlin 40 >> ENTRYLO_PFN_SHIFT) << pfn_shift
1826     >> vpn_shift << vpn_shift;
1827 dpavlin 28 paddr1 = ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK)
1828 dpavlin 40 >> ENTRYLO_PFN_SHIFT) << pfn_shift
1829     >> vpn_shift << vpn_shift;
1830 dpavlin 24
1831 dpavlin 28 if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1832 dpavlin 32 vaddr0 = cp->tlbs[index].hi &
1833     (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1834 dpavlin 24 /* 44 addressable bits: */
1835 dpavlin 28 if (vaddr0 & 0x80000000000ULL)
1836 dpavlin 32 vaddr0 |= 0x3ffff00000000000ULL;
1837 dpavlin 24 } else if (cpu->is_32bit) {
1838     /* MIPS32 etc.: */
1839 dpavlin 28 vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1840     vaddr0 = (int32_t)vaddr0;
1841 dpavlin 14 } else {
1842 dpavlin 24 /* Assume MMU4K */
1843 dpavlin 32 vaddr0 = cp->tlbs[index].hi &
1844     (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK);
1845 dpavlin 24 /* 40 addressable bits: */
1846 dpavlin 28 if (vaddr0 & 0x8000000000ULL)
1847 dpavlin 32 vaddr0 |= 0x3fffff0000000000ULL;
1848 dpavlin 14 }
1849 dpavlin 24
1850 dpavlin 28 vaddr1 = vaddr0 | (1 << vpn_shift);
1851 dpavlin 24
1852 dpavlin 28 g_bit = (cp->reg[COP0_ENTRYLO0] &
1853     cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
1854 dpavlin 14
1855 dpavlin 28 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1856     /* NOTE: The VR4131 (and possibly others) don't have
1857     a Global bit in entryhi */
1858     cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK];
1859     } else {
1860     cp->tlbs[index].lo0 &= ~ENTRYLO_G;
1861     cp->tlbs[index].lo1 &= ~ENTRYLO_G;
1862 dpavlin 14
1863 dpavlin 28 cp->tlbs[index].hi &= ~TLB_G;
1864     if (g_bit)
1865     cp->tlbs[index].hi |= TLB_G;
1866     }
1867    
1868     /*
1869     * Invalidate any code translations, if we are writing Dirty
1870     * pages to the TLB: (TODO: 4KB hardcoded... ugly)
1871     */
1872 dpavlin 40 psize = 1 << pfn_shift;
1873     for (ptmp = 0; ptmp < psize; ptmp += 0x1000) {
1874 dpavlin 28 if (wf0)
1875     cpu->invalidate_code_translation(cpu,
1876     paddr0 + ptmp, INVALIDATE_PADDR);
1877     if (wf1)
1878     cpu->invalidate_code_translation(cpu,
1879     paddr1 + ptmp, INVALIDATE_PADDR);
1880     }
1881    
1882     /*
1883     * If we have a memblock (host page) for the physical page,
1884     * then add a translation for it immediately, to save some
1885     * time. (It would otherwise be added later on anyway,
1886     * because of a translation miss.)
1887     *
1888     * NOTE/TODO: This is only for 4KB pages so far. It would
1889     * be too expensive to add e.g. 16MB pages like
1890     * this.
1891     */
1892     memblock = memory_paddr_to_hostaddr(cpu->mem, paddr0, 0);
1893     if (memblock != NULL && cp->reg[COP0_ENTRYLO0] & ENTRYLO_V)
1894     cpu->update_translation_table(cpu, vaddr0, memblock,
1895     wf0, paddr0);
1896     memblock = memory_paddr_to_hostaddr(cpu->mem, paddr1, 0);
1897     if (memblock != NULL && cp->reg[COP0_ENTRYLO1] & ENTRYLO_V)
1898     cpu->update_translation_table(cpu, vaddr1, memblock,
1899     wf1, paddr1);
1900 dpavlin 32
1901     /* Set new last_written_tlb_index hint: */
1902     cpu->cd.mips.last_written_tlb_index = index;
1903 dpavlin 28 }
1904 dpavlin 14 }
1905    
1906    
1907     /*
1908     * coproc_eret():
1909     *
1910     * Return from exception. (R4000 etc.)
1911     */
1912     void coproc_eret(struct cpu *cpu)
1913     {
1914     if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {
1915 dpavlin 24 cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC];
1916 dpavlin 14 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
1917     } else {
1918 dpavlin 24 cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC];
1919     cpu->delay_slot = 0;
1920 dpavlin 14 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;
1921     }
1922    
1923     cpu->cd.mips.rmw = 0; /* the "LL bit" */
1924     }
1925    
1926    
1927     /*
1928     * coproc_function():
1929     *
1930     * Execute a coprocessor specific instruction. cp must be != NULL.
1931     * Debug trace should be printed for known instructions, if
1932     * unassemble_only is non-zero. (This will NOT execute the instruction.)
1933     *
1934     * TODO: This is a mess and should be restructured (again).
1935     */
1936     void coproc_function(struct cpu *cpu, struct mips_coproc *cp, int cpnr,
1937     uint32_t function, int unassemble_only, int running)
1938     {
1939     int co_bit, op, rt, rd, fs, copz;
1940     uint64_t tmpvalue;
1941    
1942     if (cp == NULL) {
1943     if (unassemble_only) {
1944     debug("cop%i\t0x%08x (coprocessor not available)\n",
1945     cpnr, (int)function);
1946     return;
1947     }
1948     fatal("[ pc=0x%016llx cop%i\t0x%08x (coprocessor not "
1949     "available)\n", (long long)cpu->pc, cpnr, (int)function);
1950     return;
1951     }
1952    
1953     /* No FPU? */
1954     if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {
1955     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);
1956     return;
1957     }
1958    
1959     /* For quick reference: */
1960     copz = (function >> 21) & 31;
1961     rt = (function >> 16) & 31;
1962     rd = (function >> 11) & 31;
1963    
1964     if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MFCz << 21))
1965     || ((function & 0x03e007f8) == (COPz_DMFCz << 21)))) {
1966     if (unassemble_only) {
1967     debug("%s%i\t%s,", copz==COPz_DMFCz? "dmfc" : "mfc",
1968     cpnr, regnames[rt]);
1969     if (cpnr == 0)
1970     debug("%s", cop0_names[rd]);
1971     else
1972 dpavlin 24 debug("r%i", rd);
1973 dpavlin 14 if (function & 7)
1974     debug(",%i", (int)(function & 7));
1975     debug("\n");
1976     return;
1977     }
1978     coproc_register_read(cpu, cpu->cd.mips.coproc[cpnr],
1979     rd, &tmpvalue, function & 7);
1980     cpu->cd.mips.gpr[rt] = tmpvalue;
1981     if (copz == COPz_MFCz) {
1982     /* Sign-extend: */
1983     cpu->cd.mips.gpr[rt] &= 0xffffffffULL;
1984     if (cpu->cd.mips.gpr[rt] & 0x80000000ULL)
1985     cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL;
1986     }
1987     return;
1988     }
1989    
1990     if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MTCz << 21))
1991     || ((function & 0x03e007f8) == (COPz_DMTCz << 21)))) {
1992     if (unassemble_only) {
1993     debug("%s%i\t%s,", copz==COPz_DMTCz? "dmtc" : "mtc",
1994     cpnr, regnames[rt]);
1995     if (cpnr == 0)
1996     debug("%s", cop0_names[rd]);
1997     else
1998 dpavlin 24 debug("r%i", rd);
1999 dpavlin 14 if (function & 7)
2000     debug(",%i", (int)(function & 7));
2001     debug("\n");
2002     return;
2003     }
2004     tmpvalue = cpu->cd.mips.gpr[rt];
2005     if (copz == COPz_MTCz) {
2006     /* Sign-extend: */
2007     tmpvalue &= 0xffffffffULL;
2008     if (tmpvalue & 0x80000000ULL)
2009     tmpvalue |= 0xffffffff00000000ULL;
2010     }
2011     coproc_register_write(cpu, cpu->cd.mips.coproc[cpnr], rd,
2012     &tmpvalue, copz == COPz_DMTCz, function & 7);
2013     return;
2014     }
2015    
2016     if (cpnr <= 1 && (((function & 0x03e007ff) == (COPz_CFCz << 21))
2017     || ((function & 0x03e007ff) == (COPz_CTCz << 21)))) {
2018     switch (copz) {
2019     case COPz_CFCz: /* Copy from FPU control register */
2020     rt = (function >> 16) & 31;
2021     fs = (function >> 11) & 31;
2022     if (unassemble_only) {
2023     debug("cfc%i\t%s,r%i\n", cpnr,
2024     regnames[rt], fs);
2025     return;
2026     }
2027 dpavlin 24 cpu->cd.mips.gpr[rt] = (int32_t)cp->fcr[fs];
2028 dpavlin 14 /* TODO: implement delay for gpr[rt]
2029     (for MIPS I,II,III only) */
2030     return;
2031     case COPz_CTCz: /* Copy to FPU control register */
2032     rt = (function >> 16) & 31;
2033     fs = (function >> 11) & 31;
2034     if (unassemble_only) {
2035     debug("ctc%i\t%s,r%i\n", cpnr,
2036     regnames[rt], fs);
2037     return;
2038     }
2039    
2040     switch (cpnr) {
2041     case 0: /* System coprocessor */
2042     fatal("[ warning: unimplemented ctc%i, "
2043     "0x%08x -> ctl reg %i ]\n", cpnr,
2044     (int)cpu->cd.mips.gpr[rt], fs);
2045     break;
2046     case 1: /* FPU */
2047     if (fs == 0)
2048     fatal("[ Attempt to write to FPU "
2049     "control register 0 (?) ]\n");
2050     else {
2051     uint64_t tmp = cpu->cd.mips.gpr[rt];
2052     cp->fcr[fs] = tmp;
2053    
2054     /* TODO: writing to control register 31
2055     should cause exceptions, depending
2056     on status bits! */
2057    
2058     switch (fs) {
2059 dpavlin 24 case MIPS_FPU_FCCR:
2060     cp->fcr[MIPS_FPU_FCSR] =
2061     (cp->fcr[MIPS_FPU_FCSR] &
2062 dpavlin 14 0x017fffffULL) | ((tmp & 1)
2063 dpavlin 24 << MIPS_FCSR_FCC0_SHIFT)
2064 dpavlin 14 | (((tmp & 0xfe) >> 1) <<
2065 dpavlin 24 MIPS_FCSR_FCC1_SHIFT);
2066 dpavlin 14 break;
2067 dpavlin 24 case MIPS_FPU_FCSR:
2068     cp->fcr[MIPS_FPU_FCCR] =
2069     (cp->fcr[MIPS_FPU_FCCR] &
2070 dpavlin 14 0xffffff00ULL) | ((tmp >>
2071 dpavlin 24 MIPS_FCSR_FCC0_SHIFT) & 1) |
2072     (((tmp >>
2073     MIPS_FCSR_FCC1_SHIFT)
2074 dpavlin 14 & 0x7f) << 1);
2075     break;
2076     default:
2077     ;
2078     }
2079     }
2080     break;
2081     }
2082    
2083     /* TODO: implement delay for gpr[rt]
2084     (for MIPS I,II,III only) */
2085     return;
2086     default:
2087     ;
2088     }
2089     }
2090    
2091     /* Math (Floating point) coprocessor calls: */
2092     if (cpnr==1) {
2093     if (fpu_function(cpu, cp, function, unassemble_only))
2094     return;
2095     }
2096    
2097    
2098     /* Ugly R5900 hacks: */
2099 dpavlin 24 if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
2100     if ((function & 0xfffff) == COP0_EI) {
2101     if (unassemble_only) {
2102     debug("ei\n");
2103     return;
2104     }
2105     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
2106     R5900_STATUS_EIE;
2107 dpavlin 14 return;
2108     }
2109    
2110 dpavlin 24 if ((function & 0xfffff) == COP0_DI) {
2111     if (unassemble_only) {
2112     debug("di\n");
2113     return;
2114     }
2115     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &=
2116     ~R5900_STATUS_EIE;
2117 dpavlin 14 return;
2118     }
2119     }
2120    
2121     co_bit = (function >> 25) & 1;
2122    
2123     /* TLB operations and other things: */
2124     if (cp->coproc_nr == 0) {
2125 dpavlin 30 if (!unassemble_only) {
2126     fatal("FATAL INTERNAL ERROR: Should be implemented"
2127     " with dyntrans instead.\n");
2128     exit(1);
2129     }
2130    
2131 dpavlin 14 switch (co_bit) {
2132 dpavlin 42 case 0:
2133     if ((function & 0x03e0ffdf) == 0x01606000) {
2134     debug("%ci", function & 0x20? 'e' : 'd');
2135     if (rt != MIPS_GPR_ZERO)
2136     debug("\t%s", regnames[rt]);
2137     debug("\n");
2138     return;
2139     }
2140     break;
2141 dpavlin 14 case 1:
2142 dpavlin 42 op = (function) & 0xff;
2143 dpavlin 14 switch (op) {
2144     case COP0_TLBR: /* Read indexed TLB entry */
2145 dpavlin 30 debug("tlbr\n");
2146 dpavlin 14 return;
2147     case COP0_TLBWI: /* Write indexed */
2148     case COP0_TLBWR: /* Write random */
2149 dpavlin 30 if (op == COP0_TLBWI)
2150     debug("tlbwi");
2151     else
2152     debug("tlbwr");
2153     if (!running) {
2154     debug("\n");
2155 dpavlin 24 return;
2156 dpavlin 14 }
2157 dpavlin 30 debug("\tindex=%08llx",
2158     (long long)cp->reg[COP0_INDEX]);
2159     debug(", random=%08llx",
2160     (long long)cp->reg[COP0_RANDOM]);
2161     debug(", mask=%016llx",
2162     (long long)cp->reg[COP0_PAGEMASK]);
2163     debug(", hi=%016llx",
2164     (long long)cp->reg[COP0_ENTRYHI]);
2165     debug(", lo0=%016llx",
2166     (long long)cp->reg[COP0_ENTRYLO0]);
2167     debug(", lo1=%016llx\n",
2168     (long long)cp->reg[COP0_ENTRYLO1]);
2169 dpavlin 14 return;
2170     case COP0_TLBP: /* Probe TLB for
2171     matching entry */
2172 dpavlin 30 debug("tlbp\n");
2173 dpavlin 14 return;
2174     case COP0_RFE: /* R2000/R3000 only:
2175     Return from Exception */
2176 dpavlin 30 debug("rfe\n");
2177     return;
2178 dpavlin 14 case COP0_ERET: /* R4000: Return from exception */
2179 dpavlin 30 debug("eret\n");
2180     return;
2181 dpavlin 24 case COP0_DERET:
2182 dpavlin 30 debug("deret\n");
2183     return;
2184     case COP0_WAIT:
2185     {
2186     int code = (function >> 6) & 0x7ffff;
2187     debug("wait");
2188     if (code > 0)
2189     debug("\t0x%x", code);
2190     debug("\n");
2191 dpavlin 24 }
2192     return;
2193 dpavlin 14 case COP0_STANDBY:
2194 dpavlin 30 debug("standby\n");
2195 dpavlin 14 return;
2196     case COP0_SUSPEND:
2197 dpavlin 30 debug("suspend\n");
2198 dpavlin 14 return;
2199     case COP0_HIBERNATE:
2200 dpavlin 30 debug("hibernate\n");
2201 dpavlin 14 return;
2202     default:
2203     ;
2204     }
2205 dpavlin 42 break;
2206 dpavlin 14 }
2207     }
2208    
2209     /* TODO: coprocessor R2020 on DECstation? */
2210     if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x0100ffff) {
2211     if (unassemble_only) {
2212     debug("decstation_r2020_writeback\n");
2213     return;
2214     }
2215     /* TODO */
2216     return;
2217     }
2218    
2219     if (unassemble_only) {
2220     debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);
2221     return;
2222     }
2223    
2224 dpavlin 24 fatal("cpu%i: UNIMPLEMENTED coproc%i function %08"PRIx32" "
2225     "(pc = %016"PRIx64")\n", cpu->cpu_id, cp->coproc_nr,
2226     (uint32_t)function, cpu->pc);
2227    
2228 dpavlin 14 mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cp->coproc_nr, 0, 0, 0);
2229     }
2230    

  ViewVC Help
Powered by ViewVC 1.1.26