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

Annotation of /trunk/src/cpus/cpu_m88k_instr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 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 dpavlin 40 /*
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 dpavlin 42 * $Id: cpu_m88k_instr.c,v 1.33 2007/06/05 06:41:30 debug Exp $
29 dpavlin 40 *
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 dpavlin 42 #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 dpavlin 40 /*
49     * nop: Do nothing.
50     */
51     X(nop)
52     {
53     }
54    
55    
56     /*
57 dpavlin 42 * br_samepage: Branch (to within the same translated page)
58     * bsr_samepage: Branch to subroutine (to within the same translated page)
59 dpavlin 40 *
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 dpavlin 42 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 dpavlin 40
73    
74     /*
75 dpavlin 42 * 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 dpavlin 40 *
80 dpavlin 42 * arg[1] = relative offset from start of page
81 dpavlin 40 */
82     X(br)
83     {
84 dpavlin 42 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 dpavlin 40
153 dpavlin 42
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 dpavlin 40 quick_pc_to_pointers(cpu);
296     }
297 dpavlin 42 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 dpavlin 40
377    
378     /*
379 dpavlin 42 * 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 dpavlin 40 * or_imm: d = s1 | imm
499 dpavlin 42 * 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 dpavlin 40 *
512     * arg[0] = pointer to register d
513     * arg[1] = pointer to register s1
514     * arg[2] = imm
515     */
516 dpavlin 42 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 dpavlin 40 {
531 dpavlin 42 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 dpavlin 40 }
537 dpavlin 42 X(divu_imm)
538 dpavlin 40 {
539 dpavlin 42 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 dpavlin 40 }
548 dpavlin 42 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 dpavlin 40
565 dpavlin 42 if (a < 0 && res >= 0) {
566     SYNCH_PC;
567     m88k_exception(cpu, M88K_EXCEPTION_INTEGER_OVERFLOW, 0);
568     return;
569     }
570 dpavlin 40
571 dpavlin 42 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 dpavlin 40 /*****************************************************************************/
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 dpavlin 42 uint32_t op26, op10, d, s1, s2, cr6, imm16;
1058 dpavlin 40 int32_t d16, d26, simm16;
1059     int offset, shift;
1060     int in_crosspage_delayslot = 0;
1061 dpavlin 42 void (*samepage_function)(struct cpu *, struct m88k_instr_call *)=NULL;
1062 dpavlin 40
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 dpavlin 42 if (cpu->cd.m88k.r[M88K_ZERO_REG] != 0) {
1116     fatal("INTERNAL ERROR! M88K_ZERO_REG != 0?\n");
1117     exit(1);
1118     }
1119 dpavlin 40
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 dpavlin 42 cr6 = (iword >> 5) & 0x3f;
1128 dpavlin 40 d16 = ((int16_t) (iword & 0xffff)) * 4;
1129     d26 = ((int32_t)((iword & 0x03ffffff) << 6)) >> 4;
1130    
1131     switch (op26) {
1132    
1133 dpavlin 42 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 dpavlin 40 shift = 0;
1203     switch (op26) {
1204 dpavlin 42 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 dpavlin 40 case 0x16: ic->f = instr(or_imm); break;
1211     case 0x17: ic->f = instr(or_imm); shift = 16; break;
1212 dpavlin 42 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 dpavlin 40 }
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 dpavlin 42 /* 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 dpavlin 40
1235 dpavlin 42 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 dpavlin 40 if (d == M88K_ZERO_REG)
1243     ic->f = instr(nop);
1244     break;
1245    
1246 dpavlin 42 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 dpavlin 40
1284 dpavlin 42 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 dpavlin 40 offset = (addr & 0xffc) + d26;
1310 dpavlin 42
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 dpavlin 40 (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
1362 dpavlin 42 }
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 dpavlin 40 ic->f = samepage_function;
1381 dpavlin 42 ic->arg[2] = (size_t) ( cpu->cd.m88k.cur_ic_page +
1382     (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
1383 dpavlin 40 }
1384     break;
1385    
1386 dpavlin 42 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 dpavlin 40 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