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