Statistics
| Branch: | Revision:

root / target-m68k / helper.c @ ce62e5ba

History | View | Annotate | Download (9.3 kB)

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