Remove broken ds1225y init, it is useless on this machine anyway.
[qemu] / target-m68k / helper.c
1 /*
2  *  m68k op helpers
3  *
4  *  Copyright (c) 2006-2007 CodeSourcery
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>
23 #include <string.h>
24
25 #include "config.h"
26 #include "cpu.h"
27 #include "exec-all.h"
28
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     if (cpu_m68k_set_model(env, cpu_model) < 0) {
130         cpu_m68k_close(env);
131         return NULL;
132     }
133         
134     cpu_reset(env);
135     return env;
136 }
137
138 void cpu_m68k_close(CPUM68KState *env)
139 {
140     qemu_free(env);
141 }
142
143 void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
144 {
145     int flags;
146     uint32_t src;
147     uint32_t dest;
148     uint32_t tmp;
149
150 #define HIGHBIT 0x80000000u
151
152 #define SET_NZ(x) do { \
153     if ((x) == 0) \
154         flags |= CCF_Z; \
155     else if ((int32_t)(x) < 0) \
156         flags |= CCF_N; \
157     } while (0)
158
159 #define SET_FLAGS_SUB(type, utype) do { \
160     SET_NZ((type)dest); \
161     tmp = dest + src; \
162     if ((utype) tmp < (utype) src) \
163         flags |= CCF_C; \
164     if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
165         flags |= CCF_V; \
166     } while (0)
167
168     flags = 0;
169     src = env->cc_src;
170     dest = env->cc_dest;
171     switch (cc_op) {
172     case CC_OP_FLAGS:
173         flags = dest;
174         break;
175     case CC_OP_LOGIC:
176         SET_NZ(dest);
177         break;
178     case CC_OP_ADD:
179         SET_NZ(dest);
180         if (dest < src)
181             flags |= CCF_C;
182         tmp = dest - src;
183         if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
184             flags |= CCF_V;
185         break;
186     case CC_OP_SUB:
187         SET_FLAGS_SUB(int32_t, uint32_t);
188         break;
189     case CC_OP_CMPB:
190         SET_FLAGS_SUB(int8_t, uint8_t);
191         break;
192     case CC_OP_CMPW:
193         SET_FLAGS_SUB(int16_t, uint16_t);
194         break;
195     case CC_OP_ADDX:
196         SET_NZ(dest);
197         if (dest <= src)
198             flags |= CCF_C;
199         tmp = dest - src - 1;
200         if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
201             flags |= CCF_V;
202         break;
203     case CC_OP_SUBX:
204         SET_NZ(dest);
205         tmp = dest + src + 1;
206         if (tmp <= src)
207             flags |= CCF_C;
208         if (HIGHBIT & (tmp ^ dest) & (tmp ^ src))
209             flags |= CCF_V;
210         break;
211     case CC_OP_SHL:
212         if (src >= 32) {
213             SET_NZ(0);
214         } else {
215             tmp = dest << src;
216             SET_NZ(tmp);
217         }
218         if (src && src <= 32 && (dest & (1 << (32 - src))))
219             flags |= CCF_C;
220         break;
221     case CC_OP_SHR:
222         if (src >= 32) {
223             SET_NZ(0);
224         } else {
225             tmp = dest >> src;
226             SET_NZ(tmp);
227         }
228         if (src && src <= 32 && ((dest >> (src - 1)) & 1))
229             flags |= CCF_C;
230         break;
231     case CC_OP_SAR:
232         if (src >= 32) {
233             SET_NZ(-1);
234         } else {
235             tmp = (int32_t)dest >> src;
236             SET_NZ(tmp);
237         }
238         if (src && src <= 32 && (((int32_t)dest >> (src - 1)) & 1))
239             flags |= CCF_C;
240         break;
241     default:
242         cpu_abort(env, "Bad CC_OP %d", cc_op);
243     }
244     env->cc_op = CC_OP_FLAGS;
245     env->cc_dest = flags;
246 }
247
248 float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1)
249 {
250     /* ??? This may incorrectly raise exceptions.  */
251     /* ??? Should flush denormals to zero.  */
252     float64 res;
253     res = float64_sub(src0, src1, &env->fp_status);
254     if (float64_is_nan(res)) {
255         /* +/-inf compares equal against itself, but sub returns nan.  */
256         if (!float64_is_nan(src0)
257             && !float64_is_nan(src1)) {
258             res = float64_zero;
259             if (float64_lt_quiet(src0, res, &env->fp_status))
260                 res = float64_chs(res);
261         }
262     }
263     return res;
264 }
265
266 void helper_movec(CPUM68KState *env, int reg, uint32_t val)
267 {
268     switch (reg) {
269     case 0x02: /* CACR */
270         env->cacr = val;
271         m68k_switch_sp(env);
272         break;
273     case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
274         /* TODO: Implement Access Control Registers.  */
275         break;
276     case 0x801: /* VBR */
277         env->vbr = val;
278         break;
279     /* TODO: Implement control registers.  */
280     default:
281         cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
282                   reg, val);
283     }
284 }
285
286 void m68k_set_macsr(CPUM68KState *env, uint32_t val)
287 {
288     uint32_t acc;
289     int8_t exthigh;
290     uint8_t extlow;
291     uint64_t regval;
292     int i;
293     if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
294         for (i = 0; i < 4; i++) {
295             regval = env->macc[i];
296             exthigh = regval >> 40;
297             if (env->macsr & MACSR_FI) {
298                 acc = regval >> 8;
299                 extlow = regval;
300             } else {
301                 acc = regval;
302                 extlow = regval >> 32;
303             }
304             if (env->macsr & MACSR_FI) {
305                 regval = (((uint64_t)acc) << 8) | extlow;
306                 regval |= ((int64_t)exthigh) << 40;
307             } else if (env->macsr & MACSR_SU) {
308                 regval = acc | (((int64_t)extlow) << 32);
309                 regval |= ((int64_t)exthigh) << 40;
310             } else {
311                 regval = acc | (((uint64_t)extlow) << 32);
312                 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
313             }
314             env->macc[i] = regval;
315         }
316     }
317     env->macsr = val;
318 }
319
320 void m68k_switch_sp(CPUM68KState *env)
321 {
322     int new_sp;
323
324     env->sp[env->current_sp] = env->aregs[7];
325     new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
326              ? M68K_SSP : M68K_USP;
327     env->aregs[7] = env->sp[new_sp];
328     env->current_sp = new_sp;
329 }
330
331 /* MMU */
332
333 /* TODO: This will need fixing once the MMU is implemented.  */
334 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
335 {
336     return addr;
337 }
338
339 #if defined(CONFIG_USER_ONLY)
340
341 int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
342                                int mmu_idx, int is_softmmu)
343 {
344     env->exception_index = EXCP_ACCESS;
345     env->mmu.ar = address;
346     return 1;
347 }
348
349 #else
350
351 int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
352                                int mmu_idx, int is_softmmu)
353 {
354     int prot;
355
356     address &= TARGET_PAGE_MASK;
357     prot = PAGE_READ | PAGE_WRITE;
358     return tlb_set_page(env, address, address, prot, mmu_idx, is_softmmu);
359 }
360
361 /* Notify CPU of a pending interrupt.  Prioritization and vectoring should
362    be handled by the interrupt controller.  Real hardware only requests
363    the vector when the interrupt is acknowledged by the CPU.  For
364    simplicitly we calculate it when the interrupt is signalled.  */
365 void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector)
366 {
367     env->pending_level = level;
368     env->pending_vector = vector;
369     if (level)
370         cpu_interrupt(env, CPU_INTERRUPT_HARD);
371     else
372         cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
373 }
374
375 #endif