1 /*
2 * M68K helper routines
3 *
4 * Copyright (c) 2007 CodeSourcery
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "qemu/osdep.h"
20 #include "qemu/log.h"
21 #include "cpu.h"
22 #include "exec/helper-proto.h"
23 #include "accel/tcg/cpu-ldst.h"
24 #include "semihosting/semihost.h"
25
26 #if !defined(CONFIG_USER_ONLY)
27
cf_rte(CPUM68KState * env)28 static void cf_rte(CPUM68KState *env)
29 {
30 uint32_t sp;
31 uint32_t fmt;
32
33 sp = env->aregs[7];
34 fmt = cpu_ldl_mmuidx_ra(env, sp, MMU_KERNEL_IDX, 0);
35 env->pc = cpu_ldl_mmuidx_ra(env, sp + 4, MMU_KERNEL_IDX, 0);
36 sp |= (fmt >> 28) & 3;
37 env->aregs[7] = sp + 8;
38
39 cpu_m68k_set_sr(env, fmt);
40 }
41
m68k_rte(CPUM68KState * env)42 static void m68k_rte(CPUM68KState *env)
43 {
44 uint32_t sp;
45 uint16_t fmt;
46 uint16_t sr;
47
48 sp = env->aregs[7];
49 throwaway:
50 sr = cpu_lduw_mmuidx_ra(env, sp, MMU_KERNEL_IDX, 0);
51 sp += 2;
52 env->pc = cpu_ldl_mmuidx_ra(env, sp, MMU_KERNEL_IDX, 0);
53 sp += 4;
54 if (m68k_feature(env, M68K_FEATURE_EXCEPTION_FORMAT_VEC)) {
55 /* all except 68000 */
56 fmt = cpu_lduw_mmuidx_ra(env, sp, MMU_KERNEL_IDX, 0);
57 sp += 2;
58 switch (fmt >> 12) {
59 case 0:
60 break;
61 case 1:
62 env->aregs[7] = sp;
63 cpu_m68k_set_sr(env, sr);
64 goto throwaway;
65 case 2:
66 case 3:
67 sp += 4;
68 break;
69 case 4:
70 sp += 8;
71 break;
72 case 7:
73 sp += 52;
74 break;
75 }
76 }
77 env->aregs[7] = sp;
78 cpu_m68k_set_sr(env, sr);
79 }
80
m68k_exception_name(int index)81 static const char *m68k_exception_name(int index)
82 {
83 switch (index) {
84 case EXCP_ACCESS:
85 return "Access Fault";
86 case EXCP_ADDRESS:
87 return "Address Error";
88 case EXCP_ILLEGAL:
89 return "Illegal Instruction";
90 case EXCP_DIV0:
91 return "Divide by Zero";
92 case EXCP_CHK:
93 return "CHK/CHK2";
94 case EXCP_TRAPCC:
95 return "FTRAPcc, TRAPcc, TRAPV";
96 case EXCP_PRIVILEGE:
97 return "Privilege Violation";
98 case EXCP_TRACE:
99 return "Trace";
100 case EXCP_LINEA:
101 return "A-Line";
102 case EXCP_LINEF:
103 return "F-Line";
104 case EXCP_DEBEGBP: /* 68020/030 only */
105 return "Copro Protocol Violation";
106 case EXCP_FORMAT:
107 return "Format Error";
108 case EXCP_UNINITIALIZED:
109 return "Uninitialized Interrupt";
110 case EXCP_SPURIOUS:
111 return "Spurious Interrupt";
112 case EXCP_INT_LEVEL_1:
113 return "Level 1 Interrupt";
114 case EXCP_INT_LEVEL_1 + 1:
115 return "Level 2 Interrupt";
116 case EXCP_INT_LEVEL_1 + 2:
117 return "Level 3 Interrupt";
118 case EXCP_INT_LEVEL_1 + 3:
119 return "Level 4 Interrupt";
120 case EXCP_INT_LEVEL_1 + 4:
121 return "Level 5 Interrupt";
122 case EXCP_INT_LEVEL_1 + 5:
123 return "Level 6 Interrupt";
124 case EXCP_INT_LEVEL_1 + 6:
125 return "Level 7 Interrupt";
126 case EXCP_TRAP0:
127 return "TRAP #0";
128 case EXCP_TRAP0 + 1:
129 return "TRAP #1";
130 case EXCP_TRAP0 + 2:
131 return "TRAP #2";
132 case EXCP_TRAP0 + 3:
133 return "TRAP #3";
134 case EXCP_TRAP0 + 4:
135 return "TRAP #4";
136 case EXCP_TRAP0 + 5:
137 return "TRAP #5";
138 case EXCP_TRAP0 + 6:
139 return "TRAP #6";
140 case EXCP_TRAP0 + 7:
141 return "TRAP #7";
142 case EXCP_TRAP0 + 8:
143 return "TRAP #8";
144 case EXCP_TRAP0 + 9:
145 return "TRAP #9";
146 case EXCP_TRAP0 + 10:
147 return "TRAP #10";
148 case EXCP_TRAP0 + 11:
149 return "TRAP #11";
150 case EXCP_TRAP0 + 12:
151 return "TRAP #12";
152 case EXCP_TRAP0 + 13:
153 return "TRAP #13";
154 case EXCP_TRAP0 + 14:
155 return "TRAP #14";
156 case EXCP_TRAP0 + 15:
157 return "TRAP #15";
158 case EXCP_FP_BSUN:
159 return "FP Branch/Set on unordered condition";
160 case EXCP_FP_INEX:
161 return "FP Inexact Result";
162 case EXCP_FP_DZ:
163 return "FP Divide by Zero";
164 case EXCP_FP_UNFL:
165 return "FP Underflow";
166 case EXCP_FP_OPERR:
167 return "FP Operand Error";
168 case EXCP_FP_OVFL:
169 return "FP Overflow";
170 case EXCP_FP_SNAN:
171 return "FP Signaling NAN";
172 case EXCP_FP_UNIMP:
173 return "FP Unimplemented Data Type";
174 case EXCP_MMU_CONF: /* 68030/68851 only */
175 return "MMU Configuration Error";
176 case EXCP_MMU_ILLEGAL: /* 68851 only */
177 return "MMU Illegal Operation";
178 case EXCP_MMU_ACCESS: /* 68851 only */
179 return "MMU Access Level Violation";
180 case 64 ... 255:
181 return "User Defined Vector";
182 }
183 return "Unassigned";
184 }
185
cf_interrupt_all(CPUM68KState * env,int is_hw)186 static void cf_interrupt_all(CPUM68KState *env, int is_hw)
187 {
188 CPUState *cs = env_cpu(env);
189 uint32_t sp;
190 uint32_t sr;
191 uint32_t fmt;
192 uint32_t retaddr;
193 uint32_t vector;
194
195 fmt = 0;
196 retaddr = env->pc;
197
198 if (!is_hw) {
199 switch (cs->exception_index) {
200 case EXCP_RTE:
201 /* Return from an exception. */
202 cf_rte(env);
203 return;
204 case EXCP_SEMIHOSTING:
205 do_m68k_semihosting(env, env->dregs[0]);
206 return;
207 }
208 }
209
210 vector = cs->exception_index << 2;
211
212 sr = env->sr | cpu_m68k_get_ccr(env);
213 if (qemu_loglevel_mask(CPU_LOG_INT)) {
214 static int count;
215 qemu_log("INT %6d: %s(%#x) pc=%08x sp=%08x sr=%04x\n",
216 ++count, m68k_exception_name(cs->exception_index),
217 vector, env->pc, env->aregs[7], sr);
218 }
219
220 fmt |= 0x40000000;
221 fmt |= vector << 16;
222 fmt |= sr;
223
224 env->sr |= SR_S;
225 if (is_hw) {
226 env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
227 env->sr &= ~SR_M;
228 }
229 m68k_switch_sp(env);
230 sp = env->aregs[7];
231 fmt |= (sp & 3) << 28;
232
233 /* ??? This could cause MMU faults. */
234 sp &= ~3;
235 sp -= 4;
236 cpu_stl_mmuidx_ra(env, sp, retaddr, MMU_KERNEL_IDX, 0);
237 sp -= 4;
238 cpu_stl_mmuidx_ra(env, sp, fmt, MMU_KERNEL_IDX, 0);
239 env->aregs[7] = sp;
240 /* Jump to vector. */
241 env->pc = cpu_ldl_mmuidx_ra(env, env->vbr + vector, MMU_KERNEL_IDX, 0);
242 }
243
do_stack_frame(CPUM68KState * env,uint32_t * sp,uint16_t format,uint16_t sr,uint32_t addr,uint32_t retaddr)244 static inline void do_stack_frame(CPUM68KState *env, uint32_t *sp,
245 uint16_t format, uint16_t sr,
246 uint32_t addr, uint32_t retaddr)
247 {
248 if (m68k_feature(env, M68K_FEATURE_EXCEPTION_FORMAT_VEC)) {
249 /* all except 68000 */
250 CPUState *cs = env_cpu(env);
251 switch (format) {
252 case 4:
253 *sp -= 4;
254 cpu_stl_mmuidx_ra(env, *sp, env->pc, MMU_KERNEL_IDX, 0);
255 *sp -= 4;
256 cpu_stl_mmuidx_ra(env, *sp, addr, MMU_KERNEL_IDX, 0);
257 break;
258 case 3:
259 case 2:
260 *sp -= 4;
261 cpu_stl_mmuidx_ra(env, *sp, addr, MMU_KERNEL_IDX, 0);
262 break;
263 }
264 *sp -= 2;
265 cpu_stw_mmuidx_ra(env, *sp, (format << 12) + (cs->exception_index << 2),
266 MMU_KERNEL_IDX, 0);
267 }
268 *sp -= 4;
269 cpu_stl_mmuidx_ra(env, *sp, retaddr, MMU_KERNEL_IDX, 0);
270 *sp -= 2;
271 cpu_stw_mmuidx_ra(env, *sp, sr, MMU_KERNEL_IDX, 0);
272 }
273
m68k_interrupt_all(CPUM68KState * env,int is_hw)274 static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
275 {
276 CPUState *cs = env_cpu(env);
277 uint32_t sp;
278 uint32_t vector;
279 uint16_t sr, oldsr;
280
281 if (!is_hw) {
282 switch (cs->exception_index) {
283 case EXCP_RTE:
284 /* Return from an exception. */
285 m68k_rte(env);
286 return;
287 }
288 }
289
290 vector = cs->exception_index << 2;
291
292 sr = env->sr | cpu_m68k_get_ccr(env);
293 if (qemu_loglevel_mask(CPU_LOG_INT)) {
294 static int count;
295 qemu_log("INT %6d: %s(%#x) pc=%08x sp=%08x sr=%04x\n",
296 ++count, m68k_exception_name(cs->exception_index),
297 vector, env->pc, env->aregs[7], sr);
298 }
299
300 /*
301 * MC68040UM/AD, chapter 9.3.10
302 */
303
304 /* "the processor first make an internal copy" */
305 oldsr = sr;
306 /* "set the mode to supervisor" */
307 sr |= SR_S;
308 /* "suppress tracing" */
309 sr &= ~SR_T;
310 /* "sets the processor interrupt mask" */
311 if (is_hw) {
312 sr |= (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
313 }
314 cpu_m68k_set_sr(env, sr);
315 sp = env->aregs[7];
316
317 if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) {
318 sp &= ~1;
319 }
320
321 switch (cs->exception_index) {
322 case EXCP_ACCESS:
323 if (env->mmu.fault) {
324 cpu_abort(cs, "DOUBLE MMU FAULT\n");
325 }
326 env->mmu.fault = true;
327 /* push data 3 */
328 sp -= 4;
329 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
330 /* push data 2 */
331 sp -= 4;
332 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
333 /* push data 1 */
334 sp -= 4;
335 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
336 /* write back 1 / push data 0 */
337 sp -= 4;
338 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
339 /* write back 1 address */
340 sp -= 4;
341 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
342 /* write back 2 data */
343 sp -= 4;
344 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
345 /* write back 2 address */
346 sp -= 4;
347 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
348 /* write back 3 data */
349 sp -= 4;
350 cpu_stl_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
351 /* write back 3 address */
352 sp -= 4;
353 cpu_stl_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0);
354 /* fault address */
355 sp -= 4;
356 cpu_stl_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0);
357 /* write back 1 status */
358 sp -= 2;
359 cpu_stw_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
360 /* write back 2 status */
361 sp -= 2;
362 cpu_stw_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
363 /* write back 3 status */
364 sp -= 2;
365 cpu_stw_mmuidx_ra(env, sp, 0, MMU_KERNEL_IDX, 0);
366 /* special status word */
367 sp -= 2;
368 cpu_stw_mmuidx_ra(env, sp, env->mmu.ssw, MMU_KERNEL_IDX, 0);
369 /* effective address */
370 sp -= 4;
371 cpu_stl_mmuidx_ra(env, sp, env->mmu.ar, MMU_KERNEL_IDX, 0);
372
373 do_stack_frame(env, &sp, 7, oldsr, 0, env->pc);
374 env->mmu.fault = false;
375 if (qemu_loglevel_mask(CPU_LOG_INT)) {
376 qemu_log(" "
377 "ssw: %08x ea: %08x sfc: %d dfc: %d\n",
378 env->mmu.ssw, env->mmu.ar, env->sfc, env->dfc);
379 }
380 break;
381
382 case EXCP_ILLEGAL:
383 do_stack_frame(env, &sp, 0, oldsr, 0, env->pc);
384 break;
385
386 case EXCP_ADDRESS:
387 do_stack_frame(env, &sp, 2, oldsr, 0, env->pc);
388 break;
389
390 case EXCP_CHK:
391 case EXCP_DIV0:
392 case EXCP_TRACE:
393 case EXCP_TRAPCC:
394 do_stack_frame(env, &sp, 2, oldsr, env->mmu.ar, env->pc);
395 break;
396
397 case EXCP_SPURIOUS ... EXCP_INT_LEVEL_7:
398 if (is_hw && (oldsr & SR_M)) {
399 do_stack_frame(env, &sp, 0, oldsr, 0, env->pc);
400 oldsr = sr;
401 env->aregs[7] = sp;
402 cpu_m68k_set_sr(env, sr & ~SR_M);
403 sp = env->aregs[7];
404 if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) {
405 sp &= ~1;
406 }
407 do_stack_frame(env, &sp, 1, oldsr, 0, env->pc);
408 break;
409 }
410 /* fall through */
411
412 default:
413 do_stack_frame(env, &sp, 0, oldsr, 0, env->pc);
414 break;
415 }
416
417 env->aregs[7] = sp;
418 /* Jump to vector. */
419 env->pc = cpu_ldl_mmuidx_ra(env, env->vbr + vector, MMU_KERNEL_IDX, 0);
420 }
421
do_interrupt_all(CPUM68KState * env,int is_hw)422 static void do_interrupt_all(CPUM68KState *env, int is_hw)
423 {
424 if (m68k_feature(env, M68K_FEATURE_M68K)) {
425 m68k_interrupt_all(env, is_hw);
426 return;
427 }
428 cf_interrupt_all(env, is_hw);
429 }
430
m68k_cpu_do_interrupt(CPUState * cs)431 void m68k_cpu_do_interrupt(CPUState *cs)
432 {
433 do_interrupt_all(cpu_env(cs), 0);
434 }
435
do_interrupt_m68k_hardirq(CPUM68KState * env)436 static inline void do_interrupt_m68k_hardirq(CPUM68KState *env)
437 {
438 do_interrupt_all(env, 1);
439 }
440
m68k_cpu_transaction_failed(CPUState * cs,hwaddr physaddr,vaddr addr,unsigned size,MMUAccessType access_type,int mmu_idx,MemTxAttrs attrs,MemTxResult response,uintptr_t retaddr)441 void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
442 unsigned size, MMUAccessType access_type,
443 int mmu_idx, MemTxAttrs attrs,
444 MemTxResult response, uintptr_t retaddr)
445 {
446 CPUM68KState *env = cpu_env(cs);
447
448 cpu_restore_state(cs, retaddr);
449
450 if (m68k_feature(env, M68K_FEATURE_M68040)) {
451 env->mmu.mmusr = 0;
452
453 /*
454 * According to the MC68040 users manual the ATC bit of the SSW is
455 * used to distinguish between ATC faults and physical bus errors.
456 * In the case of a bus error e.g. during nubus read from an empty
457 * slot this bit should not be set
458 */
459 if (response != MEMTX_DECODE_ERROR) {
460 env->mmu.ssw |= M68K_ATC_040;
461 }
462
463 /* FIXME: manage MMU table access error */
464 env->mmu.ssw &= ~M68K_TM_040;
465 if (env->sr & SR_S) { /* SUPERVISOR */
466 env->mmu.ssw |= M68K_TM_040_SUPER;
467 }
468 if (access_type == MMU_INST_FETCH) { /* instruction or data */
469 env->mmu.ssw |= M68K_TM_040_CODE;
470 } else {
471 env->mmu.ssw |= M68K_TM_040_DATA;
472 }
473 env->mmu.ssw &= ~M68K_BA_SIZE_MASK;
474 switch (size) {
475 case 1:
476 env->mmu.ssw |= M68K_BA_SIZE_BYTE;
477 break;
478 case 2:
479 env->mmu.ssw |= M68K_BA_SIZE_WORD;
480 break;
481 case 4:
482 env->mmu.ssw |= M68K_BA_SIZE_LONG;
483 break;
484 }
485
486 if (access_type != MMU_DATA_STORE) {
487 env->mmu.ssw |= M68K_RW_040;
488 }
489
490 env->mmu.ar = addr;
491
492 cs->exception_index = EXCP_ACCESS;
493 cpu_loop_exit(cs);
494 }
495 }
496
m68k_cpu_exec_interrupt(CPUState * cs,int interrupt_request)497 bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
498 {
499 CPUM68KState *env = cpu_env(cs);
500
501 if (interrupt_request & CPU_INTERRUPT_HARD
502 && ((env->sr & SR_I) >> SR_I_SHIFT) < env->pending_level) {
503 /*
504 * Real hardware gets the interrupt vector via an IACK cycle
505 * at this point. Current emulated hardware doesn't rely on
506 * this, so we provide/save the vector when the interrupt is
507 * first signalled.
508 */
509 cs->exception_index = env->pending_vector;
510 do_interrupt_m68k_hardirq(env);
511 return true;
512 }
513 return false;
514 }
515
516 #endif /* !CONFIG_USER_ONLY */
517
518 G_NORETURN static void
raise_exception_ra(CPUM68KState * env,int tt,uintptr_t raddr)519 raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr)
520 {
521 CPUState *cs = env_cpu(env);
522
523 cs->exception_index = tt;
524 cpu_loop_exit_restore(cs, raddr);
525 }
526
raise_exception(CPUM68KState * env,int tt)527 G_NORETURN static void raise_exception(CPUM68KState *env, int tt)
528 {
529 raise_exception_ra(env, tt, 0);
530 }
531
HELPER(raise_exception)532 void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt)
533 {
534 raise_exception(env, tt);
535 }
536
537 G_NORETURN static void
raise_exception_format2(CPUM68KState * env,int tt,int ilen,uintptr_t raddr)538 raise_exception_format2(CPUM68KState *env, int tt, int ilen, uintptr_t raddr)
539 {
540 CPUState *cs = env_cpu(env);
541
542 cs->exception_index = tt;
543
544 /* Recover PC and CC_OP for the beginning of the insn. */
545 cpu_restore_state(cs, raddr);
546
547 /* Flags are current in env->cc_*, or are undefined. */
548 env->cc_op = CC_OP_FLAGS;
549
550 /*
551 * Remember original pc in mmu.ar, for the Format 2 stack frame.
552 * Adjust PC to end of the insn.
553 */
554 env->mmu.ar = env->pc;
555 env->pc += ilen;
556
557 cpu_loop_exit(cs);
558 }
559
HELPER(divuw)560 void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den, int ilen)
561 {
562 uint32_t num = env->dregs[destr];
563 uint32_t quot, rem;
564
565 env->cc_c = 0; /* always cleared, even if div0 */
566
567 if (den == 0) {
568 raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
569 }
570 quot = num / den;
571 rem = num % den;
572
573 if (quot > 0xffff) {
574 env->cc_v = -1;
575 /*
576 * real 68040 keeps N and unset Z on overflow,
577 * whereas documentation says "undefined"
578 */
579 env->cc_z = 1;
580 return;
581 }
582 env->dregs[destr] = deposit32(quot, 16, 16, rem);
583 env->cc_z = (int16_t)quot;
584 env->cc_n = (int16_t)quot;
585 env->cc_v = 0;
586 }
587
HELPER(divsw)588 void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den, int ilen)
589 {
590 int32_t num = env->dregs[destr];
591 uint32_t quot, rem;
592
593 env->cc_c = 0; /* always cleared, even if overflow/div0 */
594
595 if (den == 0) {
596 raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
597 }
598 quot = num / den;
599 rem = num % den;
600
601 if (quot != (int16_t)quot) {
602 env->cc_v = -1;
603 /* nothing else is modified */
604 /*
605 * real 68040 keeps N and unset Z on overflow,
606 * whereas documentation says "undefined"
607 */
608 env->cc_z = 1;
609 return;
610 }
611 env->dregs[destr] = deposit32(quot, 16, 16, rem);
612 env->cc_z = (int16_t)quot;
613 env->cc_n = (int16_t)quot;
614 env->cc_v = 0;
615 }
616
HELPER(divul)617 void HELPER(divul)(CPUM68KState *env, int numr, int regr,
618 uint32_t den, int ilen)
619 {
620 uint32_t num = env->dregs[numr];
621 uint32_t quot, rem;
622
623 env->cc_c = 0; /* always cleared, even if div0 */
624
625 if (den == 0) {
626 raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
627 }
628 quot = num / den;
629 rem = num % den;
630
631 env->cc_z = quot;
632 env->cc_n = quot;
633 env->cc_v = 0;
634
635 if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) {
636 if (numr == regr) {
637 env->dregs[numr] = quot;
638 } else {
639 env->dregs[regr] = rem;
640 }
641 } else {
642 env->dregs[regr] = rem;
643 env->dregs[numr] = quot;
644 }
645 }
646
HELPER(divsl)647 void HELPER(divsl)(CPUM68KState *env, int numr, int regr,
648 int32_t den, int ilen)
649 {
650 int32_t num = env->dregs[numr];
651 int32_t quot, rem;
652
653 env->cc_c = 0; /* always cleared, even if overflow/div0 */
654
655 if (den == 0) {
656 raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
657 }
658 quot = num / den;
659 rem = num % den;
660
661 env->cc_z = quot;
662 env->cc_n = quot;
663 env->cc_v = 0;
664
665 if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) {
666 if (numr == regr) {
667 env->dregs[numr] = quot;
668 } else {
669 env->dregs[regr] = rem;
670 }
671 } else {
672 env->dregs[regr] = rem;
673 env->dregs[numr] = quot;
674 }
675 }
676
HELPER(divull)677 void HELPER(divull)(CPUM68KState *env, int numr, int regr,
678 uint32_t den, int ilen)
679 {
680 uint64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]);
681 uint64_t quot;
682 uint32_t rem;
683
684 env->cc_c = 0; /* always cleared, even if overflow/div0 */
685
686 if (den == 0) {
687 raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
688 }
689 quot = num / den;
690 rem = num % den;
691
692 if (quot > 0xffffffffULL) {
693 env->cc_v = -1;
694 /*
695 * real 68040 keeps N and unset Z on overflow,
696 * whereas documentation says "undefined"
697 */
698 env->cc_z = 1;
699 return;
700 }
701 env->cc_z = quot;
702 env->cc_n = quot;
703 env->cc_v = 0;
704
705 /*
706 * If Dq and Dr are the same, the quotient is returned.
707 * therefore we set Dq last.
708 */
709
710 env->dregs[regr] = rem;
711 env->dregs[numr] = quot;
712 }
713
HELPER(divsll)714 void HELPER(divsll)(CPUM68KState *env, int numr, int regr,
715 int32_t den, int ilen)
716 {
717 int64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]);
718 int64_t quot;
719 int32_t rem;
720
721 env->cc_c = 0; /* always cleared, even if overflow/div0 */
722
723 if (den == 0) {
724 raise_exception_format2(env, EXCP_DIV0, ilen, GETPC());
725 }
726 quot = num / den;
727 rem = num % den;
728
729 if (quot != (int32_t)quot) {
730 env->cc_v = -1;
731 /*
732 * real 68040 keeps N and unset Z on overflow,
733 * whereas documentation says "undefined"
734 */
735 env->cc_z = 1;
736 return;
737 }
738 env->cc_z = quot;
739 env->cc_n = quot;
740 env->cc_v = 0;
741
742 /*
743 * If Dq and Dr are the same, the quotient is returned.
744 * therefore we set Dq last.
745 */
746
747 env->dregs[regr] = rem;
748 env->dregs[numr] = quot;
749 }
750
751 /* We're executing in a serial context -- no need to be atomic. */
HELPER(cas2w)752 void HELPER(cas2w)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2)
753 {
754 uint32_t Dc1 = extract32(regs, 9, 3);
755 uint32_t Dc2 = extract32(regs, 6, 3);
756 uint32_t Du1 = extract32(regs, 3, 3);
757 uint32_t Du2 = extract32(regs, 0, 3);
758 int16_t c1 = env->dregs[Dc1];
759 int16_t c2 = env->dregs[Dc2];
760 int16_t u1 = env->dregs[Du1];
761 int16_t u2 = env->dregs[Du2];
762 int16_t l1, l2;
763 uintptr_t ra = GETPC();
764
765 l1 = cpu_lduw_data_ra(env, a1, ra);
766 l2 = cpu_lduw_data_ra(env, a2, ra);
767 if (l1 == c1 && l2 == c2) {
768 cpu_stw_data_ra(env, a1, u1, ra);
769 cpu_stw_data_ra(env, a2, u2, ra);
770 }
771
772 if (c1 != l1) {
773 env->cc_n = l1;
774 env->cc_v = c1;
775 } else {
776 env->cc_n = l2;
777 env->cc_v = c2;
778 }
779 env->cc_op = CC_OP_CMPW;
780 env->dregs[Dc1] = deposit32(env->dregs[Dc1], 0, 16, l1);
781 env->dregs[Dc2] = deposit32(env->dregs[Dc2], 0, 16, l2);
782 }
783
do_cas2l(CPUM68KState * env,uint32_t regs,uint32_t a1,uint32_t a2,bool parallel)784 static void do_cas2l(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2,
785 bool parallel)
786 {
787 uint32_t Dc1 = extract32(regs, 9, 3);
788 uint32_t Dc2 = extract32(regs, 6, 3);
789 uint32_t Du1 = extract32(regs, 3, 3);
790 uint32_t Du2 = extract32(regs, 0, 3);
791 uint32_t c1 = env->dregs[Dc1];
792 uint32_t c2 = env->dregs[Dc2];
793 uint32_t u1 = env->dregs[Du1];
794 uint32_t u2 = env->dregs[Du2];
795 uint32_t l1, l2;
796 uintptr_t ra = GETPC();
797 #if defined(CONFIG_ATOMIC64)
798 int mmu_idx = cpu_mmu_index(env_cpu(env), 0);
799 MemOpIdx oi = make_memop_idx(MO_BEUQ, mmu_idx);
800 #endif
801
802 if (parallel) {
803 /* We're executing in a parallel context -- must be atomic. */
804 #ifdef CONFIG_ATOMIC64
805 uint64_t c, u, l;
806 if ((a1 & 7) == 0 && a2 == a1 + 4) {
807 c = deposit64(c2, 32, 32, c1);
808 u = deposit64(u2, 32, 32, u1);
809 l = cpu_atomic_cmpxchgq_be_mmu(env, a1, c, u, oi, ra);
810 l1 = l >> 32;
811 l2 = l;
812 } else if ((a2 & 7) == 0 && a1 == a2 + 4) {
813 c = deposit64(c1, 32, 32, c2);
814 u = deposit64(u1, 32, 32, u2);
815 l = cpu_atomic_cmpxchgq_be_mmu(env, a2, c, u, oi, ra);
816 l2 = l >> 32;
817 l1 = l;
818 } else
819 #endif
820 {
821 /* Tell the main loop we need to serialize this insn. */
822 cpu_loop_exit_atomic(env_cpu(env), ra);
823 }
824 } else {
825 /* We're executing in a serial context -- no need to be atomic. */
826 l1 = cpu_ldl_data_ra(env, a1, ra);
827 l2 = cpu_ldl_data_ra(env, a2, ra);
828 if (l1 == c1 && l2 == c2) {
829 cpu_stl_data_ra(env, a1, u1, ra);
830 cpu_stl_data_ra(env, a2, u2, ra);
831 }
832 }
833
834 if (c1 != l1) {
835 env->cc_n = l1;
836 env->cc_v = c1;
837 } else {
838 env->cc_n = l2;
839 env->cc_v = c2;
840 }
841 env->cc_op = CC_OP_CMPL;
842 env->dregs[Dc1] = l1;
843 env->dregs[Dc2] = l2;
844 }
845
HELPER(cas2l)846 void HELPER(cas2l)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2)
847 {
848 do_cas2l(env, regs, a1, a2, false);
849 }
850
HELPER(cas2l_parallel)851 void HELPER(cas2l_parallel)(CPUM68KState *env, uint32_t regs, uint32_t a1,
852 uint32_t a2)
853 {
854 do_cas2l(env, regs, a1, a2, true);
855 }
856
857 struct bf_data {
858 uint32_t addr;
859 uint32_t bofs;
860 uint32_t blen;
861 uint32_t len;
862 };
863
bf_prep(uint32_t addr,int32_t ofs,uint32_t len)864 static struct bf_data bf_prep(uint32_t addr, int32_t ofs, uint32_t len)
865 {
866 int bofs, blen;
867
868 /* Bound length; map 0 to 32. */
869 len = ((len - 1) & 31) + 1;
870
871 /* Note that ofs is signed. */
872 addr += ofs / 8;
873 bofs = ofs % 8;
874 if (bofs < 0) {
875 bofs += 8;
876 addr -= 1;
877 }
878
879 /*
880 * Compute the number of bytes required (minus one) to
881 * satisfy the bitfield.
882 */
883 blen = (bofs + len - 1) / 8;
884
885 /*
886 * Canonicalize the bit offset for data loaded into a 64-bit big-endian
887 * word. For the cases where BLEN is not a power of 2, adjust ADDR so
888 * that we can use the next power of two sized load without crossing a
889 * page boundary, unless the field itself crosses the boundary.
890 */
891 switch (blen) {
892 case 0:
893 bofs += 56;
894 break;
895 case 1:
896 bofs += 48;
897 break;
898 case 2:
899 if (addr & 1) {
900 bofs += 8;
901 addr -= 1;
902 }
903 /* fallthru */
904 case 3:
905 bofs += 32;
906 break;
907 case 4:
908 if (addr & 3) {
909 bofs += 8 * (addr & 3);
910 addr &= -4;
911 }
912 break;
913 default:
914 g_assert_not_reached();
915 }
916
917 return (struct bf_data){
918 .addr = addr,
919 .bofs = bofs,
920 .blen = blen,
921 .len = len,
922 };
923 }
924
bf_load(CPUM68KState * env,uint32_t addr,int blen,uintptr_t ra)925 static uint64_t bf_load(CPUM68KState *env, uint32_t addr, int blen,
926 uintptr_t ra)
927 {
928 switch (blen) {
929 case 0:
930 return cpu_ldub_data_ra(env, addr, ra);
931 case 1:
932 return cpu_lduw_data_ra(env, addr, ra);
933 case 2:
934 case 3:
935 return cpu_ldl_data_ra(env, addr, ra);
936 case 4:
937 return cpu_ldq_data_ra(env, addr, ra);
938 default:
939 g_assert_not_reached();
940 }
941 }
942
bf_store(CPUM68KState * env,uint32_t addr,int blen,uint64_t data,uintptr_t ra)943 static void bf_store(CPUM68KState *env, uint32_t addr, int blen,
944 uint64_t data, uintptr_t ra)
945 {
946 switch (blen) {
947 case 0:
948 cpu_stb_data_ra(env, addr, data, ra);
949 break;
950 case 1:
951 cpu_stw_data_ra(env, addr, data, ra);
952 break;
953 case 2:
954 case 3:
955 cpu_stl_data_ra(env, addr, data, ra);
956 break;
957 case 4:
958 cpu_stq_data_ra(env, addr, data, ra);
959 break;
960 default:
961 g_assert_not_reached();
962 }
963 }
964
HELPER(bfexts_mem)965 uint32_t HELPER(bfexts_mem)(CPUM68KState *env, uint32_t addr,
966 int32_t ofs, uint32_t len)
967 {
968 uintptr_t ra = GETPC();
969 struct bf_data d = bf_prep(addr, ofs, len);
970 uint64_t data = bf_load(env, d.addr, d.blen, ra);
971
972 return (int64_t)(data << d.bofs) >> (64 - d.len);
973 }
974
HELPER(bfextu_mem)975 uint64_t HELPER(bfextu_mem)(CPUM68KState *env, uint32_t addr,
976 int32_t ofs, uint32_t len)
977 {
978 uintptr_t ra = GETPC();
979 struct bf_data d = bf_prep(addr, ofs, len);
980 uint64_t data = bf_load(env, d.addr, d.blen, ra);
981
982 /*
983 * Put CC_N at the top of the high word; put the zero-extended value
984 * at the bottom of the low word.
985 */
986 data <<= d.bofs;
987 data >>= 64 - d.len;
988 data |= data << (64 - d.len);
989
990 return data;
991 }
992
HELPER(bfins_mem)993 uint32_t HELPER(bfins_mem)(CPUM68KState *env, uint32_t addr, uint32_t val,
994 int32_t ofs, uint32_t len)
995 {
996 uintptr_t ra = GETPC();
997 struct bf_data d = bf_prep(addr, ofs, len);
998 uint64_t data = bf_load(env, d.addr, d.blen, ra);
999 uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
1000
1001 data = (data & ~mask) | (((uint64_t)val << (64 - d.len)) >> d.bofs);
1002
1003 bf_store(env, d.addr, d.blen, data, ra);
1004
1005 /* The field at the top of the word is also CC_N for CC_OP_LOGIC. */
1006 return val << (32 - d.len);
1007 }
1008
HELPER(bfchg_mem)1009 uint32_t HELPER(bfchg_mem)(CPUM68KState *env, uint32_t addr,
1010 int32_t ofs, uint32_t len)
1011 {
1012 uintptr_t ra = GETPC();
1013 struct bf_data d = bf_prep(addr, ofs, len);
1014 uint64_t data = bf_load(env, d.addr, d.blen, ra);
1015 uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
1016
1017 bf_store(env, d.addr, d.blen, data ^ mask, ra);
1018
1019 return ((data & mask) << d.bofs) >> 32;
1020 }
1021
HELPER(bfclr_mem)1022 uint32_t HELPER(bfclr_mem)(CPUM68KState *env, uint32_t addr,
1023 int32_t ofs, uint32_t len)
1024 {
1025 uintptr_t ra = GETPC();
1026 struct bf_data d = bf_prep(addr, ofs, len);
1027 uint64_t data = bf_load(env, d.addr, d.blen, ra);
1028 uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
1029
1030 bf_store(env, d.addr, d.blen, data & ~mask, ra);
1031
1032 return ((data & mask) << d.bofs) >> 32;
1033 }
1034
HELPER(bfset_mem)1035 uint32_t HELPER(bfset_mem)(CPUM68KState *env, uint32_t addr,
1036 int32_t ofs, uint32_t len)
1037 {
1038 uintptr_t ra = GETPC();
1039 struct bf_data d = bf_prep(addr, ofs, len);
1040 uint64_t data = bf_load(env, d.addr, d.blen, ra);
1041 uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
1042
1043 bf_store(env, d.addr, d.blen, data | mask, ra);
1044
1045 return ((data & mask) << d.bofs) >> 32;
1046 }
1047
HELPER(bfffo_reg)1048 uint32_t HELPER(bfffo_reg)(uint32_t n, uint32_t ofs, uint32_t len)
1049 {
1050 return (n ? clz32(n) : len) + ofs;
1051 }
1052
HELPER(bfffo_mem)1053 uint64_t HELPER(bfffo_mem)(CPUM68KState *env, uint32_t addr,
1054 int32_t ofs, uint32_t len)
1055 {
1056 uintptr_t ra = GETPC();
1057 struct bf_data d = bf_prep(addr, ofs, len);
1058 uint64_t data = bf_load(env, d.addr, d.blen, ra);
1059 uint64_t mask = -1ull << (64 - d.len) >> d.bofs;
1060 uint64_t n = (data & mask) << d.bofs;
1061 uint32_t ffo = helper_bfffo_reg(n >> 32, ofs, d.len);
1062
1063 /*
1064 * Return FFO in the low word and N in the high word.
1065 * Note that because of MASK and the shift, the low word
1066 * is already zero.
1067 */
1068 return n | ffo;
1069 }
1070
HELPER(chk)1071 void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub)
1072 {
1073 /*
1074 * From the specs:
1075 * X: Not affected, C,V,Z: Undefined,
1076 * N: Set if val < 0; cleared if val > ub, undefined otherwise
1077 * We implement here values found from a real MC68040:
1078 * X,V,Z: Not affected
1079 * N: Set if val < 0; cleared if val >= 0
1080 * C: if 0 <= ub: set if val < 0 or val > ub, cleared otherwise
1081 * if 0 > ub: set if val > ub and val < 0, cleared otherwise
1082 */
1083 env->cc_n = val;
1084 env->cc_c = 0 <= ub ? val < 0 || val > ub : val > ub && val < 0;
1085
1086 if (val < 0 || val > ub) {
1087 raise_exception_format2(env, EXCP_CHK, 2, GETPC());
1088 }
1089 }
1090
HELPER(chk2)1091 void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub)
1092 {
1093 /*
1094 * From the specs:
1095 * X: Not affected, N,V: Undefined,
1096 * Z: Set if val is equal to lb or ub
1097 * C: Set if val < lb or val > ub, cleared otherwise
1098 * We implement here values found from a real MC68040:
1099 * X,N,V: Not affected
1100 * Z: Set if val is equal to lb or ub
1101 * C: if lb <= ub: set if val < lb or val > ub, cleared otherwise
1102 * if lb > ub: set if val > ub and val < lb, cleared otherwise
1103 */
1104 env->cc_z = val != lb && val != ub;
1105 env->cc_c = lb <= ub ? val < lb || val > ub : val > ub && val < lb;
1106
1107 if (env->cc_c) {
1108 raise_exception_format2(env, EXCP_CHK, 4, GETPC());
1109 }
1110 }
1111