Statistics
| Branch: | Revision:

root / target-m68k / helper.c @ 5fafdf24

History | View | Annotate | Download (9.2 kB)

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