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

Parent Directory Parent Directory | Revision Log Revision Log


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

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


1 /*
2 * Copyright (C) 2007 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_m88k_instr.c,v 1.33 2007/06/05 06:41:30 debug Exp $
29 *
30 * M88K 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 #define SYNCH_PC { \
40 int low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page) \
41 / sizeof(struct m88k_instr_call); \
42 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) \
43 << M88K_INSTR_ALIGNMENT_SHIFT); \
44 cpu->pc += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT); \
45 }
46
47
48 /*
49 * nop: Do nothing.
50 */
51 X(nop)
52 {
53 }
54
55
56 /*
57 * br_samepage: Branch (to within the same translated page)
58 * bsr_samepage: Branch to subroutine (to within the same translated page)
59 *
60 * arg[0] = pointer to new instr_call
61 */
62 X(br_samepage)
63 {
64 cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[0];
65 }
66 X(bsr_samepage)
67 {
68 SYNCH_PC;
69 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + sizeof(uint32_t);
70 cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[0];
71 }
72
73
74 /*
75 * br: Branch (to a different translated page)
76 * br.n: Branch (to a different translated page) with delay slot
77 * bsr: Branch to subroutine (to a different translated page)
78 * bsr.n: Branch to subroutine (to a different page) with delay slot
79 *
80 * arg[1] = relative offset from start of page
81 */
82 X(br)
83 {
84 cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[1]);
85 quick_pc_to_pointers(cpu);
86 }
87 X(br_n)
88 {
89 cpu->cd.m88k.delay_target = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
90 M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[1];
91 cpu->delay_slot = TO_BE_DELAYED;
92 ic[1].f(cpu, ic+1);
93 cpu->n_translated_instrs ++;
94 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
95 /* Note: Must be non-delayed when jumping to the new pc: */
96 cpu->delay_slot = NOT_DELAYED;
97 cpu->pc = cpu->cd.m88k.delay_target;
98 quick_pc_to_pointers(cpu);
99 } else
100 cpu->delay_slot = NOT_DELAYED;
101 }
102 X(bsr)
103 {
104 SYNCH_PC;
105 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + sizeof(uint32_t);
106 cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[1]);
107 quick_pc_to_pointers(cpu);
108 }
109 X(bsr_n)
110 {
111 cpu->cd.m88k.delay_target = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
112 M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[1];
113 SYNCH_PC;
114 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + sizeof(uint32_t) * 2;
115 cpu->delay_slot = TO_BE_DELAYED;
116 ic[1].f(cpu, ic+1);
117 cpu->n_translated_instrs ++;
118 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
119 /* Note: Must be non-delayed when jumping to the new pc: */
120 cpu->delay_slot = NOT_DELAYED;
121 cpu->pc = cpu->cd.m88k.delay_target;
122 quick_pc_to_pointers(cpu);
123 } else
124 cpu->delay_slot = NOT_DELAYED;
125 }
126 X(bsr_trace)
127 {
128 SYNCH_PC;
129 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + sizeof(uint32_t);
130 cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[1]);
131 cpu_functioncall_trace(cpu, cpu->pc);
132 quick_pc_to_pointers(cpu);
133 }
134 X(bsr_n_trace)
135 {
136 cpu->cd.m88k.delay_target = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
137 M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[1];
138 SYNCH_PC;
139 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + sizeof(uint32_t) * 2;
140 cpu->delay_slot = TO_BE_DELAYED;
141 ic[1].f(cpu, ic+1);
142 cpu->n_translated_instrs ++;
143 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
144 /* Note: Must be non-delayed when jumping to the new pc: */
145 cpu->delay_slot = NOT_DELAYED;
146 cpu->pc = cpu->cd.m88k.delay_target;
147 cpu_functioncall_trace(cpu, cpu->pc);
148 quick_pc_to_pointers(cpu);
149 } else
150 cpu->delay_slot = NOT_DELAYED;
151 }
152
153
154 /*
155 * bb? Branch if a bit in a register is 0 or 1.
156 * bb?_samepage: Branch within the same translated page.
157 * bb?_n_*: With delay slot.
158 *
159 * arg[0] = pointer to source register to test (s1).
160 * arg[1] = uint32_t mask to test (e.g. 0x00010000 to test bit 16)
161 * arg[2] = offset from start of current page _OR_ pointer to new instr_call
162 */
163 X(bb0)
164 {
165 if (!(reg(ic->arg[0]) & ic->arg[1])) {
166 cpu->pc = (cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
167 quick_pc_to_pointers(cpu);
168 }
169 }
170 X(bb0_samepage)
171 {
172 if (!(reg(ic->arg[0]) & ic->arg[1]))
173 cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[2];
174 }
175 X(bb0_n)
176 {
177 int cond = !(reg(ic->arg[0]) & ic->arg[1]);
178 cpu->cd.m88k.delay_target = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
179 M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[2];
180 cpu->delay_slot = TO_BE_DELAYED;
181 ic[1].f(cpu, ic+1);
182 cpu->n_translated_instrs ++;
183 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
184 /* Note: Must be non-delayed when jumping to the new pc: */
185 cpu->delay_slot = NOT_DELAYED;
186 if (cond) {
187 cpu->pc = cpu->cd.m88k.delay_target;
188 quick_pc_to_pointers(cpu);
189 } else
190 cpu->cd.m88k.next_ic ++;
191 } else
192 cpu->delay_slot = NOT_DELAYED;
193 }
194 X(bb1)
195 {
196 if (reg(ic->arg[0]) & ic->arg[1]) {
197 cpu->pc = (cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
198 quick_pc_to_pointers(cpu);
199 }
200 }
201 X(bb1_samepage)
202 {
203 if (reg(ic->arg[0]) & ic->arg[1])
204 cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[2];
205 }
206 X(bb1_n)
207 {
208 int cond = reg(ic->arg[0]) & ic->arg[1];
209 cpu->cd.m88k.delay_target = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
210 M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[2];
211 cpu->delay_slot = TO_BE_DELAYED;
212 ic[1].f(cpu, ic+1);
213 cpu->n_translated_instrs ++;
214 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
215 /* Note: Must be non-delayed when jumping to the new pc: */
216 cpu->delay_slot = NOT_DELAYED;
217 if (cond) {
218 cpu->pc = cpu->cd.m88k.delay_target;
219 quick_pc_to_pointers(cpu);
220 } else
221 cpu->cd.m88k.next_ic ++;
222 } else
223 cpu->delay_slot = NOT_DELAYED;
224 }
225
226
227 /*
228 * ff0, ff1: Find first cleared/set bit in a register
229 *
230 * arg[0] = pointer to register d
231 * arg[2] = pointer to register s2
232 */
233 X(ff0)
234 {
235 uint32_t mask = 0x80000000, s2 = reg(ic->arg[2]);
236 int n = 31;
237
238 for (;;) {
239 if (!(s2 & mask)) {
240 reg(ic->arg[0]) = n;
241 return;
242 }
243 mask >>= 1; n--;
244 if (mask == 0) {
245 reg(ic->arg[0]) = 32;
246 return;
247 }
248 }
249 }
250 X(ff1)
251 {
252 uint32_t mask = 0x80000000, s2 = reg(ic->arg[2]);
253 int n = 31;
254
255 for (;;) {
256 if (s2 & mask) {
257 reg(ic->arg[0]) = n;
258 return;
259 }
260 mask >>= 1; n--;
261 if (mask == 0) {
262 reg(ic->arg[0]) = 32;
263 return;
264 }
265 }
266 }
267
268
269 /* Include all automatically generated bcnd and bcnd.n instructions: */
270 #include "tmp_m88k_bcnd.c"
271
272
273 /* Include all automatically generated load/store instructions: */
274 #include "tmp_m88k_loadstore.c"
275 #define M88K_LOADSTORE_STORE 4
276 #define M88K_LOADSTORE_SIGNEDNESS 8
277 #define M88K_LOADSTORE_ENDIANNESS 16
278 #define M88K_LOADSTORE_SCALEDNESS 32
279 #define M88K_LOADSTORE_USR 64
280 #define M88K_LOADSTORE_REGISTEROFFSET 128
281
282
283 /*
284 * jmp: Jump to register
285 * jmp.n: Jump to register, with delay slot
286 * jsr: Jump to register, set r1 to return address
287 * jsr.n: Jump to register, set r1 to return address, with delay slot
288 *
289 * arg[1] = offset to return address, from start of current page
290 * arg[2] = pointer to register s2
291 */
292 X(jmp)
293 {
294 cpu->pc = reg(ic->arg[2]) & ~3;
295 quick_pc_to_pointers(cpu);
296 }
297 X(jmp_n)
298 {
299 cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3;
300 cpu->delay_slot = TO_BE_DELAYED;
301 ic[1].f(cpu, ic+1);
302 cpu->n_translated_instrs ++;
303 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
304 /* Note: Must be non-delayed when jumping to the new pc: */
305 cpu->delay_slot = NOT_DELAYED;
306 cpu->pc = cpu->cd.m88k.delay_target;
307 quick_pc_to_pointers(cpu);
308 } else
309 cpu->delay_slot = NOT_DELAYED;
310 }
311 X(jmp_trace)
312 {
313 cpu->pc = reg(ic->arg[2]) & ~3;
314 cpu_functioncall_trace_return(cpu);
315 quick_pc_to_pointers(cpu);
316 }
317 X(jmp_n_trace)
318 {
319 cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3;
320 cpu->delay_slot = TO_BE_DELAYED;
321 ic[1].f(cpu, ic+1);
322 cpu->n_translated_instrs ++;
323 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
324 /* Note: Must be non-delayed when jumping to the new pc: */
325 cpu->delay_slot = NOT_DELAYED;
326 cpu->pc = cpu->cd.m88k.delay_target;
327 cpu_functioncall_trace_return(cpu);
328 quick_pc_to_pointers(cpu);
329 } else
330 cpu->delay_slot = NOT_DELAYED;
331 }
332 X(jsr)
333 {
334 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1];
335 cpu->pc = reg(ic->arg[2]) & ~3;
336 quick_pc_to_pointers(cpu);
337 }
338 X(jsr_n)
339 {
340 cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3;
341 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1];
342 cpu->delay_slot = TO_BE_DELAYED;
343 ic[1].f(cpu, ic+1);
344 cpu->n_translated_instrs ++;
345 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
346 /* Note: Must be non-delayed when jumping to the new pc: */
347 cpu->delay_slot = NOT_DELAYED;
348 cpu->pc = cpu->cd.m88k.delay_target;
349 quick_pc_to_pointers(cpu);
350 } else
351 cpu->delay_slot = NOT_DELAYED;
352 }
353 X(jsr_trace)
354 {
355 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1];
356 cpu->pc = reg(ic->arg[2]) & ~3;
357 cpu_functioncall_trace(cpu, cpu->pc);
358 quick_pc_to_pointers(cpu);
359 }
360 X(jsr_n_trace)
361 {
362 cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3;
363 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1];
364 cpu->delay_slot = TO_BE_DELAYED;
365 ic[1].f(cpu, ic+1);
366 cpu->n_translated_instrs ++;
367 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
368 /* Note: Must be non-delayed when jumping to the new pc: */
369 cpu->delay_slot = NOT_DELAYED;
370 cpu->pc = cpu->cd.m88k.delay_target;
371 cpu_functioncall_trace(cpu, cpu->pc);
372 quick_pc_to_pointers(cpu);
373 } else
374 cpu->delay_slot = NOT_DELAYED;
375 }
376
377
378 /*
379 * cmp_imm: Compare S1 with immediate value.
380 * cmp: Compare S1 with S2.
381 *
382 * arg[0] = pointer to register d
383 * arg[1] = pointer to register s1
384 * arg[2] = pointer to register s2 or imm
385 */
386 static void m88k_cmp(struct cpu *cpu, struct m88k_instr_call *ic, uint32_t y)
387 {
388 uint32_t x = reg(ic->arg[1]);
389 uint32_t r;
390
391 if (x == y) {
392 r = M88K_CMP_HS | M88K_CMP_LS | M88K_CMP_GE
393 | M88K_CMP_LE | M88K_CMP_EQ;
394 } else {
395 if (x > y)
396 r = M88K_CMP_NE | M88K_CMP_HS | M88K_CMP_HI;
397 else
398 r = M88K_CMP_NE | M88K_CMP_LO | M88K_CMP_LS;
399 if ((int32_t)x > (int32_t)y)
400 r |= M88K_CMP_GE | M88K_CMP_GT;
401 else
402 r |= M88K_CMP_LT | M88K_CMP_LE;
403 }
404
405 reg(ic->arg[0]) = r;
406 }
407 X(cmp_imm) { m88k_cmp(cpu, ic, ic->arg[2]); }
408 X(cmp) { m88k_cmp(cpu, ic, reg(ic->arg[2])); }
409
410
411 /*
412 * extu_imm: Extract bits, unsigned, immediate W<O>.
413 * extu: Extract bits, unsigned, W<O> taken from register s2.
414 * ext_imm: Extract bits, signed, immediate W<O>.
415 * ext: Extract bits, signed, W<O> taken from register s2.
416 * mak_imm: Make bit field, immediate W<O>.
417 * mak: Make bit field, W<O> taken from register s2.
418 * clr: Clear bits, W<O> taken from register s2.
419 * set: Set bits, W<O> taken from register s2.
420 *
421 * arg[0] = pointer to register d
422 * arg[1] = pointer to register s1
423 * arg[2] = pointer to register s2 or 10 bits wwwwwooooo
424 */
425 static void m88k_extu(struct cpu *cpu, struct m88k_instr_call *ic, int w, int o)
426 {
427 uint32_t x = reg(ic->arg[1]) >> o;
428 if (w != 0) {
429 x <<= (32-w);
430 x >>= (32-w);
431 }
432 reg(ic->arg[0]) = x;
433 }
434 static void m88k_ext(struct cpu *cpu, struct m88k_instr_call *ic, int w, int o)
435 {
436 int32_t x = reg(ic->arg[1]) >> o;
437 if (w != 0) {
438 x <<= (32-w);
439 x >>= (32-w);
440 }
441 reg(ic->arg[0]) = x;
442 }
443 static void m88k_mak(struct cpu *cpu, struct m88k_instr_call *ic, int w, int o)
444 {
445 uint32_t x = reg(ic->arg[1]);
446 if (w != 0) {
447 x <<= (32-w);
448 x >>= (32-w);
449 }
450 reg(ic->arg[0]) = x << o;
451 }
452 X(extu_imm)
453 {
454 m88k_extu(cpu, ic, ic->arg[2] >> 5, ic->arg[2] & 0x1f);
455 }
456 X(extu)
457 {
458 m88k_extu(cpu, ic, (reg(ic->arg[2]) >> 5) & 0x1f,
459 reg(ic->arg[2]) & 0x1f);
460 }
461 X(ext_imm)
462 {
463 m88k_ext(cpu, ic, ic->arg[2] >> 5, ic->arg[2] & 0x1f);
464 }
465 X(ext)
466 {
467 m88k_ext(cpu, ic, (reg(ic->arg[2]) >> 5) & 0x1f,
468 reg(ic->arg[2]) & 0x1f);
469 }
470 X(mak_imm)
471 {
472 m88k_mak(cpu, ic, ic->arg[2] >> 5, ic->arg[2] & 0x1f);
473 }
474 X(mak)
475 {
476 m88k_mak(cpu, ic, (reg(ic->arg[2]) >> 5) & 0x1f,
477 reg(ic->arg[2]) & 0x1f);
478 }
479 X(clr)
480 {
481 int w = (reg(ic->arg[2]) >> 5) & 0x1f, o = reg(ic->arg[2]) & 0x1f;
482 uint32_t x = w == 0? 0xffffffff : (1 << w) - 1;
483 x <<= o;
484 reg(ic->arg[0]) = reg(ic->arg[1]) & ~x;
485 }
486 X(set)
487 {
488 int w = (reg(ic->arg[2]) >> 5) & 0x1f, o = reg(ic->arg[2]) & 0x1f;
489 uint32_t x = w == 0? 0xffffffff : (1 << w) - 1;
490 x <<= o;
491 reg(ic->arg[0]) = reg(ic->arg[1]) | x;
492 }
493
494
495 /*
496 * or_r0_imm0: d = 0 (optimized case when s1 = r0, imm = 0)
497 * or_r0_imm: d = imm (optimized case when s1 = r0)
498 * or_imm: d = s1 | imm
499 * xor_imm: d = s1 ^ imm
500 * and_imm: d = (s1 & imm) | (s1 & 0xffff0000)
501 * and_u_imm: d = (s1 & imm) | (s1 & 0xffff)
502 * mask_imm: d = s1 & imm
503 * addu_imm: d = s1 + imm
504 * subu_imm: d = s1 - imm
505 * inc_reg: d ++; (addu special case; d = d + 1)
506 * dec_reg: d --; (subu special case; d = d - 1)
507 * mulu_imm: d = s1 * imm
508 * divu_imm: d = s1 / imm (unsigned)
509 * div_imm: d = s1 / imm (signed)
510 * sub_imm: d = s1 - imm (subtraction with overflow exception)
511 *
512 * arg[0] = pointer to register d
513 * arg[1] = pointer to register s1
514 * arg[2] = imm
515 */
516 X(or_r0_imm0) { reg(ic->arg[0]) = 0; }
517 X(or_r0_imm) { reg(ic->arg[0]) = ic->arg[2]; }
518 X(or_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) | ic->arg[2]; }
519 X(xor_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) ^ ic->arg[2]; }
520 X(and_imm) { reg(ic->arg[0]) = (reg(ic->arg[1]) & ic->arg[2])
521 | (reg(ic->arg[1]) & 0xffff0000); }
522 X(and_u_imm) { reg(ic->arg[0]) = (reg(ic->arg[1]) & ic->arg[2])
523 | (reg(ic->arg[1]) & 0xffff); }
524 X(mask_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) & ic->arg[2]; }
525 X(addu_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) + ic->arg[2]; }
526 X(subu_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) - ic->arg[2]; }
527 X(inc_reg) { reg(ic->arg[0]) ++; }
528 X(dec_reg) { reg(ic->arg[0]) --; }
529 X(mulu_imm)
530 {
531 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
532 SYNCH_PC;
533 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
534 } else
535 reg(ic->arg[0]) = reg(ic->arg[1]) * ic->arg[2];
536 }
537 X(divu_imm)
538 {
539 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
540 SYNCH_PC;
541 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
542 } else if (ic->arg[2] == 0) {
543 SYNCH_PC;
544 m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0);
545 } else
546 reg(ic->arg[0]) = (uint32_t) reg(ic->arg[1]) / ic->arg[2];
547 }
548 X(div_imm)
549 {
550 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
551 SYNCH_PC;
552 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
553 } else if (ic->arg[2] == 0) {
554 SYNCH_PC;
555 m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0);
556 } else
557 reg(ic->arg[0]) = (int32_t) reg(ic->arg[1]) / ic->arg[2];
558 }
559 X(sub_imm)
560 {
561 int32_t a = reg(ic->arg[1]);
562 int32_t b = ic->arg[2];
563 int32_t res = a - b;
564
565 if (a < 0 && res >= 0) {
566 SYNCH_PC;
567 m88k_exception(cpu, M88K_EXCEPTION_INTEGER_OVERFLOW, 0);
568 return;
569 }
570
571 reg(ic->arg[0]) = res;
572 }
573
574
575 /*
576 * or: d = s1 | s2
577 * or_c: d = s1 | ~s2
578 * or_r0: d = s2
579 * xor: d = s1 ^ s2
580 * xor_c: d = s1 ^ ~s2
581 * and: d = s1 & s2
582 * and_c: d = s1 & ~s2
583 * addu: d = s1 + s2
584 * addu_co: d = s1 + s2 carry out
585 * addu_ci: d = s1 + s2 + carry carry in
586 * lda_reg_X: same as addu, but s2 is scaled by 2, 4, or 8
587 * subu: d = s1 - s2
588 * subu_co: d = s1 - s2 carry/borrow out
589 * subu_ci: d = s1 - s2 - (carry? 0 : 1) carry in
590 * mul: d = s1 * s2
591 * divu: d = s1 / s2 (unsigned)
592 * div: d = s1 / s2 (signed)
593 *
594 * arg[0] = pointer to register d
595 * arg[1] = pointer to register s1
596 * arg[2] = pointer to register s2
597 */
598 X(or) { reg(ic->arg[0]) = reg(ic->arg[1]) | reg(ic->arg[2]); }
599 X(or_c) { reg(ic->arg[0]) = reg(ic->arg[1]) | ~(reg(ic->arg[2])); }
600 X(or_r0){ reg(ic->arg[0]) = reg(ic->arg[2]); }
601 X(xor) { reg(ic->arg[0]) = reg(ic->arg[1]) ^ reg(ic->arg[2]); }
602 X(xor_c){ reg(ic->arg[0]) = reg(ic->arg[1]) ^ ~(reg(ic->arg[2])); }
603 X(and) { reg(ic->arg[0]) = reg(ic->arg[1]) & reg(ic->arg[2]); }
604 X(and_c){ reg(ic->arg[0]) = reg(ic->arg[1]) & ~(reg(ic->arg[2])); }
605 X(addu) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]); }
606 X(addu_s2r0) { reg(ic->arg[0]) = reg(ic->arg[1]); }
607 X(lda_reg_2) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]) * 2; }
608 X(lda_reg_4) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]) * 4; }
609 X(lda_reg_8) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]) * 8; }
610 X(subu) { reg(ic->arg[0]) = reg(ic->arg[1]) - reg(ic->arg[2]); }
611 X(mul)
612 {
613 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
614 SYNCH_PC;
615 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
616 } else
617 reg(ic->arg[0]) = reg(ic->arg[1]) * reg(ic->arg[2]);
618 }
619 X(divu)
620 {
621 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
622 SYNCH_PC;
623 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
624 } else if (reg(ic->arg[2]) == 0) {
625 SYNCH_PC;
626 m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0);
627 } else
628 reg(ic->arg[0]) = (uint32_t) reg(ic->arg[1]) / reg(ic->arg[2]);
629 }
630 X(div)
631 {
632 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
633 SYNCH_PC;
634 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
635 } else if (reg(ic->arg[2]) == 0) {
636 SYNCH_PC;
637 m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0);
638 } else
639 reg(ic->arg[0]) = (int32_t) reg(ic->arg[1]) / reg(ic->arg[2]);
640 }
641 X(addu_co)
642 {
643 uint64_t a = reg(ic->arg[1]), b = reg(ic->arg[2]);
644 a += b;
645 reg(ic->arg[0]) = a;
646 cpu->cd.m88k.cr[M88K_CR_PSR] &= ~M88K_PSR_C;
647 if ((a >> 32) & 1)
648 cpu->cd.m88k.cr[M88K_CR_PSR] |= M88K_PSR_C;
649 }
650 X(addu_ci)
651 {
652 uint32_t result = reg(ic->arg[1]) + reg(ic->arg[2]);
653 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_C)
654 result ++;
655 reg(ic->arg[0]) = result;
656 }
657 X(subu_co)
658 {
659 uint64_t a = reg(ic->arg[1]), b = reg(ic->arg[2]);
660 a -= b;
661 reg(ic->arg[0]) = a;
662 cpu->cd.m88k.cr[M88K_CR_PSR] |= M88K_PSR_C;
663 if ((a >> 32) & 1)
664 cpu->cd.m88k.cr[M88K_CR_PSR] &= ~M88K_PSR_C;
665 }
666 X(subu_ci)
667 {
668 uint32_t result = reg(ic->arg[1]) - reg(ic->arg[2]);
669 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_C))
670 result --;
671 reg(ic->arg[0]) = result;
672 }
673
674
675 /*
676 * ldcr: Load value from a control register, store in register d.
677 * fldcr: Load value from a floating point control register, store in reg d.
678 *
679 * arg[0] = pointer to register d
680 * arg[1] = 6-bit control register number
681 */
682 X(ldcr)
683 {
684 SYNCH_PC;
685
686 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)
687 m88k_ldcr(cpu, (uint32_t *) (void *) ic->arg[0], ic->arg[1]);
688 else
689 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
690 }
691 X(fldcr)
692 {
693 SYNCH_PC;
694
695 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE || ic->arg[1] >= 62)
696 reg(ic->arg[0]) = cpu->cd.m88k.fcr[ic->arg[1]];
697 else {
698 /* TODO: The manual says "floating point privilege
699 violation", not just "privilege violation"! */
700 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
701 }
702 }
703
704
705 /*
706 * stcr: Store a value into a control register.
707 * fstcr: Store a value into a floating point control register.
708 *
709 * arg[0] = pointer to source register
710 * arg[1] = 6-bit control register number
711 */
712 X(stcr)
713 {
714 SYNCH_PC;
715
716 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)
717 m88k_stcr(cpu, reg(ic->arg[0]), ic->arg[1], 0);
718 else
719 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
720 }
721 X(fstcr)
722 {
723 SYNCH_PC;
724
725 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE || ic->arg[1] >= 62)
726 m88k_fstcr(cpu, reg(ic->arg[0]), ic->arg[1]);
727 else {
728 /* TODO: The manual says "floating point privilege
729 violation", not just "privilege violation"! */
730 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
731 }
732 }
733
734
735 /*
736 * xcr: Exchange (load + store) control register.
737 *
738 * arg[0] = pointer to register d
739 * arg[1] = pointer to register s1
740 * arg[2] = 6-bit control register number
741 */
742 X(xcr)
743 {
744 uint32_t tmp, tmp2;
745 SYNCH_PC;
746
747 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE) {
748 tmp = reg(ic->arg[1]);
749 m88k_ldcr(cpu, &tmp2, ic->arg[2]);
750 m88k_stcr(cpu, tmp, ic->arg[2], 0);
751 reg(ic->arg[0]) = tmp2;
752 } else
753 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
754 }
755
756
757 /*
758 * rte: Return from exception
759 */
760 X(rte)
761 {
762 /* If executed from user mode, then cause an exception: */
763 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) {
764 SYNCH_PC;
765 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
766 return;
767 }
768
769 m88k_stcr(cpu, cpu->cd.m88k.cr[M88K_CR_EPSR], M88K_CR_PSR, 1);
770
771 /* First try the NIP, if it is Valid: */
772 if (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_V) {
773 cpu->pc = cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR;
774 if (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_E) {
775 fatal("rte: NIP: TODO: single-step support\n");
776 goto abort_dump;
777 }
778 } else {
779 /* The FIP must be valid... */
780 if (!(cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_NIP_V)) {
781 fatal("rte: neither FIP nor NIP valid? TODO\n");
782 goto abort_dump;
783 }
784 cpu->pc = cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_ADDR;
785 }
786
787 if (cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_E) {
788 fatal("rte: TODO: FIP single-step support\n");
789 goto abort_dump;
790 }
791
792 if (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_FIP_V &&
793 cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_V &&
794 (cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_ADDR)
795 != (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR) + 4) {
796 /*
797 * The NIP instruction should first be executed (this
798 * is the one the exception handler choose to return to),
799 * and then the FIP instruction should run (the target
800 * of a delayed branch).
801 */
802
803 fatal("FIP != NIP + 4: TODO\n");
804 goto abort_dump;
805 }
806
807 quick_pc_to_pointers(cpu);
808 return;
809
810 abort_dump:
811 fatal("NIP=0x%08"PRIx32", FIP=0x%08"PRIx32"\n",
812 cpu->cd.m88k.cr[M88K_CR_SNIP], cpu->cd.m88k.cr[M88K_CR_SFIP]);
813 exit(1);
814 }
815
816
817 /*
818 * xmem_slow: Unoptimized xmem (exchange register with memory)
819 *
820 * arg[0] = copy of the instruction word
821 */
822 X(xmem_slow)
823 {
824 uint32_t iword = ic->arg[0], addr;
825 uint8_t tmp[4];
826 uint8_t data[4];
827 int d = (iword >> 21) & 0x1f;
828 int s1 = (iword >> 16) & 0x1f;
829 int s2 = iword & 0x1f;
830 int imm16 = iword & 0xffff;
831 int scaled = iword & 0x200;
832 int size = iword & 0x400;
833 int user = iword & 0x80;
834
835 SYNCH_PC;
836
837 if (user) {
838 fatal("xmem_slow: user: not yet (TODO)\n");
839 exit(1);
840 }
841
842 if ((iword & 0xf0000000) == 0) {
843 /* immediate offset: */
844 addr = imm16;
845 scaled = 0;
846 size = (iword >> 26) & 1;
847 user = 0;
848 } else {
849 /* register offset: */
850 addr = cpu->cd.m88k.r[s2];
851 if (scaled && size)
852 addr *= sizeof(uint32_t);
853 }
854
855 addr += cpu->cd.m88k.r[s1];
856
857 if (size) {
858 uint32_t x = cpu->cd.m88k.r[d];
859 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
860 x = LE32_TO_HOST(x);
861 else
862 x = BE32_TO_HOST(x);
863 *((uint32_t *)&tmp[0]) = x;
864
865 if (addr & 3) {
866 m88k_exception(cpu,
867 M88K_EXCEPTION_MISALIGNED_ACCESS, 0);
868 return;
869 }
870 } else
871 tmp[0] = cpu->cd.m88k.r[d];
872
873 if (!cpu->memory_rw(cpu, cpu->mem, addr, (uint8_t *) &data,
874 size? 4 : 1, MEM_READ, CACHE_DATA)) {
875 /* Exception. */
876
877 fatal("XMEM exception: TODO: update the transaction"
878 " registers!\n");
879 exit(1);
880 /* return; */
881 }
882
883 if (!cpu->memory_rw(cpu, cpu->mem, addr, (uint8_t *) &tmp,
884 size? 4 : 1, MEM_WRITE, CACHE_DATA)) {
885 /* Exception. */
886
887 fatal("XMEM exception: TODO: update the transaction"
888 " registers!\n");
889 exit(1);
890 /* return; */
891 }
892
893 if (size) {
894 uint32_t x = *((uint32_t *)&data[0]);
895 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
896 x = LE32_TO_HOST(x);
897 else
898 x = BE32_TO_HOST(x);
899 cpu->cd.m88k.r[d] = x;
900 } else
901 cpu->cd.m88k.r[d] = data[0];
902 }
903
904
905 /*
906 * prom-call:
907 */
908 X(prom_call)
909 {
910 /* If executed from user mode, then cause an exception: */
911 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) {
912 SYNCH_PC;
913 m88k_exception(cpu, M88K_EXCEPTION_UNIMPLEMENTED_OPCODE, 0);
914 return;
915 }
916
917 switch (cpu->machine->machine_type) {
918 case MACHINE_MVME88K:
919 mvmeprom_emul(cpu);
920 break;
921 default:fatal("m88k prom_call: unimplemented machine type\n");
922 exit(1);
923 }
924
925 if (!cpu->running) {
926 cpu->n_translated_instrs --;
927 cpu->cd.m88k.next_ic = &nothing_call;
928 }
929 }
930
931
932 /*
933 * tb0, tb1: Trap on bit Clear/Set
934 *
935 * arg[0] = bitmask to check (e.g. 0x00020000 for bit 17)
936 * arg[1] = pointer to register s1
937 * arg[2] = 9-bit vector number
938 */
939 X(tb0)
940 {
941 SYNCH_PC;
942
943 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)
944 && ic->arg[2] < M88K_EXCEPTION_USER_TRAPS_START) {
945 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
946 return;
947 }
948
949 if (!(reg(ic->arg[1]) & ic->arg[0]))
950 m88k_exception(cpu, ic->arg[2], 1);
951 }
952 X(tb1)
953 {
954 SYNCH_PC;
955
956 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)
957 && ic->arg[2] < M88K_EXCEPTION_USER_TRAPS_START) {
958 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
959 return;
960 }
961
962 if (reg(ic->arg[1]) & ic->arg[0])
963 m88k_exception(cpu, ic->arg[2], 1);
964 }
965
966
967 /*****************************************************************************/
968
969
970 X(end_of_page)
971 {
972 /* Update the PC: (offset 0, but on the next page) */
973 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
974 M88K_INSTR_ALIGNMENT_SHIFT);
975 cpu->pc += (M88K_IC_ENTRIES_PER_PAGE << M88K_INSTR_ALIGNMENT_SHIFT);
976
977 /* end_of_page doesn't count as an executed instruction: */
978 cpu->n_translated_instrs --;
979
980 /*
981 * Find the new physpage and update translation pointers.
982 *
983 * Note: This may cause an exception, if e.g. the new page is
984 * not accessible.
985 */
986 quick_pc_to_pointers(cpu);
987
988 /* Simple jump to the next page (if we are lucky): */
989 if (cpu->delay_slot == NOT_DELAYED)
990 return;
991
992 /*
993 * If we were in a delay slot, and we got an exception while doing
994 * quick_pc_to_pointers, then return. The function which called
995 * end_of_page should handle this case.
996 */
997 if (cpu->delay_slot == EXCEPTION_IN_DELAY_SLOT)
998 return;
999
1000 /*
1001 * Tricky situation; the delay slot is on the next virtual page.
1002 * Calling to_be_translated will translate one instruction manually,
1003 * execute it, and then discard it.
1004 */
1005 /* fatal("[ end_of_page: delay slot across page boundary! ]\n"); */
1006
1007 instr(to_be_translated)(cpu, cpu->cd.m88k.next_ic);
1008
1009 /* The instruction in the delay slot has now executed. */
1010 /* fatal("[ end_of_page: back from executing the delay slot, %i ]\n",
1011 cpu->delay_slot); */
1012
1013 /* Find the physpage etc of the instruction in the delay slot
1014 (or, if there was an exception, the exception handler): */
1015 quick_pc_to_pointers(cpu);
1016 }
1017
1018
1019 X(end_of_page2)
1020 {
1021 /* Synchronize PC on the _second_ instruction on the next page: */
1022 int low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page)
1023 / sizeof(struct m88k_instr_call);
1024 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1)
1025 << M88K_INSTR_ALIGNMENT_SHIFT);
1026 cpu->pc += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT);
1027
1028 /* This doesn't count as an executed instruction. */
1029 cpu->n_translated_instrs --;
1030
1031 quick_pc_to_pointers(cpu);
1032
1033 if (cpu->delay_slot == NOT_DELAYED)
1034 return;
1035
1036 fatal("end_of_page2: fatal error, we're in a delay slot\n");
1037 exit(1);
1038 }
1039
1040
1041 /*****************************************************************************/
1042
1043
1044 /*
1045 * m88k_instr_to_be_translated():
1046 *
1047 * Translate an instruction word into a m88k_instr_call. ic is filled in with
1048 * valid data for the translated instruction, or a "nothing" instruction if
1049 * there was a translation failure. The newly translated instruction is then
1050 * executed.
1051 */
1052 X(to_be_translated)
1053 {
1054 uint32_t addr, low_pc, iword;
1055 unsigned char *page;
1056 unsigned char ib[4];
1057 uint32_t op26, op10, d, s1, s2, cr6, imm16;
1058 int32_t d16, d26, simm16;
1059 int offset, shift;
1060 int in_crosspage_delayslot = 0;
1061 void (*samepage_function)(struct cpu *, struct m88k_instr_call *)=NULL;
1062
1063 /* Figure out the (virtual) address of the instruction: */
1064 low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page)
1065 / sizeof(struct m88k_instr_call);
1066
1067 /* Special case for branch with delayslot on the next page: */
1068 if (cpu->delay_slot == TO_BE_DELAYED && low_pc == 0) {
1069 /* fatal("[ delay-slot translation across page "
1070 "boundary ]\n"); */
1071 in_crosspage_delayslot = 1;
1072 }
1073
1074 addr = cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1)
1075 << M88K_INSTR_ALIGNMENT_SHIFT);
1076 addr += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT);
1077 cpu->pc = (MODE_int_t)addr;
1078 addr &= ~((1 << M88K_INSTR_ALIGNMENT_SHIFT) - 1);
1079
1080 /* Read the instruction word from memory: */
1081 page = cpu->cd.m88k.host_load[(uint32_t)addr >> 12];
1082
1083 if (page != NULL) {
1084 /* fatal("TRANSLATION HIT!\n"); */
1085 memcpy(ib, page + (addr & 0xffc), sizeof(ib));
1086 } else {
1087 /* fatal("TRANSLATION MISS!\n"); */
1088 if (!cpu->memory_rw(cpu, cpu->mem, addr, ib,
1089 sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
1090 fatal("to_be_translated(): read failed: TODO\n");
1091 goto bad;
1092 }
1093 }
1094
1095 iword = *((uint32_t *)&ib[0]);
1096 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1097 iword = LE32_TO_HOST(iword);
1098 else
1099 iword = BE32_TO_HOST(iword);
1100
1101
1102 #define DYNTRANS_TO_BE_TRANSLATED_HEAD
1103 #include "cpu_dyntrans.c"
1104 #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
1105
1106
1107 /*
1108 * Translate the instruction:
1109 *
1110 * NOTE: _NEVER_ allow writes to the zero register; all instructions
1111 * that use the zero register as their destination should be treated
1112 * as NOPs, except those that access memory (they should use the
1113 * scratch register instead).
1114 */
1115 if (cpu->cd.m88k.r[M88K_ZERO_REG] != 0) {
1116 fatal("INTERNAL ERROR! M88K_ZERO_REG != 0?\n");
1117 exit(1);
1118 }
1119
1120 op26 = (iword >> 26) & 0x3f;
1121 op10 = (iword >> 10) & 0x3f;
1122 d = (iword >> 21) & 0x1f;
1123 s1 = (iword >> 16) & 0x1f;
1124 s2 = iword & 0x1f;
1125 imm16 = iword & 0xffff;
1126 simm16 = (int16_t) (iword & 0xffff);
1127 cr6 = (iword >> 5) & 0x3f;
1128 d16 = ((int16_t) (iword & 0xffff)) * 4;
1129 d26 = ((int32_t)((iword & 0x03ffffff) << 6)) >> 4;
1130
1131 switch (op26) {
1132
1133 case 0x00:
1134 case 0x01:
1135 ic->f = instr(xmem_slow);
1136 ic->arg[0] = iword;
1137 if (d == M88K_ZERO_REG)
1138 ic->f = instr(nop);
1139 if (iword == 0)
1140 goto bad;
1141 break;
1142
1143 case 0x02: /* ld.hu */
1144 case 0x03: /* ld.bu */
1145 case 0x04: /* ld.d */
1146 case 0x05: /* ld */
1147 case 0x06: /* ld.h */
1148 case 0x07: /* ld.b */
1149 case 0x08: /* st.d */
1150 case 0x09: /* st */
1151 case 0x0a: /* st.h */
1152 case 0x0b: /* st.b */
1153 {
1154 int store = 0, signedness = 0, opsize = 0;
1155
1156 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1157 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1158 ic->arg[2] = imm16;
1159
1160 switch (op26) {
1161 case 0x02: opsize = 1; break;
1162 case 0x03: opsize = 0; break;
1163 case 0x04: opsize = 3; break;
1164 case 0x05: opsize = 2; break;
1165 case 0x06: opsize = 1; signedness = 1; break;
1166 case 0x07: opsize = 0; signedness = 1; break;
1167 case 0x08: store = 1; opsize = 3; break;
1168 case 0x09: store = 1; opsize = 2; break;
1169 case 0x0a: store = 1; opsize = 1; break;
1170 case 0x0b: store = 1; opsize = 0; break;
1171 }
1172
1173 if (opsize == 3 && d == 31) {
1174 fatal("m88k load/store of register pair r31/r0"
1175 " is not yet implemented\n");
1176 goto bad;
1177 }
1178
1179 ic->f = m88k_loadstore[ opsize
1180 + (store? M88K_LOADSTORE_STORE : 0)
1181 + (signedness? M88K_LOADSTORE_SIGNEDNESS:0)
1182 + (cpu->byte_order == EMUL_BIG_ENDIAN?
1183 M88K_LOADSTORE_ENDIANNESS : 0) ];
1184 }
1185 break;
1186
1187 case 0x10: /* and imm */
1188 case 0x11: /* and.u imm */
1189 case 0x12: /* mask imm */
1190 case 0x13: /* mask.u imm */
1191 case 0x14: /* xor imm */
1192 case 0x15: /* xor.u imm */
1193 case 0x16: /* or imm */
1194 case 0x17: /* or.u imm */
1195 case 0x18: /* addu imm */
1196 case 0x19: /* subu imm */
1197 case 0x1a: /* divu imm */
1198 case 0x1b: /* mulu imm */
1199 case 0x1d: /* sub imm */
1200 case 0x1e: /* div imm */
1201 case 0x1f: /* cmp imm */
1202 shift = 0;
1203 switch (op26) {
1204 case 0x10: ic->f = instr(and_imm); break;
1205 case 0x11: ic->f = instr(and_u_imm); shift = 16; break;
1206 case 0x12: ic->f = instr(mask_imm); break;
1207 case 0x13: ic->f = instr(mask_imm); shift = 16; break;
1208 case 0x14: ic->f = instr(xor_imm); break;
1209 case 0x15: ic->f = instr(xor_imm); shift = 16; break;
1210 case 0x16: ic->f = instr(or_imm); break;
1211 case 0x17: ic->f = instr(or_imm); shift = 16; break;
1212 case 0x18: ic->f = instr(addu_imm); break;
1213 case 0x19: ic->f = instr(subu_imm); break;
1214 case 0x1a: ic->f = instr(divu_imm); break;
1215 case 0x1b: ic->f = instr(mulu_imm); break;
1216 case 0x1d: ic->f = instr(sub_imm); break;
1217 case 0x1e: ic->f = instr(div_imm); break;
1218 case 0x1f: ic->f = instr(cmp_imm); break;
1219 }
1220
1221 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1222 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1223 ic->arg[2] = imm16 << shift;
1224
1225 /* Optimization for or d,r0,imm and similar */
1226 if (s1 == M88K_ZERO_REG && ic->f == instr(or_imm)) {
1227 if (ic->arg[2] == 0)
1228 ic->f = instr(or_r0_imm0);
1229 else
1230 ic->f = instr(or_r0_imm);
1231 }
1232 if (ic->arg[2] == 0 && ic->f == instr(addu_imm))
1233 ic->f = instr(addu_s2r0);
1234
1235 if (d == s1 && ic->arg[2] == 1) {
1236 if (ic->f == instr(addu_imm))
1237 ic->f = instr(inc_reg);
1238 if (ic->f == instr(subu_imm))
1239 ic->f = instr(dec_reg);
1240 }
1241
1242 if (d == M88K_ZERO_REG)
1243 ic->f = instr(nop);
1244 break;
1245
1246 case 0x20:
1247 if ((iword & 0x001ff81f) == 0x00004000) {
1248 ic->f = instr(ldcr);
1249 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1250 ic->arg[1] = cr6;
1251 if (d == M88K_ZERO_REG)
1252 ic->arg[0] = (size_t)
1253 &cpu->cd.m88k.zero_scratch;
1254 } else if ((iword & 0x001ff81f) == 0x00004800) {
1255 ic->f = instr(fldcr);
1256 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1257 ic->arg[1] = cr6;
1258 if (d == M88K_ZERO_REG)
1259 ic->arg[0] = (size_t)
1260 &cpu->cd.m88k.zero_scratch;
1261 } else if ((iword & 0x03e0f800) == 0x00008000) {
1262 ic->f = instr(stcr);
1263 ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
1264 ic->arg[1] = cr6;
1265 if (s1 != s2)
1266 goto bad;
1267 } else if ((iword & 0x03e0f800) == 0x00008800) {
1268 ic->f = instr(fstcr);
1269 ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
1270 ic->arg[1] = cr6;
1271 if (s1 != s2)
1272 goto bad;
1273 } else if ((iword & 0x0000f800) == 0x0000c000) {
1274 ic->f = instr(xcr);
1275 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1276 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1277 ic->arg[2] = cr6;
1278 if (s1 != s2)
1279 goto bad;
1280 } else
1281 goto bad;
1282 break;
1283
1284 case 0x30: /* br */
1285 case 0x31: /* br.n */
1286 case 0x32: /* bsr */
1287 case 0x33: /* bsr.n */
1288 switch (op26) {
1289 case 0x30:
1290 ic->f = instr(br);
1291 samepage_function = instr(br_samepage);
1292 if (cpu->translation_readahead > 1)
1293 cpu->translation_readahead = 1;
1294 break;
1295 case 0x31:
1296 ic->f = instr(br_n);
1297 if (cpu->translation_readahead > 2)
1298 cpu->translation_readahead = 2;
1299 break;
1300 case 0x32:
1301 ic->f = instr(bsr);
1302 samepage_function = instr(bsr_samepage);
1303 break;
1304 case 0x33:
1305 ic->f = instr(bsr_n);
1306 break;
1307 }
1308
1309 offset = (addr & 0xffc) + d26;
1310
1311 /* Prepare both samepage and offset style args.
1312 (Only one will be used in the actual instruction.) */
1313 ic->arg[0] = (size_t) ( cpu->cd.m88k.cur_ic_page +
1314 (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
1315 ic->arg[1] = offset;
1316
1317 if (offset >= 0 && offset <= 0xffc &&
1318 samepage_function != NULL)
1319 ic->f = samepage_function;
1320
1321 if (cpu->machine->show_trace_tree) {
1322 if (op26 == 0x32)
1323 ic->f = instr(bsr_trace);
1324 if (op26 == 0x33)
1325 ic->f = instr(bsr_n_trace);
1326 }
1327
1328 break;
1329
1330 case 0x34: /* bb0 */
1331 case 0x35: /* bb0.n */
1332 case 0x36: /* bb1 */
1333 case 0x37: /* bb1.n */
1334 switch (op26) {
1335 case 0x34:
1336 ic->f = instr(bb0);
1337 samepage_function = instr(bb0_samepage);
1338 break;
1339 case 0x35:
1340 ic->f = instr(bb0_n);
1341 break;
1342 case 0x36:
1343 ic->f = instr(bb1);
1344 samepage_function = instr(bb1_samepage);
1345 break;
1346 case 0x37:
1347 ic->f = instr(bb1_n);
1348 break;
1349 }
1350
1351 ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
1352 ic->arg[1] = (uint32_t) (1 << d);
1353
1354 offset = (addr & 0xffc) + d16;
1355 ic->arg[2] = offset;
1356
1357 if (offset >= 0 && offset <= 0xffc &&
1358 samepage_function != NULL) {
1359 ic->f = samepage_function;
1360 ic->arg[2] = (size_t) ( cpu->cd.m88k.cur_ic_page +
1361 (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
1362 }
1363 break;
1364
1365 case 0x3a: /* bcnd */
1366 case 0x3b: /* bcnd.n */
1367 ic->f = m88k_bcnd[d + 32 * (op26 & 1)];
1368 samepage_function = m88k_bcnd[64 + d + 32 * (op26 & 1)];
1369
1370 if (ic->f == NULL)
1371 goto bad;
1372
1373 ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
1374
1375 offset = (addr & 0xffc) + d16;
1376 ic->arg[2] = offset;
1377
1378 if (offset >= 0 && offset <= 0xffc &&
1379 samepage_function != NULL) {
1380 ic->f = samepage_function;
1381 ic->arg[2] = (size_t) ( cpu->cd.m88k.cur_ic_page +
1382 (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
1383 }
1384 break;
1385
1386 case 0x3c:
1387 switch (op10) {
1388
1389 case 0x20: /* clr */
1390 case 0x22: /* set */
1391 case 0x24: /* ext */
1392 case 0x26: /* extu */
1393 case 0x28: /* mak */
1394 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1395 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1396 ic->arg[2] = iword & 0x3ff;
1397
1398 switch (op10) {
1399 case 0x20: ic->f = instr(mask_imm);
1400 {
1401 int w = ic->arg[2] >> 5;
1402 int o = ic->arg[2] & 0x1f;
1403 uint32_t x = w == 0? 0xffffffff
1404 : (1 << w) - 1;
1405 x <<= o;
1406 ic->arg[2] = ~x;
1407 }
1408 break;
1409 case 0x22: ic->f = instr(or_imm);
1410 {
1411 int w = ic->arg[2] >> 5;
1412 int o = ic->arg[2] & 0x1f;
1413 uint32_t x = w == 0? 0xffffffff
1414 : (1 << w) - 1;
1415 x <<= o;
1416 ic->arg[2] = x;
1417 }
1418 break;
1419 case 0x24: ic->f = instr(ext_imm); break;
1420 case 0x26: ic->f = instr(extu_imm); break;
1421 case 0x28: ic->f = instr(mak_imm); break;
1422 }
1423
1424 if (d == M88K_ZERO_REG)
1425 ic->f = instr(nop);
1426 break;
1427
1428 case 0x34: /* tb0 */
1429 case 0x36: /* tb1 */
1430 ic->arg[0] = 1 << d;
1431 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1432 ic->arg[2] = iword & 0x1ff;
1433 switch (op10) {
1434 case 0x34: ic->f = instr(tb0); break;
1435 case 0x36: ic->f = instr(tb1); break;
1436 }
1437 break;
1438
1439 default:goto bad;
1440 }
1441 break;
1442
1443 case 0x3d:
1444 if ((iword & 0xf000) <= 0x3fff ) {
1445 /* Load, Store, xmem, and lda: */
1446 int op = 0, opsize, user = 0, wt = 0;
1447 int signedness = 1, scaled = 0;
1448
1449 switch (iword & 0xf000) {
1450 case 0x2000: op = 1; /* st */ break;
1451 case 0x3000: op = 2; /* lda */ break;
1452 default: if ((iword & 0xf800) >= 0x0800)
1453 op = 0; /* ld */
1454 else
1455 op = 3; /* xmem */
1456 }
1457
1458 /* for (most) ld, st, lda: */
1459 opsize = (iword >> 10) & 3;
1460
1461 /* Turn opsize into x, where size = 1 << x: */
1462 opsize = 3 - opsize;
1463
1464 if (op == 3) {
1465 /* xmem: */
1466 switch ((iword >> 10) & 3) {
1467 case 0: opsize = 0; break;
1468 case 1: opsize = 2; break;
1469 default:fatal("Weird xmem opsize/type?\n");
1470 goto bad;
1471 }
1472 } else {
1473 if ((iword & 0xf800) == 0x800) {
1474 signedness = 0;
1475 if ((iword & 0xf00) < 0xc00)
1476 opsize = 1;
1477 else
1478 opsize = 0;
1479 } else {
1480 if (opsize >= 2 || op == 1)
1481 signedness = 0;
1482 }
1483 }
1484
1485 if (iword & 0x100)
1486 user = 1;
1487 if (iword & 0x80)
1488 wt = 1;
1489 if (iword & 0x200)
1490 scaled = 1;
1491
1492 if (wt) {
1493 fatal("wt bit not yet implemented! TODO\n");
1494 goto bad;
1495 }
1496
1497 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1498 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1499 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
1500
1501 if (op == 0 || op == 1) {
1502 /* ld or st: */
1503 ic->f = m88k_loadstore[ opsize
1504 + (op==1? M88K_LOADSTORE_STORE : 0)
1505 + (signedness? M88K_LOADSTORE_SIGNEDNESS:0)
1506 + (cpu->byte_order == EMUL_BIG_ENDIAN?
1507 M88K_LOADSTORE_ENDIANNESS : 0)
1508 + (scaled? M88K_LOADSTORE_SCALEDNESS : 0)
1509 + (user? M88K_LOADSTORE_USR : 0)
1510 + M88K_LOADSTORE_REGISTEROFFSET ];
1511
1512 if (op == 0 && d == M88K_ZERO_REG)
1513 ic->f = instr(nop);
1514
1515 if (opsize == 3 && d == 31) {
1516 fatal("m88k load/store of register "
1517 "pair r31/r0: TODO\n");
1518 goto bad;
1519 }
1520 } else if (op == 2) {
1521 /* lda: */
1522 if (scaled) {
1523 switch (opsize) {
1524 case 0: ic->f = instr(addu); break;
1525 case 1: ic->f = instr(lda_reg_2); break;
1526 case 2: ic->f = instr(lda_reg_4); break;
1527 case 3: ic->f = instr(lda_reg_8); break;
1528 }
1529 } else {
1530 ic->f = instr(addu);
1531 }
1532 } else {
1533 /* xmem: */
1534 ic->f = instr(xmem_slow);
1535 ic->arg[0] = iword;
1536 if (d == M88K_ZERO_REG)
1537 ic->f = instr(nop);
1538 }
1539 } else switch ((iword >> 8) & 0xff) {
1540 case 0x40: /* and */
1541 case 0x44: /* and.c */
1542 case 0x50: /* xor */
1543 case 0x54: /* xor.c */
1544 case 0x58: /* or */
1545 case 0x5c: /* or.c */
1546 case 0x60: /* addu */
1547 case 0x61: /* addu.co */
1548 case 0x62: /* addu.ci */
1549 case 0x64: /* subu */
1550 case 0x65: /* subu.co */
1551 case 0x66: /* subu.ci */
1552 case 0x68: /* divu */
1553 case 0x6c: /* mul */
1554 case 0x78: /* div */
1555 case 0x7c: /* cmp */
1556 case 0x80: /* clr */
1557 case 0x88: /* set */
1558 case 0x90: /* ext */
1559 case 0x98: /* extu */
1560 case 0xa0: /* mak */
1561 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1562 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1563 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
1564
1565 switch ((iword >> 8) & 0xff) {
1566 case 0x40: ic->f = instr(and); break;
1567 case 0x44: ic->f = instr(and_c); break;
1568 case 0x50: ic->f = instr(xor); break;
1569 case 0x54: ic->f = instr(xor_c); break;
1570 case 0x58: ic->f = instr(or); break;
1571 case 0x5c: ic->f = instr(or_c); break;
1572 case 0x60: ic->f = instr(addu); break;
1573 case 0x61: ic->f = instr(addu_co); break;
1574 case 0x62: ic->f = instr(addu_ci); break;
1575 case 0x64: ic->f = instr(subu); break;
1576 case 0x65: ic->f = instr(subu_co); break;
1577 case 0x66: ic->f = instr(subu_ci); break;
1578 case 0x68: ic->f = instr(divu); break;
1579 case 0x6c: ic->f = instr(mul); break;
1580 case 0x78: ic->f = instr(div); break;
1581 case 0x7c: ic->f = instr(cmp); break;
1582 case 0x80: ic->f = instr(clr); break;
1583 case 0x88: ic->f = instr(set); break;
1584 case 0x90: ic->f = instr(ext); break;
1585 case 0x98: ic->f = instr(extu); break;
1586 case 0xa0: ic->f = instr(mak); break;
1587 }
1588
1589 /* Optimization for or rX,r0,rY etc: */
1590 if (s1 == M88K_ZERO_REG && ic->f == instr(or))
1591 ic->f = instr(or_r0);
1592 if (s2 == M88K_ZERO_REG && ic->f == instr(addu))
1593 ic->f = instr(addu_s2r0);
1594 if (d == M88K_ZERO_REG)
1595 ic->f = instr(nop);
1596 break;
1597 case 0xc0: /* jmp */
1598 case 0xc4: /* jmp.n */
1599 case 0xc8: /* jsr */
1600 case 0xcc: /* jsr.n */
1601 switch ((iword >> 8) & 0xff) {
1602 case 0xc0: ic->f = instr(jmp);
1603 if (cpu->translation_readahead > 1)
1604 cpu->translation_readahead = 1;
1605 break;
1606 case 0xc4: ic->f = instr(jmp_n);
1607 if (cpu->translation_readahead > 2)
1608 cpu->translation_readahead = 2;
1609 break;
1610 case 0xc8: ic->f = instr(jsr); break;
1611 case 0xcc: ic->f = instr(jsr_n); break;
1612 }
1613
1614 ic->arg[1] = (addr & 0xffc) + 4;
1615 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
1616
1617 if (((iword >> 8) & 0x04) == 0x04)
1618 ic->arg[1] = (addr & 0xffc) + 8;
1619
1620 if (cpu->machine->show_trace_tree &&
1621 s2 == M88K_RETURN_REG) {
1622 if (ic->f == instr(jmp))
1623 ic->f = instr(jmp_trace);
1624 if (ic->f == instr(jmp_n))
1625 ic->f = instr(jmp_n_trace);
1626 }
1627 if (cpu->machine->show_trace_tree) {
1628 if (ic->f == instr(jsr))
1629 ic->f = instr(jsr_trace);
1630 if (ic->f == instr(jsr_n))
1631 ic->f = instr(jsr_n_trace);
1632 }
1633 break;
1634 case 0xe8: /* ff1 */
1635 case 0xec: /* ff0 */
1636 switch ((iword >> 8) & 0xff) {
1637 case 0xe8: ic->f = instr(ff1); break;
1638 case 0xec: ic->f = instr(ff0); break;
1639 }
1640
1641 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
1642 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
1643
1644 if (d == M88K_ZERO_REG)
1645 ic->f = instr(nop);
1646 break;
1647 case 0xfc:
1648 switch (iword & 0xff) {
1649 case 0x00:
1650 ic->f = instr(rte);
1651 break;
1652 case (M88K_PROM_INSTR & 0xff):
1653 ic->f = instr(prom_call);
1654 break;
1655 default:fatal("Unimplemented 3d/fc instruction\n");
1656 goto bad;
1657 }
1658 break;
1659 default:goto bad;
1660 }
1661 break;
1662
1663 default:goto bad;
1664 }
1665
1666
1667 #define DYNTRANS_TO_BE_TRANSLATED_TAIL
1668 #include "cpu_dyntrans.c"
1669 #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
1670 }
1671

  ViewVC Help
Powered by ViewVC 1.1.26