Spelling fix, by Stefan Weil.
[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 struct m68k_def_t {
37     const char * name;
38     enum m68k_cpuid id;
39 };
40
41 static m68k_def_t m68k_cpu_defs[] = {
42     {"m5206", M68K_CPUID_M5206}, 
43     {"m5208", M68K_CPUID_M5208}, 
44     {"cfv4e", M68K_CPUID_CFV4E},
45     {"any", M68K_CPUID_ANY},
46     {NULL, 0}, 
47 };
48
49 static void m68k_set_feature(CPUM68KState *env, int feature)
50 {
51     env->features |= (1u << feature);
52 }
53
54 int cpu_m68k_set_model(CPUM68KState *env, const char * name)
55 {
56     m68k_def_t *def;
57
58     for (def = m68k_cpu_defs; def->name; def++) {
59         if (strcmp(def->name, name) == 0)
60             break;
61     }
62     if (!def->name)
63         return 1;
64
65     switch (def->id) {
66     case M68K_CPUID_M5206:
67         m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
68         break;
69     case M68K_CPUID_M5208:
70         m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
71         m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
72         m68k_set_feature(env, M68K_FEATURE_BRAL);
73         m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
74         m68k_set_feature(env, M68K_FEATURE_USP);
75         break;
76     case M68K_CPUID_CFV4E:
77         m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
78         m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
79         m68k_set_feature(env, M68K_FEATURE_BRAL);
80         m68k_set_feature(env, M68K_FEATURE_CF_FPU);
81         m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
82         m68k_set_feature(env, M68K_FEATURE_USP);
83         break;
84     case M68K_CPUID_ANY:
85         m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
86         m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
87         m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
88         m68k_set_feature(env, M68K_FEATURE_BRAL);
89         m68k_set_feature(env, M68K_FEATURE_CF_FPU);
90         /* MAC and EMAC are mututally exclusive, so pick EMAC.
91            It's mostly backwards compatible.  */
92         m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
93         m68k_set_feature(env, M68K_FEATURE_CF_EMAC_B);
94         m68k_set_feature(env, M68K_FEATURE_USP);
95         m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
96         m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
97         break;
98     }
99
100     register_m68k_insns(env);
101
102     return 0;
103 }
104
105 void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
106 {
107     int flags;
108     uint32_t src;
109     uint32_t dest;
110     uint32_t tmp;
111
112 #define HIGHBIT 0x80000000u
113
114 #define SET_NZ(x) do { \
115     if ((x) == 0) \
116         flags |= CCF_Z; \
117     else if ((int32_t)(x) < 0) \
118         flags |= CCF_N; \
119     } while (0)
120
121 #define SET_FLAGS_SUB(type, utype) do { \
122     SET_NZ((type)dest); \
123     tmp = dest + src; \
124     if ((utype) tmp < (utype) src) \
125         flags |= CCF_C; \
126     if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
127         flags |= CCF_V; \
128     } while (0)
129
130     flags = 0;
131     src = env->cc_src;
132     dest = env->cc_dest;
133     switch (cc_op) {
134     case CC_OP_FLAGS:
135         flags = dest;
136         break;
137     case CC_OP_LOGIC:
138         SET_NZ(dest);
139         break;
140     case CC_OP_ADD:
141         SET_NZ(dest);
142         if (dest < src)
143             flags |= CCF_C;
144         tmp = dest - src;
145         if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
146             flags |= CCF_V;
147         break;
148     case CC_OP_SUB:
149         SET_FLAGS_SUB(int32_t, uint32_t);
150         break;
151     case CC_OP_CMPB:
152         SET_FLAGS_SUB(int8_t, uint8_t);
153         break;
154     case CC_OP_CMPW:
155         SET_FLAGS_SUB(int16_t, uint16_t);
156         break;
157     case CC_OP_ADDX:
158         SET_NZ(dest);
159         if (dest <= src)
160             flags |= CCF_C;
161         tmp = dest - src - 1;
162         if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
163             flags |= CCF_V;
164         break;
165     case CC_OP_SUBX:
166         SET_NZ(dest);
167         tmp = dest + src + 1;
168         if (tmp <= src)
169             flags |= CCF_C;
170         if (HIGHBIT & (tmp ^ dest) & (tmp ^ src))
171             flags |= CCF_V;
172         break;
173     case CC_OP_SHL:
174         if (src >= 32) {
175             SET_NZ(0);
176         } else {
177             tmp = dest << src;
178             SET_NZ(tmp);
179         }
180         if (src && src <= 32 && (dest & (1 << (32 - src))))
181             flags |= CCF_C;
182         break;
183     case CC_OP_SHR:
184         if (src >= 32) {
185             SET_NZ(0);
186         } else {
187             tmp = dest >> src;
188             SET_NZ(tmp);
189         }
190         if (src && src <= 32 && ((dest >> (src - 1)) & 1))
191             flags |= CCF_C;
192         break;
193     case CC_OP_SAR:
194         if (src >= 32) {
195             SET_NZ(-1);
196         } else {
197             tmp = (int32_t)dest >> src;
198             SET_NZ(tmp);
199         }
200         if (src && src <= 32 && (((int32_t)dest >> (src - 1)) & 1))
201             flags |= CCF_C;
202         break;
203     default:
204         cpu_abort(env, "Bad CC_OP %d", cc_op);
205     }
206     env->cc_op = CC_OP_FLAGS;
207     env->cc_dest = flags;
208 }
209
210 float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1)
211 {
212     /* ??? This may incorrectly raise exceptions.  */
213     /* ??? Should flush denormals to zero.  */
214     float64 res;
215     res = float64_sub(src0, src1, &env->fp_status);
216     if (float64_is_nan(res)) {
217         /* +/-inf compares equal against itself, but sub returns nan.  */
218         if (!float64_is_nan(src0)
219             && !float64_is_nan(src1)) {
220             res = 0;
221             if (float64_lt_quiet(src0, res, &env->fp_status))
222                 res = float64_chs(res);
223         }
224     }
225     return res;
226 }
227
228 void helper_movec(CPUM68KState *env, int reg, uint32_t val)
229 {
230     switch (reg) {
231     case 0x02: /* CACR */
232         env->cacr = val;
233         m68k_switch_sp(env);
234         break;
235     case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
236         /* TODO: Implement Access Control Registers.  */
237         break;
238     case 0x801: /* VBR */
239         env->vbr = val;
240         break;
241     /* TODO: Implement control registers.  */
242     default:
243         cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
244                   reg, val);
245     }
246 }
247
248 void m68k_set_macsr(CPUM68KState *env, uint32_t val)
249 {
250     uint32_t acc;
251     int8_t exthigh;
252     uint8_t extlow;
253     uint64_t regval;
254     int i;
255     if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
256         for (i = 0; i < 4; i++) {
257             regval = env->macc[i];
258             exthigh = regval >> 40;
259             if (env->macsr & MACSR_FI) {
260                 acc = regval >> 8;
261                 extlow = regval;
262             } else {
263                 acc = regval;
264                 extlow = regval >> 32;
265             }
266             if (env->macsr & MACSR_FI) {
267                 regval = (((uint64_t)acc) << 8) | extlow;
268                 regval |= ((int64_t)exthigh) << 40;
269             } else if (env->macsr & MACSR_SU) {
270                 regval = acc | (((int64_t)extlow) << 32);
271                 regval |= ((int64_t)exthigh) << 40;
272             } else {
273                 regval = acc | (((uint64_t)extlow) << 32);
274                 regval |= ((uint64_t)(uint8_t)exthigh) << 40;
275             }
276             env->macc[i] = regval;
277         }
278     }
279     env->macsr = val;
280 }
281
282 void m68k_switch_sp(CPUM68KState *env)
283 {
284     int new_sp;
285
286     env->sp[env->current_sp] = env->aregs[7];
287     new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
288              ? M68K_SSP : M68K_USP;
289     env->aregs[7] = env->sp[new_sp];
290     env->current_sp = new_sp;
291 }
292
293 /* MMU */
294
295 /* TODO: This will need fixing once the MMU is implemented.  */
296 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
297 {
298     return addr;
299 }
300
301 #if defined(CONFIG_USER_ONLY) 
302
303 int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
304                                int is_user, int is_softmmu)
305 {
306     env->exception_index = EXCP_ACCESS;
307     env->mmu.ar = address;
308     return 1;
309 }
310
311 #else
312
313 int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
314                                int is_user, int is_softmmu)
315 {
316     int prot;
317
318     address &= TARGET_PAGE_MASK;
319     prot = PAGE_READ | PAGE_WRITE;
320     return tlb_set_page(env, address, address, prot, is_user, is_softmmu);
321 }
322
323 /* Notify CPU of a pending interrupt.  Prioritization and vectoring should
324    be handled by the interrupt controller.  Real hardware only requests
325    the vector when the interrupt is acknowledged by the CPU.  For
326    simplicitly we calculate it when the interrupt is signalled.  */
327 void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector)
328 {
329     env->pending_level = level;
330     env->pending_vector = vector;
331     if (level)
332         cpu_interrupt(env, CPU_INTERRUPT_HARD);
333     else
334         cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
335 }
336
337 #endif