/[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 32 - (hide annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 65372 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


1 dpavlin 14 /*
2 dpavlin 24 * Copyright (C) 2003-2006 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 32 * $Id: cpu_mips_coproc.c,v 1.60 2006/10/14 23:47:37 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 24 static void invalidate_asid(struct cpu *cpu, int asid)
539 dpavlin 14 {
540 dpavlin 24 struct mips_coproc *cp = cpu->cd.mips.coproc[0];
541     int i, ntlbs = cp->nr_of_tlbs;
542     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     int inval = 0, old_asid, oldmode;
687    
688     switch (cp->coproc_nr) {
689     case 0:
690     /* COPROC 0: */
691     switch (reg_nr) {
692     case COP0_INDEX:
693     case COP0_RANDOM:
694     unimpl = 0;
695     break;
696     case COP0_ENTRYLO0:
697     unimpl = 0;
698     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
699     (tmp & 0xff)!=0) {
700     /* char *symbol;
701     uint64_t offset;
702 dpavlin 24 symbol = get_symbol_name(cpu->pc, &offset);
703 dpavlin 14 fatal("YO! pc = 0x%08llx <%s> "
704     "lo=%016llx\n", (long long)
705 dpavlin 24 cpu->pc, symbol? symbol :
706 dpavlin 14 "no symbol", (long long)tmp); */
707     tmp &= (R2K3K_ENTRYLO_PFN_MASK |
708     R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |
709     R2K3K_ENTRYLO_V | R2K3K_ENTRYLO_G);
710     } else if (cpu->cd.mips.cpu_type.mmu_model == MMU4K) {
711     tmp &= (ENTRYLO_PFN_MASK | ENTRYLO_C_MASK |
712     ENTRYLO_D | ENTRYLO_V | ENTRYLO_G);
713     }
714     break;
715     case COP0_BADVADDR:
716     /* Hm. Irix writes to this register. (Why?) */
717     unimpl = 0;
718     break;
719     case COP0_ENTRYLO1:
720     unimpl = 0;
721     if (cpu->cd.mips.cpu_type.mmu_model == MMU4K) {
722     tmp &= (ENTRYLO_PFN_MASK | ENTRYLO_C_MASK |
723     ENTRYLO_D | ENTRYLO_V | ENTRYLO_G);
724     }
725     break;
726     case COP0_CONTEXT:
727     old = cp->reg[COP0_CONTEXT];
728     cp->reg[COP0_CONTEXT] = tmp;
729     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
730     cp->reg[COP0_CONTEXT] &=
731     ~R2K3K_CONTEXT_BADVPN_MASK;
732     cp->reg[COP0_CONTEXT] |=
733     (old & R2K3K_CONTEXT_BADVPN_MASK);
734     } else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
735     cp->reg[COP0_CONTEXT] &=
736     ~CONTEXT_BADVPN2_MASK_R4100;
737     cp->reg[COP0_CONTEXT] |=
738     (old & CONTEXT_BADVPN2_MASK_R4100);
739     } else {
740     cp->reg[COP0_CONTEXT] &=
741     ~CONTEXT_BADVPN2_MASK;
742     cp->reg[COP0_CONTEXT] |=
743     (old & CONTEXT_BADVPN2_MASK);
744     }
745     return;
746     case COP0_PAGEMASK:
747     tmp2 = tmp >> PAGEMASK_SHIFT;
748     if (tmp2 != 0x000 &&
749     tmp2 != 0x003 &&
750     tmp2 != 0x00f &&
751     tmp2 != 0x03f &&
752     tmp2 != 0x0ff &&
753     tmp2 != 0x3ff &&
754     tmp2 != 0xfff)
755     fatal("cpu%i: trying to write an invalid"
756     " pagemask 0x%08lx to COP0_PAGEMASK\n",
757     cpu->cpu_id, (long)tmp);
758     unimpl = 0;
759     break;
760     case COP0_WIRED:
761     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
762     fatal("cpu%i: r2k/r3k wired register must "
763     "always be 8\n", cpu->cpu_id);
764     tmp = 8;
765     }
766     cp->reg[COP0_RANDOM] = cp->nr_of_tlbs-1;
767     tmp &= INDEX_MASK;
768     unimpl = 0;
769     break;
770     case COP0_COUNT:
771 dpavlin 22 if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
772 dpavlin 14 fatal("WARNING: trying to write a 64-bit value"
773     " to the COUNT register!\n");
774     tmp = (int64_t)(int32_t)tmp;
775     unimpl = 0;
776     break;
777     case COP0_COMPARE:
778 dpavlin 32 if (cpu->machine->emulated_hz > 0) {
779     int32_t compare_diff = tmp -
780     cp->reg[COP0_COMPARE];
781     double hz;
782    
783     if (compare_diff < 0)
784     hz = tmp - cp->reg[COP0_COUNT];
785    
786     if (compare_diff == 0)
787     hz = 0;
788     else
789     hz = (double)cpu->machine->emulated_hz
790     / (double)compare_diff;
791     /*
792     * TODO: DON'T HARDCODE THIS!
793     */
794     hz = 100.0;
795    
796     /* Initialize or re-set the periodic timer: */
797     if (hz > 0) {
798     if (cpu->cd.mips.timer == NULL)
799     cpu->cd.mips.timer = timer_add(
800     hz, mips_timer_tick, cpu);
801     else
802     timer_update_frequency(
803     cpu->cd.mips.timer, hz);
804     }
805     }
806    
807     /* Ack the periodic timer, if it was asserted: */
808     if (cp->reg[COP0_CAUSE] & 0x8000 &&
809     cpu->cd.mips.compare_interrupts_pending > 0)
810     cpu->cd.mips.compare_interrupts_pending --;
811    
812     /* Clear the timer interrupt assertion (bit 7): */
813 dpavlin 14 mips_cpu_interrupt_ack(cpu, 7);
814 dpavlin 32
815 dpavlin 22 if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
816 dpavlin 14 fatal("WARNING: trying to write a 64-bit value"
817     " to the COMPARE register!\n");
818 dpavlin 32
819 dpavlin 14 tmp = (int64_t)(int32_t)tmp;
820 dpavlin 32 cpu->cd.mips.compare_register_set = 1;
821 dpavlin 14 unimpl = 0;
822     break;
823     case COP0_ENTRYHI:
824     /*
825 dpavlin 24 * Translation caches must be invalidated if the
826     * ASID changes:
827 dpavlin 14 */
828     switch (cpu->cd.mips.cpu_type.mmu_model) {
829     case MMU3K:
830 dpavlin 24 old_asid = cp->reg[COP0_ENTRYHI] &
831     R2K3K_ENTRYHI_ASID_MASK;
832 dpavlin 14 if ((cp->reg[COP0_ENTRYHI] &
833     R2K3K_ENTRYHI_ASID_MASK) !=
834     (tmp & R2K3K_ENTRYHI_ASID_MASK))
835     inval = 1;
836     break;
837     default:
838     old_asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
839     if ((cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID) !=
840     (tmp & ENTRYHI_ASID))
841     inval = 1;
842     break;
843     }
844 dpavlin 24
845 dpavlin 14 if (inval)
846 dpavlin 24 invalidate_asid(cpu, old_asid);
847    
848 dpavlin 14 unimpl = 0;
849     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
850     (tmp & 0x3f)!=0) {
851     /* char *symbol;
852     uint64_t offset;
853 dpavlin 24 symbol = get_symbol_name(cpu->pc,
854     &offset);
855 dpavlin 14 fatal("YO! pc = 0x%08llx <%s> "
856 dpavlin 24 "hi=%016llx\n", (long long)cpu->pc,
857     symbol? symbol :
858 dpavlin 14 "no symbol", (long long)tmp); */
859     tmp &= ~0x3f;
860     }
861     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
862     tmp &= (R2K3K_ENTRYHI_VPN_MASK |
863     R2K3K_ENTRYHI_ASID_MASK);
864     else if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
865     tmp &= (ENTRYHI_R_MASK |
866     ENTRYHI_VPN2_MASK_R10K | ENTRYHI_ASID);
867     else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
868     tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK |
869     0x1800 | ENTRYHI_ASID);
870     else
871     tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK |
872     ENTRYHI_ASID);
873     break;
874     case COP0_EPC:
875     unimpl = 0;
876     break;
877     case COP0_PRID:
878     readonly = 1;
879     break;
880     case COP0_CONFIG:
881     if (select > 0) {
882     switch (select) {
883     case 1: cpu->cd.mips.cop0_config_select1 = tmp;
884     break;
885     default:fatal("coproc_register_write(): unimpl"
886     "emented config register select "
887     "%i\n", select);
888     exit(1);
889     }
890     return;
891     }
892    
893     /* fatal("COP0_CONFIG: modifying K0 bits: "
894     "0x%08x => ", cp->reg[reg_nr]); */
895     tmp = *ptr;
896     tmp &= 0x3; /* only bits 2..0 can be written */
897     cp->reg[reg_nr] &= ~(0x3); cp->reg[reg_nr] |= tmp;
898     /* fatal("0x%08x\n", cp->reg[reg_nr]); */
899     return;
900     case COP0_STATUS:
901     oldmode = cp->reg[COP0_STATUS];
902     tmp &= ~(1 << 21); /* bit 21 is read-only */
903 dpavlin 26
904 dpavlin 24 /*
905 dpavlin 26 * When isolating caches, invalidate all translations.
906     * During the isolation, a special hack in memory_rw.c
907     * prevents translation tables from being updated, so
908     * the translation caches don't have to be invalidated
909     * when switching back to normal mode.
910 dpavlin 24 */
911 dpavlin 14 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
912 dpavlin 24 (oldmode & MIPS1_ISOL_CACHES) !=
913 dpavlin 14 (tmp & MIPS1_ISOL_CACHES)) {
914 dpavlin 26 /* Invalidate everything if we are switching
915     to isolated mode: */
916     if (tmp & MIPS1_ISOL_CACHES) {
917     cpu->invalidate_translation_caches(
918     cpu, 0, INVALIDATE_ALL);
919     }
920 dpavlin 14 }
921     unimpl = 0;
922     break;
923     case COP0_CAUSE:
924     /* A write to the cause register only
925     affects IM bits 0 and 1: */
926     cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);
927     cp->reg[reg_nr] |= (tmp & (0x3 << STATUS_IM_SHIFT));
928     return;
929     case COP0_FRAMEMASK:
930     /* TODO: R10000 */
931     unimpl = 0;
932     break;
933     case COP0_TAGDATA_LO:
934     case COP0_TAGDATA_HI:
935     /* TODO: R4300 and others? */
936     unimpl = 0;
937     break;
938     case COP0_LLADDR:
939     unimpl = 0;
940     break;
941     case COP0_WATCHLO:
942     case COP0_WATCHHI:
943     unimpl = 0;
944     break;
945     case COP0_XCONTEXT:
946     /*
947     * TODO: According to the R10000 manual, the R4400
948     * shares the PTEbase portion of the context registers
949     * (that is, xcontext and context). On R10000, they
950     * are separate registers.
951     */
952     /* debug("[ xcontext 0x%016llx ]\n", tmp); */
953     unimpl = 0;
954     break;
955    
956     /* Most of these are actually TODOs: */
957     case COP0_ERROREPC:
958     case COP0_DEPC:
959     case COP0_RESERV22: /* Used by Linux on Linksys WRT54G */
960     case COP0_DESAVE:
961     case COP0_PERFCNT:
962     case COP0_ERRCTL: /* R10000 */
963     unimpl = 0;
964     break;
965     }
966     break;
967    
968     case 1:
969     /* COPROC 1: */
970     unimpl = 0;
971     break;
972     }
973    
974     if (unimpl) {
975     fatal("cpu%i: warning: write to unimplemented coproc%i "
976     "register %i (%s), data = 0x%016llx\n", cpu->cpu_id,
977     cp->coproc_nr, reg_nr, cp->coproc_nr==0?
978     cop0_names[reg_nr] : "?", (long long)tmp);
979    
980     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0,
981     cp->coproc_nr, 0, 0, 0);
982     return;
983     }
984    
985     if (readonly) {
986     fatal("cpu%i: warning: write to READONLY coproc%i register "
987     "%i ignored\n", cpu->cpu_id, cp->coproc_nr, reg_nr);
988     return;
989     }
990    
991     cp->reg[reg_nr] = tmp;
992    
993     if (!flag64)
994     cp->reg[reg_nr] = (int64_t)(int32_t)cp->reg[reg_nr];
995     }
996    
997    
998     /*
999     * MIPS floating-point stuff:
1000     *
1001     * TODO: Move this to some other file?
1002     */
1003 dpavlin 20 static int mips_fmt_to_ieee_fmt[32] = {
1004     0, 0, 0, 0, 0, 0, 0, 0,
1005     0, 0, 0, 0, 0, 0, 0, 0,
1006     IEEE_FMT_S, IEEE_FMT_D, 0, 0,
1007     IEEE_FMT_W, IEEE_FMT_L, /* PS (Paired Single) */ 0, 0,
1008     0, 0, 0, 0, 0, 0, 0, 0 };
1009    
1010 dpavlin 24 static char *fmtname[32] = {
1011     "0", "1", "2", "3", "4", "5", "6", "7",
1012     "8", "9", "10", "11", "12", "13", "14", "15",
1013     "s", "d", "18", "19", "w", "l", "ps", "23",
1014     "24", "25", "26", "27", "28", "29", "30", "31" };
1015 dpavlin 14
1016 dpavlin 24 static char *ccname[16] = {
1017     "f", "un", "eq", "ueq", "olt", "ult", "ole", "ule",
1018     "sf", "ngle", "seq", "ngl", "lt", "nge", "le", "ngt" };
1019    
1020 dpavlin 14 #define FPU_OP_ADD 1
1021     #define FPU_OP_SUB 2
1022     #define FPU_OP_MUL 3
1023     #define FPU_OP_DIV 4
1024     #define FPU_OP_SQRT 5
1025     #define FPU_OP_MOV 6
1026     #define FPU_OP_CVT 7
1027     #define FPU_OP_C 8
1028     #define FPU_OP_ABS 9
1029     #define FPU_OP_NEG 10
1030 dpavlin 20 /* TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W, RSQRT */
1031 dpavlin 14
1032    
1033     /*
1034     * fpu_store_float_value():
1035     *
1036     * Stores a float value (actually a double) in fmt format.
1037     */
1038     static void fpu_store_float_value(struct mips_coproc *cp, int fd,
1039     double nf, int fmt, int nan)
1040     {
1041 dpavlin 20 int ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1042     uint64_t r = ieee_store_float_value(nf, ieee_fmt, nan);
1043 dpavlin 14
1044     /*
1045 dpavlin 20 * TODO: This is for 32-bit mode. It has to be updated later
1046     * for 64-bit coprocessor functionality!
1047 dpavlin 14 */
1048 dpavlin 24 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) {
1049 dpavlin 14 cp->reg[fd] = r & 0xffffffffULL;
1050     cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;
1051    
1052     if (cp->reg[fd] & 0x80000000ULL)
1053     cp->reg[fd] |= 0xffffffff00000000ULL;
1054     if (cp->reg[fd+1] & 0x80000000ULL)
1055     cp->reg[fd+1] |= 0xffffffff00000000ULL;
1056     } else {
1057     cp->reg[fd] = r & 0xffffffffULL;
1058    
1059     if (cp->reg[fd] & 0x80000000ULL)
1060     cp->reg[fd] |= 0xffffffff00000000ULL;
1061     }
1062     }
1063    
1064    
1065     /*
1066     * fpu_op():
1067     *
1068 dpavlin 20 * Perform a floating-point operation. For those of fs and ft that are >= 0,
1069     * those numbers are interpreted into local variables.
1070 dpavlin 14 *
1071 dpavlin 20 * Only FPU_OP_C (compare) returns anything of interest, 1 for true, 0 for
1072     * false.
1073 dpavlin 14 */
1074     static int fpu_op(struct cpu *cpu, struct mips_coproc *cp, int op, int fmt,
1075     int ft, int fs, int fd, int cond, int output_fmt)
1076     {
1077     /* Potentially two input registers, fs and ft */
1078 dpavlin 20 struct ieee_float_value float_value[2];
1079     int unordered, nan, ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1080 dpavlin 14 uint64_t fs_v = 0;
1081     double nf;
1082    
1083     if (fs >= 0) {
1084     fs_v = cp->reg[fs];
1085     /* TODO: register-pair mode and plain
1086     register mode? "FR" bit? */
1087 dpavlin 24 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1088 dpavlin 14 fs_v = (fs_v & 0xffffffffULL) +
1089     (cp->reg[(fs + 1) & 31] << 32);
1090 dpavlin 20 ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);
1091 dpavlin 14 }
1092     if (ft >= 0) {
1093     uint64_t v = cp->reg[ft];
1094     /* TODO: register-pair mode and
1095     plain register mode? "FR" bit? */
1096 dpavlin 24 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1097 dpavlin 14 v = (v & 0xffffffffULL) +
1098     (cp->reg[(ft + 1) & 31] << 32);
1099 dpavlin 20 ieee_interpret_float_value(v, &float_value[1], ieee_fmt);
1100 dpavlin 14 }
1101    
1102     switch (op) {
1103     case FPU_OP_ADD:
1104     nf = float_value[0].f + float_value[1].f;
1105     /* debug(" add: %f + %f = %f\n",
1106     float_value[0].f, float_value[1].f, nf); */
1107     fpu_store_float_value(cp, fd, nf, output_fmt,
1108     float_value[0].nan || float_value[1].nan);
1109     break;
1110     case FPU_OP_SUB:
1111     nf = float_value[0].f - float_value[1].f;
1112     /* debug(" sub: %f - %f = %f\n",
1113     float_value[0].f, float_value[1].f, nf); */
1114     fpu_store_float_value(cp, fd, nf, output_fmt,
1115     float_value[0].nan || float_value[1].nan);
1116     break;
1117     case FPU_OP_MUL:
1118     nf = float_value[0].f * float_value[1].f;
1119     /* debug(" mul: %f * %f = %f\n",
1120     float_value[0].f, float_value[1].f, nf); */
1121     fpu_store_float_value(cp, fd, nf, output_fmt,
1122     float_value[0].nan || float_value[1].nan);
1123     break;
1124     case FPU_OP_DIV:
1125     nan = float_value[0].nan || float_value[1].nan;
1126     if (fabs(float_value[1].f) > 0.00000000001)
1127     nf = float_value[0].f / float_value[1].f;
1128     else {
1129     fatal("DIV by zero !!!!\n");
1130     nf = 0.0; /* TODO */
1131     nan = 1;
1132     }
1133     /* debug(" div: %f / %f = %f\n",
1134     float_value[0].f, float_value[1].f, nf); */
1135     fpu_store_float_value(cp, fd, nf, output_fmt, nan);
1136     break;
1137     case FPU_OP_SQRT:
1138     nan = float_value[0].nan;
1139     if (float_value[0].f >= 0.0)
1140     nf = sqrt(float_value[0].f);
1141     else {
1142     fatal("SQRT by less than zero, %f !!!!\n",
1143     float_value[0].f);
1144     nf = 0.0; /* TODO */
1145     nan = 1;
1146     }
1147     /* debug(" sqrt: %f => %f\n", float_value[0].f, nf); */
1148     fpu_store_float_value(cp, fd, nf, output_fmt, nan);
1149     break;
1150     case FPU_OP_ABS:
1151     nf = fabs(float_value[0].f);
1152     /* debug(" abs: %f => %f\n", float_value[0].f, nf); */
1153     fpu_store_float_value(cp, fd, nf, output_fmt,
1154     float_value[0].nan);
1155     break;
1156     case FPU_OP_NEG:
1157     nf = - float_value[0].f;
1158     /* debug(" neg: %f => %f\n", float_value[0].f, nf); */
1159     fpu_store_float_value(cp, fd, nf, output_fmt,
1160     float_value[0].nan);
1161     break;
1162     case FPU_OP_CVT:
1163     nf = float_value[0].f;
1164     /* debug(" mov: %f => %f\n", float_value[0].f, nf); */
1165     fpu_store_float_value(cp, fd, nf, output_fmt,
1166     float_value[0].nan);
1167     break;
1168     case FPU_OP_MOV:
1169     /* Non-arithmetic move: */
1170     /*
1171     * TODO: this is for 32-bit mode. It has to be updated later
1172     * for 64-bit coprocessor stuff.
1173     */
1174 dpavlin 24 if (output_fmt == COP1_FMT_D || output_fmt == COP1_FMT_L) {
1175 dpavlin 14 cp->reg[fd] = fs_v & 0xffffffffULL;
1176     cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;
1177     if (cp->reg[fd] & 0x80000000ULL)
1178     cp->reg[fd] |= 0xffffffff00000000ULL;
1179     if (cp->reg[fd+1] & 0x80000000ULL)
1180     cp->reg[fd+1] |= 0xffffffff00000000ULL;
1181     } else {
1182     cp->reg[fd] = fs_v & 0xffffffffULL;
1183     if (cp->reg[fd] & 0x80000000ULL)
1184     cp->reg[fd] |= 0xffffffff00000000ULL;
1185     }
1186     break;
1187     case FPU_OP_C:
1188     /* debug(" c: cond=%i\n", cond); */
1189    
1190     unordered = 0;
1191     if (float_value[0].nan || float_value[1].nan)
1192     unordered = 1;
1193    
1194     switch (cond) {
1195     case 2: /* Equal */
1196     return (float_value[0].f == float_value[1].f);
1197     case 4: /* Ordered or Less than */
1198     return (float_value[0].f < float_value[1].f)
1199     || !unordered;
1200     case 5: /* Unordered or Less than */
1201     return (float_value[0].f < float_value[1].f)
1202     || unordered;
1203     case 6: /* Ordered or Less than or Equal */
1204     return (float_value[0].f <= float_value[1].f)
1205     || !unordered;
1206     case 7: /* Unordered or Less than or Equal */
1207     return (float_value[0].f <= float_value[1].f)
1208     || unordered;
1209     case 12:/* Less than */
1210     return (float_value[0].f < float_value[1].f);
1211     case 14:/* Less than or equal */
1212     return (float_value[0].f <= float_value[1].f);
1213    
1214     /* The following are not commonly used, so I'll move these out
1215     of the if-0 on a case-by-case basis. */
1216     #if 0
1217     case 0: return 0; /* False */
1218     case 1: return 0; /* Unordered */
1219     case 3: return (float_value[0].f == float_value[1].f);
1220     /* Unordered or Equal */
1221     case 8: return 0; /* Signaling false */
1222     case 9: return 0; /* Not Greater than or Less than or Equal */
1223     case 10:return (float_value[0].f == float_value[1].f); /* Signaling Equal */
1224     case 11:return (float_value[0].f == float_value[1].f); /* Not Greater
1225     than or Less than */
1226     case 13:return !(float_value[0].f >= float_value[1].f); /* Not greater
1227     than or equal */
1228     case 15:return !(float_value[0].f > float_value[1].f); /* Not greater than */
1229     #endif
1230    
1231     default:
1232     fatal("fpu_op(): unimplemented condition "
1233     "code %i. see cpu_mips_coproc.c\n", cond);
1234     }
1235     break;
1236     default:
1237     fatal("fpu_op(): unimplemented op %i\n", op);
1238     }
1239    
1240     return 0;
1241     }
1242    
1243    
1244     /*
1245     * fpu_function():
1246     *
1247     * Returns 1 if function was implemented, 0 otherwise.
1248     * Debug trace should be printed for known instructions.
1249     */
1250     static int fpu_function(struct cpu *cpu, struct mips_coproc *cp,
1251     uint32_t function, int unassemble_only)
1252     {
1253     int fd, fs, ft, fmt, cond, cc;
1254    
1255     fmt = (function >> 21) & 31;
1256     ft = (function >> 16) & 31;
1257     fs = (function >> 11) & 31;
1258     cc = (function >> 8) & 7;
1259     fd = (function >> 6) & 31;
1260     cond = (function >> 0) & 15;
1261    
1262    
1263     /* bc1f, bc1t, bc1fl, bc1tl: */
1264     if ((function & 0x03e00000) == 0x01000000) {
1265 dpavlin 30 int nd, tf, imm;
1266 dpavlin 14 char *instr_mnem;
1267    
1268     /* cc are bits 20..18: */
1269     cc = (function >> 18) & 7;
1270     nd = (function >> 17) & 1;
1271     tf = (function >> 16) & 1;
1272     imm = function & 65535;
1273     if (imm >= 32768)
1274     imm -= 65536;
1275    
1276     instr_mnem = NULL;
1277     if (nd == 0 && tf == 0) instr_mnem = "bc1f";
1278     if (nd == 0 && tf == 1) instr_mnem = "bc1t";
1279     if (nd == 1 && tf == 0) instr_mnem = "bc1fl";
1280     if (nd == 1 && tf == 1) instr_mnem = "bc1tl";
1281    
1282     if (cpu->machine->instruction_trace || unassemble_only)
1283     debug("%s\t%i,0x%016llx\n", instr_mnem, cc,
1284     (long long) (cpu->pc + (imm << 2)));
1285     if (unassemble_only)
1286     return 1;
1287    
1288 dpavlin 30 fatal("INTERNAL ERROR: MIPS coprocessor branches should not"
1289     " be implemented in cpu_mips_coproc.c, but in"
1290     " cpu_mips_instr.c!\n");
1291     exit(1);
1292 dpavlin 14 }
1293    
1294     /* add.fmt: Floating-point add */
1295     if ((function & 0x0000003f) == 0x00000000) {
1296     if (cpu->machine->instruction_trace || unassemble_only)
1297 dpavlin 24 debug("add.%s\tr%i,r%i,r%i\n",
1298     fmtname[fmt], fd, fs, ft);
1299 dpavlin 14 if (unassemble_only)
1300     return 1;
1301    
1302     fpu_op(cpu, cp, FPU_OP_ADD, fmt, ft, fs, fd, -1, fmt);
1303     return 1;
1304     }
1305    
1306     /* sub.fmt: Floating-point subtract */
1307     if ((function & 0x0000003f) == 0x00000001) {
1308     if (cpu->machine->instruction_trace || unassemble_only)
1309 dpavlin 24 debug("sub.%s\tr%i,r%i,r%i\n",
1310     fmtname[fmt], fd, fs, ft);
1311 dpavlin 14 if (unassemble_only)
1312     return 1;
1313    
1314     fpu_op(cpu, cp, FPU_OP_SUB, fmt, ft, fs, fd, -1, fmt);
1315     return 1;
1316     }
1317    
1318     /* mul.fmt: Floating-point multiply */
1319     if ((function & 0x0000003f) == 0x00000002) {
1320     if (cpu->machine->instruction_trace || unassemble_only)
1321 dpavlin 24 debug("mul.%s\tr%i,r%i,r%i\n",
1322     fmtname[fmt], fd, fs, ft);
1323 dpavlin 14 if (unassemble_only)
1324     return 1;
1325    
1326     fpu_op(cpu, cp, FPU_OP_MUL, fmt, ft, fs, fd, -1, fmt);
1327     return 1;
1328     }
1329    
1330     /* div.fmt: Floating-point divide */
1331     if ((function & 0x0000003f) == 0x00000003) {
1332     if (cpu->machine->instruction_trace || unassemble_only)
1333 dpavlin 24 debug("div.%s\tr%i,r%i,r%i\n",
1334     fmtname[fmt], fd, fs, ft);
1335 dpavlin 14 if (unassemble_only)
1336     return 1;
1337    
1338     fpu_op(cpu, cp, FPU_OP_DIV, fmt, ft, fs, fd, -1, fmt);
1339     return 1;
1340     }
1341    
1342     /* sqrt.fmt: Floating-point square-root */
1343     if ((function & 0x001f003f) == 0x00000004) {
1344     if (cpu->machine->instruction_trace || unassemble_only)
1345 dpavlin 24 debug("sqrt.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1346 dpavlin 14 if (unassemble_only)
1347     return 1;
1348    
1349     fpu_op(cpu, cp, FPU_OP_SQRT, fmt, -1, fs, fd, -1, fmt);
1350     return 1;
1351     }
1352    
1353     /* abs.fmt: Floating-point absolute value */
1354     if ((function & 0x001f003f) == 0x00000005) {
1355     if (cpu->machine->instruction_trace || unassemble_only)
1356 dpavlin 24 debug("abs.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1357 dpavlin 14 if (unassemble_only)
1358     return 1;
1359    
1360     fpu_op(cpu, cp, FPU_OP_ABS, fmt, -1, fs, fd, -1, fmt);
1361     return 1;
1362     }
1363    
1364     /* mov.fmt: Floating-point (non-arithmetic) move */
1365     if ((function & 0x0000003f) == 0x00000006) {
1366     if (cpu->machine->instruction_trace || unassemble_only)
1367 dpavlin 24 debug("mov.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1368 dpavlin 14 if (unassemble_only)
1369     return 1;
1370    
1371     fpu_op(cpu, cp, FPU_OP_MOV, fmt, -1, fs, fd, -1, fmt);
1372     return 1;
1373     }
1374    
1375     /* neg.fmt: Floating-point negate */
1376     if ((function & 0x001f003f) == 0x00000007) {
1377     if (cpu->machine->instruction_trace || unassemble_only)
1378 dpavlin 24 debug("neg.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1379 dpavlin 14 if (unassemble_only)
1380     return 1;
1381    
1382     fpu_op(cpu, cp, FPU_OP_NEG, fmt, -1, fs, fd, -1, fmt);
1383     return 1;
1384     }
1385    
1386     /* trunc.l.fmt: Truncate */
1387     if ((function & 0x001f003f) == 0x00000009) {
1388     if (cpu->machine->instruction_trace || unassemble_only)
1389 dpavlin 24 debug("trunc.l.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1390 dpavlin 14 if (unassemble_only)
1391     return 1;
1392    
1393     /* TODO: not CVT? */
1394    
1395 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_L);
1396 dpavlin 14 return 1;
1397     }
1398    
1399     /* trunc.w.fmt: Truncate */
1400     if ((function & 0x001f003f) == 0x0000000d) {
1401     if (cpu->machine->instruction_trace || unassemble_only)
1402 dpavlin 24 debug("trunc.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1403 dpavlin 14 if (unassemble_only)
1404     return 1;
1405    
1406     /* TODO: not CVT? */
1407    
1408 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W);
1409 dpavlin 14 return 1;
1410     }
1411    
1412     /* c.cond.fmt: Floating-point compare */
1413     if ((function & 0x000000f0) == 0x00000030) {
1414     int cond_true;
1415     int bit;
1416    
1417     if (cpu->machine->instruction_trace || unassemble_only)
1418 dpavlin 24 debug("c.%s.%s\tcc%i,r%i,r%i\n", ccname[cond],
1419     fmtname[fmt], cc, fs, ft);
1420 dpavlin 14 if (unassemble_only)
1421     return 1;
1422    
1423     cond_true = fpu_op(cpu, cp, FPU_OP_C, fmt,
1424     ft, fs, -1, cond, fmt);
1425    
1426     /*
1427     * Both the FCCR and FCSR contain condition code bits:
1428     * FCCR: bits 7..0
1429     * FCSR: bits 31..25 and 23
1430     */
1431 dpavlin 24 cp->fcr[MIPS_FPU_FCCR] &= ~(1 << cc);
1432 dpavlin 14 if (cond_true)
1433 dpavlin 24 cp->fcr[MIPS_FPU_FCCR] |= (1 << cc);
1434 dpavlin 14
1435     if (cc == 0) {
1436 dpavlin 24 bit = 1 << MIPS_FCSR_FCC0_SHIFT;
1437     cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1438 dpavlin 14 if (cond_true)
1439 dpavlin 24 cp->fcr[MIPS_FPU_FCSR] |= bit;
1440 dpavlin 14 } else {
1441 dpavlin 24 bit = 1 << (MIPS_FCSR_FCC1_SHIFT + cc-1);
1442     cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1443 dpavlin 14 if (cond_true)
1444 dpavlin 24 cp->fcr[MIPS_FPU_FCSR] |= bit;
1445 dpavlin 14 }
1446    
1447     return 1;
1448     }
1449    
1450     /* cvt.s.fmt: Convert to single floating-point */
1451     if ((function & 0x001f003f) == 0x00000020) {
1452     if (cpu->machine->instruction_trace || unassemble_only)
1453 dpavlin 24 debug("cvt.s.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1454 dpavlin 14 if (unassemble_only)
1455     return 1;
1456    
1457 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_S);
1458 dpavlin 14 return 1;
1459     }
1460    
1461     /* cvt.d.fmt: Convert to double floating-point */
1462     if ((function & 0x001f003f) == 0x00000021) {
1463     if (cpu->machine->instruction_trace || unassemble_only)
1464 dpavlin 24 debug("cvt.d.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1465 dpavlin 14 if (unassemble_only)
1466     return 1;
1467    
1468 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_D);
1469 dpavlin 14 return 1;
1470     }
1471    
1472     /* cvt.w.fmt: Convert to word fixed-point */
1473     if ((function & 0x001f003f) == 0x00000024) {
1474     if (cpu->machine->instruction_trace || unassemble_only)
1475 dpavlin 24 debug("cvt.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1476 dpavlin 14 if (unassemble_only)
1477     return 1;
1478    
1479 dpavlin 24 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W);
1480 dpavlin 14 return 1;
1481     }
1482    
1483     return 0;
1484     }
1485    
1486    
1487     /*
1488     * coproc_tlbpr():
1489     *
1490     * 'tlbp' and 'tlbr'.
1491     */
1492     void coproc_tlbpr(struct cpu *cpu, int readflag)
1493     {
1494     struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1495     int i, found, g_bit;
1496     uint64_t vpn2, xmask;
1497    
1498     /* Read: */
1499     if (readflag) {
1500     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1501     i = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK) >>
1502     R2K3K_INDEX_SHIFT;
1503     if (i >= cp->nr_of_tlbs) {
1504     /* TODO: exception? */
1505 dpavlin 30 fatal("[ warning: tlbr from index %i (too "
1506     "high) ]\n", i);
1507 dpavlin 14 return;
1508     }
1509    
1510 dpavlin 30 cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi;
1511     cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;
1512 dpavlin 14 } else {
1513     /* R4000: */
1514     i = cp->reg[COP0_INDEX] & INDEX_MASK;
1515     if (i >= cp->nr_of_tlbs) /* TODO: exception */
1516     return;
1517    
1518     cp->reg[COP0_PAGEMASK] = cp->tlbs[i].mask;
1519     cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi;
1520     cp->reg[COP0_ENTRYLO1] = cp->tlbs[i].lo1;
1521     cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;
1522    
1523     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1524     /* R4100 don't have the G bit in entryhi */
1525     } else {
1526     /* R4000 etc: */
1527     cp->reg[COP0_ENTRYHI] &= ~TLB_G;
1528     g_bit = cp->tlbs[i].hi & TLB_G;
1529    
1530     cp->reg[COP0_ENTRYLO0] &= ~ENTRYLO_G;
1531     cp->reg[COP0_ENTRYLO1] &= ~ENTRYLO_G;
1532     if (g_bit) {
1533     cp->reg[COP0_ENTRYLO0] |= ENTRYLO_G;
1534     cp->reg[COP0_ENTRYLO1] |= ENTRYLO_G;
1535     }
1536     }
1537     }
1538    
1539     return;
1540     }
1541    
1542     /* Probe: */
1543     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1544     vpn2 = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1545     found = -1;
1546     for (i=0; i<cp->nr_of_tlbs; i++)
1547     if ( ((cp->tlbs[i].hi & R2K3K_ENTRYHI_ASID_MASK) ==
1548     (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK))
1549     || cp->tlbs[i].lo0 & R2K3K_ENTRYLO_G)
1550     if ((cp->tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK)
1551     == vpn2) {
1552     found = i;
1553     break;
1554     }
1555     } else {
1556     /* R4000 and R10000: */
1557     if (cpu->cd.mips.cpu_type.mmu_model == MMU10K)
1558     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K;
1559     else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
1560     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800;
1561     else
1562     xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK;
1563     vpn2 = cp->reg[COP0_ENTRYHI] & xmask;
1564     found = -1;
1565     for (i=0; i<cp->nr_of_tlbs; i++) {
1566     int gbit = cp->tlbs[i].hi & TLB_G;
1567     if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
1568     gbit = (cp->tlbs[i].lo0 & ENTRYLO_G) &&
1569     (cp->tlbs[i].lo1 & ENTRYLO_G);
1570    
1571     if ( ((cp->tlbs[i].hi & ENTRYHI_ASID) ==
1572     (cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID)) || gbit) {
1573     uint64_t a = vpn2 & ~cp->tlbs[i].mask;
1574     uint64_t b = (cp->tlbs[i].hi & xmask) &
1575     ~cp->tlbs[i].mask;
1576     if (a == b) {
1577     found = i;
1578     break;
1579     }
1580     }
1581     }
1582     }
1583     if (found == -1)
1584     cp->reg[COP0_INDEX] = INDEX_P;
1585     else {
1586     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1587     cp->reg[COP0_INDEX] = found << R2K3K_INDEX_SHIFT;
1588     else
1589     cp->reg[COP0_INDEX] = found;
1590     }
1591    
1592     /* Sign extend the index register: */
1593     if ((cp->reg[COP0_INDEX] >> 32) == 0 &&
1594     cp->reg[COP0_INDEX] & 0x80000000)
1595     cp->reg[COP0_INDEX] |=
1596     0xffffffff00000000ULL;
1597     }
1598    
1599    
1600     /*
1601     * coproc_tlbwri():
1602     *
1603 dpavlin 24 * MIPS TLB write random (tlbwr) and write indexed (tlbwi) instructions.
1604 dpavlin 14 */
1605     void coproc_tlbwri(struct cpu *cpu, int randomflag)
1606     {
1607     struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1608 dpavlin 28 int index, g_bit;
1609 dpavlin 14 uint64_t oldvaddr;
1610    
1611     if (randomflag) {
1612 dpavlin 24 if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
1613 dpavlin 28 index = ((cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
1614     >> R2K3K_RANDOM_SHIFT) - 1;
1615     /* R3000 always has 8 wired entries: */
1616     if (index < 8)
1617     index = cp->nr_of_tlbs - 1;
1618     cp->reg[COP0_RANDOM] = index << R2K3K_RANDOM_SHIFT;
1619 dpavlin 24 } else {
1620     cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1621     % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
1622 dpavlin 14 index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
1623 dpavlin 24 }
1624 dpavlin 14 } else {
1625     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1626     index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK)
1627     >> R2K3K_INDEX_SHIFT;
1628     else
1629     index = cp->reg[COP0_INDEX] & INDEX_MASK;
1630     }
1631    
1632     if (index >= cp->nr_of_tlbs) {
1633     fatal("warning: tlb index %i too high (max is %i)\n",
1634     index, cp->nr_of_tlbs - 1);
1635     /* TODO: cause an exception? */
1636     return;
1637     }
1638    
1639 dpavlin 24
1640 dpavlin 14 #if 0
1641     /* Debug dump of the previous entry at that index: */
1642 dpavlin 24 fatal("{ old TLB entry at index %02x:", index);
1643     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1644     fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1645     fatal(" lo=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1646     } else {
1647     if (cpu->is_32bit) {
1648     fatal(" mask=%08"PRIx32,(uint32_t)cp->tlbs[index].mask);
1649     fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1650     fatal(" lo0=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1651     fatal(" lo1=%08"PRIx32, (uint32_t)cp->tlbs[index].lo1);
1652     } else {
1653     fatal(" mask=%016"PRIx64, cp->tlbs[index].mask);
1654     fatal(" hi=%016"PRIx64, cp->tlbs[index].hi);
1655     fatal(" lo0=%016"PRIx64, cp->tlbs[index].lo0);
1656     fatal(" lo1=%016"PRIx64, cp->tlbs[index].lo1);
1657     }
1658     }
1659     fatal(" }\n");
1660 dpavlin 14 #endif
1661    
1662 dpavlin 24 /*
1663     * Any virtual address translation for the old TLB entry must be
1664     * invalidated first:
1665 dpavlin 28 *
1666     * (Only Valid entries need to be invalidated, and only those that
1667     * are either Global, or have the same ASID as the new entry will
1668     * have. No other address translations should be active anyway.)
1669 dpavlin 24 */
1670    
1671 dpavlin 14 switch (cpu->cd.mips.cpu_type.mmu_model) {
1672 dpavlin 24
1673 dpavlin 14 case MMU3K:
1674     oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
1675 dpavlin 28 oldvaddr = (int32_t) oldvaddr;
1676 dpavlin 14
1677 dpavlin 28 if (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_V &&
1678     (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_G ||
1679     (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK) ==
1680     (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK) ))
1681     cpu->invalidate_translation_caches(cpu, oldvaddr,
1682     INVALIDATE_VADDR);
1683 dpavlin 32
1684 dpavlin 24 break;
1685 dpavlin 14
1686 dpavlin 24 default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1687 dpavlin 32 oldvaddr = cp->tlbs[index].hi &
1688     (ENTRYHI_VPN2_MASK_R10K | ENTRYHI_R_MASK);
1689 dpavlin 14 /* 44 addressable bits: */
1690     if (oldvaddr & 0x80000000000ULL)
1691 dpavlin 32 oldvaddr |= 0x3ffff00000000000ULL;
1692 dpavlin 24 } else if (cpu->is_32bit) {
1693     /* MIPS32 etc.: */
1694     oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1695     oldvaddr = (int32_t)oldvaddr;
1696 dpavlin 14 } else {
1697     /* Assume MMU4K */
1698 dpavlin 32 oldvaddr = cp->tlbs[index].hi &
1699     (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK);
1700 dpavlin 14 /* 40 addressable bits: */
1701     if (oldvaddr & 0x8000000000ULL)
1702 dpavlin 32 oldvaddr |= 0x3fffff0000000000ULL;
1703 dpavlin 14 }
1704    
1705     /*
1706     * TODO: non-4KB page sizes!
1707     */
1708 dpavlin 28 if (cp->tlbs[index].lo0 & ENTRYLO_V)
1709     cpu->invalidate_translation_caches(cpu, oldvaddr,
1710     INVALIDATE_VADDR);
1711     if (cp->tlbs[index].lo1 & ENTRYLO_V)
1712     cpu->invalidate_translation_caches(cpu, oldvaddr|0x1000,
1713     INVALIDATE_VADDR);
1714 dpavlin 14 }
1715    
1716 dpavlin 28 #if 0
1717 dpavlin 14 /*
1718     * Check for duplicate entries. (There should not be two mappings
1719     * from one virtual address to physical addresses.)
1720     *
1721     * TODO: Do this for MMU3K and R4100 too.
1722     *
1723     * TODO: Make this detection more robust.
1724     */
1725     if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&
1726     cpu->cd.mips.cpu_type.rev != MIPS_R4100) {
1727     uint64_t vaddr1, vaddr2;
1728 dpavlin 22 int i;
1729     unsigned int asid;
1730 dpavlin 14
1731 dpavlin 32 vaddr1 = cp->reg[COP0_ENTRYHI] &
1732     (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1733 dpavlin 14 asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
1734     /* Since this is just a warning, it's probably not necessary
1735     to use R4000 masks etc. */
1736    
1737     for (i=0; i<cp->nr_of_tlbs; i++) {
1738     if (i == index && !randomflag)
1739     continue;
1740    
1741     if (!(cp->tlbs[i].hi & TLB_G) &&
1742     (cp->tlbs[i].hi & ENTRYHI_ASID) != asid)
1743     continue;
1744    
1745 dpavlin 32 vaddr2 = cp->tlbs[i].hi &
1746     (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1747 dpavlin 14 if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 &
1748     ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V)))
1749     fatal("\n[ WARNING! tlbw%s to index 0x%02x "
1750     "vaddr=0x%llx (asid 0x%02x) is already in"
1751     " the TLB (entry 0x%02x) ! ]\n\n",
1752     randomflag? "r" : "i", index,
1753     (long long)vaddr1, asid, i);
1754     }
1755     }
1756 dpavlin 28 #endif
1757 dpavlin 14
1758     /* Write the new entry: */
1759    
1760     if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1761 dpavlin 24 uint32_t vaddr, paddr;
1762 dpavlin 14 int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;
1763     unsigned char *memblock = NULL;
1764    
1765     cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI];
1766     cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0];
1767    
1768     vaddr = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1769     paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;
1770    
1771 dpavlin 24 memblock = memory_paddr_to_hostaddr(cpu->mem, paddr, 0);
1772 dpavlin 14
1773 dpavlin 24 /* Invalidate any code translation, if we are writing
1774     a Dirty page to the TLB: */
1775     if (wf) {
1776     cpu->invalidate_code_translation(cpu, paddr,
1777     INVALIDATE_PADDR);
1778     }
1779    
1780 dpavlin 32 /* Set new last_written_tlb_index hint: */
1781     cpu->cd.mips.last_written_tlb_index = index;
1782    
1783 dpavlin 28 if (cp->reg[COP0_STATUS] & MIPS1_ISOL_CACHES) {
1784     fatal("Wow! Interesting case; tlbw* while caches"
1785     " are isolated. TODO\n");
1786     /* Don't update the translation table in this
1787     case... */
1788     exit(1);
1789     }
1790    
1791 dpavlin 24 /* If we have a memblock (host page) for the physical
1792     page, then add a translation for it immediately: */
1793 dpavlin 14 if (memblock != NULL &&
1794 dpavlin 28 cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V)
1795 dpavlin 14 cpu->update_translation_table(cpu, vaddr, memblock,
1796     wf, paddr);
1797     } else {
1798 dpavlin 28 /* R4000 etc.: */
1799     unsigned char *memblock = NULL;
1800     int pfn_shift = 12, vpn_shift = 12;
1801     int wf0, wf1, mask;
1802     uint64_t vaddr0, vaddr1, paddr0, paddr1, ptmp;
1803    
1804 dpavlin 14 cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];
1805     cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI];
1806     cp->tlbs[index].lo1 = cp->reg[COP0_ENTRYLO1];
1807     cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0];
1808    
1809 dpavlin 28 wf0 = cp->tlbs[index].lo0 & ENTRYLO_D;
1810     wf1 = cp->tlbs[index].lo1 & ENTRYLO_D;
1811    
1812     mask = cp->reg[COP0_PAGEMASK];
1813 dpavlin 14 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1814 dpavlin 28 pfn_shift = 10;
1815     mask |= 0x07ff;
1816 dpavlin 14 } else {
1817 dpavlin 28 mask |= 0x1fff;
1818 dpavlin 14 }
1819 dpavlin 28 switch (mask) {
1820     case 0x00007ff:
1821     if (cp->tlbs[index].lo0 & ENTRYLO_V ||
1822     cp->tlbs[index].lo1 & ENTRYLO_V) {
1823     fatal("1KB pages don't work with dyntrans.\n");
1824     exit(1);
1825     }
1826     vpn_shift = 10;
1827     break;
1828     case 0x0001fff: break;
1829     case 0x0007fff: vpn_shift = 14; break;
1830     case 0x001ffff: vpn_shift = 16; break;
1831     case 0x007ffff: vpn_shift = 18; break;
1832     case 0x01fffff: vpn_shift = 20; break;
1833     case 0x07fffff: vpn_shift = 22; break;
1834     case 0x1ffffff: vpn_shift = 24; break;
1835     case 0x7ffffff: vpn_shift = 26; break;
1836     default:fatal("Unimplemented MASK = 0x%016x\n", mask);
1837 dpavlin 26 exit(1);
1838     }
1839 dpavlin 24
1840 dpavlin 28 paddr0 = ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)
1841     >> ENTRYLO_PFN_SHIFT) << pfn_shift;
1842     paddr1 = ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK)
1843     >> ENTRYLO_PFN_SHIFT) << pfn_shift;
1844 dpavlin 24
1845 dpavlin 28 if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1846 dpavlin 32 vaddr0 = cp->tlbs[index].hi &
1847     (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1848 dpavlin 24 /* 44 addressable bits: */
1849 dpavlin 28 if (vaddr0 & 0x80000000000ULL)
1850 dpavlin 32 vaddr0 |= 0x3ffff00000000000ULL;
1851 dpavlin 24 } else if (cpu->is_32bit) {
1852     /* MIPS32 etc.: */
1853 dpavlin 28 vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1854     vaddr0 = (int32_t)vaddr0;
1855 dpavlin 14 } else {
1856 dpavlin 24 /* Assume MMU4K */
1857 dpavlin 32 vaddr0 = cp->tlbs[index].hi &
1858     (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK);
1859 dpavlin 24 /* 40 addressable bits: */
1860 dpavlin 28 if (vaddr0 & 0x8000000000ULL)
1861 dpavlin 32 vaddr0 |= 0x3fffff0000000000ULL;
1862 dpavlin 14 }
1863 dpavlin 24
1864 dpavlin 28 vaddr1 = vaddr0 | (1 << vpn_shift);
1865 dpavlin 24
1866 dpavlin 28 g_bit = (cp->reg[COP0_ENTRYLO0] &
1867     cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
1868 dpavlin 14
1869 dpavlin 28 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1870     /* NOTE: The VR4131 (and possibly others) don't have
1871     a Global bit in entryhi */
1872     cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK];
1873     } else {
1874     cp->tlbs[index].lo0 &= ~ENTRYLO_G;
1875     cp->tlbs[index].lo1 &= ~ENTRYLO_G;
1876 dpavlin 14
1877 dpavlin 28 cp->tlbs[index].hi &= ~TLB_G;
1878     if (g_bit)
1879     cp->tlbs[index].hi |= TLB_G;
1880     }
1881    
1882     /*
1883     * Invalidate any code translations, if we are writing Dirty
1884     * pages to the TLB: (TODO: 4KB hardcoded... ugly)
1885     */
1886     for (ptmp = 0; ptmp < (1 << pfn_shift); ptmp += 0x1000) {
1887     if (wf0)
1888     cpu->invalidate_code_translation(cpu,
1889     paddr0 + ptmp, INVALIDATE_PADDR);
1890     if (wf1)
1891     cpu->invalidate_code_translation(cpu,
1892     paddr1 + ptmp, INVALIDATE_PADDR);
1893     }
1894    
1895     /*
1896     * If we have a memblock (host page) for the physical page,
1897     * then add a translation for it immediately, to save some
1898     * time. (It would otherwise be added later on anyway,
1899     * because of a translation miss.)
1900     *
1901     * NOTE/TODO: This is only for 4KB pages so far. It would
1902     * be too expensive to add e.g. 16MB pages like
1903     * this.
1904     */
1905     memblock = memory_paddr_to_hostaddr(cpu->mem, paddr0, 0);
1906     if (memblock != NULL && cp->reg[COP0_ENTRYLO0] & ENTRYLO_V)
1907     cpu->update_translation_table(cpu, vaddr0, memblock,
1908     wf0, paddr0);
1909     memblock = memory_paddr_to_hostaddr(cpu->mem, paddr1, 0);
1910     if (memblock != NULL && cp->reg[COP0_ENTRYLO1] & ENTRYLO_V)
1911     cpu->update_translation_table(cpu, vaddr1, memblock,
1912     wf1, paddr1);
1913 dpavlin 32
1914     /* Set new last_written_tlb_index hint: */
1915     cpu->cd.mips.last_written_tlb_index = index;
1916 dpavlin 28 }
1917 dpavlin 14 }
1918    
1919    
1920     /*
1921     * coproc_eret():
1922     *
1923     * Return from exception. (R4000 etc.)
1924     */
1925     void coproc_eret(struct cpu *cpu)
1926     {
1927     if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {
1928 dpavlin 24 cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC];
1929 dpavlin 14 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
1930     } else {
1931 dpavlin 24 cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC];
1932     cpu->delay_slot = 0;
1933 dpavlin 14 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;
1934     }
1935    
1936     cpu->cd.mips.rmw = 0; /* the "LL bit" */
1937     }
1938    
1939    
1940     /*
1941     * coproc_function():
1942     *
1943     * Execute a coprocessor specific instruction. cp must be != NULL.
1944     * Debug trace should be printed for known instructions, if
1945     * unassemble_only is non-zero. (This will NOT execute the instruction.)
1946     *
1947     * TODO: This is a mess and should be restructured (again).
1948     */
1949     void coproc_function(struct cpu *cpu, struct mips_coproc *cp, int cpnr,
1950     uint32_t function, int unassemble_only, int running)
1951     {
1952     int co_bit, op, rt, rd, fs, copz;
1953     uint64_t tmpvalue;
1954    
1955     if (cp == NULL) {
1956     if (unassemble_only) {
1957     debug("cop%i\t0x%08x (coprocessor not available)\n",
1958     cpnr, (int)function);
1959     return;
1960     }
1961     fatal("[ pc=0x%016llx cop%i\t0x%08x (coprocessor not "
1962     "available)\n", (long long)cpu->pc, cpnr, (int)function);
1963     return;
1964     }
1965    
1966     /* No FPU? */
1967     if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {
1968     mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);
1969     return;
1970     }
1971    
1972     /* For quick reference: */
1973     copz = (function >> 21) & 31;
1974     rt = (function >> 16) & 31;
1975     rd = (function >> 11) & 31;
1976    
1977     if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MFCz << 21))
1978     || ((function & 0x03e007f8) == (COPz_DMFCz << 21)))) {
1979     if (unassemble_only) {
1980     debug("%s%i\t%s,", copz==COPz_DMFCz? "dmfc" : "mfc",
1981     cpnr, regnames[rt]);
1982     if (cpnr == 0)
1983     debug("%s", cop0_names[rd]);
1984     else
1985 dpavlin 24 debug("r%i", rd);
1986 dpavlin 14 if (function & 7)
1987     debug(",%i", (int)(function & 7));
1988     debug("\n");
1989     return;
1990     }
1991     coproc_register_read(cpu, cpu->cd.mips.coproc[cpnr],
1992     rd, &tmpvalue, function & 7);
1993     cpu->cd.mips.gpr[rt] = tmpvalue;
1994     if (copz == COPz_MFCz) {
1995     /* Sign-extend: */
1996     cpu->cd.mips.gpr[rt] &= 0xffffffffULL;
1997     if (cpu->cd.mips.gpr[rt] & 0x80000000ULL)
1998     cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL;
1999     }
2000     return;
2001     }
2002    
2003     if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MTCz << 21))
2004     || ((function & 0x03e007f8) == (COPz_DMTCz << 21)))) {
2005     if (unassemble_only) {
2006     debug("%s%i\t%s,", copz==COPz_DMTCz? "dmtc" : "mtc",
2007     cpnr, regnames[rt]);
2008     if (cpnr == 0)
2009     debug("%s", cop0_names[rd]);
2010     else
2011 dpavlin 24 debug("r%i", rd);
2012 dpavlin 14 if (function & 7)
2013     debug(",%i", (int)(function & 7));
2014     debug("\n");
2015     return;
2016     }
2017     tmpvalue = cpu->cd.mips.gpr[rt];
2018     if (copz == COPz_MTCz) {
2019     /* Sign-extend: */
2020     tmpvalue &= 0xffffffffULL;
2021     if (tmpvalue & 0x80000000ULL)
2022     tmpvalue |= 0xffffffff00000000ULL;
2023     }
2024     coproc_register_write(cpu, cpu->cd.mips.coproc[cpnr], rd,
2025     &tmpvalue, copz == COPz_DMTCz, function & 7);
2026     return;
2027     }
2028    
2029     if (cpnr <= 1 && (((function & 0x03e007ff) == (COPz_CFCz << 21))
2030     || ((function & 0x03e007ff) == (COPz_CTCz << 21)))) {
2031     switch (copz) {
2032     case COPz_CFCz: /* Copy from FPU control register */
2033     rt = (function >> 16) & 31;
2034     fs = (function >> 11) & 31;
2035     if (unassemble_only) {
2036     debug("cfc%i\t%s,r%i\n", cpnr,
2037     regnames[rt], fs);
2038     return;
2039     }
2040 dpavlin 24 cpu->cd.mips.gpr[rt] = (int32_t)cp->fcr[fs];
2041 dpavlin 14 /* TODO: implement delay for gpr[rt]
2042     (for MIPS I,II,III only) */
2043     return;
2044     case COPz_CTCz: /* Copy to FPU control register */
2045     rt = (function >> 16) & 31;
2046     fs = (function >> 11) & 31;
2047     if (unassemble_only) {
2048     debug("ctc%i\t%s,r%i\n", cpnr,
2049     regnames[rt], fs);
2050     return;
2051     }
2052    
2053     switch (cpnr) {
2054     case 0: /* System coprocessor */
2055     fatal("[ warning: unimplemented ctc%i, "
2056     "0x%08x -> ctl reg %i ]\n", cpnr,
2057     (int)cpu->cd.mips.gpr[rt], fs);
2058     break;
2059     case 1: /* FPU */
2060     if (fs == 0)
2061     fatal("[ Attempt to write to FPU "
2062     "control register 0 (?) ]\n");
2063     else {
2064     uint64_t tmp = cpu->cd.mips.gpr[rt];
2065     cp->fcr[fs] = tmp;
2066    
2067     /* TODO: writing to control register 31
2068     should cause exceptions, depending
2069     on status bits! */
2070    
2071     switch (fs) {
2072 dpavlin 24 case MIPS_FPU_FCCR:
2073     cp->fcr[MIPS_FPU_FCSR] =
2074     (cp->fcr[MIPS_FPU_FCSR] &
2075 dpavlin 14 0x017fffffULL) | ((tmp & 1)
2076 dpavlin 24 << MIPS_FCSR_FCC0_SHIFT)
2077 dpavlin 14 | (((tmp & 0xfe) >> 1) <<
2078 dpavlin 24 MIPS_FCSR_FCC1_SHIFT);
2079 dpavlin 14 break;
2080 dpavlin 24 case MIPS_FPU_FCSR:
2081     cp->fcr[MIPS_FPU_FCCR] =
2082     (cp->fcr[MIPS_FPU_FCCR] &
2083 dpavlin 14 0xffffff00ULL) | ((tmp >>
2084 dpavlin 24 MIPS_FCSR_FCC0_SHIFT) & 1) |
2085     (((tmp >>
2086     MIPS_FCSR_FCC1_SHIFT)
2087 dpavlin 14 & 0x7f) << 1);
2088     break;
2089     default:
2090     ;
2091     }
2092     }
2093     break;
2094     }
2095    
2096     /* TODO: implement delay for gpr[rt]
2097     (for MIPS I,II,III only) */
2098     return;
2099     default:
2100     ;
2101     }
2102     }
2103    
2104     /* Math (Floating point) coprocessor calls: */
2105     if (cpnr==1) {
2106     if (fpu_function(cpu, cp, function, unassemble_only))
2107     return;
2108     }
2109    
2110    
2111     /* Ugly R5900 hacks: */
2112 dpavlin 24 if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
2113     if ((function & 0xfffff) == COP0_EI) {
2114     if (unassemble_only) {
2115     debug("ei\n");
2116     return;
2117     }
2118     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
2119     R5900_STATUS_EIE;
2120 dpavlin 14 return;
2121     }
2122    
2123 dpavlin 24 if ((function & 0xfffff) == COP0_DI) {
2124     if (unassemble_only) {
2125     debug("di\n");
2126     return;
2127     }
2128     cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &=
2129     ~R5900_STATUS_EIE;
2130 dpavlin 14 return;
2131     }
2132     }
2133    
2134     co_bit = (function >> 25) & 1;
2135    
2136     /* TLB operations and other things: */
2137     if (cp->coproc_nr == 0) {
2138 dpavlin 30 if (!unassemble_only) {
2139     fatal("FATAL INTERNAL ERROR: Should be implemented"
2140     " with dyntrans instead.\n");
2141     exit(1);
2142     }
2143    
2144 dpavlin 14 op = (function) & 0xff;
2145     switch (co_bit) {
2146     case 1:
2147     switch (op) {
2148     case COP0_TLBR: /* Read indexed TLB entry */
2149 dpavlin 30 debug("tlbr\n");
2150 dpavlin 14 return;
2151     case COP0_TLBWI: /* Write indexed */
2152     case COP0_TLBWR: /* Write random */
2153 dpavlin 30 if (op == COP0_TLBWI)
2154     debug("tlbwi");
2155     else
2156     debug("tlbwr");
2157     if (!running) {
2158     debug("\n");
2159 dpavlin 24 return;
2160 dpavlin 14 }
2161 dpavlin 30 debug("\tindex=%08llx",
2162     (long long)cp->reg[COP0_INDEX]);
2163     debug(", random=%08llx",
2164     (long long)cp->reg[COP0_RANDOM]);
2165     debug(", mask=%016llx",
2166     (long long)cp->reg[COP0_PAGEMASK]);
2167     debug(", hi=%016llx",
2168     (long long)cp->reg[COP0_ENTRYHI]);
2169     debug(", lo0=%016llx",
2170     (long long)cp->reg[COP0_ENTRYLO0]);
2171     debug(", lo1=%016llx\n",
2172     (long long)cp->reg[COP0_ENTRYLO1]);
2173 dpavlin 14 return;
2174     case COP0_TLBP: /* Probe TLB for
2175     matching entry */
2176 dpavlin 30 debug("tlbp\n");
2177 dpavlin 14 return;
2178     case COP0_RFE: /* R2000/R3000 only:
2179     Return from Exception */
2180 dpavlin 30 debug("rfe\n");
2181     return;
2182 dpavlin 14 case COP0_ERET: /* R4000: Return from exception */
2183 dpavlin 30 debug("eret\n");
2184     return;
2185 dpavlin 24 case COP0_DERET:
2186 dpavlin 30 debug("deret\n");
2187     return;
2188     case COP0_WAIT:
2189     {
2190     int code = (function >> 6) & 0x7ffff;
2191     debug("wait");
2192     if (code > 0)
2193     debug("\t0x%x", code);
2194     debug("\n");
2195 dpavlin 24 }
2196     return;
2197 dpavlin 14 case COP0_STANDBY:
2198 dpavlin 30 debug("standby\n");
2199 dpavlin 14 return;
2200     case COP0_SUSPEND:
2201 dpavlin 30 debug("suspend\n");
2202 dpavlin 14 return;
2203     case COP0_HIBERNATE:
2204 dpavlin 30 debug("hibernate\n");
2205 dpavlin 14 return;
2206     default:
2207     ;
2208     }
2209     default:
2210     ;
2211     }
2212     }
2213    
2214     /* TODO: coprocessor R2020 on DECstation? */
2215     if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x0100ffff) {
2216     if (unassemble_only) {
2217     debug("decstation_r2020_writeback\n");
2218     return;
2219     }
2220     /* TODO */
2221     return;
2222     }
2223    
2224     if (unassemble_only) {
2225     debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);
2226     return;
2227     }
2228    
2229 dpavlin 24 fatal("cpu%i: UNIMPLEMENTED coproc%i function %08"PRIx32" "
2230     "(pc = %016"PRIx64")\n", cpu->cpu_id, cp->coproc_nr,
2231     (uint32_t)function, cpu->pc);
2232    
2233 dpavlin 14 mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cp->coproc_nr, 0, 0, 0);
2234     }
2235    
2236     #endif /* ENABLE_MIPS */

  ViewVC Help
Powered by ViewVC 1.1.26