/[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 40 - (hide annotations)
Mon Oct 8 16:22:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 65511 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1539 2007/05/01 04:03:51 debug Exp $
20070415	Landisk PCLOCK should be 33.33 MHz, not 50 MHz. (This makes
		the clock run at correct speed.)
		FINALLY found and fixed the bug which caused OpenBSD/landisk
		to randomly bug out: an &-sign was missing in the special case
		handling of FPSCR in the 'LDS.L @Rm+,FPSCR' instruction.
		Adding similar special case handling for 'LDC.L @Rm+,SR'
		(calling sh_update_sr() instead of just loading).
		Implementing the 'FCNVSD FPUL,DRn' and 'FCNVDS DRm,FPUL'
		SuperH instructions.
		The 'LDC Rm,SR' instruction now immediately breaks out of the
		dyntrans loop if an interrupt is to be triggered.
20070416	In memory_rw.c, if mapping a page as writable, make sure to
		invalidate code translations even if the data access was a
		read.
		Minor SuperH updates.
20070418	Removing the dummy M68K emulation mode.
		Minor SH update (turning unnecessary sts_mach_rn, sts_macl_rn,
		and sts_pr_rn instruction handlers into mov_rm_rn).
20070419	Beginning to add a skeleton for an M88K mode: Adding a hack to
		allow OpenBSD/m88k a.out binaries to be loaded, and disassembly
		of a few simple 88K instructions.
		Commenting out the 'LDC Rm,SR' fix from a few days ago, because
		it made Linux/dreamcast bug out.
		Adding a hack to dev_sh4.c (an extra translation cache
		invalidation), which allows OpenBSD/landisk to boot ok after
		an install. Upgrading the Landisk machine mode to stable,
		updating documentation, etc.
20070420	Experimenting with adding a PCI controller (pcic) to dev_sh4.
		Adding a dummy Realtek 8139C+ skeleton device (dev_rtl8139c).
		Implementing the first M88K instructions (br, or[.u] imm), and
		adding disassembly of some more instructions.
20070421	Continuing a little on dev_rtl8139c.
20070422	Implementing the 9346 EEPROM "read" command for dev_rtl8139c.
		Finally found and fixed an old bug in the log n symbol search
		(it sometimes missed symbols). Debug trace (-i, -t etc) should
		now show more symbols. :-)
20070423	Continuing a little on M88K disassembly.
20070428	Fixing a memset arg order bug in src/net/net.c (thanks to
		Nigel Horne for noticing the bug).
		Applying parts of a patch from Carl van Schaik to clear out
		bottom bits of MIPS addresses more correctly, when using large
		page sizes, and doing some other minor cleanup/refactoring.
		Fixing a couple of warnings given by gcc with the -W option (a
		few more warnings than just plain -Wall).
		Reducing SuperH dyntrans physical address space from 64-bit to
		32-bit (since SH5/SH64 isn't imlemented yet anyway).
		Adding address-to-symbol annotation to a few more instructions
		in the SuperH instruction trace output.
		Beginning regression testing for the next release.
		Reverting the value of SCIF_DELAYED_TX_VALUE from 1 to 2,
		because OpenBSD/landisk may otherwise hang randomly.
20070429	The ugly hack/workaround to get OpenBSD/landisk booting without
		crashing does NOT work anymore (with the April 21 snapshot
		of OpenBSD/landisk). Strangely enough, removing the hack
		completely causes OpenBSD/landisk to work (!).
		More regression testing (re-testing everything SuperH-related,
		and some other things).
		Cobalt interrupts were actually broken; fixing by commenting
		out the DEC21143s in the Cobalt machine.
20070430	More regression testing.
20070501	Updating the OpenBSD/landisk install instructions to use
		4.1 instead of the current snapshot.
		GAAAH! OpenBSD/landisk 4.1 _needs_ the ugly hack/workaround;
		reintroducing it again. (The 4.1 kernel is actually from
		2007-03-11.)
		Simplifying the NetBSD/evbarm install instructions a bit.
		More regression testing.

==============  RELEASE 0.4.5.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26