Statistics
| Branch: | Revision:

root / target-m68k / helper.c @ 20dcee94

History | View | Annotate | Download (9 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_EMAC);
72
        m68k_set_feature(env, M68K_FEATURE_USP);
73
        break;
74
    case M68K_CPUID_CFV4E:
75
        m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
76
        m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
77
        m68k_set_feature(env, M68K_FEATURE_CF_ISA_C);
78
        m68k_set_feature(env, M68K_FEATURE_CF_FPU);
79
        m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
80
        m68k_set_feature(env, M68K_FEATURE_USP);
81
        break;
82
    case M68K_CPUID_ANY:
83
        m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
84
        m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
85
        m68k_set_feature(env, M68K_FEATURE_CF_ISA_C);
86
        m68k_set_feature(env, M68K_FEATURE_CF_FPU);
87
        /* MAC and EMAC are mututally exclusive, so pick EMAC.
88
           It's mostly backwards compatible.  */
89
        m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
90
        m68k_set_feature(env, M68K_FEATURE_USP);
91
        m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
92
        break;
93
    }
94

    
95
    register_m68k_insns(env);
96

    
97
    return 0;
98
}
99

    
100
void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
101
{
102
    int flags;
103
    uint32_t src;
104
    uint32_t dest;
105
    uint32_t tmp;
106

    
107
#define HIGHBIT 0x80000000u
108

    
109
#define SET_NZ(x) do { \
110
    if ((x) == 0) \
111
        flags |= CCF_Z; \
112
    else if ((int32_t)(x) < 0) \
113
        flags |= CCF_N; \
114
    } while (0)
115

    
116
#define SET_FLAGS_SUB(type, utype) do { \
117
    SET_NZ((type)dest); \
118
    tmp = dest + src; \
119
    if ((utype) tmp < (utype) src) \
120
        flags |= CCF_C; \
121
    if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
122
        flags |= CCF_V; \
123
    } while (0)
124

    
125
    flags = 0;
126
    src = env->cc_src;
127
    dest = env->cc_dest;
128
    switch (cc_op) {
129
    case CC_OP_FLAGS:
130
        flags = dest;
131
        break;
132
    case CC_OP_LOGIC:
133
        SET_NZ(dest);
134
        break;
135
    case CC_OP_ADD:
136
        SET_NZ(dest);
137
        if (dest < src)
138
            flags |= CCF_C;
139
        tmp = dest - src;
140
        if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
141
            flags |= CCF_V;
142
        break;
143
    case CC_OP_SUB:
144
        SET_FLAGS_SUB(int32_t, uint32_t);
145
        break;
146
    case CC_OP_CMPB:
147
        SET_FLAGS_SUB(int8_t, uint8_t);
148
        break;
149
    case CC_OP_CMPW:
150
        SET_FLAGS_SUB(int16_t, uint16_t);
151
        break;
152
    case CC_OP_ADDX:
153
        SET_NZ(dest);
154
        if (dest <= src)
155
            flags |= CCF_C;
156
        tmp = dest - src - 1;
157
        if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
158
            flags |= CCF_V;
159
        break;
160
    case CC_OP_SUBX:
161
        SET_NZ(dest);
162
        tmp = dest + src + 1;
163
        if (tmp <= src)
164
            flags |= CCF_C;
165
        if (HIGHBIT & (tmp ^ dest) & (tmp ^ src))
166
            flags |= CCF_V;
167
        break;
168
    case CC_OP_SHL:
169
        if (src >= 32) {
170
            SET_NZ(0);
171
        } else {
172
            tmp = dest << src;
173
            SET_NZ(tmp);
174
        }
175
        if (src && src <= 32 && (dest & (1 << (32 - src))))
176
            flags |= CCF_C;
177
        break;
178
    case CC_OP_SHR:
179
        if (src >= 32) {
180
            SET_NZ(0);
181
        } else {
182
            tmp = dest >> src;
183
            SET_NZ(tmp);
184
        }
185
        if (src && src <= 32 && ((dest >> (src - 1)) & 1))
186
            flags |= CCF_C;
187
        break;
188
    case CC_OP_SAR:
189
        if (src >= 32) {
190
            SET_NZ(-1);
191
        } else {
192
            tmp = (int32_t)dest >> src;
193
            SET_NZ(tmp);
194
        }
195
        if (src && src <= 32 && (((int32_t)dest >> (src - 1)) & 1))
196
            flags |= CCF_C;
197
        break;
198
    default:
199
        cpu_abort(env, "Bad CC_OP %d", cc_op);
200
    }
201
    env->cc_op = CC_OP_FLAGS;
202
    env->cc_dest = flags;
203
}
204

    
205
float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1)
206
{
207
    /* ??? This may incorrectly raise exceptions.  */
208
    /* ??? Should flush denormals to zero.  */
209
    float64 res;
210
    res = float64_sub(src0, src1, &env->fp_status);
211
    if (float64_is_nan(res)) {
212
        /* +/-inf compares equal against itself, but sub returns nan.  */
213
        if (!float64_is_nan(src0)
214
            && !float64_is_nan(src1)) {
215
            res = 0;
216
            if (float64_lt_quiet(src0, res, &env->fp_status))
217
                res = float64_chs(res);
218
        }
219
    }
220
    return res;
221
}
222

    
223
void helper_movec(CPUM68KState *env, int reg, uint32_t val)
224
{
225
    switch (reg) {
226
    case 0x02: /* CACR */
227
        env->cacr = val;
228
        m68k_switch_sp(env);
229
        break;
230
    case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
231
        /* TODO: Implement Access Control Registers.  */
232
        break;
233
    case 0x801: /* VBR */
234
        env->vbr = val;
235
        break;
236
    /* TODO: Implement control registers.  */
237
    default:
238
        cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
239
                  reg, val);
240
    }
241
}
242

    
243
void m68k_set_macsr(CPUM68KState *env, uint32_t val)
244
{
245
    uint32_t acc;
246
    int8_t exthigh;
247
    uint8_t extlow;
248
    uint64_t regval;
249
    int i;
250
    if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
251
        for (i = 0; i < 4; i++) {
252
            regval = env->macc[i];
253
            exthigh = regval >> 40;
254
            if (env->macsr & MACSR_FI) {
255
                acc = regval >> 8;
256
                extlow = regval;
257
            } else {
258
                acc = regval;
259
                extlow = regval >> 32;
260
            }
261
            if (env->macsr & MACSR_FI) {
262
                regval = (((uint64_t)acc) << 8) | extlow;
263
                regval |= ((int64_t)exthigh) << 40;
264
            } else if (env->macsr & MACSR_SU) {
265
                regval = acc | (((int64_t)extlow) << 32);
266
                regval |= ((int64_t)exthigh) << 40;
267
            } else {
268
                regval = acc | (((uint64_t)extlow) << 32);
269
                regval |= ((uint64_t)(uint8_t)exthigh) << 40;
270
            }
271
            env->macc[i] = regval;
272
        }
273
    }
274
    env->macsr = val;
275
}
276

    
277
void m68k_switch_sp(CPUM68KState *env)
278
{
279
    int new_sp;
280

    
281
    env->sp[env->current_sp] = env->aregs[7];
282
    new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
283
             ? M68K_SSP : M68K_USP;
284
    env->aregs[7] = env->sp[new_sp];
285
    env->current_sp = new_sp;
286
}
287

    
288
/* MMU */
289

    
290
/* TODO: This will need fixing once the MMU is implemented.  */
291
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
292
{
293
    return addr;
294
}
295

    
296
#if defined(CONFIG_USER_ONLY) 
297

    
298
int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
299
                               int is_user, int is_softmmu)
300
{
301
    env->exception_index = EXCP_ACCESS;
302
    env->mmu.ar = address;
303
    return 1;
304
}
305

    
306
#else
307

    
308
int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
309
                               int is_user, int is_softmmu)
310
{
311
    int prot;
312

    
313
    address &= TARGET_PAGE_MASK;
314
    prot = PAGE_READ | PAGE_WRITE;
315
    return tlb_set_page(env, address, address, prot, is_user, is_softmmu);
316
}
317

    
318
/* Notify CPU of a pending interrupt.  Prioritization and vectoring should
319
   be handled by the interrupt controller.  Real hardware only requests
320
   the vector when the interrupt is acknowledged by the CPU.  For
321
   simplicitly we calculate it when the interrupt is signalled.  */
322
void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector)
323
{
324
    env->pending_level = level;
325
    env->pending_vector = vector;
326
    if (level)
327
        cpu_interrupt(env, CPU_INTERRUPT_HARD);
328
    else
329
        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
330
}
331

    
332
#endif