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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (13 years, 1 month 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 /*
2 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_mips_coproc.c,v 1.60 2006/10/14 23:47:37 debug Exp $
29 *
30 * Emulation of MIPS coprocessors.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <math.h>
37
38 #include "cop0.h"
39 #include "cpu.h"
40 #include "cpu_mips.h"
41 #include "emul.h"
42 #include "float_emul.h"
43 #include "machine.h"
44 #include "memory.h"
45 #include "mips_cpu_types.h"
46 #include "misc.h"
47 #include "opcodes_mips.h"
48 #include "timer.h"
49
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 const int m16 = 0; /* TODO: MIPS16 support */
80 int IB, DB, SB, IC, DC, SC, IA, DA;
81
82 /* 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
127 return;
128 }
129
130 switch (cpu->cd.mips.cpu_type.rev) {
131 case MIPS_R2000:
132 case MIPS_R3000:
133 /* No config register. */
134 break;
135 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 default:fatal("Internal error: No initialization code for"
320 " config0? cpu rev = 0x%x", cpu->cd.mips.cpu_type.rev);
321 exit(1);
322 }
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 c->tlbs = zeroed_alloc(c->nr_of_tlbs * sizeof(struct mips_tlb));
389
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 /* 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 c->reg[COP0_PAGEMASK] = 0x1fff;
417
418 /* Note: .rev may contain the company ID as well! */
419 c->reg[COP0_PRID] =
420 (0x00 << 24) /* Company Options */
421 | (0x00 << 16) /* Company ID */
422 | (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 c->reg[COP0_STATUS] = (int32_t)c->reg[COP0_STATUS];
432 }
433
434 if (coproc_nr == 1)
435 initialize_cop1(cpu, c);
436
437 return c;
438 }
439
440
441 /*
442 * 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 * 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 * 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 */
538 static void invalidate_asid(struct cpu *cpu, int asid)
539 {
540 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
544 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 }
553 } else {
554 int non4kpages = 0;
555 uint64_t topbit = 1, fillmask = 0xffffff0000000000ULL;
556
557 if (cpu->is_32bit) {
558 topbit = 0x80000000;
559 fillmask = 0xffffffff00000000ULL;
560 } else if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
561 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 }
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 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 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 symbol = get_symbol_name(cpu->pc, &offset);
703 fatal("YO! pc = 0x%08llx <%s> "
704 "lo=%016llx\n", (long long)
705 cpu->pc, symbol? symbol :
706 "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 if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
772 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 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 mips_cpu_interrupt_ack(cpu, 7);
814
815 if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
816 fatal("WARNING: trying to write a 64-bit value"
817 " to the COMPARE register!\n");
818
819 tmp = (int64_t)(int32_t)tmp;
820 cpu->cd.mips.compare_register_set = 1;
821 unimpl = 0;
822 break;
823 case COP0_ENTRYHI:
824 /*
825 * Translation caches must be invalidated if the
826 * ASID changes:
827 */
828 switch (cpu->cd.mips.cpu_type.mmu_model) {
829 case MMU3K:
830 old_asid = cp->reg[COP0_ENTRYHI] &
831 R2K3K_ENTRYHI_ASID_MASK;
832 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
845 if (inval)
846 invalidate_asid(cpu, old_asid);
847
848 unimpl = 0;
849 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
850 (tmp & 0x3f)!=0) {
851 /* char *symbol;
852 uint64_t offset;
853 symbol = get_symbol_name(cpu->pc,
854 &offset);
855 fatal("YO! pc = 0x%08llx <%s> "
856 "hi=%016llx\n", (long long)cpu->pc,
857 symbol? symbol :
858 "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
904 /*
905 * 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 */
911 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
912 (oldmode & MIPS1_ISOL_CACHES) !=
913 (tmp & MIPS1_ISOL_CACHES)) {
914 /* 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 }
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 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 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
1016 static char *ccname[16] = {
1017 "f", "un", "eq", "ueq", "olt", "ult", "ole", "ule",
1018 "sf", "ngle", "seq", "ngl", "lt", "nge", "le", "ngt" };
1019
1020 #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 /* TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W, RSQRT */
1031
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 int ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1042 uint64_t r = ieee_store_float_value(nf, ieee_fmt, nan);
1043
1044 /*
1045 * TODO: This is for 32-bit mode. It has to be updated later
1046 * for 64-bit coprocessor functionality!
1047 */
1048 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) {
1049 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 * Perform a floating-point operation. For those of fs and ft that are >= 0,
1069 * those numbers are interpreted into local variables.
1070 *
1071 * Only FPU_OP_C (compare) returns anything of interest, 1 for true, 0 for
1072 * false.
1073 */
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 struct ieee_float_value float_value[2];
1079 int unordered, nan, ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1080 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 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1088 fs_v = (fs_v & 0xffffffffULL) +
1089 (cp->reg[(fs + 1) & 31] << 32);
1090 ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);
1091 }
1092 if (ft >= 0) {
1093 uint64_t v = cp->reg[ft];
1094 /* TODO: register-pair mode and
1095 plain register mode? "FR" bit? */
1096 if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1097 v = (v & 0xffffffffULL) +
1098 (cp->reg[(ft + 1) & 31] << 32);
1099 ieee_interpret_float_value(v, &float_value[1], ieee_fmt);
1100 }
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 if (output_fmt == COP1_FMT_D || output_fmt == COP1_FMT_L) {
1175 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 int nd, tf, imm;
1266 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 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 }
1293
1294 /* add.fmt: Floating-point add */
1295 if ((function & 0x0000003f) == 0x00000000) {
1296 if (cpu->machine->instruction_trace || unassemble_only)
1297 debug("add.%s\tr%i,r%i,r%i\n",
1298 fmtname[fmt], fd, fs, ft);
1299 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 debug("sub.%s\tr%i,r%i,r%i\n",
1310 fmtname[fmt], fd, fs, ft);
1311 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 debug("mul.%s\tr%i,r%i,r%i\n",
1322 fmtname[fmt], fd, fs, ft);
1323 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 debug("div.%s\tr%i,r%i,r%i\n",
1334 fmtname[fmt], fd, fs, ft);
1335 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 debug("sqrt.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1346 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 debug("abs.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1357 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 debug("mov.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1368 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 debug("neg.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1379 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 debug("trunc.l.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1390 if (unassemble_only)
1391 return 1;
1392
1393 /* TODO: not CVT? */
1394
1395 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_L);
1396 return 1;
1397 }
1398
1399 /* trunc.w.fmt: Truncate */
1400 if ((function & 0x001f003f) == 0x0000000d) {
1401 if (cpu->machine->instruction_trace || unassemble_only)
1402 debug("trunc.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1403 if (unassemble_only)
1404 return 1;
1405
1406 /* TODO: not CVT? */
1407
1408 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W);
1409 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 debug("c.%s.%s\tcc%i,r%i,r%i\n", ccname[cond],
1419 fmtname[fmt], cc, fs, ft);
1420 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 cp->fcr[MIPS_FPU_FCCR] &= ~(1 << cc);
1432 if (cond_true)
1433 cp->fcr[MIPS_FPU_FCCR] |= (1 << cc);
1434
1435 if (cc == 0) {
1436 bit = 1 << MIPS_FCSR_FCC0_SHIFT;
1437 cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1438 if (cond_true)
1439 cp->fcr[MIPS_FPU_FCSR] |= bit;
1440 } else {
1441 bit = 1 << (MIPS_FCSR_FCC1_SHIFT + cc-1);
1442 cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1443 if (cond_true)
1444 cp->fcr[MIPS_FPU_FCSR] |= bit;
1445 }
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 debug("cvt.s.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1454 if (unassemble_only)
1455 return 1;
1456
1457 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_S);
1458 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 debug("cvt.d.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1465 if (unassemble_only)
1466 return 1;
1467
1468 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_D);
1469 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 debug("cvt.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1476 if (unassemble_only)
1477 return 1;
1478
1479 fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W);
1480 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 fatal("[ warning: tlbr from index %i (too "
1506 "high) ]\n", i);
1507 return;
1508 }
1509
1510 cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi;
1511 cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;
1512 } 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 * MIPS TLB write random (tlbwr) and write indexed (tlbwi) instructions.
1604 */
1605 void coproc_tlbwri(struct cpu *cpu, int randomflag)
1606 {
1607 struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1608 int index, g_bit;
1609 uint64_t oldvaddr;
1610
1611 if (randomflag) {
1612 if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
1613 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 } else {
1620 cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1621 % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
1622 index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
1623 }
1624 } 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
1640 #if 0
1641 /* Debug dump of the previous entry at that index: */
1642 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 #endif
1661
1662 /*
1663 * Any virtual address translation for the old TLB entry must be
1664 * invalidated first:
1665 *
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 */
1670
1671 switch (cpu->cd.mips.cpu_type.mmu_model) {
1672
1673 case MMU3K:
1674 oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
1675 oldvaddr = (int32_t) oldvaddr;
1676
1677 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
1684 break;
1685
1686 default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1687 oldvaddr = cp->tlbs[index].hi &
1688 (ENTRYHI_VPN2_MASK_R10K | ENTRYHI_R_MASK);
1689 /* 44 addressable bits: */
1690 if (oldvaddr & 0x80000000000ULL)
1691 oldvaddr |= 0x3ffff00000000000ULL;
1692 } else if (cpu->is_32bit) {
1693 /* MIPS32 etc.: */
1694 oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1695 oldvaddr = (int32_t)oldvaddr;
1696 } else {
1697 /* Assume MMU4K */
1698 oldvaddr = cp->tlbs[index].hi &
1699 (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK);
1700 /* 40 addressable bits: */
1701 if (oldvaddr & 0x8000000000ULL)
1702 oldvaddr |= 0x3fffff0000000000ULL;
1703 }
1704
1705 /*
1706 * TODO: non-4KB page sizes!
1707 */
1708 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 }
1715
1716 #if 0
1717 /*
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 int i;
1729 unsigned int asid;
1730
1731 vaddr1 = cp->reg[COP0_ENTRYHI] &
1732 (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1733 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 vaddr2 = cp->tlbs[i].hi &
1746 (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1747 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 #endif
1757
1758 /* Write the new entry: */
1759
1760 if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1761 uint32_t vaddr, paddr;
1762 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 memblock = memory_paddr_to_hostaddr(cpu->mem, paddr, 0);
1772
1773 /* 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 /* Set new last_written_tlb_index hint: */
1781 cpu->cd.mips.last_written_tlb_index = index;
1782
1783 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 /* If we have a memblock (host page) for the physical
1792 page, then add a translation for it immediately: */
1793 if (memblock != NULL &&
1794 cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V)
1795 cpu->update_translation_table(cpu, vaddr, memblock,
1796 wf, paddr);
1797 } else {
1798 /* 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 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 wf0 = cp->tlbs[index].lo0 & ENTRYLO_D;
1810 wf1 = cp->tlbs[index].lo1 & ENTRYLO_D;
1811
1812 mask = cp->reg[COP0_PAGEMASK];
1813 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1814 pfn_shift = 10;
1815 mask |= 0x07ff;
1816 } else {
1817 mask |= 0x1fff;
1818 }
1819 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 exit(1);
1838 }
1839
1840 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
1845 if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1846 vaddr0 = cp->tlbs[index].hi &
1847 (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1848 /* 44 addressable bits: */
1849 if (vaddr0 & 0x80000000000ULL)
1850 vaddr0 |= 0x3ffff00000000000ULL;
1851 } else if (cpu->is_32bit) {
1852 /* MIPS32 etc.: */
1853 vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1854 vaddr0 = (int32_t)vaddr0;
1855 } else {
1856 /* Assume MMU4K */
1857 vaddr0 = cp->tlbs[index].hi &
1858 (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK);
1859 /* 40 addressable bits: */
1860 if (vaddr0 & 0x8000000000ULL)
1861 vaddr0 |= 0x3fffff0000000000ULL;
1862 }
1863
1864 vaddr1 = vaddr0 | (1 << vpn_shift);
1865
1866 g_bit = (cp->reg[COP0_ENTRYLO0] &
1867 cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
1868
1869 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
1877 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
1914 /* Set new last_written_tlb_index hint: */
1915 cpu->cd.mips.last_written_tlb_index = index;
1916 }
1917 }
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 cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC];
1929 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
1930 } else {
1931 cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC];
1932 cpu->delay_slot = 0;
1933 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 debug("r%i", rd);
1986 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 debug("r%i", rd);
2012 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 cpu->cd.mips.gpr[rt] = (int32_t)cp->fcr[fs];
2041 /* 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 case MIPS_FPU_FCCR:
2073 cp->fcr[MIPS_FPU_FCSR] =
2074 (cp->fcr[MIPS_FPU_FCSR] &
2075 0x017fffffULL) | ((tmp & 1)
2076 << MIPS_FCSR_FCC0_SHIFT)
2077 | (((tmp & 0xfe) >> 1) <<
2078 MIPS_FCSR_FCC1_SHIFT);
2079 break;
2080 case MIPS_FPU_FCSR:
2081 cp->fcr[MIPS_FPU_FCCR] =
2082 (cp->fcr[MIPS_FPU_FCCR] &
2083 0xffffff00ULL) | ((tmp >>
2084 MIPS_FCSR_FCC0_SHIFT) & 1) |
2085 (((tmp >>
2086 MIPS_FCSR_FCC1_SHIFT)
2087 & 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 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 return;
2121 }
2122
2123 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 return;
2131 }
2132 }
2133
2134 co_bit = (function >> 25) & 1;
2135
2136 /* TLB operations and other things: */
2137 if (cp->coproc_nr == 0) {
2138 if (!unassemble_only) {
2139 fatal("FATAL INTERNAL ERROR: Should be implemented"
2140 " with dyntrans instead.\n");
2141 exit(1);
2142 }
2143
2144 op = (function) & 0xff;
2145 switch (co_bit) {
2146 case 1:
2147 switch (op) {
2148 case COP0_TLBR: /* Read indexed TLB entry */
2149 debug("tlbr\n");
2150 return;
2151 case COP0_TLBWI: /* Write indexed */
2152 case COP0_TLBWR: /* Write random */
2153 if (op == COP0_TLBWI)
2154 debug("tlbwi");
2155 else
2156 debug("tlbwr");
2157 if (!running) {
2158 debug("\n");
2159 return;
2160 }
2161 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 return;
2174 case COP0_TLBP: /* Probe TLB for
2175 matching entry */
2176 debug("tlbp\n");
2177 return;
2178 case COP0_RFE: /* R2000/R3000 only:
2179 Return from Exception */
2180 debug("rfe\n");
2181 return;
2182 case COP0_ERET: /* R4000: Return from exception */
2183 debug("eret\n");
2184 return;
2185 case COP0_DERET:
2186 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 }
2196 return;
2197 case COP0_STANDBY:
2198 debug("standby\n");
2199 return;
2200 case COP0_SUSPEND:
2201 debug("suspend\n");
2202 return;
2203 case COP0_HIBERNATE:
2204 debug("hibernate\n");
2205 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 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 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