Statistics
| Branch: | Revision:

root / target-alpha / helper.c @ 21d2beaa

History | View | Annotate | Download (8.8 kB)

1
/*
2
 *  Alpha emulation cpu helpers for qemu.
3
 *
4
 *  Copyright (c) 2007 Jocelyn Mayer
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 */
19

    
20
#include <stdint.h>
21
#include <stdlib.h>
22
#include <stdio.h>
23

    
24
#include "cpu.h"
25
#include "exec-all.h"
26
#include "softfloat.h"
27

    
28
uint64_t cpu_alpha_load_fpcr (CPUState *env)
29
{
30
    uint64_t r = 0;
31
    uint8_t t;
32

    
33
    t = env->fpcr_exc_status;
34
    if (t) {
35
        r = FPCR_SUM;
36
        if (t & float_flag_invalid) {
37
            r |= FPCR_INV;
38
        }
39
        if (t & float_flag_divbyzero) {
40
            r |= FPCR_DZE;
41
        }
42
        if (t & float_flag_overflow) {
43
            r |= FPCR_OVF;
44
        }
45
        if (t & float_flag_underflow) {
46
            r |= FPCR_UNF;
47
        }
48
        if (t & float_flag_inexact) {
49
            r |= FPCR_INE;
50
        }
51
    }
52

    
53
    t = env->fpcr_exc_mask;
54
    if (t & float_flag_invalid) {
55
        r |= FPCR_INVD;
56
    }
57
    if (t & float_flag_divbyzero) {
58
        r |= FPCR_DZED;
59
    }
60
    if (t & float_flag_overflow) {
61
        r |= FPCR_OVFD;
62
    }
63
    if (t & float_flag_underflow) {
64
        r |= FPCR_UNFD;
65
    }
66
    if (t & float_flag_inexact) {
67
        r |= FPCR_INED;
68
    }
69

    
70
    switch (env->fpcr_dyn_round) {
71
    case float_round_nearest_even:
72
        r |= FPCR_DYN_NORMAL;
73
        break;
74
    case float_round_down:
75
        r |= FPCR_DYN_MINUS;
76
        break;
77
    case float_round_up:
78
        r |= FPCR_DYN_PLUS;
79
        break;
80
    case float_round_to_zero:
81
        r |= FPCR_DYN_CHOPPED;
82
        break;
83
    }
84

    
85
    if (env->fpcr_dnz) {
86
        r |= FPCR_DNZ;
87
    }
88
    if (env->fpcr_dnod) {
89
        r |= FPCR_DNOD;
90
    }
91
    if (env->fpcr_undz) {
92
        r |= FPCR_UNDZ;
93
    }
94

    
95
    return r;
96
}
97

    
98
void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
99
{
100
    uint8_t t;
101

    
102
    t = 0;
103
    if (val & FPCR_INV) {
104
        t |= float_flag_invalid;
105
    }
106
    if (val & FPCR_DZE) {
107
        t |= float_flag_divbyzero;
108
    }
109
    if (val & FPCR_OVF) {
110
        t |= float_flag_overflow;
111
    }
112
    if (val & FPCR_UNF) {
113
        t |= float_flag_underflow;
114
    }
115
    if (val & FPCR_INE) {
116
        t |= float_flag_inexact;
117
    }
118
    env->fpcr_exc_status = t;
119

    
120
    t = 0;
121
    if (val & FPCR_INVD) {
122
        t |= float_flag_invalid;
123
    }
124
    if (val & FPCR_DZED) {
125
        t |= float_flag_divbyzero;
126
    }
127
    if (val & FPCR_OVFD) {
128
        t |= float_flag_overflow;
129
    }
130
    if (val & FPCR_UNFD) {
131
        t |= float_flag_underflow;
132
    }
133
    if (val & FPCR_INED) {
134
        t |= float_flag_inexact;
135
    }
136
    env->fpcr_exc_mask = t;
137

    
138
    switch (val & FPCR_DYN_MASK) {
139
    case FPCR_DYN_CHOPPED:
140
        t = float_round_to_zero;
141
        break;
142
    case FPCR_DYN_MINUS:
143
        t = float_round_down;
144
        break;
145
    case FPCR_DYN_NORMAL:
146
        t = float_round_nearest_even;
147
        break;
148
    case FPCR_DYN_PLUS:
149
        t = float_round_up;
150
        break;
151
    }
152
    env->fpcr_dyn_round = t;
153

    
154
    env->fpcr_flush_to_zero
155
      = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
156

    
157
    env->fpcr_dnz = (val & FPCR_DNZ) != 0;
158
    env->fpcr_dnod = (val & FPCR_DNOD) != 0;
159
    env->fpcr_undz = (val & FPCR_UNDZ) != 0;
160
}
161

    
162
#if defined(CONFIG_USER_ONLY)
163
int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
164
                                int mmu_idx, int is_softmmu)
165
{
166
    env->exception_index = EXCP_MMFAULT;
167
    env->trap_arg0 = address;
168
    return 1;
169
}
170
#else
171
void swap_shadow_regs(CPUState *env)
172
{
173
    uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
174

    
175
    i0 = env->ir[8];
176
    i1 = env->ir[9];
177
    i2 = env->ir[10];
178
    i3 = env->ir[11];
179
    i4 = env->ir[12];
180
    i5 = env->ir[13];
181
    i6 = env->ir[14];
182
    i7 = env->ir[25];
183

    
184
    env->ir[8]  = env->shadow[0];
185
    env->ir[9]  = env->shadow[1];
186
    env->ir[10] = env->shadow[2];
187
    env->ir[11] = env->shadow[3];
188
    env->ir[12] = env->shadow[4];
189
    env->ir[13] = env->shadow[5];
190
    env->ir[14] = env->shadow[6];
191
    env->ir[25] = env->shadow[7];
192

    
193
    env->shadow[0] = i0;
194
    env->shadow[1] = i1;
195
    env->shadow[2] = i2;
196
    env->shadow[3] = i3;
197
    env->shadow[4] = i4;
198
    env->shadow[5] = i5;
199
    env->shadow[6] = i6;
200
    env->shadow[7] = i7;
201
}
202

    
203
target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
204
{
205
    return -1;
206
}
207

    
208
int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
209
                                int mmu_idx, int is_softmmu)
210
{
211
    return 0;
212
}
213
#endif /* USER_ONLY */
214

    
215
void do_interrupt (CPUState *env)
216
{
217
    int i = env->exception_index;
218

    
219
    if (qemu_loglevel_mask(CPU_LOG_INT)) {
220
        static int count;
221
        const char *name = "<unknown>";
222

    
223
        switch (i) {
224
        case EXCP_RESET:
225
            name = "reset";
226
            break;
227
        case EXCP_MCHK:
228
            name = "mchk";
229
            break;
230
        case EXCP_SMP_INTERRUPT:
231
            name = "smp_interrupt";
232
            break;
233
        case EXCP_CLK_INTERRUPT:
234
            name = "clk_interrupt";
235
            break;
236
        case EXCP_DEV_INTERRUPT:
237
            name = "dev_interrupt";
238
            break;
239
        case EXCP_MMFAULT:
240
            name = "mmfault";
241
            break;
242
        case EXCP_UNALIGN:
243
            name = "unalign";
244
            break;
245
        case EXCP_OPCDEC:
246
            name = "opcdec";
247
            break;
248
        case EXCP_ARITH:
249
            name = "arith";
250
            break;
251
        case EXCP_FEN:
252
            name = "fen";
253
            break;
254
        case EXCP_CALL_PAL:
255
            name = "call_pal";
256
            break;
257
        case EXCP_STL_C:
258
            name = "stl_c";
259
            break;
260
        case EXCP_STQ_C:
261
            name = "stq_c";
262
            break;
263
        }
264
        qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
265
                 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
266
    }
267

    
268
    env->exception_index = -1;
269

    
270
#if !defined(CONFIG_USER_ONLY)
271
    switch (i) {
272
    case EXCP_RESET:
273
        i = 0x0000;
274
        break;
275
    case EXCP_MCHK:
276
        i = 0x0080;
277
        break;
278
    case EXCP_SMP_INTERRUPT:
279
        i = 0x0100;
280
        break;
281
    case EXCP_CLK_INTERRUPT:
282
        i = 0x0180;
283
        break;
284
    case EXCP_DEV_INTERRUPT:
285
        i = 0x0200;
286
        break;
287
    case EXCP_MMFAULT:
288
        i = 0x0280;
289
        break;
290
    case EXCP_UNALIGN:
291
        i = 0x0300;
292
        break;
293
    case EXCP_OPCDEC:
294
        i = 0x0380;
295
        break;
296
    case EXCP_ARITH:
297
        i = 0x0400;
298
        break;
299
    case EXCP_FEN:
300
        i = 0x0480;
301
        break;
302
    case EXCP_CALL_PAL:
303
        i = env->error_code;
304
        /* There are 64 entry points for both privileged and unprivileged,
305
           with bit 0x80 indicating unprivileged.  Each entry point gets
306
           64 bytes to do its job.  */
307
        if (i & 0x80) {
308
            i = 0x2000 + (i - 0x80) * 64;
309
        } else {
310
            i = 0x1000 + i * 64;
311
        }
312
        break;
313
    default:
314
        cpu_abort(env, "Unhandled CPU exception");
315
    }
316

    
317
    /* Remember where the exception happened.  Emulate real hardware in
318
       that the low bit of the PC indicates PALmode.  */
319
    env->exc_addr = env->pc | env->pal_mode;
320

    
321
    /* Continue execution at the PALcode entry point.  */
322
    env->pc = env->palbr + i;
323

    
324
    /* Switch to PALmode.  */
325
    if (!env->pal_mode) {
326
        env->pal_mode = 1;
327
        swap_shadow_regs(env);
328
    }
329
#endif /* !USER_ONLY */
330
}
331

    
332
void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
333
                     int flags)
334
{
335
    static const char *linux_reg_names[] = {
336
        "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
337
        "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
338
        "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
339
        "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
340
    };
341
    int i;
342

    
343
    cpu_fprintf(f, "     PC  " TARGET_FMT_lx "      PS  %02x\n",
344
                env->pc, env->ps);
345
    for (i = 0; i < 31; i++) {
346
        cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
347
                    linux_reg_names[i], env->ir[i]);
348
        if ((i % 3) == 2)
349
            cpu_fprintf(f, "\n");
350
    }
351

    
352
    cpu_fprintf(f, "lock_a   " TARGET_FMT_lx " lock_v   " TARGET_FMT_lx "\n",
353
                env->lock_addr, env->lock_value);
354

    
355
    for (i = 0; i < 31; i++) {
356
        cpu_fprintf(f, "FIR%02d    " TARGET_FMT_lx " ", i,
357
                    *((uint64_t *)(&env->fir[i])));
358
        if ((i % 3) == 2)
359
            cpu_fprintf(f, "\n");
360
    }
361
    cpu_fprintf(f, "\n");
362
}