1 /*
2 * Copyright (C) 2007-2021 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 * M88K instructions.
29 *
30 * Individual functions should keep track of cpu->n_translated_instrs.
31 * (If no instruction was executed, then it should be decreased. If, say, 4
32 * instructions were combined into one function and executed, then it should
33 * be increased by 3.)
34 */
35
36
37 #define SYNCH_PC { \
38 int low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page) \
39 / sizeof(struct m88k_instr_call); \
40 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) \
41 << M88K_INSTR_ALIGNMENT_SHIFT); \
42 cpu->pc += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT); \
43 }
44
45 #define ABORT_EXECUTION { SYNCH_PC; \
46 fatal("Execution aborted at: pc = 0x%08x\n", (int)cpu->pc); \
47 cpu->cd.m88k.next_ic = ¬hing_call; \
48 cpu->running = 0; \
49 debugger_n_steps_left_before_interaction = 0; }
50
51
52 /*
53 * nop: Do nothing.
54 */
X(nop)55 X(nop)
56 {
57 }
58
59
60 /*
61 * br_samepage: Branch (to within the same translated page)
62 * bsr_samepage: Branch to subroutine (to within the same translated page)
63 *
64 * arg[0] = pointer to new instr_call
65 * arg[2] = offset to return address, from start of page
66 */
X(br_samepage)67 X(br_samepage)
68 {
69 cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[0];
70 }
X(bsr_samepage)71 X(bsr_samepage)
72 {
73 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc &
74 ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT))
75 + ic->arg[2];
76 cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[0];
77 }
78
79
80 /*
81 * br: Branch (to a different translated page)
82 * br.n: Branch (to a different translated page) with delay slot
83 * bsr: Branch to subroutine (to a different translated page)
84 * bsr.n: Branch to subroutine (to a different page) with delay slot
85 *
86 * arg[1] = relative offset from start of page
87 * arg[2] = offset to return address, from start of page
88 */
X(br)89 X(br)
90 {
91 cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[1]);
92 quick_pc_to_pointers(cpu);
93 }
X(br_n)94 X(br_n)
95 {
96 cpu->cd.m88k.delay_target = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
97 M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[1];
98 cpu->delay_slot = TO_BE_DELAYED;
99 ic[1].f(cpu, ic+1);
100 cpu->n_translated_instrs ++;
101 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
102 /* Note: Must be non-delayed when jumping to the new pc: */
103 cpu->delay_slot = NOT_DELAYED;
104 cpu->pc = cpu->cd.m88k.delay_target;
105 quick_pc_to_pointers(cpu);
106 } else
107 cpu->delay_slot = NOT_DELAYED;
108 }
X(bsr)109 X(bsr)
110 {
111 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
112 M88K_INSTR_ALIGNMENT_SHIFT);
113 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + ic->arg[2];
114 cpu->pc = (uint32_t) (cpu->pc + ic->arg[1]);
115 quick_pc_to_pointers(cpu);
116 }
X(bsr_n)117 X(bsr_n)
118 {
119 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
120 M88K_INSTR_ALIGNMENT_SHIFT);
121 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + ic->arg[2] + 4;
122 cpu->cd.m88k.delay_target = cpu->pc + ic->arg[1];
123 cpu->delay_slot = TO_BE_DELAYED;
124 ic[1].f(cpu, ic+1);
125 cpu->n_translated_instrs ++;
126 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
127 /* Note: Must be non-delayed when jumping to the new pc: */
128 cpu->delay_slot = NOT_DELAYED;
129 cpu->pc = cpu->cd.m88k.delay_target;
130 quick_pc_to_pointers(cpu);
131 } else
132 cpu->delay_slot = NOT_DELAYED;
133 }
X(bsr_trace)134 X(bsr_trace)
135 {
136 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
137 M88K_INSTR_ALIGNMENT_SHIFT);
138 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + ic->arg[2];
139 cpu->pc = (uint32_t) (cpu->pc + ic->arg[1]);
140 cpu_functioncall_trace(cpu, cpu->pc);
141 quick_pc_to_pointers(cpu);
142 }
X(bsr_n_trace)143 X(bsr_n_trace)
144 {
145 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
146 M88K_INSTR_ALIGNMENT_SHIFT);
147 cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + ic->arg[2] + 4;
148 cpu->cd.m88k.delay_target = cpu->pc + ic->arg[1];
149 cpu->delay_slot = TO_BE_DELAYED;
150 ic[1].f(cpu, ic+1);
151 cpu->n_translated_instrs ++;
152 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
153 /* Note: Must be non-delayed when jumping to the new pc: */
154 cpu->delay_slot = NOT_DELAYED;
155 cpu->pc = cpu->cd.m88k.delay_target;
156 cpu_functioncall_trace(cpu, cpu->pc);
157 quick_pc_to_pointers(cpu);
158 } else
159 cpu->delay_slot = NOT_DELAYED;
160 }
161
162
163 /*
164 * bb? Branch if a bit in a register is 0 or 1.
165 * bb?_samepage: Branch within the same translated page.
166 * bb?_n_*: With delay slot.
167 *
168 * arg[0] = pointer to source register to test (s1).
169 * arg[1] = uint32_t mask to test (e.g. 0x00010000 to test bit 16)
170 * arg[2] = offset from start of current page _OR_ pointer to new instr_call
171 */
X(bb0)172 X(bb0)
173 {
174 if (!(reg(ic->arg[0]) & ic->arg[1])) {
175 cpu->pc = (cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
176 quick_pc_to_pointers(cpu);
177 }
178 }
X(bb0_samepage)179 X(bb0_samepage)
180 {
181 if (!(reg(ic->arg[0]) & ic->arg[1]))
182 cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[2];
183 }
X(bb0_n)184 X(bb0_n)
185 {
186 int cond = !(reg(ic->arg[0]) & (uint32_t)ic->arg[1]);
187
188 SYNCH_PC;
189
190 if (cond)
191 cpu->cd.m88k.delay_target =
192 (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
193 M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[2];
194 else
195 cpu->cd.m88k.delay_target = cpu->pc + 8;
196
197 cpu->delay_slot = TO_BE_DELAYED;
198 ic[1].f(cpu, ic+1);
199 cpu->n_translated_instrs ++;
200 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
201 /* Note: Must be non-delayed when jumping to the new pc: */
202 cpu->delay_slot = NOT_DELAYED;
203 if (cond) {
204 cpu->pc = cpu->cd.m88k.delay_target;
205 quick_pc_to_pointers(cpu);
206 } else
207 cpu->cd.m88k.next_ic ++;
208 } else
209 cpu->delay_slot = NOT_DELAYED;
210 }
X(bb1)211 X(bb1)
212 {
213 if (reg(ic->arg[0]) & ic->arg[1]) {
214 cpu->pc = (cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
215 quick_pc_to_pointers(cpu);
216 }
217 }
X(bb1_samepage)218 X(bb1_samepage)
219 {
220 if (reg(ic->arg[0]) & ic->arg[1])
221 cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[2];
222 }
X(bb1_n)223 X(bb1_n)
224 {
225 int cond = reg(ic->arg[0]) & ic->arg[1];
226
227 SYNCH_PC;
228
229 if (cond)
230 cpu->cd.m88k.delay_target =
231 (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
232 M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[2];
233 else
234 cpu->cd.m88k.delay_target = cpu->pc + 8;
235
236 cpu->delay_slot = TO_BE_DELAYED;
237 ic[1].f(cpu, ic+1);
238 cpu->n_translated_instrs ++;
239 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
240 /* Note: Must be non-delayed when jumping to the new pc: */
241 cpu->delay_slot = NOT_DELAYED;
242 if (cond) {
243 cpu->pc = cpu->cd.m88k.delay_target;
244 quick_pc_to_pointers(cpu);
245 } else
246 cpu->cd.m88k.next_ic ++;
247 } else
248 cpu->delay_slot = NOT_DELAYED;
249 }
250
251
252 /*
253 * ff0, ff1: Find first cleared/set bit in a register
254 *
255 * arg[0] = pointer to register d
256 * arg[2] = pointer to register s2
257 */
X(ff0)258 X(ff0)
259 {
260 uint32_t mask = 0x80000000, s2 = reg(ic->arg[2]);
261 int n = 31;
262
263 for (;;) {
264 if (!(s2 & mask)) {
265 reg(ic->arg[0]) = n;
266 return;
267 }
268 mask >>= 1; n--;
269 if (mask == 0) {
270 reg(ic->arg[0]) = 32;
271 return;
272 }
273 }
274 }
X(ff1)275 X(ff1)
276 {
277 uint32_t mask = 0x80000000, s2 = reg(ic->arg[2]);
278 int n = 31;
279
280 for (;;) {
281 if (s2 & mask) {
282 reg(ic->arg[0]) = n;
283 return;
284 }
285 mask >>= 1; n--;
286 if (mask == 0) {
287 reg(ic->arg[0]) = 32;
288 return;
289 }
290 }
291 }
292
293
294 /* Include all automatically generated bcnd and bcnd.n instructions: */
295 #include "tmp_m88k_bcnd.cc"
296
297
298 /* Include all automatically generated load/store instructions: */
299 #include "tmp_m88k_loadstore.cc"
300 #define M88K_LOADSTORE_STORE 4
301 #define M88K_LOADSTORE_SIGNEDNESS 8
302 #define M88K_LOADSTORE_ENDIANNESS 16
303 #define M88K_LOADSTORE_SCALEDNESS 32
304 #define M88K_LOADSTORE_USR 64
305 #define M88K_LOADSTORE_REGISTEROFFSET 128
306 #define M88K_LOADSTORE_NO_PC_SYNC 256
307
308
309 /*
310 * jmp: Jump to register
311 * jmp.n: Jump to register, with delay slot
312 * jsr: Jump to register, set r1 to return address
313 * jsr.n: Jump to register, set r1 to return address, with delay slot
314 *
315 * arg[1] = offset to return address, from start of current page
316 * arg[2] = pointer to register s2
317 */
X(jmp)318 X(jmp)
319 {
320 cpu->pc = reg(ic->arg[2]) & ~3;
321 quick_pc_to_pointers(cpu);
322 }
X(jmp_n)323 X(jmp_n)
324 {
325 cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3;
326 cpu->delay_slot = TO_BE_DELAYED;
327 ic[1].f(cpu, ic+1);
328 cpu->n_translated_instrs ++;
329 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
330 /* Note: Must be non-delayed when jumping to the new pc: */
331 cpu->delay_slot = NOT_DELAYED;
332 cpu->pc = cpu->cd.m88k.delay_target;
333 quick_pc_to_pointers(cpu);
334 } else
335 cpu->delay_slot = NOT_DELAYED;
336 }
X(jmp_trace)337 X(jmp_trace)
338 {
339 cpu->pc = reg(ic->arg[2]) & ~3;
340 cpu_functioncall_trace_return(cpu);
341 quick_pc_to_pointers(cpu);
342 }
X(jmp_n_trace)343 X(jmp_n_trace)
344 {
345 cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3;
346 cpu->delay_slot = TO_BE_DELAYED;
347 ic[1].f(cpu, ic+1);
348 cpu->n_translated_instrs ++;
349 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
350 /* Note: Must be non-delayed when jumping to the new pc: */
351 cpu->delay_slot = NOT_DELAYED;
352 cpu->pc = cpu->cd.m88k.delay_target;
353 cpu_functioncall_trace_return(cpu);
354 quick_pc_to_pointers(cpu);
355 } else
356 cpu->delay_slot = NOT_DELAYED;
357 }
X(jsr)358 X(jsr)
359 {
360 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1];
361 cpu->pc = reg(ic->arg[2]) & ~3;
362 quick_pc_to_pointers(cpu);
363 }
X(jsr_n)364 X(jsr_n)
365 {
366 cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3;
367 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1];
368 cpu->delay_slot = TO_BE_DELAYED;
369 ic[1].f(cpu, ic+1);
370 cpu->n_translated_instrs ++;
371 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
372 /* Note: Must be non-delayed when jumping to the new pc: */
373 cpu->delay_slot = NOT_DELAYED;
374 cpu->pc = cpu->cd.m88k.delay_target;
375 quick_pc_to_pointers(cpu);
376 } else
377 cpu->delay_slot = NOT_DELAYED;
378 }
X(jsr_trace)379 X(jsr_trace)
380 {
381 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1];
382 cpu->pc = reg(ic->arg[2]) & ~3;
383 cpu_functioncall_trace(cpu, cpu->pc);
384 quick_pc_to_pointers(cpu);
385 }
X(jsr_n_trace)386 X(jsr_n_trace)
387 {
388 cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3;
389 cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1];
390 cpu->delay_slot = TO_BE_DELAYED;
391 ic[1].f(cpu, ic+1);
392 cpu->n_translated_instrs ++;
393 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
394 /* Note: Must be non-delayed when jumping to the new pc: */
395 cpu->delay_slot = NOT_DELAYED;
396 cpu->pc = cpu->cd.m88k.delay_target;
397 cpu_functioncall_trace(cpu, cpu->pc);
398 quick_pc_to_pointers(cpu);
399 } else
400 cpu->delay_slot = NOT_DELAYED;
401 }
402
403
404 /*
405 * cmp_imm: Compare S1 with immediate value.
406 * cmp: Compare S1 with S2.
407 *
408 * arg[0] = pointer to register d
409 * arg[1] = pointer to register s1
410 * arg[2] = pointer to register s2 or imm
411 */
m88k_cmp(struct cpu * cpu,struct m88k_instr_call * ic,uint32_t y)412 static void m88k_cmp(struct cpu *cpu, struct m88k_instr_call *ic, uint32_t y)
413 {
414 uint32_t x = reg(ic->arg[1]);
415 uint32_t r;
416
417 if (x == y) {
418 r = M88K_CMP_HS | M88K_CMP_LS | M88K_CMP_GE
419 | M88K_CMP_LE | M88K_CMP_EQ;
420 } else {
421 if (x > y)
422 r = M88K_CMP_NE | M88K_CMP_HS | M88K_CMP_HI;
423 else
424 r = M88K_CMP_NE | M88K_CMP_LO | M88K_CMP_LS;
425 if ((int32_t)x > (int32_t)y)
426 r |= M88K_CMP_GE | M88K_CMP_GT;
427 else
428 r |= M88K_CMP_LT | M88K_CMP_LE;
429 }
430
431 reg(ic->arg[0]) = r;
432 }
X(cmp_imm)433 X(cmp_imm) { m88k_cmp(cpu, ic, ic->arg[2]); }
X(cmp)434 X(cmp) { m88k_cmp(cpu, ic, reg(ic->arg[2])); }
435
436
437 /*
438 * extu_imm: Extract bits, unsigned, immediate W<O>.
439 * extu: Extract bits, unsigned, W<O> taken from register s2.
440 * ext_imm: Extract bits, signed, immediate W<O>.
441 * ext: Extract bits, signed, W<O> taken from register s2.
442 * mak_imm: Make bit field, immediate W<O>.
443 * mak: Make bit field, W<O> taken from register s2.
444 * rot: Rotate s1 right, nr of steps taken from s2.
445 * clr: Clear bits, W<O> taken from register s2.
446 * set: Set bits, W<O> taken from register s2.
447 *
448 * arg[0] = pointer to register d
449 * arg[1] = pointer to register s1
450 * arg[2] = pointer to register s2 or 10 bits wwwwwooooo
451 */
m88k_extu(struct cpu * cpu,struct m88k_instr_call * ic,int w,int o)452 static void m88k_extu(struct cpu *cpu, struct m88k_instr_call *ic, int w, int o)
453 {
454 uint32_t x = reg(ic->arg[1]) >> o;
455 if (w != 0) {
456 x <<= (32-w);
457 x >>= (32-w);
458 }
459 reg(ic->arg[0]) = x;
460 }
m88k_ext(struct cpu * cpu,struct m88k_instr_call * ic,int w,int o)461 static void m88k_ext(struct cpu *cpu, struct m88k_instr_call *ic, int w, int o)
462 {
463 int32_t x = reg(ic->arg[1]);
464 x >>= o; /* signed (arithmetic) shift */
465 if (w != 0) {
466 x <<= (32-w);
467 x >>= (32-w);
468 }
469 reg(ic->arg[0]) = x;
470 }
m88k_mak(struct cpu * cpu,struct m88k_instr_call * ic,int w,int o)471 static void m88k_mak(struct cpu *cpu, struct m88k_instr_call *ic, int w, int o)
472 {
473 uint32_t x = reg(ic->arg[1]);
474 if (w != 0) {
475 x <<= (32-w);
476 x >>= (32-w);
477 }
478 reg(ic->arg[0]) = x << o;
479 }
X(extu_imm)480 X(extu_imm)
481 {
482 m88k_extu(cpu, ic, ic->arg[2] >> 5, ic->arg[2] & 0x1f);
483 }
X(extu)484 X(extu)
485 {
486 m88k_extu(cpu, ic, (reg(ic->arg[2]) >> 5) & 0x1f,
487 reg(ic->arg[2]) & 0x1f);
488 }
X(ext_imm)489 X(ext_imm)
490 {
491 m88k_ext(cpu, ic, ic->arg[2] >> 5, ic->arg[2] & 0x1f);
492 }
X(ext)493 X(ext)
494 {
495 m88k_ext(cpu, ic, (reg(ic->arg[2]) >> 5) & 0x1f,
496 reg(ic->arg[2]) & 0x1f);
497 }
X(mak_imm)498 X(mak_imm)
499 {
500 m88k_mak(cpu, ic, ic->arg[2] >> 5, ic->arg[2] & 0x1f);
501 }
X(mak)502 X(mak)
503 {
504 m88k_mak(cpu, ic, (reg(ic->arg[2]) >> 5) & 0x1f,
505 reg(ic->arg[2]) & 0x1f);
506 }
m88k_rot(struct cpu * cpu,struct m88k_instr_call * ic,int n)507 static void m88k_rot(struct cpu *cpu, struct m88k_instr_call *ic, int n)
508 {
509 uint32_t x = reg(ic->arg[1]);
510
511 if (n != 0) {
512 uint32_t mask = (1 << n) - 1;
513 uint32_t bits = x & mask;
514 x >>= n;
515 x |= (bits << (32-n));
516 }
517
518 reg(ic->arg[0]) = x;
519 }
X(rot_imm)520 X(rot_imm)
521 {
522 m88k_rot(cpu, ic, ic->arg[2] & 0x1f);
523 }
X(rot)524 X(rot)
525 {
526 m88k_rot(cpu, ic, reg(ic->arg[2]) & 0x1f);
527 }
X(clr)528 X(clr)
529 {
530 int w = (reg(ic->arg[2]) >> 5) & 0x1f, o = reg(ic->arg[2]) & 0x1f;
531 uint32_t x = w == 0? 0xffffffff : ((uint32_t)1 << w) - 1;
532 x <<= o;
533 reg(ic->arg[0]) = reg(ic->arg[1]) & ~x;
534 }
X(set)535 X(set)
536 {
537 int w = (reg(ic->arg[2]) >> 5) & 0x1f, o = reg(ic->arg[2]) & 0x1f;
538 uint32_t x = w == 0? 0xffffffff : ((uint32_t)1 << w) - 1;
539 x <<= o;
540 reg(ic->arg[0]) = reg(ic->arg[1]) | x;
541 }
542
543
544 /*
545 * or_r0_imm0: d = 0 (optimized case when s1 = r0, imm = 0)
546 * or_r0_imm: d = imm (optimized case when s1 = r0)
547 * or_imm: d = s1 | imm
548 * xor_imm: d = s1 ^ imm
549 * and_imm: d = (s1 & imm) | (s1 & 0xffff0000)
550 * and_u_imm: d = (s1 & imm) | (s1 & 0xffff)
551 * mask_imm: d = s1 & imm
552 * add_imm: d = s1 - imm (addition with overflow exception)
553 * addu_imm: d = s1 + imm
554 * subu_imm: d = s1 - imm
555 * inc_reg: d ++; (addu special case; d = d + 1)
556 * dec_reg: d --; (subu special case; d = d - 1)
557 * mulu_imm: d = s1 * imm
558 * divu_imm: d = s1 / imm (unsigned)
559 * div_imm: d = s1 / imm (signed)
560 * sub_imm: d = s1 - imm (subtraction with overflow exception)
561 *
562 * arg[0] = pointer to register d
563 * arg[1] = pointer to register s1
564 * arg[2] = imm
565 */
X(or_r0_imm0)566 X(or_r0_imm0) { reg(ic->arg[0]) = 0; }
X(or_r0_imm)567 X(or_r0_imm) { reg(ic->arg[0]) = ic->arg[2]; }
X(or_imm)568 X(or_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) | ic->arg[2]; }
X(xor_imm)569 X(xor_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) ^ ic->arg[2]; }
X(and_imm)570 X(and_imm) { reg(ic->arg[0]) = (reg(ic->arg[1]) & ic->arg[2])
571 | (reg(ic->arg[1]) & 0xffff0000); }
X(and_u_imm)572 X(and_u_imm) { reg(ic->arg[0]) = (reg(ic->arg[1]) & ic->arg[2])
573 | (reg(ic->arg[1]) & 0xffff); }
X(mask_imm)574 X(mask_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) & ic->arg[2]; }
X(add_imm)575 X(add_imm)
576 {
577 uint64_t a = (int32_t) reg(ic->arg[1]);
578 uint64_t b = ic->arg[2];
579 uint64_t res = a + b;
580 uint64_t res2 = (int32_t) res;
581
582 if (res != res2) {
583 SYNCH_PC;
584 m88k_exception(cpu, M88K_EXCEPTION_INTEGER_OVERFLOW, 0);
585 return;
586 }
587
588 reg(ic->arg[0]) = res;
589 }
X(addu_imm)590 X(addu_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) + ic->arg[2]; }
X(subu_imm)591 X(subu_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) - ic->arg[2]; }
X(inc_reg)592 X(inc_reg) { reg(ic->arg[0]) ++; }
X(dec_reg)593 X(dec_reg) { reg(ic->arg[0]) --; }
X(mulu_imm)594 X(mulu_imm)
595 {
596 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
597 SYNCH_PC;
598 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
599 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
600 } else
601 reg(ic->arg[0]) = reg(ic->arg[1]) * ic->arg[2];
602 }
X(divu_imm)603 X(divu_imm)
604 {
605 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
606 SYNCH_PC;
607 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
608 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
609 } else if (ic->arg[2] == 0) {
610 SYNCH_PC;
611 m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0);
612 } else
613 reg(ic->arg[0]) = (uint32_t) reg(ic->arg[1]) / (uint32_t) ic->arg[2];
614 }
X(div_imm)615 X(div_imm)
616 {
617 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
618 SYNCH_PC;
619 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
620 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
621 } else if (ic->arg[2] == 0) {
622 SYNCH_PC;
623 m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0);
624 } else {
625 int32_t res = (int32_t) reg(ic->arg[1]) / (int32_t) ic->arg[2];
626 reg(ic->arg[0]) = res;
627 }
628 }
X(sub_imm)629 X(sub_imm)
630 {
631 uint64_t a = (int32_t) reg(ic->arg[1]);
632 uint64_t b = ic->arg[2];
633 uint64_t res = a - b;
634 uint64_t res2 = (int32_t) res;
635
636 if (res != res2) {
637 SYNCH_PC;
638 m88k_exception(cpu, M88K_EXCEPTION_INTEGER_OVERFLOW, 0);
639 return;
640 }
641
642 reg(ic->arg[0]) = res;
643 }
644
645
646 /*
647 * or: d = s1 | s2
648 * or_c: d = s1 | ~s2
649 * or_r0: d = s2
650 * xor: d = s1 ^ s2
651 * xor_c: d = s1 ^ ~s2
652 * and: d = s1 & s2
653 * and_c: d = s1 & ~s2
654 * add: d = s1 + s2 with trap on overflow
655 * addu: d = s1 + s2
656 * addu_co: d = s1 + s2 carry out
657 * addu_ci: d = s1 + s2 + carry carry in
658 * addu_cio: d = s1 + s2 + carry carry in & carry out
659 * lda_reg_X: same as addu, but s2 is scaled by 2, 4, or 8
660 * subu: d = s1 - s2
661 * subu_co: d = s1 - s2 carry/borrow out
662 * subu_ci: d = s1 - s2 - (carry? 0 : 1) carry in
663 * subu_cio: d = s1 - s2 - (carry? 0 : 1) carry in & carry/borrow out
664 * mul: d = s1 * s2
665 * divu: d = s1 / s2 (unsigned)
666 * div: d = s1 / s2 (signed)
667 *
668 * arg[0] = pointer to register d
669 * arg[1] = pointer to register s1
670 * arg[2] = pointer to register s2
671 */
X(or)672 X(or) { reg(ic->arg[0]) = reg(ic->arg[1]) | reg(ic->arg[2]); }
X(or_c)673 X(or_c) { reg(ic->arg[0]) = reg(ic->arg[1]) | ~(reg(ic->arg[2])); }
X(or_r0)674 X(or_r0){ reg(ic->arg[0]) = reg(ic->arg[2]); }
X(xor)675 X(xor) { reg(ic->arg[0]) = reg(ic->arg[1]) ^ reg(ic->arg[2]); }
X(xor_c)676 X(xor_c){ reg(ic->arg[0]) = reg(ic->arg[1]) ^ ~(reg(ic->arg[2])); }
X(and)677 X(and) { reg(ic->arg[0]) = reg(ic->arg[1]) & reg(ic->arg[2]); }
X(and_c)678 X(and_c){ reg(ic->arg[0]) = reg(ic->arg[1]) & ~(reg(ic->arg[2])); }
X(addu)679 X(addu) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]); }
X(addu_s2r0)680 X(addu_s2r0) { reg(ic->arg[0]) = reg(ic->arg[1]); }
X(lda_reg_2)681 X(lda_reg_2) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]) * 2; }
X(lda_reg_4)682 X(lda_reg_4) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]) * 4; }
X(lda_reg_8)683 X(lda_reg_8) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]) * 8; }
X(subu)684 X(subu) { reg(ic->arg[0]) = reg(ic->arg[1]) - reg(ic->arg[2]); }
X(add)685 X(add)
686 {
687 uint64_t s1 = (int32_t) reg(ic->arg[1]);
688 uint64_t s2 = (int32_t) reg(ic->arg[2]);
689 uint64_t d = s1 + s2;
690 uint64_t dx = (int32_t) d;
691
692 /* "If the result cannot be represented as a signed 32-bit integer"
693 then there should be an exception. */
694 if (d != dx) {
695 SYNCH_PC;
696 m88k_exception(cpu, M88K_EXCEPTION_INTEGER_OVERFLOW, 0);
697 } else {
698 reg(ic->arg[0]) = d;
699 }
700 }
X(mul)701 X(mul)
702 {
703 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
704 SYNCH_PC;
705 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
706 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
707 } else
708 reg(ic->arg[0]) = reg(ic->arg[1]) * reg(ic->arg[2]);
709 }
X(divu)710 X(divu)
711 {
712 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
713 SYNCH_PC;
714 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
715 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
716 } else if (reg(ic->arg[2]) == 0) {
717 SYNCH_PC;
718 m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0);
719 } else
720 reg(ic->arg[0]) = (uint32_t) reg(ic->arg[1]) / (uint32_t) reg(ic->arg[2]);
721 }
X(div)722 X(div)
723 {
724 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
725 SYNCH_PC;
726 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
727 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
728 } else if (reg(ic->arg[2]) == 0) {
729 SYNCH_PC;
730 m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0);
731 } else {
732 int32_t res = (int32_t) reg(ic->arg[1]) / (int32_t) reg(ic->arg[2]);
733 reg(ic->arg[0]) = res;
734 }
735 }
X(addu_co)736 X(addu_co)
737 {
738 uint64_t a = reg(ic->arg[1]), b = reg(ic->arg[2]);
739 a += b;
740 reg(ic->arg[0]) = a;
741 cpu->cd.m88k.cr[M88K_CR_PSR] &= ~M88K_PSR_C;
742 if ((a >> 32) & 1)
743 cpu->cd.m88k.cr[M88K_CR_PSR] |= M88K_PSR_C;
744 }
X(addu_cio)745 X(addu_cio)
746 {
747 uint64_t a = reg(ic->arg[1]), b = reg(ic->arg[2]);
748 a += b;
749 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_C)
750 a ++;
751 reg(ic->arg[0]) = a;
752 cpu->cd.m88k.cr[M88K_CR_PSR] &= ~M88K_PSR_C;
753 if ((a >> 32) & 1)
754 cpu->cd.m88k.cr[M88K_CR_PSR] |= M88K_PSR_C;
755 }
X(addu_ci)756 X(addu_ci)
757 {
758 uint32_t result = reg(ic->arg[1]) + reg(ic->arg[2]);
759 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_C)
760 result ++;
761 reg(ic->arg[0]) = result;
762 }
X(subu_cio)763 X(subu_cio)
764 {
765 uint64_t a = reg(ic->arg[1]), b = reg(ic->arg[2]) ^ 0xffffffff;
766 a += b;
767 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_C)
768 a ++;
769 reg(ic->arg[0]) = a;
770 cpu->cd.m88k.cr[M88K_CR_PSR] &= ~M88K_PSR_C;
771 if ((a >> 32) & 1)
772 cpu->cd.m88k.cr[M88K_CR_PSR] |= M88K_PSR_C;
773 }
X(subu_co)774 X(subu_co)
775 {
776 uint64_t a = reg(ic->arg[1]), b = reg(ic->arg[2]) ^ 0xffffffff;
777 a += b + 1;
778 reg(ic->arg[0]) = a;
779 cpu->cd.m88k.cr[M88K_CR_PSR] &= ~M88K_PSR_C;
780 if ((a >> 32) & 1)
781 cpu->cd.m88k.cr[M88K_CR_PSR] |= M88K_PSR_C;
782 }
X(subu_ci)783 X(subu_ci)
784 {
785 uint32_t result = reg(ic->arg[1]) + ~reg(ic->arg[2]);
786 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_C)
787 result ++;
788 reg(ic->arg[0]) = result;
789 }
790
791
792 /*
793 * ldcr: Load value from a control register, store in register d.
794 * fldcr: Load value from a floating point control register, store in reg d.
795 *
796 * arg[0] = pointer to register d
797 * arg[1] = 6-bit control register number
798 */
X(ldcr)799 X(ldcr)
800 {
801 SYNCH_PC;
802
803 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)
804 m88k_ldcr(cpu, (uint32_t *) (void *) ic->arg[0], ic->arg[1]);
805 else
806 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
807 }
X(fldcr)808 X(fldcr)
809 {
810 SYNCH_PC;
811
812 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE || ic->arg[1] >= 62)
813 reg(ic->arg[0]) = cpu->cd.m88k.fcr[ic->arg[1]];
814 else {
815 /* TODO: The manual says "floating point privilege
816 violation", not just "privilege violation"! */
817 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
818 }
819 }
820
821
822 /*
823 * stcr: Store a value into a control register.
824 * fstcr: Store a value into a floating point control register.
825 *
826 * arg[0] = pointer to source register
827 * arg[1] = 6-bit control register number
828 */
X(stcr)829 X(stcr)
830 {
831 SYNCH_PC;
832
833 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)
834 m88k_stcr(cpu, reg(ic->arg[0]), ic->arg[1], 0);
835 else
836 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
837 }
X(fstcr)838 X(fstcr)
839 {
840 SYNCH_PC;
841
842 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE || ic->arg[1] >= 62)
843 m88k_fstcr(cpu, reg(ic->arg[0]), ic->arg[1]);
844 else {
845 /* TODO: The manual says "floating point privilege
846 violation", not just "privilege violation"! */
847 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
848 }
849 }
850
851
852 /*
853 * fadd.xxx: Floating point addition
854 * fsub.xxx: Floating point subtraction
855 * fmul.xxx: Floating point multiplication
856 * fdiv.xxx: Floating point multiplication
857 *
858 * arg[0] = pointer to destination register
859 * arg[1] = pointer to source register s1
860 * arg[2] = pointer to source register s2
861 *
862 * Note: For 'd' variants, arg[x] points to a _pair_ of registers!
863 */
X(fadd_sss)864 X(fadd_sss)
865 {
866 struct ieee_float_value f1;
867 struct ieee_float_value f2;
868 uint32_t d;
869 uint32_t s2 = reg(ic->arg[2]);
870 uint32_t s1 = reg(ic->arg[1]);
871
872 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
873 SYNCH_PC;
874 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
875 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
876 return;
877 }
878
879 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
880 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
881
882 d = ieee_store_float_value(f1.f + f2.f, IEEE_FMT_S);
883
884 reg(ic->arg[0]) = d;
885 }
X(fadd_dsd)886 X(fadd_dsd)
887 {
888 struct ieee_float_value f1;
889 struct ieee_float_value f2;
890 uint64_t d;
891 uint64_t s2 = reg(ic->arg[2]);
892 uint32_t s1 = reg(ic->arg[1]);
893 s2 = (s2 << 32) + reg(ic->arg[2] + 4);
894
895 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
896 SYNCH_PC;
897 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
898 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
899 return;
900 }
901
902 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
903 ieee_interpret_float_value(s2, &f2, IEEE_FMT_D);
904
905 d = ieee_store_float_value(f1.f + f2.f, IEEE_FMT_D);
906
907 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
908 reg(ic->arg[0] + 4) = d; /* and low word. */
909 }
X(fadd_dds)910 X(fadd_dds)
911 {
912 struct ieee_float_value f1;
913 struct ieee_float_value f2;
914 uint64_t d;
915 uint32_t s2 = reg(ic->arg[2]);
916 uint64_t s1 = reg(ic->arg[1]);
917 s1 = (s1 << 32) + reg(ic->arg[1] + 4);
918
919 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
920 SYNCH_PC;
921 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
922 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
923 return;
924 }
925
926 ieee_interpret_float_value(s1, &f1, IEEE_FMT_D);
927 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
928
929 d = ieee_store_float_value(f1.f + f2.f, IEEE_FMT_D);
930
931 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
932 reg(ic->arg[0] + 4) = d; /* and low word. */
933 }
X(fadd_ddd)934 X(fadd_ddd)
935 {
936 struct ieee_float_value f1;
937 struct ieee_float_value f2;
938 uint64_t d;
939 uint64_t s1 = reg(ic->arg[1]);
940 uint64_t s2 = reg(ic->arg[2]);
941 s1 = (s1 << 32) + reg(ic->arg[1] + 4);
942 s2 = (s2 << 32) + reg(ic->arg[2] + 4);
943
944 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
945 SYNCH_PC;
946 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
947 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
948 return;
949 }
950
951 ieee_interpret_float_value(s1, &f1, IEEE_FMT_D);
952 ieee_interpret_float_value(s2, &f2, IEEE_FMT_D);
953
954 d = ieee_store_float_value(f1.f + f2.f, IEEE_FMT_D);
955
956 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
957 reg(ic->arg[0] + 4) = d; /* and low word. */
958 }
X(fsub_sss)959 X(fsub_sss)
960 {
961 struct ieee_float_value f1;
962 struct ieee_float_value f2;
963 uint32_t d;
964 uint32_t s2 = reg(ic->arg[2]);
965 uint32_t s1 = reg(ic->arg[1]);
966
967 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
968 SYNCH_PC;
969 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
970 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
971 return;
972 }
973
974 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
975 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
976
977 d = ieee_store_float_value(f1.f - f2.f, IEEE_FMT_S);
978 reg(ic->arg[0]) = d;
979 }
X(fsub_sds)980 X(fsub_sds)
981 {
982 struct ieee_float_value f1;
983 struct ieee_float_value f2;
984 uint32_t d;
985 uint32_t s2 = reg(ic->arg[2]);
986 uint64_t s1 = reg(ic->arg[1]);
987 s1 = (s1 << 32) + reg(ic->arg[1] + 4);
988
989 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
990 SYNCH_PC;
991 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
992 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
993 return;
994 }
995
996 ieee_interpret_float_value(s1, &f1, IEEE_FMT_D);
997 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
998
999 d = ieee_store_float_value(f1.f - f2.f, IEEE_FMT_S);
1000 reg(ic->arg[0]) = d;
1001 }
X(fsub_dss)1002 X(fsub_dss)
1003 {
1004 struct ieee_float_value f1;
1005 struct ieee_float_value f2;
1006 uint64_t d;
1007 uint32_t s2 = reg(ic->arg[2]);
1008 uint32_t s1 = reg(ic->arg[1]);
1009
1010 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1011 SYNCH_PC;
1012 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1013 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1014 return;
1015 }
1016
1017 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
1018 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
1019
1020 d = ieee_store_float_value(f1.f - f2.f, IEEE_FMT_D);
1021
1022 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
1023 reg(ic->arg[0] + 4) = d; /* and low word. */
1024 }
X(fsub_dsd)1025 X(fsub_dsd)
1026 {
1027 struct ieee_float_value f1;
1028 struct ieee_float_value f2;
1029 uint64_t d;
1030 uint64_t s2 = reg(ic->arg[2]);
1031 uint32_t s1 = reg(ic->arg[1]);
1032 s2 = (s2 << 32) + reg(ic->arg[2] + 4);
1033
1034 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1035 SYNCH_PC;
1036 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1037 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1038 return;
1039 }
1040
1041 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
1042 ieee_interpret_float_value(s2, &f2, IEEE_FMT_D);
1043
1044 d = ieee_store_float_value(f1.f - f2.f, IEEE_FMT_D);
1045
1046 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
1047 reg(ic->arg[0] + 4) = d; /* and low word. */
1048 }
X(fsub_dds)1049 X(fsub_dds)
1050 {
1051 struct ieee_float_value f1;
1052 struct ieee_float_value f2;
1053 uint64_t d;
1054 uint32_t s2 = reg(ic->arg[2]);
1055 uint64_t s1 = reg(ic->arg[1]);
1056 s1 = (s1 << 32) + reg(ic->arg[1] + 4);
1057
1058 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1059 SYNCH_PC;
1060 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1061 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1062 return;
1063 }
1064
1065 ieee_interpret_float_value(s1, &f1, IEEE_FMT_D);
1066 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
1067
1068 d = ieee_store_float_value(f1.f - f2.f, IEEE_FMT_D);
1069
1070 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
1071 reg(ic->arg[0] + 4) = d; /* and low word. */
1072 }
X(fsub_ddd)1073 X(fsub_ddd)
1074 {
1075 struct ieee_float_value f1;
1076 struct ieee_float_value f2;
1077 uint64_t d;
1078 uint64_t s1 = reg(ic->arg[1]);
1079 uint64_t s2 = reg(ic->arg[2]);
1080 s1 = (s1 << 32) + reg(ic->arg[1] + 4);
1081 s2 = (s2 << 32) + reg(ic->arg[2] + 4);
1082
1083 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1084 SYNCH_PC;
1085 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1086 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1087 return;
1088 }
1089
1090 ieee_interpret_float_value(s1, &f1, IEEE_FMT_D);
1091 ieee_interpret_float_value(s2, &f2, IEEE_FMT_D);
1092
1093 d = ieee_store_float_value(f1.f - f2.f, IEEE_FMT_D);
1094
1095 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
1096 reg(ic->arg[0] + 4) = d; /* and low word. */
1097 }
X(fmul_sss)1098 X(fmul_sss)
1099 {
1100 struct ieee_float_value f1;
1101 struct ieee_float_value f2;
1102 uint32_t d;
1103 uint32_t s2 = reg(ic->arg[2]);
1104 uint32_t s1 = reg(ic->arg[1]);
1105
1106 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1107 SYNCH_PC;
1108 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1109 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1110 return;
1111 }
1112
1113 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
1114 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
1115
1116 d = ieee_store_float_value(f1.f * f2.f, IEEE_FMT_S);
1117 reg(ic->arg[0]) = d;
1118 }
X(fmul_dss)1119 X(fmul_dss)
1120 {
1121 struct ieee_float_value f1;
1122 struct ieee_float_value f2;
1123 uint64_t d;
1124 uint32_t s2 = reg(ic->arg[2]);
1125 uint32_t s1 = reg(ic->arg[1]);
1126
1127 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1128 SYNCH_PC;
1129 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1130 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1131 return;
1132 }
1133
1134 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
1135 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
1136
1137 d = ieee_store_float_value(f1.f * f2.f, IEEE_FMT_D);
1138
1139 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
1140 reg(ic->arg[0] + 4) = d; /* and low word. */
1141 }
X(fmul_dsd)1142 X(fmul_dsd)
1143 {
1144 struct ieee_float_value f1;
1145 struct ieee_float_value f2;
1146 uint64_t d;
1147 uint64_t s2 = reg(ic->arg[2]);
1148 uint32_t s1 = reg(ic->arg[1]);
1149 s2 = (s2 << 32) + reg(ic->arg[2] + 4);
1150
1151 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1152 SYNCH_PC;
1153 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1154 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1155 return;
1156 }
1157
1158 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
1159 ieee_interpret_float_value(s2, &f2, IEEE_FMT_D);
1160
1161 d = ieee_store_float_value(f1.f * f2.f, IEEE_FMT_D);
1162
1163 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
1164 reg(ic->arg[0] + 4) = d; /* and low word. */
1165 }
X(fmul_dds)1166 X(fmul_dds)
1167 {
1168 struct ieee_float_value f1;
1169 struct ieee_float_value f2;
1170 uint64_t d;
1171 uint32_t s2 = reg(ic->arg[2]);
1172 uint64_t s1 = reg(ic->arg[1]);
1173 s1 = (s1 << 32) + reg(ic->arg[1] + 4);
1174
1175 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1176 SYNCH_PC;
1177 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1178 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1179 return;
1180 }
1181
1182 ieee_interpret_float_value(s1, &f1, IEEE_FMT_D);
1183 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
1184
1185 d = ieee_store_float_value(f1.f * f2.f, IEEE_FMT_D);
1186
1187 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
1188 reg(ic->arg[0] + 4) = d; /* and low word. */
1189 }
X(fmul_ddd)1190 X(fmul_ddd)
1191 {
1192 struct ieee_float_value f1;
1193 struct ieee_float_value f2;
1194 uint64_t d;
1195 uint64_t s1 = reg(ic->arg[1]);
1196 uint64_t s2 = reg(ic->arg[2]);
1197 s1 = (s1 << 32) + reg(ic->arg[1] + 4);
1198 s2 = (s2 << 32) + reg(ic->arg[2] + 4);
1199
1200 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1201 SYNCH_PC;
1202 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1203 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1204 return;
1205 }
1206
1207 ieee_interpret_float_value(s1, &f1, IEEE_FMT_D);
1208 ieee_interpret_float_value(s2, &f2, IEEE_FMT_D);
1209
1210 d = ieee_store_float_value(f1.f * f2.f, IEEE_FMT_D);
1211
1212 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
1213 reg(ic->arg[0] + 4) = d; /* and low word. */
1214 }
X(fdiv_sss)1215 X(fdiv_sss)
1216 {
1217 struct ieee_float_value f1;
1218 struct ieee_float_value f2;
1219 uint32_t d;
1220 uint32_t s1 = reg(ic->arg[1]);
1221 uint32_t s2 = reg(ic->arg[2]);
1222
1223 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1224 SYNCH_PC;
1225 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1226 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1227 return;
1228 }
1229
1230 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
1231 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
1232
1233 if (f2.f == 0) {
1234 SYNCH_PC;
1235 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FDVZ;
1236 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1237 return;
1238 }
1239
1240 d = ieee_store_float_value(f1.f / f2.f, IEEE_FMT_S);
1241
1242 reg(ic->arg[0]) = d;
1243 }
X(fdiv_dss)1244 X(fdiv_dss)
1245 {
1246 struct ieee_float_value f1;
1247 struct ieee_float_value f2;
1248 uint64_t d;
1249 uint32_t s1 = reg(ic->arg[1]);
1250 uint32_t s2 = reg(ic->arg[2]);
1251
1252 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1253 SYNCH_PC;
1254 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1255 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1256 return;
1257 }
1258
1259 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
1260 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
1261
1262 if (f2.f == 0) {
1263 SYNCH_PC;
1264 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FDVZ;
1265 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1266 return;
1267 }
1268
1269 d = ieee_store_float_value(f1.f / f2.f, IEEE_FMT_D);
1270
1271 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
1272 reg(ic->arg[0] + 4) = d; /* and low word. */
1273 }
X(fdiv_dsd)1274 X(fdiv_dsd)
1275 {
1276 struct ieee_float_value f1;
1277 struct ieee_float_value f2;
1278 uint64_t d;
1279 uint32_t s1 = reg(ic->arg[1]);
1280 uint64_t s2 = reg(ic->arg[2]);
1281 s2 = (s2 << 32) + reg(ic->arg[2] + 4);
1282
1283 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1284 SYNCH_PC;
1285 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1286 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1287 return;
1288 }
1289
1290 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
1291 ieee_interpret_float_value(s2, &f2, IEEE_FMT_D);
1292
1293 if (f2.f == 0) {
1294 SYNCH_PC;
1295 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FDVZ;
1296 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1297 return;
1298 }
1299
1300 d = ieee_store_float_value(f1.f / f2.f, IEEE_FMT_D);
1301
1302 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
1303 reg(ic->arg[0] + 4) = d; /* and low word. */
1304 }
X(fdiv_ddd)1305 X(fdiv_ddd)
1306 {
1307 struct ieee_float_value f1;
1308 struct ieee_float_value f2;
1309 uint64_t d;
1310 uint64_t s1 = reg(ic->arg[1]);
1311 uint64_t s2 = reg(ic->arg[2]);
1312 s1 = (s1 << 32) + reg(ic->arg[1] + 4);
1313 s2 = (s2 << 32) + reg(ic->arg[2] + 4);
1314
1315 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1316 SYNCH_PC;
1317 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1318 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1319 return;
1320 }
1321
1322 ieee_interpret_float_value(s1, &f1, IEEE_FMT_D);
1323 ieee_interpret_float_value(s2, &f2, IEEE_FMT_D);
1324
1325 if (f2.f == 0) {
1326 SYNCH_PC;
1327 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FDVZ;
1328 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1329 return;
1330 }
1331
1332 d = ieee_store_float_value(f1.f / f2.f, IEEE_FMT_D);
1333
1334 reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */
1335 reg(ic->arg[0] + 4) = d; /* and low word. */
1336 }
1337
1338
1339 /*
1340 * fcmp.sXX: Floating point comparison
1341 *
1342 * arg[0] = pointer to destination register
1343 * arg[1] = pointer to source register s1
1344 * arg[2] = pointer to source register s2
1345 *
1346 * Note: For 'd' variants, arg[x] points to a _pair_ of registers!
1347 */
m88k_fcmp_common(struct ieee_float_value * f1,struct ieee_float_value * f2)1348 static uint32_t m88k_fcmp_common(struct ieee_float_value *f1,
1349 struct ieee_float_value *f2)
1350 {
1351 uint32_t d;
1352
1353 /* TODO: Implement all bits correctly, e.g. "in range" bits. */
1354 d = 0;
1355 if (isnan(f1->f) || isnan(f2->f))
1356 d |= (1 << 0);
1357 else {
1358 d |= (1 << 1);
1359 if (f1->f == f2->f)
1360 d |= (1 << 2);
1361 else
1362 d |= (1 << 3);
1363 if (f1->f > f2->f)
1364 d |= (1 << 4);
1365 else
1366 d |= (1 << 5);
1367 if (f1->f < f2->f)
1368 d |= (1 << 6);
1369 else
1370 d |= (1 << 7);
1371 }
1372
1373 return d;
1374 }
X(fcmp_sss)1375 X(fcmp_sss)
1376 {
1377 struct ieee_float_value f1;
1378 struct ieee_float_value f2;
1379 uint32_t s2 = reg(ic->arg[2]);
1380 uint32_t s1 = reg(ic->arg[1]);
1381
1382 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1383 SYNCH_PC;
1384 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1385 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1386 return;
1387 }
1388
1389 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
1390 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
1391 reg(ic->arg[0]) = m88k_fcmp_common(&f1, &f2);
1392 }
X(fcmp_ssd)1393 X(fcmp_ssd)
1394 {
1395 struct ieee_float_value f1;
1396 struct ieee_float_value f2;
1397 uint64_t s2 = reg(ic->arg[2]);
1398 uint32_t s1 = reg(ic->arg[1]);
1399 s2 = (s2 << 32) + reg(ic->arg[2] + 4);
1400
1401 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1402 SYNCH_PC;
1403 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1404 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1405 return;
1406 }
1407
1408 ieee_interpret_float_value(s1, &f1, IEEE_FMT_S);
1409 ieee_interpret_float_value(s2, &f2, IEEE_FMT_D);
1410 reg(ic->arg[0]) = m88k_fcmp_common(&f1, &f2);
1411 }
X(fcmp_sds)1412 X(fcmp_sds)
1413 {
1414 struct ieee_float_value f1;
1415 struct ieee_float_value f2;
1416 uint32_t s2 = reg(ic->arg[2]);
1417 uint64_t s1 = reg(ic->arg[1]);
1418 s1 = (s1 << 32) + reg(ic->arg[1] + 4);
1419
1420 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1421 SYNCH_PC;
1422 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1423 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1424 return;
1425 }
1426
1427 ieee_interpret_float_value(s1, &f1, IEEE_FMT_D);
1428 ieee_interpret_float_value(s2, &f2, IEEE_FMT_S);
1429 reg(ic->arg[0]) = m88k_fcmp_common(&f1, &f2);
1430 }
X(fcmp_sdd)1431 X(fcmp_sdd)
1432 {
1433 struct ieee_float_value f1;
1434 struct ieee_float_value f2;
1435 uint64_t s1 = reg(ic->arg[1]);
1436 uint64_t s2 = reg(ic->arg[2]);
1437 s1 = (s1 << 32) + reg(ic->arg[1] + 4);
1438 s2 = (s2 << 32) + reg(ic->arg[2] + 4);
1439
1440 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1441 SYNCH_PC;
1442 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1443 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1444 return;
1445 }
1446
1447 ieee_interpret_float_value(s1, &f1, IEEE_FMT_D);
1448 ieee_interpret_float_value(s2, &f2, IEEE_FMT_D);
1449 reg(ic->arg[0]) = m88k_fcmp_common(&f1, &f2);
1450 }
1451
1452
1453 /*
1454 * flt.ss and flt.ds: Convert integer to floating point.
1455 *
1456 * arg[0] = pointer to destination register
1457 * arg[1] = pointer to source register s2
1458 *
1459 * Note: For flt.ds, arg[0] points to a _pair_ of registers!
1460 */
X(flt_ss)1461 X(flt_ss)
1462 {
1463 int32_t x = reg(ic->arg[1]);
1464
1465 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1466 SYNCH_PC;
1467 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1468 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1469 return;
1470 }
1471
1472 reg(ic->arg[0]) = ieee_store_float_value((double)x, IEEE_FMT_S);
1473 }
X(flt_ds)1474 X(flt_ds)
1475 {
1476 int32_t x = reg(ic->arg[1]);
1477 uint64_t result;
1478
1479 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1480 SYNCH_PC;
1481 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1482 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1483 return;
1484 }
1485
1486 result = ieee_store_float_value((double)x, IEEE_FMT_D);
1487
1488 reg(ic->arg[0]) = result >> 32; /* High 32-bit word, */
1489 reg(ic->arg[0] + 4) = result; /* and low word. */
1490 }
1491
1492
1493 /*
1494 * trnc.ss and trnc.sd: Truncate floating point to interger.
1495 *
1496 * arg[0] = pointer to destination register
1497 * arg[1] = pointer to source register s2
1498 *
1499 * Note: For trnc.sd, arg[1] points to a _pair_ of registers!
1500 */
X(trnc_ss)1501 X(trnc_ss)
1502 {
1503 struct ieee_float_value f1;
1504 ieee_interpret_float_value(reg(ic->arg[1]), &f1, IEEE_FMT_S);
1505
1506 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1507 SYNCH_PC;
1508 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1509 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1510 return;
1511 }
1512
1513 reg(ic->arg[0]) = (int32_t) f1.f;
1514 }
X(trnc_sd)1515 X(trnc_sd)
1516 {
1517 struct ieee_float_value f1;
1518 uint64_t x = reg(ic->arg[1]);
1519 x = (x << 32) + reg(ic->arg[1] + 4);
1520 ieee_interpret_float_value(x, &f1, IEEE_FMT_D);
1521
1522 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) {
1523 SYNCH_PC;
1524 cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP;
1525 m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0);
1526 return;
1527 }
1528
1529 reg(ic->arg[0]) = (int32_t) f1.f;
1530 }
1531
1532
1533 /*
1534 * xcr: Exchange (load + store) control register.
1535 *
1536 * arg[0] = pointer to register d
1537 * arg[1] = pointer to register s1
1538 * arg[2] = 6-bit control register number
1539 */
X(xcr)1540 X(xcr)
1541 {
1542 uint32_t tmp, tmp2;
1543 SYNCH_PC;
1544
1545 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE) {
1546 tmp = reg(ic->arg[1]);
1547 m88k_ldcr(cpu, &tmp2, ic->arg[2]);
1548 m88k_stcr(cpu, tmp, ic->arg[2], 0);
1549 reg(ic->arg[0]) = tmp2;
1550 } else
1551 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
1552 }
1553
1554
1555 /*
1556 * rte: Return from exception
1557 */
X(rte)1558 X(rte)
1559 {
1560 /* If executed from user mode, then cause an exception: */
1561 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) {
1562 SYNCH_PC;
1563 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
1564 return;
1565 }
1566
1567 m88k_stcr(cpu, cpu->cd.m88k.cr[M88K_CR_EPSR], M88K_CR_PSR, 1);
1568
1569 if (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_E) {
1570 fatal("rte: NIP: TODO: single-step support\n");
1571 goto abort_dump;
1572 }
1573
1574 if (cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_E) {
1575 fatal("rte: TODO: FIP single-step support\n");
1576 goto abort_dump;
1577 }
1578
1579 /* First try the NIP, if it is Valid: */
1580 cpu->pc = cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR;
1581
1582 /* If the NIP is not valid, then try the FIP: */
1583 if (!(cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_V)) {
1584 /* Neither the NIP nor the FIP valid? */
1585 if (!(cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_V)) {
1586 if ((cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_ADDR)
1587 != (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR) + 4) {
1588 fatal("[ TODO: Neither FIP nor NIP has the "
1589 "Valid bit set?! ]\n");
1590 goto abort_dump;
1591 }
1592
1593 /* For now, continue anyway, using NIP. */
1594 } else {
1595 cpu->pc = cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_ADDR;
1596 }
1597 } else if (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_V &&
1598 cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_V &&
1599 (cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_ADDR)
1600 != (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR) + 4) {
1601 /*
1602 * The NIP instruction should first be executed (this
1603 * is the one the exception handler choose to return to),
1604 * and then the FIP instruction should run (the target
1605 * of a delayed branch).
1606 */
1607
1608 uint32_t nip = cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR;
1609 uint32_t fip = cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_ADDR;
1610
1611 cpu->pc = nip;
1612 cpu->delay_slot = NOT_DELAYED;
1613 quick_pc_to_pointers(cpu);
1614
1615 if (cpu->pc != nip) {
1616 fatal("NIP execution caused exception?! TODO\n");
1617 goto abort_dump;
1618 }
1619
1620 instr(to_be_translated)(cpu, cpu->cd.m88k.next_ic);
1621
1622 if ((cpu->pc & 0xfffff000) != (nip & 0xfffff000)) {
1623 fatal("instruction in delay slot when returning via"
1624 " rte caused an exception?! nip=0x%08x, but pc "
1625 "changed to 0x%08x! TODO\n", nip, (int)cpu->pc);
1626 goto abort_dump;
1627 }
1628
1629 cpu->pc = fip;
1630 cpu->delay_slot = NOT_DELAYED;
1631 quick_pc_to_pointers(cpu);
1632 return;
1633 }
1634
1635 /* fatal("RTE: NIP=0x%08" PRIx32", FIP=0x%08" PRIx32"\n",
1636 cpu->cd.m88k.cr[M88K_CR_SNIP], cpu->cd.m88k.cr[M88K_CR_SFIP]); */
1637
1638 quick_pc_to_pointers(cpu);
1639 return;
1640
1641 abort_dump:
1642 fatal("RTE failed. NIP=0x%08" PRIx32", FIP=0x%08" PRIx32"\n",
1643 cpu->cd.m88k.cr[M88K_CR_SNIP], cpu->cd.m88k.cr[M88K_CR_SFIP]);
1644
1645 ABORT_EXECUTION;
1646 }
1647
1648
1649 /*
1650 * xmem_slow: Unoptimized xmem (exchange register with memory)
1651 *
1652 * arg[0] = copy of the instruction word
1653 */
X(xmem_slow)1654 X(xmem_slow)
1655 {
1656 uint32_t iword = ic->arg[0];
1657 uint32_t tmp;
1658 int d = (iword >> 21) & 0x1f;
1659 int s1 = (iword >> 16) & 0x1f;
1660 int s2 = iword & 0x1f;
1661 int imm16 = iword & 0xffff;
1662 int regofs = (iword & 0xf0000000) != 0;
1663 int scaled = iword & 0x200;
1664 int size = iword & 0x400;
1665 int user = iword & 0x80;
1666 uint32_t pc_before_memory_access;
1667 void (*xmem_load)(struct cpu*, struct m88k_instr_call*);
1668 void (*xmem_store)(struct cpu*, struct m88k_instr_call*);
1669 struct m88k_instr_call call;
1670
1671 SYNCH_PC;
1672 pc_before_memory_access = (uint32_t)cpu->pc;
1673
1674 if (!regofs) {
1675 /* immediate offset: */
1676 scaled = 0;
1677 size = (iword >> 26) & 1;
1678 user = 0;
1679 }
1680
1681 tmp = cpu->cd.m88k.r[d];
1682
1683 xmem_load = m88k_loadstore[ (size? 2 : 0)
1684 + (cpu->byte_order == EMUL_BIG_ENDIAN? M88K_LOADSTORE_ENDIANNESS : 0)
1685 + (scaled? M88K_LOADSTORE_SCALEDNESS : 0)
1686 + (user? M88K_LOADSTORE_USR : 0)
1687 + (regofs? M88K_LOADSTORE_REGISTEROFFSET : 0)
1688 + M88K_LOADSTORE_NO_PC_SYNC ];
1689
1690 call.f = xmem_load;
1691 call.arg[0] = (size_t) &cpu->cd.m88k.r[d];
1692 call.arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1693 if (regofs)
1694 call.arg[2] = (size_t) &cpu->cd.m88k.r[s2];
1695 else
1696 call.arg[2] = imm16;
1697
1698 if (d == M88K_ZERO_REG)
1699 call.arg[0] = (size_t)&cpu->cd.m88k.zero_scratch;
1700
1701 xmem_load(cpu, &call);
1702
1703 // If there was an exception in the load or store call, then the pc
1704 // will have changed. Alternatively, one could check for changes in
1705 // the transaction registers. (But handling the theoretical tiny risk
1706 // that the pc was the same before and after, i.e. that the faulting
1707 // instruction was the same as the exception handler, is not worth it.)
1708 if ((uint32_t)cpu->pc != pc_before_memory_access) {
1709 // printf("xmem_load exception, pc_before_memory_access = %08x\n", pc_before_memory_access);
1710 return;
1711 }
1712
1713 xmem_store = m88k_loadstore[ (size? 2 : 0)
1714 + M88K_LOADSTORE_STORE
1715 + (cpu->byte_order == EMUL_BIG_ENDIAN? M88K_LOADSTORE_ENDIANNESS : 0)
1716 + (scaled? M88K_LOADSTORE_SCALEDNESS : 0)
1717 + (user? M88K_LOADSTORE_USR : 0)
1718 + (regofs? M88K_LOADSTORE_REGISTEROFFSET : 0)
1719 + M88K_LOADSTORE_NO_PC_SYNC ];
1720
1721 call.f = xmem_store;
1722 call.arg[0] = (size_t) &tmp;
1723 call.arg[1] = (size_t) &cpu->cd.m88k.r[s1];
1724 if (regofs)
1725 call.arg[2] = (size_t) &cpu->cd.m88k.r[s2];
1726 else
1727 call.arg[2] = imm16;
1728
1729 if (d == M88K_ZERO_REG)
1730 tmp = 0;
1731
1732 xmem_store(cpu, &call);
1733
1734 // If there was an exception in xmem_store(), then return the d register
1735 // to what it was before the xmem_load().
1736 if ((uint32_t)cpu->pc != pc_before_memory_access) {
1737 // printf("xmem_store exception, pc_before_memory_access = %08x\n", pc_before_memory_access);
1738 cpu->cd.m88k.r[d] = tmp;
1739 return;
1740 }
1741 }
1742
1743
1744 /*
1745 * prom-call:
1746 */
X(prom_call)1747 X(prom_call)
1748 {
1749 /* If executed from user mode, then cause an exception: */
1750 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) {
1751 SYNCH_PC;
1752 m88k_exception(cpu, M88K_EXCEPTION_UNIMPLEMENTED_OPCODE, 0);
1753 return;
1754 }
1755
1756 switch (cpu->machine->machine_type) {
1757
1758 case MACHINE_LUNA88K:
1759 luna88kprom_emul(cpu);
1760 break;
1761
1762 case MACHINE_MVME88K:
1763 mvmeprom_emul(cpu);
1764 break;
1765
1766 default:fatal("m88k prom_call: unimplemented machine type\n");
1767 ABORT_EXECUTION;
1768 }
1769
1770 if (!cpu->running) {
1771 cpu->n_translated_instrs --;
1772 cpu->cd.m88k.next_ic = ¬hing_call;
1773 }
1774 }
1775
1776
1777 /*
1778 * tb0, tb1: Trap on bit Clear/Set
1779 *
1780 * arg[0] = bitmask to check (e.g. 0x00020000 for bit 17)
1781 * arg[1] = pointer to register s1
1782 * arg[2] = 9-bit vector number
1783 */
X(tb0)1784 X(tb0)
1785 {
1786 SYNCH_PC;
1787
1788 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)
1789 && ic->arg[2] < M88K_EXCEPTION_USER_TRAPS_START) {
1790 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
1791 return;
1792 }
1793
1794 if (!(reg(ic->arg[1]) & ic->arg[0]))
1795 m88k_exception(cpu, ic->arg[2], 1);
1796 }
X(tb1)1797 X(tb1)
1798 {
1799 SYNCH_PC;
1800
1801 if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)
1802 && ic->arg[2] < M88K_EXCEPTION_USER_TRAPS_START) {
1803 m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0);
1804 return;
1805 }
1806
1807 if (reg(ic->arg[1]) & ic->arg[0])
1808 m88k_exception(cpu, ic->arg[2], 1);
1809 }
1810
1811
1812 /*
1813 * idle:
1814 *
1815 * s: ld rX,rY,ofs
1816 * bcnd eq0,rX,s
1817 */
X(idle)1818 X(idle)
1819 {
1820 uint32_t rY = reg(ic[0].arg[1]) + ic[0].arg[2];
1821 uint32_t index = rY >> 12;
1822 unsigned char *p = cpu->cd.m88k.host_load[index];
1823 uint32_t *p32 = (uint32_t *) p;
1824 uint32_t v;
1825
1826 /* Fallback: */
1827 if (p == NULL || (rY & 3)) {
1828 instr(ld_u_4_be)(cpu, ic);
1829 return;
1830 }
1831
1832 v = p32[(rY & 0xfff) >> 2];
1833 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1834 v = LE32_TO_HOST(v);
1835 else
1836 v = BE32_TO_HOST(v);
1837
1838 reg(ic[0].arg[0]) = v;
1839
1840 if (v == 0) {
1841 SYNCH_PC;
1842 usleep(50);
1843 cpu->has_been_idling = 1;
1844 cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 2;
1845 cpu->cd.m88k.next_ic = ¬hing_call;
1846 } else {
1847 cpu->n_translated_instrs ++;
1848 cpu->cd.m88k.next_ic = &ic[2];
1849 }
1850 }
1851
1852
1853 /*
1854 * idle_with_tb1:
1855 *
1856 * s: tb1 bit,r0,vector
1857 * ld rX,rY,ofs
1858 * bcnd eq0,rX,s
1859 */
X(idle_with_tb1)1860 X(idle_with_tb1)
1861 {
1862 uint32_t rY = reg(ic[1].arg[1]) + ic[1].arg[2];
1863 uint32_t index = rY >> 12;
1864 unsigned char *p = cpu->cd.m88k.host_load[index];
1865 uint32_t *p32 = (uint32_t *) p;
1866 uint32_t v;
1867
1868 /* Fallback: */
1869 if (p == NULL || (rY & 3)) {
1870 instr(tb1)(cpu, ic);
1871 return;
1872 }
1873
1874 v = p32[(rY & 0xfff) >> 2];
1875 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1876 v = LE32_TO_HOST(v);
1877 else
1878 v = BE32_TO_HOST(v);
1879
1880 reg(ic[1].arg[0]) = v;
1881
1882 if (v == 0) {
1883 SYNCH_PC;
1884 usleep(50);
1885 cpu->has_been_idling = 1;
1886 cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 2;
1887 cpu->cd.m88k.next_ic = ¬hing_call;
1888 } else {
1889 cpu->n_translated_instrs += 2;
1890 cpu->cd.m88k.next_ic = &ic[3];
1891 }
1892 }
1893
1894
1895 /*****************************************************************************/
1896
1897
X(end_of_page)1898 X(end_of_page)
1899 {
1900 /* Update the PC: (offset 0, but on the next page) */
1901 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) <<
1902 M88K_INSTR_ALIGNMENT_SHIFT);
1903 cpu->pc += (M88K_IC_ENTRIES_PER_PAGE << M88K_INSTR_ALIGNMENT_SHIFT);
1904
1905 /* end_of_page doesn't count as an executed instruction: */
1906 cpu->n_translated_instrs --;
1907
1908 /*
1909 * Find the new physpage and update translation pointers.
1910 *
1911 * Note: This may cause an exception, if e.g. the new page is
1912 * not accessible.
1913 */
1914 quick_pc_to_pointers(cpu);
1915
1916 /* Simple jump to the next page (if we are lucky): */
1917 if (cpu->delay_slot == NOT_DELAYED)
1918 return;
1919
1920 /*
1921 * If we were in a delay slot, and we got an exception while doing
1922 * quick_pc_to_pointers, then return. The function which called
1923 * end_of_page should handle this case.
1924 */
1925 if (cpu->delay_slot == EXCEPTION_IN_DELAY_SLOT)
1926 return;
1927
1928 /*
1929 * Tricky situation; the delay slot is on the next virtual page.
1930 * Calling to_be_translated will translate one instruction manually,
1931 * execute it, and then discard it.
1932 */
1933 /* fatal("[ end_of_page: delay slot across page boundary! ]\n"); */
1934
1935 instr(to_be_translated)(cpu, cpu->cd.m88k.next_ic);
1936
1937 /* The instruction in the delay slot has now executed. */
1938 /* fatal("[ end_of_page: back from executing the delay slot, %i ]\n",
1939 cpu->delay_slot); */
1940
1941 /* Find the physpage etc of the instruction in the delay slot
1942 (or, if there was an exception, the exception handler): */
1943 quick_pc_to_pointers(cpu);
1944 }
1945
1946
X(end_of_page2)1947 X(end_of_page2)
1948 {
1949 /* Synchronize PC on the _second_ instruction on the next page: */
1950 int low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page)
1951 / sizeof(struct m88k_instr_call);
1952 cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1)
1953 << M88K_INSTR_ALIGNMENT_SHIFT);
1954 cpu->pc += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT);
1955
1956 if (low_pc < 0 || low_pc > ((M88K_IC_ENTRIES_PER_PAGE+1)
1957 << M88K_INSTR_ALIGNMENT_SHIFT)) {
1958 printf("[ end_of_page2: HUH? low_pc=%i, cpu->pc = %08"
1959 PRIx32" ]\n", low_pc, (uint32_t) cpu->pc);
1960 }
1961
1962 /* This doesn't count as an executed instruction. */
1963 cpu->n_translated_instrs --;
1964
1965 quick_pc_to_pointers(cpu);
1966
1967 if (cpu->delay_slot == NOT_DELAYED)
1968 return;
1969
1970 fatal("end_of_page2: fatal error, we're in a delay slot\n");
1971 exit(1);
1972 }
1973
1974
1975 /*****************************************************************************/
1976
1977
1978 /*
1979 * Idle loop detection, e.g.:
1980 *
1981 * s00028d44: 15b7d650 ld r13,r23,0xd650 ; [<_sched_whichqs>]
1982 * s00028d48: e84dffff bcnd eq0,r13,0x00028d44 ; <_sched_idle+0xc4>
1983 *
1984 * or
1985 *
1986 * s00079d78: f020d8ff tb1 1,r0,0xff
1987 * s00079d7c: 15ac7320 ld r13,r12,0x7320 ; [<_sched_whichqs>]
1988 * s00079d80: e84dfffe bcnd eq0,r13,0x00079d78 ; <_sched_idle+0x158>
1989 */
COMBINE(idle)1990 void COMBINE(idle)(struct cpu *cpu, struct m88k_instr_call *ic, int low_addr)
1991 {
1992 int n_back = (low_addr >> M88K_INSTR_ALIGNMENT_SHIFT)
1993 & (M88K_IC_ENTRIES_PER_PAGE-1);
1994 if (n_back < 2)
1995 return;
1996
1997 if (ic[0].f == instr(bcnd_samepage_eq0) &&
1998 ic[0].arg[2] == (size_t) &ic[-1] &&
1999 ic[-1].f == instr(ld_u_4_be) &&
2000 ic[0].arg[0] == ic[-1].arg[0] &&
2001 ic[0].arg[0] != (size_t) &cpu->cd.m88k.r[M88K_ZERO_REG]) {
2002 ic[-1].f = instr(idle);
2003 return;
2004 }
2005
2006 if (ic[0].f == instr(bcnd_samepage_eq0) &&
2007 ic[0].arg[2] == (size_t) &ic[-2] &&
2008 ic[-2].f == instr(tb1) &&
2009 ic[-2].arg[1] == (size_t) &cpu->cd.m88k.r[M88K_ZERO_REG] &&
2010 ic[-1].f == instr(ld_u_4_be) &&
2011 ic[0].arg[0] == ic[-1].arg[0] &&
2012 ic[0].arg[0] != (size_t) &cpu->cd.m88k.r[M88K_ZERO_REG]) {
2013 ic[-2].f = instr(idle_with_tb1);
2014 return;
2015 }
2016 }
2017
2018
2019 /*****************************************************************************/
2020
2021
2022 /*
2023 * m88k_instr_to_be_translated():
2024 *
2025 * Translate an instruction word into a m88k_instr_call. ic is filled in with
2026 * valid data for the translated instruction, or a "nothing" instruction if
2027 * there was a translation failure. The newly translated instruction is then
2028 * executed.
2029 */
X(to_be_translated)2030 X(to_be_translated)
2031 {
2032 uint32_t addr, low_pc, iword;
2033 unsigned char *page;
2034 unsigned char ib[4];
2035 uint32_t op26, op10, op11, d, s1, s2, cr6, imm16;
2036 int32_t d16, d26; //, simm16;
2037 int offset, shift;
2038 int in_crosspage_delayslot = 0;
2039 void (*samepage_function)(struct cpu *, struct m88k_instr_call *)=NULL;
2040
2041 /* Figure out the (virtual) address of the instruction: */
2042 low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page)
2043 / sizeof(struct m88k_instr_call);
2044
2045 /* Special case for branch with delayslot on the next page: */
2046 if (cpu->delay_slot == TO_BE_DELAYED && low_pc == 0) {
2047 /* fatal("[ delay-slot translation across page "
2048 "boundary ]\n"); */
2049 in_crosspage_delayslot = 1;
2050 }
2051
2052 addr = cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1)
2053 << M88K_INSTR_ALIGNMENT_SHIFT);
2054 addr += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT);
2055 cpu->pc = (MODE_int_t)addr;
2056 addr &= ~((1 << M88K_INSTR_ALIGNMENT_SHIFT) - 1);
2057
2058 /* Read the instruction word from memory: */
2059 page = cpu->cd.m88k.host_load[(uint32_t)addr >> 12];
2060
2061 if (page != NULL) {
2062 /* fatal("TRANSLATION HIT!\n"); */
2063 memcpy(ib, page + (addr & 0xffc), sizeof(ib));
2064 } else {
2065 /* fatal("TRANSLATION MISS!\n"); */
2066 if (!cpu->memory_rw(cpu, cpu->mem, addr, ib,
2067 sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
2068 fatal("to_be_translated(): read failed: TODO\n");
2069 goto bad;
2070 }
2071 }
2072
2073 {
2074 uint32_t *p = (uint32_t *) ib;
2075 iword = *p;
2076 }
2077
2078 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
2079 iword = LE32_TO_HOST(iword);
2080 else
2081 iword = BE32_TO_HOST(iword);
2082
2083
2084 #define DYNTRANS_TO_BE_TRANSLATED_HEAD
2085 #include "cpu_dyntrans.cc"
2086 #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
2087
2088
2089 /*
2090 * Translate the instruction:
2091 *
2092 * NOTE: _NEVER_ allow writes to the zero register; all instructions
2093 * that use the zero register as their destination should be treated
2094 * as NOPs, except those that access memory (they should use the
2095 * scratch register instead).
2096 */
2097 if (cpu->cd.m88k.r[M88K_ZERO_REG] != 0) {
2098 fatal("INTERNAL ERROR! M88K_ZERO_REG != 0?\n");
2099 exit(1);
2100 }
2101
2102 op26 = (iword >> 26) & 0x3f;
2103 op11 = (iword >> 11) & 0x1f;
2104 op10 = (iword >> 10) & 0x3f;
2105 d = (iword >> 21) & 0x1f;
2106 s1 = (iword >> 16) & 0x1f;
2107 s2 = iword & 0x1f;
2108 imm16 = iword & 0xffff;
2109 // simm16 = (int16_t) (iword & 0xffff);
2110 cr6 = (iword >> 5) & 0x3f;
2111 d16 = ((int16_t) (iword & 0xffff)) * 4;
2112 d26 = ((int32_t)((iword & 0x03ffffff) << 6)) >> 4;
2113
2114 switch (op26) {
2115
2116 case 0x00:
2117 case 0x01:
2118 ic->f = instr(xmem_slow);
2119 ic->arg[0] = iword;
2120 if (d == M88K_ZERO_REG)
2121 ic->f = instr(nop);
2122 if (iword == 0)
2123 goto bad;
2124 break;
2125
2126 case 0x02: /* ld.hu */
2127 case 0x03: /* ld.bu */
2128 case 0x04: /* ld.d */
2129 case 0x05: /* ld */
2130 case 0x06: /* ld.h */
2131 case 0x07: /* ld.b */
2132 case 0x08: /* st.d */
2133 case 0x09: /* st */
2134 case 0x0a: /* st.h */
2135 case 0x0b: /* st.b */
2136 {
2137 int store = 0, signedness = 0, opsize = 0;
2138
2139 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2140 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
2141 ic->arg[2] = imm16;
2142
2143 switch (op26) {
2144 case 0x02: opsize = 1; break;
2145 case 0x03: opsize = 0; break;
2146 case 0x04: opsize = 3; break;
2147 case 0x05: opsize = 2; break;
2148 case 0x06: opsize = 1; signedness = 1; break;
2149 case 0x07: opsize = 0; signedness = 1; break;
2150 case 0x08: store = 1; opsize = 3; break;
2151 case 0x09: store = 1; opsize = 2; break;
2152 case 0x0a: store = 1; opsize = 1; break;
2153 case 0x0b: store = 1; opsize = 0; break;
2154 }
2155
2156 if (opsize == 3 && d == 31) {
2157 fatal("m88k load/store of register pair r31/r0"
2158 " is not yet implemented\n");
2159 goto bad;
2160 }
2161
2162 ic->f = m88k_loadstore[ opsize
2163 + (store? M88K_LOADSTORE_STORE : 0)
2164 + (signedness? M88K_LOADSTORE_SIGNEDNESS:0)
2165 + (cpu->byte_order == EMUL_BIG_ENDIAN?
2166 M88K_LOADSTORE_ENDIANNESS : 0) ];
2167
2168 if (!store && d == 0)
2169 ic->arg[0] = (size_t) &cpu->cd.m88k.zero_scratch;
2170 }
2171 break;
2172
2173 case 0x10: /* and imm */
2174 case 0x11: /* and.u imm */
2175 case 0x12: /* mask imm */
2176 case 0x13: /* mask.u imm */
2177 case 0x14: /* xor imm */
2178 case 0x15: /* xor.u imm */
2179 case 0x16: /* or imm */
2180 case 0x17: /* or.u imm */
2181 case 0x18: /* addu imm */
2182 case 0x19: /* subu imm */
2183 case 0x1a: /* divu imm */
2184 case 0x1b: /* mulu imm */
2185 case 0x1c: /* add imm */
2186 case 0x1d: /* sub imm */
2187 case 0x1e: /* div imm */
2188 case 0x1f: /* cmp imm */
2189 shift = 0;
2190 switch (op26) {
2191 case 0x10: ic->f = instr(and_imm); break;
2192 case 0x11: ic->f = instr(and_u_imm); shift = 16; break;
2193 case 0x12: ic->f = instr(mask_imm); break;
2194 case 0x13: ic->f = instr(mask_imm); shift = 16; break;
2195 case 0x14: ic->f = instr(xor_imm); break;
2196 case 0x15: ic->f = instr(xor_imm); shift = 16; break;
2197 case 0x16: ic->f = instr(or_imm); break;
2198 case 0x17: ic->f = instr(or_imm); shift = 16; break;
2199 case 0x18: ic->f = instr(addu_imm); break;
2200 case 0x19: ic->f = instr(subu_imm); break;
2201 case 0x1a: ic->f = instr(divu_imm); break;
2202 case 0x1b: ic->f = instr(mulu_imm); break;
2203 case 0x1c: ic->f = instr(add_imm); break;
2204 case 0x1d: ic->f = instr(sub_imm); break;
2205 case 0x1e: ic->f = instr(div_imm); break;
2206 case 0x1f: ic->f = instr(cmp_imm); break;
2207 }
2208
2209 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2210 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
2211 ic->arg[2] = imm16 << shift;
2212
2213 /* Optimization for or d,r0,imm and similar */
2214 if (s1 == M88K_ZERO_REG && ic->f == instr(or_imm)) {
2215 if (ic->arg[2] == 0)
2216 ic->f = instr(or_r0_imm0);
2217 else
2218 ic->f = instr(or_r0_imm);
2219 }
2220 if (ic->arg[2] == 0 && ic->f == instr(addu_imm))
2221 ic->f = instr(addu_s2r0);
2222
2223 if (d == s1 && ic->arg[2] == 1) {
2224 if (ic->f == instr(addu_imm))
2225 ic->f = instr(inc_reg);
2226 if (ic->f == instr(subu_imm))
2227 ic->f = instr(dec_reg);
2228 }
2229
2230 if (d == M88K_ZERO_REG)
2231 ic->f = instr(nop);
2232 break;
2233
2234 case 0x20:
2235 if ((iword & 0x001ff81f) == 0x00004000) {
2236 ic->f = instr(ldcr);
2237 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2238 ic->arg[1] = cr6;
2239 if (d == M88K_ZERO_REG)
2240 ic->arg[0] = (size_t)
2241 &cpu->cd.m88k.zero_scratch;
2242 } else if ((iword & 0x001ff81f) == 0x00004800) {
2243 ic->f = instr(fldcr);
2244 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2245 ic->arg[1] = cr6;
2246 if (d == M88K_ZERO_REG)
2247 ic->arg[0] = (size_t)
2248 &cpu->cd.m88k.zero_scratch;
2249 } else if ((iword & 0x03e0f800) == 0x00008000) {
2250 ic->f = instr(stcr);
2251 ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
2252 ic->arg[1] = cr6;
2253 if (s1 != s2)
2254 goto bad;
2255 } else if ((iword & 0x03e0f800) == 0x00008800) {
2256 ic->f = instr(fstcr);
2257 ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
2258 ic->arg[1] = cr6;
2259 if (s1 != s2)
2260 goto bad;
2261 } else if ((iword & 0x0000f800) == 0x0000c000) {
2262 ic->f = instr(xcr);
2263 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2264 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
2265 ic->arg[2] = cr6;
2266 if (s1 != s2)
2267 goto bad;
2268 } else
2269 goto bad;
2270 break;
2271
2272 case 0x21:
2273 switch (op11) {
2274
2275 case 0x00: /* fmul */
2276 if (d == 0) {
2277 /* d = 0 isn't allowed. for now, let's abort execution. */
2278 fatal("TODO: exception for d = 0 in fmul.xxx instruction\n");
2279 goto bad;
2280 }
2281 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2282 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
2283 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
2284 switch ((iword >> 5) & 0x3f) {
2285 case 0x00: ic->f = instr(fmul_sss); break;
2286 case 0x01: ic->f = instr(fmul_dss); break;
2287 case 0x05: ic->f = instr(fmul_dsd); break;
2288 case 0x11: ic->f = instr(fmul_dds); break;
2289 case 0x15: ic->f = instr(fmul_ddd); break;
2290 default:if (!cpu->translation_readahead)
2291 fatal("Unimplemented fmul combination 0x%x.\n",
2292 (iword >> 5) & 0x3f);
2293 goto bad;
2294 }
2295 break;
2296
2297 case 0x04: /* flt */
2298 if (d == 0) {
2299 /* d = 0 isn't allowed. for now, let's abort execution. */
2300 fatal("TODO: exception for d = 0 in flt.xx instruction\n");
2301 goto bad;
2302 }
2303 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2304 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s2];
2305 if ((iword >> 5) & 1) {
2306 ic->f = instr(flt_ds);
2307 if (d & 1) {
2308 fatal("TODO: double precision load into uneven register r%i?\n", d);
2309 goto bad;
2310 }
2311 } else {
2312 ic->f = instr(flt_ss);
2313 }
2314 break;
2315
2316 case 0x05: /* fadd */
2317 if (d == 0) {
2318 /* d = 0 isn't allowed. for now, let's abort execution. */
2319 fatal("TODO: exception for d = 0 in fadd.xxx instruction\n");
2320 goto bad;
2321 }
2322 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2323 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
2324 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
2325 switch ((iword >> 5) & 0x3f) {
2326 case 0x00: ic->f = instr(fadd_sss); break;
2327 case 0x05: ic->f = instr(fadd_dsd); break;
2328 case 0x11: ic->f = instr(fadd_dds); break;
2329 case 0x15: ic->f = instr(fadd_ddd); break;
2330 default:if (!cpu->translation_readahead)
2331 fatal("Unimplemented fadd combination 0x%x.\n",
2332 (iword >> 5) & 0x3f);
2333 goto bad;
2334 }
2335 break;
2336
2337 case 0x06: /* fsub */
2338 if (d == 0) {
2339 /* d = 0 isn't allowed. for now, let's abort execution. */
2340 fatal("TODO: exception for d = 0 in fsub.xxx instruction\n");
2341 goto bad;
2342 }
2343 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2344 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
2345 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
2346 switch ((iword >> 5) & 0x3f) {
2347 case 0x00: ic->f = instr(fsub_sss); break;
2348 case 0x01: ic->f = instr(fsub_dss); break;
2349 case 0x05: ic->f = instr(fsub_dsd); break;
2350 case 0x10: ic->f = instr(fsub_sds); break;
2351 case 0x11: ic->f = instr(fsub_dds); break;
2352 case 0x15: ic->f = instr(fsub_ddd); break;
2353 default:if (!cpu->translation_readahead)
2354 fatal("Unimplemented fsub combination 0x%x.\n",
2355 (iword >> 5) & 0x3f);
2356 goto bad;
2357 }
2358 break;
2359
2360 case 0x07: /* fcmp */
2361 if (d == 0) {
2362 /* d = 0 isn't allowed. for now, let's abort execution. */
2363 fatal("TODO: exception for d = 0 in fcmp.xxx instruction\n");
2364 goto bad;
2365 }
2366 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2367 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
2368 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
2369 switch ((iword >> 5) & 0x3f) {
2370 case 0x00: ic->f = instr(fcmp_sss); break;
2371 case 0x04: ic->f = instr(fcmp_ssd); break;
2372 case 0x10: ic->f = instr(fcmp_sds); break;
2373 case 0x14: ic->f = instr(fcmp_sdd); break;
2374 default:if (!cpu->translation_readahead)
2375 fatal("Unimplemented fcmp combination 0x%x.\n",
2376 (iword >> 5) & 0x3f);
2377 goto bad;
2378 }
2379 break;
2380
2381 case 0x0b: /* trnc */
2382 if (d == 0) {
2383 /* d = 0 isn't allowed. for now, let's abort execution. */
2384 fatal("TODO: exception for d = 0 in trnc.xx instruction\n");
2385 goto bad;
2386 }
2387 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2388 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s2];
2389 if ((iword >> 7) & 1) {
2390 ic->f = instr(trnc_sd);
2391 if (s2 & 1) {
2392 fatal("TODO: double precision truncation into uneven register r%i?\n", d);
2393 goto bad;
2394 }
2395 } else {
2396 ic->f = instr(trnc_ss);
2397 }
2398 break;
2399
2400 case 0x0e: /* fdiv */
2401 if (d == 0) {
2402 /* d = 0 isn't allowed. for now, let's abort execution. */
2403 fatal("TODO: exception for d = 0 in fdiv.xxx instruction\n");
2404 goto bad;
2405 }
2406 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2407 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
2408 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
2409 switch ((iword >> 5) & 0x3f) {
2410 case 0x00: ic->f = instr(fdiv_sss); break;
2411 case 0x01: ic->f = instr(fdiv_dss); break;
2412 case 0x05: ic->f = instr(fdiv_dsd); break;
2413 case 0x15: ic->f = instr(fdiv_ddd); break;
2414 default:if (!cpu->translation_readahead)
2415 fatal("Unimplemented fdiv combination 0x%x.\n",
2416 (iword >> 5) & 0x3f);
2417 goto bad;
2418 }
2419 break;
2420
2421 default:goto bad;
2422 }
2423 break;
2424
2425 case 0x30: /* br */
2426 case 0x31: /* br.n */
2427 case 0x32: /* bsr */
2428 case 0x33: /* bsr.n */
2429 switch (op26) {
2430 case 0x30:
2431 ic->f = instr(br);
2432 samepage_function = instr(br_samepage);
2433 if (cpu->translation_readahead > 1)
2434 cpu->translation_readahead = 1;
2435 break;
2436 case 0x31:
2437 ic->f = instr(br_n);
2438 if (cpu->translation_readahead > 2)
2439 cpu->translation_readahead = 2;
2440 break;
2441 case 0x32:
2442 ic->f = instr(bsr);
2443 samepage_function = instr(bsr_samepage);
2444 break;
2445 case 0x33:
2446 ic->f = instr(bsr_n);
2447 break;
2448 }
2449
2450 offset = (addr & 0xffc) + d26;
2451
2452 /* Prepare both samepage and offset style args.
2453 (Only one will be used in the actual instruction.) */
2454 ic->arg[0] = (size_t) ( cpu->cd.m88k.cur_ic_page +
2455 (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
2456 ic->arg[1] = offset;
2457 ic->arg[2] = (addr & 0xffc) + 4; /* Return offset
2458 for bsr_samepage */
2459
2460 if (offset >= 0 && offset <= 0xffc &&
2461 samepage_function != NULL)
2462 ic->f = samepage_function;
2463
2464 if (cpu->machine->show_trace_tree) {
2465 if (op26 == 0x32)
2466 ic->f = instr(bsr_trace);
2467 if (op26 == 0x33)
2468 ic->f = instr(bsr_n_trace);
2469 }
2470
2471 break;
2472
2473 case 0x34: /* bb0 */
2474 case 0x35: /* bb0.n */
2475 case 0x36: /* bb1 */
2476 case 0x37: /* bb1.n */
2477 switch (op26) {
2478 case 0x34:
2479 ic->f = instr(bb0);
2480 samepage_function = instr(bb0_samepage);
2481 break;
2482 case 0x35:
2483 ic->f = instr(bb0_n);
2484 break;
2485 case 0x36:
2486 ic->f = instr(bb1);
2487 samepage_function = instr(bb1_samepage);
2488 break;
2489 case 0x37:
2490 ic->f = instr(bb1_n);
2491 break;
2492 }
2493
2494 ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
2495 ic->arg[1] = (uint32_t) (1 << d);
2496
2497 offset = (addr & 0xffc) + d16;
2498 ic->arg[2] = offset;
2499
2500 if (offset >= 0 && offset <= 0xffc &&
2501 samepage_function != NULL) {
2502 ic->f = samepage_function;
2503 ic->arg[2] = (size_t) ( cpu->cd.m88k.cur_ic_page +
2504 (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
2505 }
2506 break;
2507
2508 case 0x3a: /* bcnd */
2509 case 0x3b: /* bcnd.n */
2510 ic->f = m88k_bcnd[d + 32 * (op26 & 1)];
2511 samepage_function = m88k_bcnd[64 + d + 32 * (op26 & 1)];
2512
2513 if (ic->f == NULL)
2514 goto bad;
2515
2516 ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1];
2517
2518 offset = (addr & 0xffc) + d16;
2519 ic->arg[2] = offset;
2520
2521 if (offset >= 0 && offset <= 0xffc &&
2522 samepage_function != NULL) {
2523 ic->f = samepage_function;
2524 ic->arg[2] = (size_t) ( cpu->cd.m88k.cur_ic_page +
2525 (offset >> M88K_INSTR_ALIGNMENT_SHIFT) );
2526 }
2527
2528 if ((iword & 0xffe0ffff) == 0xe840ffff ||
2529 (iword & 0xffe0ffff) == 0xe840fffe)
2530 cpu->cd.m88k.combination_check = COMBINE(idle);
2531
2532 break;
2533
2534 case 0x3c:
2535 switch (op10) {
2536
2537 case 0x20: /* clr */
2538 case 0x22: /* set */
2539 case 0x24: /* ext */
2540 case 0x26: /* extu */
2541 case 0x28: /* mak */
2542 case 0x2a: /* rot */
2543 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2544 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
2545 ic->arg[2] = iword & 0x3ff;
2546
2547 switch (op10) {
2548 case 0x20: ic->f = instr(mask_imm);
2549 {
2550 int w = ic->arg[2] >> 5;
2551 int o = ic->arg[2] & 0x1f;
2552 uint32_t x = w == 0? 0xffffffff
2553 : ((uint32_t)1 << w) - 1;
2554 x <<= o;
2555 ic->arg[2] = ~x;
2556 }
2557 break;
2558 case 0x22: ic->f = instr(or_imm);
2559 {
2560 int w = ic->arg[2] >> 5;
2561 int o = ic->arg[2] & 0x1f;
2562 uint32_t x = w == 0? 0xffffffff
2563 : ((uint32_t)1 << w) - 1;
2564 x <<= o;
2565 ic->arg[2] = x;
2566 }
2567 break;
2568 case 0x24: ic->f = instr(ext_imm); break;
2569 case 0x26: ic->f = instr(extu_imm); break;
2570 case 0x28: ic->f = instr(mak_imm); break;
2571 case 0x2a: ic->f = instr(rot_imm); break;
2572 }
2573
2574 if (d == M88K_ZERO_REG)
2575 ic->f = instr(nop);
2576 break;
2577
2578 case 0x34: /* tb0 */
2579 case 0x36: /* tb1 */
2580 ic->arg[0] = 1 << d;
2581 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
2582 ic->arg[2] = iword & 0x1ff;
2583 switch (op10) {
2584 case 0x34: ic->f = instr(tb0); break;
2585 case 0x36: ic->f = instr(tb1); break;
2586 }
2587 break;
2588
2589 default:goto bad;
2590 }
2591 break;
2592
2593 case 0x3d:
2594 if ((iword & 0xf000) <= 0x3fff ) {
2595 /* Load, Store, xmem, and lda: */
2596 int op = 0, opsize, user = 0, wt = 0;
2597 int signedness = 1, scaled = 0;
2598
2599 switch (iword & 0xf000) {
2600 case 0x2000: op = 1; /* st */ break;
2601 case 0x3000: op = 2; /* lda */ break;
2602 default: if ((iword & 0xf800) >= 0x0800)
2603 op = 0; /* ld */
2604 else
2605 op = 3; /* xmem */
2606 }
2607
2608 /* for (most) ld, st, lda: */
2609 opsize = (iword >> 10) & 3;
2610
2611 /* Turn opsize into x, where size = 1 << x: */
2612 opsize = 3 - opsize;
2613
2614 if (op == 3) {
2615 /* xmem: */
2616 switch ((iword >> 10) & 3) {
2617 case 0: opsize = 0; break;
2618 case 1: opsize = 2; break;
2619 default:fatal("Weird xmem opsize/type?\n");
2620 goto bad;
2621 }
2622 } else {
2623 if ((iword & 0xf800) == 0x800) {
2624 signedness = 0;
2625 if ((iword & 0xf00) < 0xc00)
2626 opsize = 1;
2627 else
2628 opsize = 0;
2629 } else {
2630 if (opsize >= 2 || op == 1)
2631 signedness = 0;
2632 }
2633 }
2634
2635 if (iword & 0x100)
2636 user = 1;
2637 if (iword & 0x80)
2638 wt = 1;
2639 if (iword & 0x200)
2640 scaled = 1;
2641
2642 if (wt) {
2643 fatal("wt bit not yet implemented! TODO\n");
2644 goto bad;
2645 }
2646
2647 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2648 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
2649 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
2650
2651 if (op == 0 || op == 1) {
2652 /* ld or st: */
2653 ic->f = m88k_loadstore[ opsize
2654 + (op==1? M88K_LOADSTORE_STORE : 0)
2655 + (signedness? M88K_LOADSTORE_SIGNEDNESS:0)
2656 + (cpu->byte_order == EMUL_BIG_ENDIAN?
2657 M88K_LOADSTORE_ENDIANNESS : 0)
2658 + (scaled? M88K_LOADSTORE_SCALEDNESS : 0)
2659 + (user? M88K_LOADSTORE_USR : 0)
2660 + M88K_LOADSTORE_REGISTEROFFSET ];
2661
2662 if (d == M88K_ZERO_REG && op == 0)
2663 ic->arg[0] = (size_t)&cpu->cd.m88k.zero_scratch;
2664
2665 if (opsize == 3 && d == 31) {
2666 fatal("m88k load/store of register "
2667 "pair r31/r0: TODO\n");
2668 goto bad;
2669 }
2670 } else if (op == 2) {
2671 /* lda: */
2672 if (scaled) {
2673 switch (opsize) {
2674 case 0: ic->f = instr(addu); break;
2675 case 1: ic->f = instr(lda_reg_2); break;
2676 case 2: ic->f = instr(lda_reg_4); break;
2677 case 3: ic->f = instr(lda_reg_8); break;
2678 }
2679 } else {
2680 ic->f = instr(addu);
2681 }
2682 if (d == M88K_ZERO_REG)
2683 ic->f = instr(nop);
2684 } else {
2685 /* xmem: */
2686 ic->f = instr(xmem_slow);
2687 ic->arg[0] = iword;
2688 if (d == M88K_ZERO_REG)
2689 ic->f = instr(nop);
2690 }
2691 } else switch ((iword >> 8) & 0xff) {
2692 case 0x40: /* and */
2693 case 0x44: /* and.c */
2694 case 0x50: /* xor */
2695 case 0x54: /* xor.c */
2696 case 0x58: /* or */
2697 case 0x5c: /* or.c */
2698 case 0x60: /* addu */
2699 case 0x61: /* addu.co */
2700 case 0x62: /* addu.ci */
2701 case 0x63: /* addu.cio */
2702 case 0x64: /* subu */
2703 case 0x65: /* subu.co */
2704 case 0x66: /* subu.ci */
2705 case 0x67: /* subu.cio */
2706 case 0x68: /* divu */
2707 case 0x6c: /* mul */
2708 case 0x70: /* add */
2709 case 0x78: /* div */
2710 case 0x7c: /* cmp */
2711 case 0x80: /* clr */
2712 case 0x88: /* set */
2713 case 0x90: /* ext */
2714 case 0x98: /* extu */
2715 case 0xa0: /* mak */
2716 case 0xa8: /* rot */
2717 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2718 ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1];
2719 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
2720
2721 switch ((iword >> 8) & 0xff) {
2722 case 0x40: ic->f = instr(and); break;
2723 case 0x44: ic->f = instr(and_c); break;
2724 case 0x50: ic->f = instr(xor); break;
2725 case 0x54: ic->f = instr(xor_c); break;
2726 case 0x58: ic->f = instr(or); break;
2727 case 0x5c: ic->f = instr(or_c); break;
2728 case 0x60: ic->f = instr(addu); break;
2729 case 0x61: ic->f = instr(addu_co); break;
2730 case 0x62: ic->f = instr(addu_ci); break;
2731 case 0x63: ic->f = instr(addu_cio); break;
2732 case 0x64: ic->f = instr(subu); break;
2733 case 0x65: ic->f = instr(subu_co); break;
2734 case 0x66: ic->f = instr(subu_ci); break;
2735 case 0x67: ic->f = instr(subu_cio); break;
2736 case 0x68: ic->f = instr(divu); break;
2737 case 0x6c: ic->f = instr(mul); break;
2738 case 0x70: ic->f = instr(add); break;
2739 case 0x78: ic->f = instr(div); break;
2740 case 0x7c: ic->f = instr(cmp); break;
2741 case 0x80: ic->f = instr(clr); break;
2742 case 0x88: ic->f = instr(set); break;
2743 case 0x90: ic->f = instr(ext); break;
2744 case 0x98: ic->f = instr(extu); break;
2745 case 0xa0: ic->f = instr(mak); break;
2746 case 0xa8: ic->f = instr(rot); break;
2747 }
2748
2749 /* Optimization for or rX,r0,rY etc: */
2750 if (s1 == M88K_ZERO_REG && ic->f == instr(or))
2751 ic->f = instr(or_r0);
2752 if (s2 == M88K_ZERO_REG && ic->f == instr(addu))
2753 ic->f = instr(addu_s2r0);
2754
2755 /*
2756 * Handle the case when the destination register is r0:
2757 *
2758 * If there is NO SIDE-EFFECT! (i.e. no carry out),
2759 * then replace the instruction with a nop. If there is
2760 * a side-effect, we still have to run the instruction,
2761 * so replace the destination register with a scratch
2762 * register.
2763 */
2764 if (d == M88K_ZERO_REG) {
2765 int opc = (iword >> 8) & 0xff;
2766 if (opc != 0x61 /* addu.co */ && opc != 0x63 /* addu.cio */ &&
2767 opc != 0x65 /* subu.co */ && opc != 0x67 /* subu.cio */ &&
2768 opc != 0x71 /* add.co */ && opc != 0x73 /* add.cio */ &&
2769 opc != 0x75 /* sub.co */ && opc != 0x77 /* sub.cio */ &&
2770 opc != 0x68 /* divu */ && opc != 0x69 /* divu.d */ &&
2771 opc != 0x6c /* mul */ && opc != 0x6d /* mulu.d */ &&
2772 opc != 0x6e /* muls */ && opc != 0x78 /* div */)
2773 ic->f = instr(nop);
2774 else
2775 ic->arg[0] = (size_t)
2776 &cpu->cd.m88k.zero_scratch;
2777 }
2778 break;
2779 case 0xc0: /* jmp */
2780 case 0xc4: /* jmp.n */
2781 case 0xc8: /* jsr */
2782 case 0xcc: /* jsr.n */
2783 switch ((iword >> 8) & 0xff) {
2784 case 0xc0: ic->f = instr(jmp);
2785 if (cpu->translation_readahead > 1)
2786 cpu->translation_readahead = 1;
2787 break;
2788 case 0xc4: ic->f = instr(jmp_n);
2789 if (cpu->translation_readahead > 2)
2790 cpu->translation_readahead = 2;
2791 break;
2792 case 0xc8: ic->f = instr(jsr); break;
2793 case 0xcc: ic->f = instr(jsr_n); break;
2794 }
2795
2796 ic->arg[1] = (addr & 0xffc) + 4;
2797 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
2798
2799 if (((iword >> 8) & 0x04) == 0x04)
2800 ic->arg[1] = (addr & 0xffc) + 8;
2801
2802 if (cpu->machine->show_trace_tree &&
2803 s2 == M88K_RETURN_REG) {
2804 if (ic->f == instr(jmp))
2805 ic->f = instr(jmp_trace);
2806 if (ic->f == instr(jmp_n))
2807 ic->f = instr(jmp_n_trace);
2808 }
2809 if (cpu->machine->show_trace_tree) {
2810 if (ic->f == instr(jsr))
2811 ic->f = instr(jsr_trace);
2812 if (ic->f == instr(jsr_n))
2813 ic->f = instr(jsr_n_trace);
2814 }
2815 break;
2816 case 0xe8: /* ff1 */
2817 case 0xec: /* ff0 */
2818 switch ((iword >> 8) & 0xff) {
2819 case 0xe8: ic->f = instr(ff1); break;
2820 case 0xec: ic->f = instr(ff0); break;
2821 }
2822
2823 ic->arg[0] = (size_t) &cpu->cd.m88k.r[d];
2824 ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2];
2825
2826 if (d == M88K_ZERO_REG)
2827 ic->f = instr(nop);
2828 break;
2829 case 0xfc:
2830 switch (iword & 0xff) {
2831 case 0x00:
2832 if (iword == 0xf400fc00)
2833 ic->f = instr(rte);
2834 else {
2835 fatal("unimplemented rte variant: 0x%08" PRIx32"\n", iword);
2836 goto bad;
2837 }
2838 break;
2839 case (M88K_PROM_INSTR & 0xff):
2840 ic->f = instr(prom_call);
2841 break;
2842 default:fatal("Unimplemented 3d/fc instruction\n");
2843 goto bad;
2844 }
2845 break;
2846 default:goto bad;
2847 }
2848 break;
2849
2850 default:goto bad;
2851 }
2852
2853
2854 #define DYNTRANS_TO_BE_TRANSLATED_TAIL
2855 #include "cpu_dyntrans.cc"
2856 #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
2857 }
2858
2859