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