qemu_put signedness fixes, by Andre Przywara.
[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     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
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)) {
260             res = float64_zero;
261             if (float64_lt_quiet(src0, res, &env->fp_status))
262                 res = float64_chs(res);
263         }
264     }
265     return res;
266 }
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