/[gxemul]/trunk/src/cpus/cpu_mips_instr.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_instr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 25252 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


1 /*
2 * Copyright (C) 2005-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_instr.c,v 1.9 2006/02/17 20:27:21 debug Exp $
29 *
30 * MIPS instructions.
31 *
32 * Individual functions should keep track of cpu->n_translated_instrs.
33 * (If no instruction was executed, then it should be decreased. If, say, 4
34 * instructions were combined into one function and executed, then it should
35 * be increased by 3.)
36 */
37
38
39 /*
40 * nop: Do nothing.
41 */
42 X(nop)
43 {
44 }
45
46
47 /*
48 * invalid_32_64: Attempt to execute a 64-bit instruction on an
49 * emulated 32-bit processor.
50 */
51 X(invalid_32_64)
52 {
53 fatal("invalid_32_64: TODO\n");
54 exit(1);
55 }
56
57
58 /*
59 * beq: Branch if equal
60 * bne: Branch if not equal
61 * b: Branch (comparing a register to itself, always true)
62 *
63 * arg[0] = pointer to rs
64 * arg[1] = pointer to rt
65 * arg[2] = (int32_t) relative offset from the next instruction
66 */
67 X(beq)
68 {
69 MODE_uint_t old_pc = cpu->pc;
70 MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]);
71 int x = rs == rt;
72 cpu->cd.mips.delay_slot = TO_BE_DELAYED;
73 ic[1].f(cpu, ic+1);
74 cpu->n_translated_instrs ++;
75 if (!(cpu->cd.mips.delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
76 if (x) {
77 old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) <<
78 MIPS_INSTR_ALIGNMENT_SHIFT);
79 cpu->pc = old_pc + (int32_t)ic->arg[2];
80 quick_pc_to_pointers(cpu);
81 } else
82 cpu->cd.mips.next_ic ++;
83 }
84 cpu->cd.mips.delay_slot = NOT_DELAYED;
85 }
86 X(beq_samepage)
87 {
88 MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]);
89 int x = rs == rt;
90 cpu->cd.mips.delay_slot = TO_BE_DELAYED;
91 ic[1].f(cpu, ic+1);
92 cpu->n_translated_instrs ++;
93 if (!(cpu->cd.mips.delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
94 if (x)
95 cpu->cd.mips.next_ic = (struct mips_instr_call *)
96 ic->arg[2];
97 else
98 cpu->cd.mips.next_ic ++;
99 }
100 cpu->cd.mips.delay_slot = NOT_DELAYED;
101 }
102 X(bne)
103 {
104 MODE_uint_t old_pc = cpu->pc;
105 MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]);
106 int x = rs != rt;
107 cpu->cd.mips.delay_slot = TO_BE_DELAYED;
108 ic[1].f(cpu, ic+1);
109 cpu->n_translated_instrs ++;
110 if (!(cpu->cd.mips.delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
111 if (x) {
112 old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) <<
113 MIPS_INSTR_ALIGNMENT_SHIFT);
114 cpu->pc = old_pc + (int32_t)ic->arg[2];
115 quick_pc_to_pointers(cpu);
116 } else
117 cpu->cd.mips.next_ic ++;
118 }
119 cpu->cd.mips.delay_slot = NOT_DELAYED;
120 }
121 X(bne_samepage)
122 {
123 MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]);
124 int x = rs != rt;
125 cpu->cd.mips.delay_slot = TO_BE_DELAYED;
126 ic[1].f(cpu, ic+1);
127 cpu->n_translated_instrs ++;
128 if (!(cpu->cd.mips.delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
129 if (x)
130 cpu->cd.mips.next_ic = (struct mips_instr_call *)
131 ic->arg[2];
132 else
133 cpu->cd.mips.next_ic ++;
134 }
135 cpu->cd.mips.delay_slot = NOT_DELAYED;
136 }
137 X(b)
138 {
139 MODE_uint_t old_pc = cpu->pc;
140 cpu->cd.mips.delay_slot = TO_BE_DELAYED;
141 ic[1].f(cpu, ic+1);
142 cpu->n_translated_instrs ++;
143 if (!(cpu->cd.mips.delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
144 old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) <<
145 MIPS_INSTR_ALIGNMENT_SHIFT);
146 cpu->pc = old_pc + (int32_t)ic->arg[2];
147 quick_pc_to_pointers(cpu);
148 }
149 cpu->cd.mips.delay_slot = NOT_DELAYED;
150 }
151 X(b_samepage)
152 {
153 cpu->cd.mips.delay_slot = TO_BE_DELAYED;
154 ic[1].f(cpu, ic+1);
155 cpu->n_translated_instrs ++;
156 if (!(cpu->cd.mips.delay_slot & EXCEPTION_IN_DELAY_SLOT))
157 cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2];
158 cpu->cd.mips.delay_slot = NOT_DELAYED;
159 }
160
161
162 /*
163 * jr, jalr: Jump to a register [and link].
164 *
165 * arg[0] = ptr to rs
166 * arg[1] = ptr to rd (for jalr)
167 * arg[2] = (int32_t) relative offset of the next instruction
168 */
169 X(jr)
170 {
171 MODE_uint_t rs = reg(ic->arg[0]);
172 cpu->cd.mips.delay_slot = TO_BE_DELAYED;
173 ic[1].f(cpu, ic+1);
174 cpu->n_translated_instrs ++;
175 if (!(cpu->cd.mips.delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
176 cpu->pc = rs;
177 quick_pc_to_pointers(cpu);
178 }
179 cpu->cd.mips.delay_slot = NOT_DELAYED;
180 }
181 X(jr_ra)
182 {
183 MODE_uint_t rs = cpu->cd.mips.gpr[MIPS_GPR_RA];
184 cpu->cd.mips.delay_slot = TO_BE_DELAYED;
185 ic[1].f(cpu, ic+1);
186 cpu->n_translated_instrs ++;
187 if (!(cpu->cd.mips.delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
188 cpu->pc = rs;
189 quick_pc_to_pointers(cpu);
190 }
191 cpu->cd.mips.delay_slot = NOT_DELAYED;
192 }
193 X(jr_ra_trace)
194 {
195 MODE_uint_t rs = cpu->cd.mips.gpr[MIPS_GPR_RA];
196 cpu->cd.mips.delay_slot = TO_BE_DELAYED;
197 ic[1].f(cpu, ic+1);
198 cpu->n_translated_instrs ++;
199 if (!(cpu->cd.mips.delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
200 cpu->pc = rs;
201 cpu_functioncall_trace_return(cpu);
202 quick_pc_to_pointers(cpu);
203 }
204 cpu->cd.mips.delay_slot = NOT_DELAYED;
205 }
206 X(jalr)
207 {
208 MODE_uint_t rs = reg(ic->arg[0]), rd;
209 cpu->cd.mips.delay_slot = TO_BE_DELAYED;
210 rd = cpu->pc & ~((MIPS_IC_ENTRIES_PER_PAGE-1) <<
211 MIPS_INSTR_ALIGNMENT_SHIFT);
212 rd += (int32_t)ic->arg[2];
213 reg(ic->arg[1]) = rd;
214 ic[1].f(cpu, ic+1);
215 cpu->n_translated_instrs ++;
216 if (!(cpu->cd.mips.delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
217 cpu->pc = rs;
218 quick_pc_to_pointers(cpu);
219 }
220 cpu->cd.mips.delay_slot = NOT_DELAYED;
221 }
222 X(jalr_trace)
223 {
224 MODE_uint_t rs = reg(ic->arg[0]), rd;
225 cpu->cd.mips.delay_slot = TO_BE_DELAYED;
226 rd = cpu->pc & ~((MIPS_IC_ENTRIES_PER_PAGE-1) <<
227 MIPS_INSTR_ALIGNMENT_SHIFT);
228 rd += (int32_t)ic->arg[2];
229 reg(ic->arg[1]) = rd;
230 ic[1].f(cpu, ic+1);
231 cpu->n_translated_instrs ++;
232 if (!(cpu->cd.mips.delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
233 cpu->pc = rs;
234 cpu_functioncall_trace(cpu, cpu->pc);
235 quick_pc_to_pointers(cpu);
236 }
237 cpu->cd.mips.delay_slot = NOT_DELAYED;
238 }
239
240
241 /*
242 * 2-register + immediate:
243 *
244 * arg[0] = pointer to rs
245 * arg[1] = pointer to rt
246 * arg[2] = uint32_t immediate value
247 */
248 X(andi) { reg(ic->arg[1]) = reg(ic->arg[0]) & (int32_t)ic->arg[2]; }
249 X(ori) { reg(ic->arg[1]) = reg(ic->arg[0]) | (int32_t)ic->arg[2]; }
250 X(xori) { reg(ic->arg[1]) = reg(ic->arg[0]) ^ (int32_t)ic->arg[2]; }
251
252
253 /*
254 * 2-register:
255 */
256 X(mult)
257 {
258 int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]);
259 int64_t res = (int64_t)a * (int64_t)b;
260 reg(&cpu->cd.mips.lo) = (int32_t)res;
261 reg(&cpu->cd.mips.hi) = (int32_t)(res >> 32);
262 }
263 X(multu)
264 {
265 uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]);
266 uint64_t res = (uint64_t)a * (uint64_t)b;
267 reg(&cpu->cd.mips.lo) = (int32_t)res;
268 reg(&cpu->cd.mips.hi) = (int32_t)(res >> 32);
269 }
270
271
272 /*
273 * 3-register:
274 */
275 X(addu) { reg(ic->arg[2]) = (int32_t)(reg(ic->arg[0]) + reg(ic->arg[1])); }
276 X(subu) { reg(ic->arg[2]) = (int32_t)(reg(ic->arg[0]) - reg(ic->arg[1])); }
277 X(daddu){ reg(ic->arg[2]) = reg(ic->arg[0]) + reg(ic->arg[1]); }
278 X(dsubu){ reg(ic->arg[2]) = reg(ic->arg[0]) + reg(ic->arg[1]); }
279 X(slt) {
280 #ifdef MODE32
281 reg(ic->arg[2]) = (int32_t)reg(ic->arg[0]) < (int32_t)reg(ic->arg[1]);
282 #else
283 reg(ic->arg[2]) = (int64_t)reg(ic->arg[0]) < (int64_t)reg(ic->arg[1]);
284 #endif
285 }
286 X(sltu) {
287 #ifdef MODE32
288 reg(ic->arg[2]) = (uint32_t)reg(ic->arg[0]) < (uint32_t)reg(ic->arg[1]);
289 #else
290 reg(ic->arg[2]) = (uint64_t)reg(ic->arg[0]) < (uint64_t)reg(ic->arg[1]);
291 #endif
292 }
293 X(or) { reg(ic->arg[2]) = reg(ic->arg[0]) | reg(ic->arg[1]); }
294 X(xor) { reg(ic->arg[2]) = reg(ic->arg[0]) ^ reg(ic->arg[1]); }
295 X(nor) { reg(ic->arg[2]) = ~(reg(ic->arg[0]) | reg(ic->arg[1])); }
296 X(sll) { reg(ic->arg[2]) = (int32_t)(reg(ic->arg[0]) << ic->arg[1]); }
297 X(srl) { reg(ic->arg[2]) = (int32_t)((uint32_t)reg(ic->arg[0]) >> ic->arg[1]); }
298 X(sra) { reg(ic->arg[2]) = (int32_t)((int32_t)reg(ic->arg[0]) >> ic->arg[1]); }
299 X(mul) { reg(ic->arg[2]) = (int32_t)
300 ( (int32_t)reg(ic->arg[0]) * (int32_t)reg(ic->arg[1]) ); }
301
302
303 /*
304 * mov: Move one register into another.
305 *
306 * arg[0] = pointer to source
307 * arg[2] = pointer to destination
308 */
309 X(mov) { reg(ic->arg[2]) = reg(ic->arg[0]); }
310
311
312 /*
313 * clz, clo, dclz, dclo: Count leading zeroes/ones.
314 *
315 * arg[0] = pointer to rs
316 * arg[1] = pointer to rd
317 */
318 X(clz)
319 {
320 uint32_t x = reg(ic->arg[0]);
321 int count;
322 for (count=0; count<32; count++) {
323 if (x & 0x80000000UL)
324 break;
325 x <<= 1;
326 }
327 reg(ic->arg[1]) = count;
328 }
329 X(clo)
330 {
331 uint32_t x = reg(ic->arg[0]);
332 int count;
333 for (count=0; count<32; count++) {
334 if (!(x & 0x80000000UL))
335 break;
336 x <<= 1;
337 }
338 reg(ic->arg[1]) = count;
339 }
340 X(dclz)
341 {
342 uint64_t x = reg(ic->arg[0]);
343 int count;
344 for (count=0; count<64; count++) {
345 if (x & 0x8000000000000000ULL)
346 break;
347 x <<= 1;
348 }
349 reg(ic->arg[1]) = count;
350 }
351 X(dclo)
352 {
353 uint64_t x = reg(ic->arg[0]);
354 int count;
355 for (count=0; count<64; count++) {
356 if (!(x & 0x8000000000000000ULL))
357 break;
358 x <<= 1;
359 }
360 reg(ic->arg[1]) = count;
361 }
362
363
364 /*
365 * addiu: Add immediate (32-bit).
366 *
367 * arg[0] = pointer to rs
368 * arg[1] = pointer to rt
369 * arg[2] = (int32_t) immediate value
370 */
371 X(addiu)
372 {
373 reg(ic->arg[1]) = (int32_t)
374 ((int32_t)reg(ic->arg[0]) + (int32_t)ic->arg[2]);
375 }
376
377
378 /*
379 * daddiu: Add immediate (64-bit).
380 *
381 * arg[0] = pointer to rs
382 * arg[1] = pointer to rt
383 * arg[2] = (int32_t) immediate value
384 */
385 X(daddiu)
386 {
387 reg(ic->arg[1]) = reg(ic->arg[0]) + (int32_t)ic->arg[2];
388 }
389
390
391 /*
392 * set: Set a register to an immediate (signed) 32-bit value.
393 *
394 * arg[0] = pointer to the register
395 * arg[1] = (int32_t) immediate value
396 */
397 X(set)
398 {
399 reg(ic->arg[0]) = (int32_t)ic->arg[1];
400 }
401
402
403 /*
404 * mfc0, dmfc0: Move from Coprocessor 0.
405 * mtc0, dmtc0: Move to Coprocessor 0.
406 * cfc1: Copy control word from Coprocessor 1.
407 *
408 * arg[0] = pointer to GPR (rt)
409 * arg[1] = coprocessor 0 register number | (select << 5)
410 * arg[2] = relative addr of this instruction within the page
411 */
412 X(mfc0)
413 {
414 int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5;
415 uint64_t tmp;
416 cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT);
417 cpu->pc |= ic->arg[2];
418 /* TODO: cause exception if necessary */
419 coproc_register_read(cpu, cpu->cd.mips.coproc[0], rd, &tmp, select);
420 reg(ic->arg[0]) = (int32_t)tmp;
421 }
422 X(mtc0)
423 {
424 int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5;
425 cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT);
426 cpu->pc |= ic->arg[2];
427 /* TODO: cause exception if necessary */
428 coproc_register_write(cpu, cpu->cd.mips.coproc[0], rd,
429 (uint64_t *)ic->arg[0], 0, select);
430 }
431 X(dmfc0)
432 {
433 int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5;
434 cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT);
435 cpu->pc |= ic->arg[2];
436 /* TODO: cause exception if necessary */
437 coproc_register_read(cpu, cpu->cd.mips.coproc[0], rd,
438 (uint64_t *)ic->arg[0], select);
439 }
440 X(dmtc0)
441 {
442 int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5;
443 cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT);
444 cpu->pc |= ic->arg[2];
445 /* TODO: cause exception if necessary */
446 coproc_register_write(cpu, cpu->cd.mips.coproc[0], rd,
447 (uint64_t *)ic->arg[0], 1, select);
448 }
449 X(cfc1)
450 {
451 cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT);
452 cpu->pc |= ic->arg[2];
453 /* TODO: cause exception if necessary */
454 reg(ic->arg[0]) = reg(ic->arg[1]);
455 }
456
457
458 /*****************************************************************************/
459
460
461 /*
462 * b_samepage_addiu:
463 *
464 * Combination of branch within the same page, followed by addiu.
465 */
466 X(b_samepage_addiu)
467 {
468 reg(ic[1].arg[1]) = reg(ic[1].arg[0]) + (int32_t)ic[1].arg[2];
469 cpu->n_translated_instrs ++;
470 cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2];
471 }
472
473
474 /*****************************************************************************/
475
476
477 X(end_of_page)
478 {
479 struct mips_instr_call self;
480
481 /* Update the PC: (offset 0, but on the next page) */
482 cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) <<
483 MIPS_INSTR_ALIGNMENT_SHIFT);
484 cpu->pc += (MIPS_IC_ENTRIES_PER_PAGE << MIPS_INSTR_ALIGNMENT_SHIFT);
485
486 /* Simple jump to the next page (if we are lucky): */
487 if (cpu->cd.mips.delay_slot == NOT_DELAYED) {
488
489 /* Find the new physpage and update translation pointers: */
490 quick_pc_to_pointers(cpu);
491
492 /* end_of_page doesn't count as an executed instruction: */
493 cpu->n_translated_instrs --;
494
495 return;
496 }
497
498 /* Tricky situation; the delay slot is on the next virtual page: */
499 /* fatal("[ end_of_page: delay slot across page boundary! ]\n"); */
500
501 /* to_be_translated will overwrite the current ic. */
502 self = *ic;
503
504 instr(to_be_translated)(cpu, ic);
505
506 /* The instruction in the delay slot has now executed. */
507
508 /* Find the physpage etc of the instruction in the delay slot
509 (or, if there was an exception, the exception handler): */
510 quick_pc_to_pointers(cpu);
511
512 /* Restore the end_of_page instr call. */
513 *ic = self;
514
515 /* fatal("[ end_of_page: back from delay slot ]\n"); */
516 }
517
518
519 X(end_of_page2)
520 {
521 fatal("this should be removed: end of page2\n");
522 exit(1);
523
524 /* Update the PC: (offset 4, but on the next page) */
525 cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) <<
526 MIPS_INSTR_ALIGNMENT_SHIFT);
527 cpu->pc += ((MIPS_IC_ENTRIES_PER_PAGE+1) << MIPS_INSTR_ALIGNMENT_SHIFT);
528
529 if (cpu->cd.mips.delay_slot == NOT_DELAYED) {
530 /* Find the new physpage and update translation pointers: */
531 quick_pc_to_pointers(cpu);
532
533 /* end_of_page doesn't count as an executed instruction: */
534 cpu->n_translated_instrs --;
535
536 return;
537 }
538
539 fatal("DELAY SLOT in DELAY SLOT across a page boundary? HUH?\n");
540 exit(1);
541 }
542
543
544 /*****************************************************************************/
545
546
547 /*
548 * Combine: [Conditional] branch, followed by addiu.
549 */
550 void COMBINE(b_addiu)(struct cpu *cpu, struct mips_instr_call *ic,
551 int low_addr)
552 {
553 int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT)
554 & (MIPS_IC_ENTRIES_PER_PAGE - 1);
555
556 if (n_back < 1)
557 return;
558
559 if (ic[-1].f == instr(b_samepage)) {
560 ic[-1].f = instr(b_samepage_addiu);
561 combined;
562 }
563
564 /* TODO: other branches that are followed by addiu should be here */
565 }
566
567
568 /*****************************************************************************/
569
570
571 /*
572 * mips_instr_to_be_translated():
573 *
574 * Translate an instruction word into an mips_instr_call. ic is filled in with
575 * valid data for the translated instruction, or a "nothing" instruction if
576 * there was a translation failure. The newly translated instruction is then
577 * executed.
578 */
579 X(to_be_translated)
580 {
581 uint64_t addr, low_pc;
582 uint32_t iword, imm;
583 unsigned char *page;
584 unsigned char ib[4];
585 #ifdef DYNTRANS_BACKEND
586 int simple = 0;
587 #endif
588 int main_opcode, rt, rs, rd, sa, s6, x64 = 0;
589 int in_crosspage_delayslot = 0;
590 int delay_slot_danger = 1;
591 void (*samepage_function)(struct cpu *, struct mips_instr_call *);
592
593 /* Figure out the (virtual) address of the instruction: */
594 low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page)
595 / sizeof(struct mips_instr_call);
596
597 /* Special case for branch with delayslot on the next page: */
598 if (low_pc >= MIPS_IC_ENTRIES_PER_PAGE) {
599 /* fatal("[ TEMPORARY delay-slot translation ]\n"); */
600 low_pc = 0;
601 in_crosspage_delayslot = 1;
602 }
603
604 addr = cpu->pc & ~((MIPS_IC_ENTRIES_PER_PAGE-1)
605 << MIPS_INSTR_ALIGNMENT_SHIFT);
606 addr += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT);
607 cpu->pc = addr;
608 addr &= ~((1 << MIPS_INSTR_ALIGNMENT_SHIFT) - 1);
609
610 /* Read the instruction word from memory: */
611 page = cpu->cd.mips.host_load[(uint32_t)addr >> 12];
612
613 if (page != NULL) {
614 /* fatal("TRANSLATION HIT!\n"); */
615 memcpy(ib, page + (addr & 0xfff), sizeof(ib));
616 } else {
617 /* fatal("TRANSLATION MISS!\n"); */
618 if (!cpu->memory_rw(cpu, cpu->mem, addr, ib,
619 sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
620 fatal("to_be_translated(): "
621 "read failed: TODO\n");
622 goto bad;
623 }
624 }
625
626 iword = *((uint32_t *)&ib[0]);
627
628 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
629 iword = LE32_TO_HOST(iword);
630 else
631 iword = BE32_TO_HOST(iword);
632
633 /* Is the instruction in the delay slot known to be safe? */
634 if ((addr & 0xffc) < 0xffc) {
635 /* TODO: check the instruction */
636 delay_slot_danger = 0;
637 }
638
639
640 #define DYNTRANS_TO_BE_TRANSLATED_HEAD
641 #include "cpu_dyntrans.c"
642 #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
643
644
645 /*
646 * Translate the instruction:
647 *
648 * NOTE: _NEVER_ allow writes to the zero register; all such
649 * instructions should be made into NOPs.
650 */
651
652 main_opcode = iword >> 26;
653 rs = (iword >> 21) & 31;
654 rt = (iword >> 16) & 31;
655 rd = (iword >> 11) & 31;
656 sa = (iword >> 6) & 31;
657 imm = (int16_t)iword;
658 s6 = iword & 63;
659
660 switch (main_opcode) {
661
662 case HI6_SPECIAL:
663 switch (s6) {
664
665 case SPECIAL_SLL:
666 case SPECIAL_SRL:
667 case SPECIAL_SRA:
668 switch (s6) {
669 case SPECIAL_SLL: ic->f = instr(sll); break;
670 case SPECIAL_SRL: ic->f = instr(srl); break;
671 case SPECIAL_SRA: ic->f = instr(sra); break;
672 }
673 ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt];
674 ic->arg[1] = sa;
675 ic->arg[2] = (size_t)&cpu->cd.mips.gpr[rd];
676 if (rd == MIPS_GPR_ZERO)
677 ic->f = instr(nop);
678 break;
679
680 case SPECIAL_ADDU:
681 case SPECIAL_SUBU:
682 case SPECIAL_DADDU:
683 case SPECIAL_DSUBU:
684 case SPECIAL_SLT:
685 case SPECIAL_SLTU:
686 case SPECIAL_OR:
687 case SPECIAL_XOR:
688 case SPECIAL_NOR:
689 case SPECIAL_MFHI:
690 case SPECIAL_MFLO:
691 case SPECIAL_MTHI:
692 case SPECIAL_MTLO:
693 switch (s6) {
694 case SPECIAL_ADDU: ic->f = instr(addu); break;
695 case SPECIAL_SUBU: ic->f = instr(subu); break;
696 case SPECIAL_DADDU: ic->f = instr(daddu); x64=1; break;
697 case SPECIAL_DSUBU: ic->f = instr(dsubu); x64=1; break;
698 case SPECIAL_SLT: ic->f = instr(slt); break;
699 case SPECIAL_SLTU: ic->f = instr(sltu); break;
700 case SPECIAL_OR: ic->f = instr(or); break;
701 case SPECIAL_XOR: ic->f = instr(xor); break;
702 case SPECIAL_NOR: ic->f = instr(nor); break;
703 case SPECIAL_MFHI: ic->f = instr(mov); break;
704 case SPECIAL_MFLO: ic->f = instr(mov); break;
705 case SPECIAL_MTHI: ic->f = instr(mov); break;
706 case SPECIAL_MTLO: ic->f = instr(mov); break;
707 }
708 ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs];
709 ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rt];
710 ic->arg[2] = (size_t)&cpu->cd.mips.gpr[rd];
711 switch (s6) {
712 case SPECIAL_MFHI:
713 ic->arg[0] = (size_t)&cpu->cd.mips.hi;
714 break;
715 case SPECIAL_MFLO:
716 ic->arg[0] = (size_t)&cpu->cd.mips.lo;
717 break;
718 case SPECIAL_MTHI:
719 ic->arg[2] = (size_t)&cpu->cd.mips.hi;
720 break;
721 case SPECIAL_MTLO:
722 ic->arg[2] = (size_t)&cpu->cd.mips.lo;
723 break;
724 }
725 /* rd==0 => nop: */
726 switch (s6) {
727 case SPECIAL_MTHI:
728 case SPECIAL_MTLO:
729 /* These instructions don't use rd. */
730 break;
731 default:if (rd == MIPS_GPR_ZERO)
732 ic->f = instr(nop);
733 }
734 break;
735
736 case SPECIAL_MULT:
737 case SPECIAL_MULTU:
738 switch (s6) {
739 case SPECIAL_MULT : ic->f = instr(mult); break;
740 case SPECIAL_MULTU: ic->f = instr(multu); break;
741 }
742 ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs];
743 ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rt];
744 /* rd is ignored for most of these instructions,
745 except for multiplication: */
746 switch (s6) {
747 case SPECIAL_MULT:
748 case SPECIAL_MULTU:
749 case SPECIAL_DMULT:
750 case SPECIAL_DMULTU:
751 ic->arg[2] = (size_t)&cpu->cd.mips.gpr[rd];
752 if (rd != MIPS_GPR_ZERO) {
753 fatal("TODO: mult with rd NON-zero\n");
754 goto bad;
755 }
756 break;
757 }
758 break;
759
760 case SPECIAL_JR:
761 case SPECIAL_JALR:
762 ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs];
763 ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rd];
764 if (main_opcode == SPECIAL_JALR && rd == MIPS_GPR_ZERO)
765 main_opcode = SPECIAL_JR;
766 ic->arg[2] = (addr & 0xffc) + 4;
767 switch (main_opcode) {
768 case SPECIAL_JR:
769 if (rs == MIPS_GPR_RA) {
770 if (cpu->machine->show_trace_tree)
771 ic->f = instr(jr_ra_trace);
772 else
773 ic->f = instr(jr_ra);
774 } else {
775 ic->f = instr(jr);
776 }
777 break;
778 case SPECIAL_JALR:
779 if (cpu->machine->show_trace_tree)
780 ic->f = instr(jalr_trace);
781 else
782 ic->f = instr(jalr);
783 break;
784 }
785 if (in_crosspage_delayslot) {
786 fatal("[ WARNING: branch in delay slot? ]\n");
787 ic->f = instr(nop);
788 }
789 break;
790
791 case SPECIAL_SYNC:
792 ic->f = instr(nop);
793 break;
794
795 default:goto bad;
796 }
797 break;
798
799 case HI6_BEQ:
800 case HI6_BNE:
801 samepage_function = NULL; /* get rid of a compiler warning */
802 switch (main_opcode) {
803 case HI6_BEQ:
804 ic->f = instr(beq);
805 samepage_function = instr(beq_samepage);
806 /* Special case: comparing a register with itself: */
807 if (rs == rt) {
808 ic->f = instr(b);
809 samepage_function = instr(b_samepage);
810 }
811 break;
812 case HI6_BNE:
813 ic->f = instr(bne);
814 samepage_function = instr(bne_samepage);
815 }
816 ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs];
817 ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rt];
818 ic->arg[2] = (imm << MIPS_INSTR_ALIGNMENT_SHIFT)
819 + (addr & 0xffc) + 4;
820 /* Is the offset from the start of the current page still
821 within the same page? Then use the samepage_function: */
822 if ((uint32_t)ic->arg[2] < ((MIPS_IC_ENTRIES_PER_PAGE - 1)
823 << MIPS_INSTR_ALIGNMENT_SHIFT) && (addr & 0xffc) < 0xffc) {
824 ic->arg[2] = (size_t) (cpu->cd.mips.cur_ic_page +
825 ((ic->arg[2] >> MIPS_INSTR_ALIGNMENT_SHIFT)
826 & (MIPS_IC_ENTRIES_PER_PAGE - 1)));
827 ic->f = samepage_function;
828 }
829 if (in_crosspage_delayslot) {
830 fatal("[ WARNING: branch in delay slot? ]\n");
831 ic->f = instr(nop);
832 }
833 break;
834
835 case HI6_ADDIU:
836 case HI6_DADDIU:
837 case HI6_ANDI:
838 case HI6_ORI:
839 case HI6_XORI:
840 ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs];
841 ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rt];
842 if (main_opcode == HI6_ADDI ||
843 main_opcode == HI6_ADDIU ||
844 main_opcode == HI6_DADDI ||
845 main_opcode == HI6_DADDIU)
846 ic->arg[2] = (int16_t)iword;
847 else
848 ic->arg[2] = (uint16_t)iword;
849 switch (main_opcode) {
850 case HI6_ADDIU: ic->f = instr(addiu); break;
851 case HI6_DADDIU: ic->f = instr(daddiu); x64 = 1; break;
852 case HI6_ANDI: ic->f = instr(andi); break;
853 case HI6_ORI: ic->f = instr(ori); break;
854 case HI6_XORI: ic->f = instr(xori); break;
855 }
856 if (rt == MIPS_GPR_ZERO)
857 ic->f = instr(nop);
858
859 if (ic->f == instr(addiu))
860 cpu->cd.mips.combination_check = COMBINE(b_addiu);
861 break;
862
863 case HI6_LUI:
864 ic->f = instr(set);
865 ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt];
866 ic->arg[1] = imm << 16;
867 if (rt == MIPS_GPR_ZERO)
868 ic->f = instr(nop);
869 break;
870
871 case HI6_COP0:
872 /* rs contains the coprocessor opcode! */
873 switch (rs) {
874 case COPz_MFCz:
875 case COPz_DMFCz:
876 ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt];
877 ic->arg[1] = rd + ((iword & 7) << 5);
878 ic->arg[2] = addr & 0xffc;
879 ic->f = rs == COPz_MFCz? instr(mfc0) : instr(dmfc0);
880 if (rt == MIPS_GPR_ZERO)
881 ic->f = instr(nop);
882 break;
883 case COPz_MTCz:
884 case COPz_DMTCz:
885 ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt];
886 ic->arg[1] = rd + ((iword & 7) << 5);
887 ic->arg[2] = addr & 0xffc;
888 ic->f = rs == COPz_MTCz? instr(mtc0) : instr(dmtc0);
889 break;
890 default:fatal("UNIMPLEMENTED cop0 (rs = %i)\n", rs);
891 goto bad;
892 }
893 break;
894
895 case HI6_COP1:
896 /* rs contains the coprocessor opcode! */
897 switch (rs) {
898 case COPz_CFCz:
899 ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt];
900 ic->arg[1] = (size_t)&cpu->cd.mips.coproc[1]->fcr[rd];
901 ic->arg[2] = addr & 0xffc;
902 ic->f = instr(cfc1);
903 if (rt == MIPS_GPR_ZERO)
904 ic->f = instr(nop);
905 break;
906 default:fatal("UNIMPLEMENTED cop1 (rs = %i)\n", rs);
907 goto bad;
908 }
909 break;
910
911 case HI6_SPECIAL2:
912 switch (s6) {
913
914 case SPECIAL2_MUL:
915 ic->f = instr(mul);
916 ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs];
917 ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rt];
918 ic->arg[2] = (size_t)&cpu->cd.mips.gpr[rd];
919 if (rd == MIPS_GPR_ZERO)
920 ic->f = instr(nop);
921 break;
922
923 case SPECIAL2_CLZ:
924 case SPECIAL2_CLO:
925 case SPECIAL2_DCLZ:
926 case SPECIAL2_DCLO:
927 switch (s6) {
928 case SPECIAL2_CLZ: ic->f = instr(clz); break;
929 case SPECIAL2_CLO: ic->f = instr(clo); break;
930 case SPECIAL2_DCLZ: ic->f = instr(dclz); break;
931 case SPECIAL2_DCLO: ic->f = instr(dclo); break;
932 }
933 ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs];
934 ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rd];
935 if (rd == MIPS_GPR_ZERO)
936 ic->f = instr(nop);
937 break;
938
939 default:goto bad;
940 }
941 break;
942
943 default:goto bad;
944 }
945
946 if (x64)
947 ic->f = instr(invalid_32_64);
948
949 if (in_crosspage_delayslot)
950 cpu->cd.mips.combination_check = NULL;
951
952 #define DYNTRANS_TO_BE_TRANSLATED_TAIL
953 #include "cpu_dyntrans.c"
954 #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
955 }
956

  ViewVC Help
Powered by ViewVC 1.1.26