|
|
1.1 root 1: /*
2: * m68k op helpers
1.1.1.2 ! root 3: *
! 4: * Copyright (c) 2006-2007 CodeSourcery
1.1 root 5: * Written by Paul Brook
6: *
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.
11: *
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.
16: *
17: * You should have received a copy of the GNU Lesser General Public
18: * License along with this library; if not, write to the Free Software
19: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20: */
21:
22: #include <stdio.h>
1.1.1.2 ! root 23: #include <string.h>
1.1 root 24:
25: #include "config.h"
26: #include "cpu.h"
27: #include "exec-all.h"
28:
1.1.1.2 ! root 29: enum m68k_cpuid {
! 30: M68K_CPUID_M5206,
! 31: M68K_CPUID_M5208,
! 32: M68K_CPUID_CFV4E,
! 33: M68K_CPUID_ANY,
! 34: };
! 35:
! 36: typedef struct m68k_def_t m68k_def_t;
! 37:
! 38: struct m68k_def_t {
! 39: const char * name;
! 40: enum m68k_cpuid id;
! 41: };
! 42:
! 43: static m68k_def_t m68k_cpu_defs[] = {
! 44: {"m5206", M68K_CPUID_M5206},
! 45: {"m5208", M68K_CPUID_M5208},
! 46: {"cfv4e", M68K_CPUID_CFV4E},
! 47: {"any", M68K_CPUID_ANY},
! 48: {NULL, 0},
! 49: };
! 50:
! 51: static void m68k_set_feature(CPUM68KState *env, int feature)
! 52: {
! 53: env->features |= (1u << feature);
! 54: }
! 55:
! 56: static int cpu_m68k_set_model(CPUM68KState *env, const char *name)
! 57: {
! 58: m68k_def_t *def;
! 59:
! 60: for (def = m68k_cpu_defs; def->name; def++) {
! 61: if (strcmp(def->name, name) == 0)
! 62: break;
! 63: }
! 64: if (!def->name)
! 65: return -1;
! 66:
! 67: switch (def->id) {
! 68: case M68K_CPUID_M5206:
! 69: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
! 70: break;
! 71: case M68K_CPUID_M5208:
! 72: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
! 73: m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
! 74: m68k_set_feature(env, M68K_FEATURE_BRAL);
! 75: m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
! 76: m68k_set_feature(env, M68K_FEATURE_USP);
! 77: break;
! 78: case M68K_CPUID_CFV4E:
! 79: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
! 80: m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
! 81: m68k_set_feature(env, M68K_FEATURE_BRAL);
! 82: m68k_set_feature(env, M68K_FEATURE_CF_FPU);
! 83: m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
! 84: m68k_set_feature(env, M68K_FEATURE_USP);
! 85: break;
! 86: case M68K_CPUID_ANY:
! 87: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
! 88: m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
! 89: m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
! 90: m68k_set_feature(env, M68K_FEATURE_BRAL);
! 91: m68k_set_feature(env, M68K_FEATURE_CF_FPU);
! 92: /* MAC and EMAC are mututally exclusive, so pick EMAC.
! 93: It's mostly backwards compatible. */
! 94: m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
! 95: m68k_set_feature(env, M68K_FEATURE_CF_EMAC_B);
! 96: m68k_set_feature(env, M68K_FEATURE_USP);
! 97: m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
! 98: m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
! 99: break;
! 100: }
! 101:
! 102: register_m68k_insns(env);
! 103: return 0;
! 104: }
! 105:
! 106: void cpu_reset(CPUM68KState *env)
! 107: {
! 108: memset(env, 0, offsetof(CPUM68KState, breakpoints));
! 109: #if !defined (CONFIG_USER_ONLY)
! 110: env->sr = 0x2700;
! 111: #endif
! 112: m68k_switch_sp(env);
! 113: /* ??? FP regs should be initialized to NaN. */
! 114: env->cc_op = CC_OP_FLAGS;
! 115: /* TODO: We should set PC from the interrupt vector. */
! 116: env->pc = 0;
! 117: tlb_flush(env, 1);
! 118: }
! 119:
! 120: CPUM68KState *cpu_m68k_init(const char *cpu_model)
! 121: {
! 122: CPUM68KState *env;
! 123:
! 124: env = malloc(sizeof(CPUM68KState));
! 125: if (!env)
! 126: return NULL;
! 127: cpu_exec_init(env);
! 128:
! 129: env->cpu_model_str = cpu_model;
! 130:
! 131: if (cpu_m68k_set_model(env, cpu_model) < 0) {
! 132: cpu_m68k_close(env);
! 133: return NULL;
! 134: }
! 135:
! 136: cpu_reset(env);
! 137: return env;
! 138: }
! 139:
! 140: void cpu_m68k_close(CPUM68KState *env)
! 141: {
! 142: qemu_free(env);
! 143: }
! 144:
1.1 root 145: void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
146: {
147: int flags;
148: uint32_t src;
149: uint32_t dest;
150: uint32_t tmp;
151:
152: #define HIGHBIT 0x80000000u
153:
154: #define SET_NZ(x) do { \
155: if ((x) == 0) \
156: flags |= CCF_Z; \
157: else if ((int32_t)(x) < 0) \
158: flags |= CCF_N; \
159: } while (0)
160:
161: #define SET_FLAGS_SUB(type, utype) do { \
162: SET_NZ((type)dest); \
163: tmp = dest + src; \
164: if ((utype) tmp < (utype) src) \
165: flags |= CCF_C; \
166: if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
167: flags |= CCF_V; \
168: } while (0)
169:
170: flags = 0;
171: src = env->cc_src;
172: dest = env->cc_dest;
173: switch (cc_op) {
174: case CC_OP_FLAGS:
175: flags = dest;
176: break;
177: case CC_OP_LOGIC:
178: SET_NZ(dest);
179: break;
180: case CC_OP_ADD:
181: SET_NZ(dest);
182: if (dest < src)
183: flags |= CCF_C;
184: tmp = dest - src;
185: if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
186: flags |= CCF_V;
187: break;
188: case CC_OP_SUB:
189: SET_FLAGS_SUB(int32_t, uint32_t);
190: break;
191: case CC_OP_CMPB:
192: SET_FLAGS_SUB(int8_t, uint8_t);
193: break;
194: case CC_OP_CMPW:
195: SET_FLAGS_SUB(int16_t, uint16_t);
196: break;
197: case CC_OP_ADDX:
198: SET_NZ(dest);
199: if (dest <= src)
200: flags |= CCF_C;
201: tmp = dest - src - 1;
202: if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
203: flags |= CCF_V;
204: break;
205: case CC_OP_SUBX:
206: SET_NZ(dest);
207: tmp = dest + src + 1;
208: if (tmp <= src)
209: flags |= CCF_C;
210: if (HIGHBIT & (tmp ^ dest) & (tmp ^ src))
211: flags |= CCF_V;
212: break;
213: case CC_OP_SHL:
214: if (src >= 32) {
215: SET_NZ(0);
216: } else {
217: tmp = dest << src;
218: SET_NZ(tmp);
219: }
220: if (src && src <= 32 && (dest & (1 << (32 - src))))
221: flags |= CCF_C;
222: break;
223: case CC_OP_SHR:
224: if (src >= 32) {
225: SET_NZ(0);
226: } else {
227: tmp = dest >> src;
228: SET_NZ(tmp);
229: }
230: if (src && src <= 32 && ((dest >> (src - 1)) & 1))
231: flags |= CCF_C;
232: break;
233: case CC_OP_SAR:
234: if (src >= 32) {
235: SET_NZ(-1);
236: } else {
237: tmp = (int32_t)dest >> src;
238: SET_NZ(tmp);
239: }
240: if (src && src <= 32 && (((int32_t)dest >> (src - 1)) & 1))
241: flags |= CCF_C;
242: break;
243: default:
244: cpu_abort(env, "Bad CC_OP %d", cc_op);
245: }
246: env->cc_op = CC_OP_FLAGS;
247: env->cc_dest = flags;
248: }
249:
250: float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1)
251: {
252: /* ??? This may incorrectly raise exceptions. */
253: /* ??? Should flush denormals to zero. */
254: float64 res;
255: res = float64_sub(src0, src1, &env->fp_status);
256: if (float64_is_nan(res)) {
257: /* +/-inf compares equal against itself, but sub returns nan. */
258: if (!float64_is_nan(src0)
259: && !float64_is_nan(src1)) {
1.1.1.2 ! root 260: res = float64_zero;
1.1 root 261: if (float64_lt_quiet(src0, res, &env->fp_status))
262: res = float64_chs(res);
263: }
264: }
265: return res;
266: }
1.1.1.2 ! root 267:
! 268: void helper_movec(CPUM68KState *env, int reg, uint32_t val)
! 269: {
! 270: switch (reg) {
! 271: case 0x02: /* CACR */
! 272: env->cacr = val;
! 273: m68k_switch_sp(env);
! 274: break;
! 275: case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
! 276: /* TODO: Implement Access Control Registers. */
! 277: break;
! 278: case 0x801: /* VBR */
! 279: env->vbr = val;
! 280: break;
! 281: /* TODO: Implement control registers. */
! 282: default:
! 283: cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
! 284: reg, val);
! 285: }
! 286: }
! 287:
! 288: void m68k_set_macsr(CPUM68KState *env, uint32_t val)
! 289: {
! 290: uint32_t acc;
! 291: int8_t exthigh;
! 292: uint8_t extlow;
! 293: uint64_t regval;
! 294: int i;
! 295: if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
! 296: for (i = 0; i < 4; i++) {
! 297: regval = env->macc[i];
! 298: exthigh = regval >> 40;
! 299: if (env->macsr & MACSR_FI) {
! 300: acc = regval >> 8;
! 301: extlow = regval;
! 302: } else {
! 303: acc = regval;
! 304: extlow = regval >> 32;
! 305: }
! 306: if (env->macsr & MACSR_FI) {
! 307: regval = (((uint64_t)acc) << 8) | extlow;
! 308: regval |= ((int64_t)exthigh) << 40;
! 309: } else if (env->macsr & MACSR_SU) {
! 310: regval = acc | (((int64_t)extlow) << 32);
! 311: regval |= ((int64_t)exthigh) << 40;
! 312: } else {
! 313: regval = acc | (((uint64_t)extlow) << 32);
! 314: regval |= ((uint64_t)(uint8_t)exthigh) << 40;
! 315: }
! 316: env->macc[i] = regval;
! 317: }
! 318: }
! 319: env->macsr = val;
! 320: }
! 321:
! 322: void m68k_switch_sp(CPUM68KState *env)
! 323: {
! 324: int new_sp;
! 325:
! 326: env->sp[env->current_sp] = env->aregs[7];
! 327: new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
! 328: ? M68K_SSP : M68K_USP;
! 329: env->aregs[7] = env->sp[new_sp];
! 330: env->current_sp = new_sp;
! 331: }
! 332:
! 333: /* MMU */
! 334:
! 335: /* TODO: This will need fixing once the MMU is implemented. */
! 336: target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
! 337: {
! 338: return addr;
! 339: }
! 340:
! 341: #if defined(CONFIG_USER_ONLY)
! 342:
! 343: int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
! 344: int mmu_idx, int is_softmmu)
! 345: {
! 346: env->exception_index = EXCP_ACCESS;
! 347: env->mmu.ar = address;
! 348: return 1;
! 349: }
! 350:
! 351: #else
! 352:
! 353: int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
! 354: int mmu_idx, int is_softmmu)
! 355: {
! 356: int prot;
! 357:
! 358: address &= TARGET_PAGE_MASK;
! 359: prot = PAGE_READ | PAGE_WRITE;
! 360: return tlb_set_page(env, address, address, prot, mmu_idx, is_softmmu);
! 361: }
! 362:
! 363: /* Notify CPU of a pending interrupt. Prioritization and vectoring should
! 364: be handled by the interrupt controller. Real hardware only requests
! 365: the vector when the interrupt is acknowledged by the CPU. For
! 366: simplicitly we calculate it when the interrupt is signalled. */
! 367: void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector)
! 368: {
! 369: env->pending_level = level;
! 370: env->pending_vector = vector;
! 371: if (level)
! 372: cpu_interrupt(env, CPU_INTERRUPT_HARD);
! 373: else
! 374: cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
! 375: }
! 376:
! 377: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.