Statistics
| Branch: | Revision:

root / target-alpha / helper.c @ 3a6fa678

History | View | Annotate | Download (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
target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
172
{
173
    return -1;
174
}
175

    
176
int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
177
                                int mmu_idx, int is_softmmu)
178
{
179
    return 0;
180
}
181
#endif /* USER_ONLY */
182

    
183
void do_interrupt (CPUState *env)
184
{
185
    int i = env->exception_index;
186

    
187
    if (qemu_loglevel_mask(CPU_LOG_INT)) {
188
        static int count;
189
        const char *name = "<unknown>";
190

    
191
        switch (i) {
192
        case EXCP_RESET:
193
            name = "reset";
194
            break;
195
        case EXCP_MCHK:
196
            name = "mchk";
197
            break;
198
        case EXCP_SMP_INTERRUPT:
199
            name = "smp_interrupt";
200
            break;
201
        case EXCP_CLK_INTERRUPT:
202
            name = "clk_interrupt";
203
            break;
204
        case EXCP_DEV_INTERRUPT:
205
            name = "dev_interrupt";
206
            break;
207
        case EXCP_MMFAULT:
208
            name = "mmfault";
209
            break;
210
        case EXCP_UNALIGN:
211
            name = "unalign";
212
            break;
213
        case EXCP_OPCDEC:
214
            name = "opcdec";
215
            break;
216
        case EXCP_ARITH:
217
            name = "arith";
218
            break;
219
        case EXCP_FEN:
220
            name = "fen";
221
            break;
222
        case EXCP_CALL_PAL:
223
            name = "call_pal";
224
            break;
225
        case EXCP_STL_C:
226
            name = "stl_c";
227
            break;
228
        case EXCP_STQ_C:
229
            name = "stq_c";
230
            break;
231
        }
232
        qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
233
                 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
234
    }
235

    
236
    env->exception_index = -1;
237

    
238
#if !defined(CONFIG_USER_ONLY)
239
    switch (i) {
240
    case EXCP_RESET:
241
        i = 0x0000;
242
        break;
243
    case EXCP_MCHK:
244
        i = 0x0080;
245
        break;
246
    case EXCP_SMP_INTERRUPT:
247
        i = 0x0100;
248
        break;
249
    case EXCP_CLK_INTERRUPT:
250
        i = 0x0180;
251
        break;
252
    case EXCP_DEV_INTERRUPT:
253
        i = 0x0200;
254
        break;
255
    case EXCP_MMFAULT:
256
        i = 0x0280;
257
        break;
258
    case EXCP_UNALIGN:
259
        i = 0x0300;
260
        break;
261
    case EXCP_OPCDEC:
262
        i = 0x0380;
263
        break;
264
    case EXCP_ARITH:
265
        i = 0x0400;
266
        break;
267
    case EXCP_FEN:
268
        i = 0x0480;
269
        break;
270
    case EXCP_CALL_PAL:
271
        i = env->error_code;
272
        /* There are 64 entry points for both privileged and unprivileged,
273
           with bit 0x80 indicating unprivileged.  Each entry point gets
274
           64 bytes to do its job.  */
275
        if (i & 0x80) {
276
            i = 0x2000 + (i - 0x80) * 64;
277
        } else {
278
            i = 0x1000 + i * 64;
279
        }
280
        break;
281
    default:
282
        cpu_abort(env, "Unhandled CPU exception");
283
    }
284

    
285
    /* Remember where the exception happened.  Emulate real hardware in
286
       that the low bit of the PC indicates PALmode.  */
287
    env->exc_addr = env->pc | env->pal_mode;
288

    
289
    /* Continue execution at the PALcode entry point.  */
290
    env->pc = env->palbr + i;
291

    
292
    /* Switch to PALmode.  */
293
    env->pal_mode = 1;
294
#endif /* !USER_ONLY */
295
}
296

    
297
void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
298
                     int flags)
299
{
300
    static const char *linux_reg_names[] = {
301
        "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
302
        "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
303
        "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
304
        "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
305
    };
306
    int i;
307

    
308
    cpu_fprintf(f, "     PC  " TARGET_FMT_lx "      PS  %02x\n",
309
                env->pc, env->ps);
310
    for (i = 0; i < 31; i++) {
311
        cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
312
                    linux_reg_names[i], env->ir[i]);
313
        if ((i % 3) == 2)
314
            cpu_fprintf(f, "\n");
315
    }
316

    
317
    cpu_fprintf(f, "lock_a   " TARGET_FMT_lx " lock_v   " TARGET_FMT_lx "\n",
318
                env->lock_addr, env->lock_value);
319

    
320
    for (i = 0; i < 31; i++) {
321
        cpu_fprintf(f, "FIR%02d    " TARGET_FMT_lx " ", i,
322
                    *((uint64_t *)(&env->fir[i])));
323
        if ((i % 3) == 2)
324
            cpu_fprintf(f, "\n");
325
    }
326
    cpu_fprintf(f, "\n");
327
}