4 * Copyright (c) 2006-2007 CodeSourcery
5 * Written by Paul Brook
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
23 #include "exec/exec-all.h"
24 #include "exec/gdbstub.h"
26 #include "exec/helper-proto.h"
28 #define SIGNBIT (1u << 31)
30 /* Sort alphabetically, except for "any". */
31 static gint
m68k_cpu_list_compare(gconstpointer a
, gconstpointer b
)
33 ObjectClass
*class_a
= (ObjectClass
*)a
;
34 ObjectClass
*class_b
= (ObjectClass
*)b
;
35 const char *name_a
, *name_b
;
37 name_a
= object_class_get_name(class_a
);
38 name_b
= object_class_get_name(class_b
);
39 if (strcmp(name_a
, "any-" TYPE_M68K_CPU
) == 0) {
41 } else if (strcmp(name_b
, "any-" TYPE_M68K_CPU
) == 0) {
44 return strcasecmp(name_a
, name_b
);
48 static void m68k_cpu_list_entry(gpointer data
, gpointer user_data
)
50 ObjectClass
*c
= data
;
51 CPUListState
*s
= user_data
;
55 typename
= object_class_get_name(c
);
56 name
= g_strndup(typename
, strlen(typename
) - strlen("-" TYPE_M68K_CPU
));
57 (*s
->cpu_fprintf
)(s
->file
, "%s\n",
62 void m68k_cpu_list(FILE *f
, fprintf_function cpu_fprintf
)
66 .cpu_fprintf
= cpu_fprintf
,
70 list
= object_class_get_list(TYPE_M68K_CPU
, false);
71 list
= g_slist_sort(list
, m68k_cpu_list_compare
);
72 g_slist_foreach(list
, m68k_cpu_list_entry
, &s
);
76 static int cf_fpu_gdb_get_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
80 stfq_p(mem_buf
, floatx80_to_float64(env
->fregs
[n
].d
, &s
));
84 case 8: /* fpcontrol */
85 stl_be_p(mem_buf
, env
->fpcr
);
87 case 9: /* fpstatus */
88 stl_be_p(mem_buf
, env
->fpsr
);
90 case 10: /* fpiar, not implemented */
91 memset(mem_buf
, 0, 4);
97 static int cf_fpu_gdb_set_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
101 env
->fregs
[n
].d
= float64_to_floatx80(ldfq_p(mem_buf
), &s
);
105 case 8: /* fpcontrol */
106 cpu_m68k_set_fpcr(env
, ldl_p(mem_buf
));
108 case 9: /* fpstatus */
109 env
->fpsr
= ldl_p(mem_buf
);
111 case 10: /* fpiar, not implemented */
117 static int m68k_fpu_gdb_get_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
120 stw_be_p(mem_buf
, env
->fregs
[n
].l
.upper
);
121 memset(mem_buf
+ 2, 0, 2);
122 stq_be_p(mem_buf
+ 4, env
->fregs
[n
].l
.lower
);
126 case 8: /* fpcontrol */
127 stl_be_p(mem_buf
, env
->fpcr
);
129 case 9: /* fpstatus */
130 stl_be_p(mem_buf
, env
->fpsr
);
132 case 10: /* fpiar, not implemented */
133 memset(mem_buf
, 0, 4);
139 static int m68k_fpu_gdb_set_reg(CPUM68KState
*env
, uint8_t *mem_buf
, int n
)
142 env
->fregs
[n
].l
.upper
= lduw_be_p(mem_buf
);
143 env
->fregs
[n
].l
.lower
= ldq_be_p(mem_buf
+ 4);
147 case 8: /* fpcontrol */
148 cpu_m68k_set_fpcr(env
, ldl_p(mem_buf
));
150 case 9: /* fpstatus */
151 env
->fpsr
= ldl_p(mem_buf
);
153 case 10: /* fpiar, not implemented */
159 void m68k_cpu_init_gdb(M68kCPU
*cpu
)
161 CPUState
*cs
= CPU(cpu
);
162 CPUM68KState
*env
= &cpu
->env
;
164 if (m68k_feature(env
, M68K_FEATURE_CF_FPU
)) {
165 gdb_register_coprocessor(cs
, cf_fpu_gdb_get_reg
, cf_fpu_gdb_set_reg
,
166 11, "cf-fp.xml", 18);
167 } else if (m68k_feature(env
, M68K_FEATURE_FPU
)) {
168 gdb_register_coprocessor(cs
, m68k_fpu_gdb_get_reg
,
169 m68k_fpu_gdb_set_reg
, 11, "m68k-fp.xml", 18);
171 /* TODO: Add [E]MAC registers. */
174 void HELPER(movec
)(CPUM68KState
*env
, uint32_t reg
, uint32_t val
)
176 M68kCPU
*cpu
= m68k_env_get_cpu(env
);
179 case 0x02: /* CACR */
183 case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
184 /* TODO: Implement Access Control Registers. */
186 case 0x801: /* VBR */
189 /* TODO: Implement control registers. */
191 cpu_abort(CPU(cpu
), "Unimplemented control register write 0x%x = 0x%x\n",
196 void HELPER(set_macsr
)(CPUM68KState
*env
, uint32_t val
)
203 if ((env
->macsr
^ val
) & (MACSR_FI
| MACSR_SU
)) {
204 for (i
= 0; i
< 4; i
++) {
205 regval
= env
->macc
[i
];
206 exthigh
= regval
>> 40;
207 if (env
->macsr
& MACSR_FI
) {
212 extlow
= regval
>> 32;
214 if (env
->macsr
& MACSR_FI
) {
215 regval
= (((uint64_t)acc
) << 8) | extlow
;
216 regval
|= ((int64_t)exthigh
) << 40;
217 } else if (env
->macsr
& MACSR_SU
) {
218 regval
= acc
| (((int64_t)extlow
) << 32);
219 regval
|= ((int64_t)exthigh
) << 40;
221 regval
= acc
| (((uint64_t)extlow
) << 32);
222 regval
|= ((uint64_t)(uint8_t)exthigh
) << 40;
224 env
->macc
[i
] = regval
;
230 void m68k_switch_sp(CPUM68KState
*env
)
234 env
->sp
[env
->current_sp
] = env
->aregs
[7];
235 new_sp
= (env
->sr
& SR_S
&& env
->cacr
& M68K_CACR_EUSP
)
236 ? M68K_SSP
: M68K_USP
;
237 env
->aregs
[7] = env
->sp
[new_sp
];
238 env
->current_sp
= new_sp
;
241 #if defined(CONFIG_USER_ONLY)
243 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int rw
,
246 M68kCPU
*cpu
= M68K_CPU(cs
);
248 cs
->exception_index
= EXCP_ACCESS
;
249 cpu
->env
.mmu
.ar
= address
;
257 /* TODO: This will need fixing once the MMU is implemented. */
258 hwaddr
m68k_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
263 int m68k_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int rw
,
268 address
&= TARGET_PAGE_MASK
;
269 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
270 tlb_set_page(cs
, address
, address
, prot
, mmu_idx
, TARGET_PAGE_SIZE
);
274 /* Notify CPU of a pending interrupt. Prioritization and vectoring should
275 be handled by the interrupt controller. Real hardware only requests
276 the vector when the interrupt is acknowledged by the CPU. For
277 simplicitly we calculate it when the interrupt is signalled. */
278 void m68k_set_irq_level(M68kCPU
*cpu
, int level
, uint8_t vector
)
280 CPUState
*cs
= CPU(cpu
);
281 CPUM68KState
*env
= &cpu
->env
;
283 env
->pending_level
= level
;
284 env
->pending_vector
= vector
;
286 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
288 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
294 uint32_t HELPER(bitrev
)(uint32_t x
)
296 x
= ((x
>> 1) & 0x55555555u
) | ((x
<< 1) & 0xaaaaaaaau
);
297 x
= ((x
>> 2) & 0x33333333u
) | ((x
<< 2) & 0xccccccccu
);
298 x
= ((x
>> 4) & 0x0f0f0f0fu
) | ((x
<< 4) & 0xf0f0f0f0u
);
302 uint32_t HELPER(ff1
)(uint32_t x
)
310 uint32_t HELPER(sats
)(uint32_t val
, uint32_t v
)
312 /* The result has the opposite sign to the original value. */
313 if ((int32_t)v
< 0) {
314 val
= (((int32_t)val
) >> 31) ^ SIGNBIT
;
319 void HELPER(set_sr
)(CPUM68KState
*env
, uint32_t val
)
321 env
->sr
= val
& 0xffe0;
322 cpu_m68k_set_ccr(env
, val
);
328 /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
329 take values, others take register numbers and manipulate the contents
331 void HELPER(mac_move
)(CPUM68KState
*env
, uint32_t dest
, uint32_t src
)
334 env
->macc
[dest
] = env
->macc
[src
];
335 mask
= MACSR_PAV0
<< dest
;
336 if (env
->macsr
& (MACSR_PAV0
<< src
))
342 uint64_t HELPER(macmuls
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
347 product
= (uint64_t)op1
* op2
;
348 res
= (product
<< 24) >> 24;
349 if (res
!= product
) {
350 env
->macsr
|= MACSR_V
;
351 if (env
->macsr
& MACSR_OMC
) {
352 /* Make sure the accumulate operation overflows. */
362 uint64_t HELPER(macmulu
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
366 product
= (uint64_t)op1
* op2
;
367 if (product
& (0xffffffull
<< 40)) {
368 env
->macsr
|= MACSR_V
;
369 if (env
->macsr
& MACSR_OMC
) {
370 /* Make sure the accumulate operation overflows. */
373 product
&= ((1ull << 40) - 1);
379 uint64_t HELPER(macmulf
)(CPUM68KState
*env
, uint32_t op1
, uint32_t op2
)
384 product
= (uint64_t)op1
* op2
;
385 if (env
->macsr
& MACSR_RT
) {
386 remainder
= product
& 0xffffff;
388 if (remainder
> 0x800000)
390 else if (remainder
== 0x800000)
391 product
+= (product
& 1);
398 void HELPER(macsats
)(CPUM68KState
*env
, uint32_t acc
)
402 tmp
= env
->macc
[acc
];
403 result
= ((tmp
<< 16) >> 16);
405 env
->macsr
|= MACSR_V
;
407 if (env
->macsr
& MACSR_V
) {
408 env
->macsr
|= MACSR_PAV0
<< acc
;
409 if (env
->macsr
& MACSR_OMC
) {
410 /* The result is saturated to 32 bits, despite overflow occurring
411 at 48 bits. Seems weird, but that's what the hardware docs
413 result
= (result
>> 63) ^ 0x7fffffff;
416 env
->macc
[acc
] = result
;
419 void HELPER(macsatu
)(CPUM68KState
*env
, uint32_t acc
)
423 val
= env
->macc
[acc
];
424 if (val
& (0xffffull
<< 48)) {
425 env
->macsr
|= MACSR_V
;
427 if (env
->macsr
& MACSR_V
) {
428 env
->macsr
|= MACSR_PAV0
<< acc
;
429 if (env
->macsr
& MACSR_OMC
) {
430 if (val
> (1ull << 53))
433 val
= (1ull << 48) - 1;
435 val
&= ((1ull << 48) - 1);
438 env
->macc
[acc
] = val
;
441 void HELPER(macsatf
)(CPUM68KState
*env
, uint32_t acc
)
446 sum
= env
->macc
[acc
];
447 result
= (sum
<< 16) >> 16;
449 env
->macsr
|= MACSR_V
;
451 if (env
->macsr
& MACSR_V
) {
452 env
->macsr
|= MACSR_PAV0
<< acc
;
453 if (env
->macsr
& MACSR_OMC
) {
454 result
= (result
>> 63) ^ 0x7fffffffffffll
;
457 env
->macc
[acc
] = result
;
460 void HELPER(mac_set_flags
)(CPUM68KState
*env
, uint32_t acc
)
463 val
= env
->macc
[acc
];
465 env
->macsr
|= MACSR_Z
;
466 } else if (val
& (1ull << 47)) {
467 env
->macsr
|= MACSR_N
;
469 if (env
->macsr
& (MACSR_PAV0
<< acc
)) {
470 env
->macsr
|= MACSR_V
;
472 if (env
->macsr
& MACSR_FI
) {
473 val
= ((int64_t)val
) >> 40;
474 if (val
!= 0 && val
!= -1)
475 env
->macsr
|= MACSR_EV
;
476 } else if (env
->macsr
& MACSR_SU
) {
477 val
= ((int64_t)val
) >> 32;
478 if (val
!= 0 && val
!= -1)
479 env
->macsr
|= MACSR_EV
;
481 if ((val
>> 32) != 0)
482 env
->macsr
|= MACSR_EV
;
486 #define EXTSIGN(val, index) ( \
487 (index == 0) ? (int8_t)(val) : ((index == 1) ? (int16_t)(val) : (val)) \
490 #define COMPUTE_CCR(op, x, n, z, v, c) { \
493 /* Everything in place. */ \
500 src1 = EXTSIGN(res - src2, op - CC_OP_ADDB); \
503 v = (res ^ src1) & ~(src1 ^ src2); \
510 src1 = EXTSIGN(res + src2, op - CC_OP_SUBB); \
513 v = (res ^ src1) & (src1 ^ src2); \
520 res = EXTSIGN(src1 - src2, op - CC_OP_CMPB); \
524 v = (res ^ src1) & (src1 ^ src2); \
531 cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", op); \
535 uint32_t cpu_m68k_get_ccr(CPUM68KState
*env
)
537 uint32_t x
, c
, n
, z
, v
;
538 uint32_t res
, src1
, src2
;
546 COMPUTE_CCR(env
->cc_op
, x
, n
, z
, v
, c
);
552 return x
* CCF_X
+ n
* CCF_N
+ z
* CCF_Z
+ v
* CCF_V
+ c
* CCF_C
;
555 uint32_t HELPER(get_ccr
)(CPUM68KState
*env
)
557 return cpu_m68k_get_ccr(env
);
560 void cpu_m68k_set_ccr(CPUM68KState
*env
, uint32_t ccr
)
562 env
->cc_x
= (ccr
& CCF_X
? 1 : 0);
563 env
->cc_n
= (ccr
& CCF_N
? -1 : 0);
564 env
->cc_z
= (ccr
& CCF_Z
? 0 : 1);
565 env
->cc_v
= (ccr
& CCF_V
? -1 : 0);
566 env
->cc_c
= (ccr
& CCF_C
? 1 : 0);
567 env
->cc_op
= CC_OP_FLAGS
;
570 void HELPER(set_ccr
)(CPUM68KState
*env
, uint32_t ccr
)
572 cpu_m68k_set_ccr(env
, ccr
);
575 void HELPER(flush_flags
)(CPUM68KState
*env
, uint32_t cc_op
)
577 uint32_t res
, src1
, src2
;
579 COMPUTE_CCR(cc_op
, env
->cc_x
, env
->cc_n
, env
->cc_z
, env
->cc_v
, env
->cc_c
);
580 env
->cc_op
= CC_OP_FLAGS
;
583 uint32_t HELPER(get_macf
)(CPUM68KState
*env
, uint64_t val
)
588 if (env
->macsr
& MACSR_SU
) {
589 /* 16-bit rounding. */
590 rem
= val
& 0xffffff;
591 val
= (val
>> 24) & 0xffffu
;
594 else if (rem
== 0x800000)
596 } else if (env
->macsr
& MACSR_RT
) {
597 /* 32-bit rounding. */
602 else if (rem
== 0x80)
608 if (env
->macsr
& MACSR_OMC
) {
610 if (env
->macsr
& MACSR_SU
) {
611 if (val
!= (uint16_t) val
) {
612 result
= ((val
>> 63) ^ 0x7fff) & 0xffff;
614 result
= val
& 0xffff;
617 if (val
!= (uint32_t)val
) {
618 result
= ((uint32_t)(val
>> 63) & 0x7fffffff);
620 result
= (uint32_t)val
;
625 if (env
->macsr
& MACSR_SU
) {
626 result
= val
& 0xffff;
628 result
= (uint32_t)val
;
634 uint32_t HELPER(get_macs
)(uint64_t val
)
636 if (val
== (int32_t)val
) {
639 return (val
>> 61) ^ ~SIGNBIT
;
643 uint32_t HELPER(get_macu
)(uint64_t val
)
645 if ((val
>> 32) == 0) {
646 return (uint32_t)val
;
652 uint32_t HELPER(get_mac_extf
)(CPUM68KState
*env
, uint32_t acc
)
655 val
= env
->macc
[acc
] & 0x00ff;
656 val
|= (env
->macc
[acc
] >> 32) & 0xff00;
657 val
|= (env
->macc
[acc
+ 1] << 16) & 0x00ff0000;
658 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xff000000;
662 uint32_t HELPER(get_mac_exti
)(CPUM68KState
*env
, uint32_t acc
)
665 val
= (env
->macc
[acc
] >> 32) & 0xffff;
666 val
|= (env
->macc
[acc
+ 1] >> 16) & 0xffff0000;
670 void HELPER(set_mac_extf
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
674 res
= env
->macc
[acc
] & 0xffffffff00ull
;
675 tmp
= (int16_t)(val
& 0xff00);
676 res
|= ((int64_t)tmp
) << 32;
678 env
->macc
[acc
] = res
;
679 res
= env
->macc
[acc
+ 1] & 0xffffffff00ull
;
680 tmp
= (val
& 0xff000000);
681 res
|= ((int64_t)tmp
) << 16;
682 res
|= (val
>> 16) & 0xff;
683 env
->macc
[acc
+ 1] = res
;
686 void HELPER(set_mac_exts
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
690 res
= (uint32_t)env
->macc
[acc
];
692 res
|= ((int64_t)tmp
) << 32;
693 env
->macc
[acc
] = res
;
694 res
= (uint32_t)env
->macc
[acc
+ 1];
695 tmp
= val
& 0xffff0000;
696 res
|= (int64_t)tmp
<< 16;
697 env
->macc
[acc
+ 1] = res
;
700 void HELPER(set_mac_extu
)(CPUM68KState
*env
, uint32_t val
, uint32_t acc
)
703 res
= (uint32_t)env
->macc
[acc
];
704 res
|= ((uint64_t)(val
& 0xffff)) << 32;
705 env
->macc
[acc
] = res
;
706 res
= (uint32_t)env
->macc
[acc
+ 1];
707 res
|= (uint64_t)(val
& 0xffff0000) << 16;
708 env
->macc
[acc
+ 1] = res
;