Statistics
| Branch: | Revision:

root / target-alpha / helper.c @ 57c83dac

History | View | Annotate | Download (12.2 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 "softfloat.h"
26

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

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

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

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

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

    
94
    return r;
95
}
96

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

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

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

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

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

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

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

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

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

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

    
202
/* Returns the OSF/1 entMM failure indication, or -1 on success.  */
203
static int get_physical_address(CPUState *env, target_ulong addr,
204
                                int prot_need, int mmu_idx,
205
                                target_ulong *pphys, int *pprot)
206
{
207
    target_long saddr = addr;
208
    target_ulong phys = 0;
209
    target_ulong L1pte, L2pte, L3pte;
210
    target_ulong pt, index;
211
    int prot = 0;
212
    int ret = MM_K_ACV;
213

    
214
    /* Ensure that the virtual address is properly sign-extended from
215
       the last implemented virtual address bit.  */
216
    if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
217
        goto exit;
218
    }
219

    
220
    /* Translate the superpage.  */
221
    /* ??? When we do more than emulate Unix PALcode, we'll need to
222
       determine which KSEG is actually active.  */
223
    if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
224
        /* User-space cannot access KSEG addresses.  */
225
        if (mmu_idx != MMU_KERNEL_IDX) {
226
            goto exit;
227
        }
228

    
229
        /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
230
           We would not do this if the 48-bit KSEG is enabled.  */
231
        phys = saddr & ((1ull << 40) - 1);
232
        phys |= (saddr & (1ull << 40)) << 3;
233

    
234
        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
235
        ret = -1;
236
        goto exit;
237
    }
238

    
239
    /* Interpret the page table exactly like PALcode does.  */
240

    
241
    pt = env->ptbr;
242

    
243
    /* L1 page table read.  */
244
    index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
245
    L1pte = ldq_phys(pt + index*8);
246

    
247
    if (unlikely((L1pte & PTE_VALID) == 0)) {
248
        ret = MM_K_TNV;
249
        goto exit;
250
    }
251
    if (unlikely((L1pte & PTE_KRE) == 0)) {
252
        goto exit;
253
    }
254
    pt = L1pte >> 32 << TARGET_PAGE_BITS;
255

    
256
    /* L2 page table read.  */
257
    index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
258
    L2pte = ldq_phys(pt + index*8);
259

    
260
    if (unlikely((L2pte & PTE_VALID) == 0)) {
261
        ret = MM_K_TNV;
262
        goto exit;
263
    }
264
    if (unlikely((L2pte & PTE_KRE) == 0)) {
265
        goto exit;
266
    }
267
    pt = L2pte >> 32 << TARGET_PAGE_BITS;
268

    
269
    /* L3 page table read.  */
270
    index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
271
    L3pte = ldq_phys(pt + index*8);
272

    
273
    phys = L3pte >> 32 << TARGET_PAGE_BITS;
274
    if (unlikely((L3pte & PTE_VALID) == 0)) {
275
        ret = MM_K_TNV;
276
        goto exit;
277
    }
278

    
279
#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
280
# error page bits out of date
281
#endif
282

    
283
    /* Check access violations.  */
284
    if (L3pte & (PTE_KRE << mmu_idx)) {
285
        prot |= PAGE_READ | PAGE_EXEC;
286
    }
287
    if (L3pte & (PTE_KWE << mmu_idx)) {
288
        prot |= PAGE_WRITE;
289
    }
290
    if (unlikely((prot & prot_need) == 0 && prot_need)) {
291
        goto exit;
292
    }
293

    
294
    /* Check fault-on-operation violations.  */
295
    prot &= ~(L3pte >> 1);
296
    ret = -1;
297
    if (unlikely((prot & prot_need) == 0)) {
298
        ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
299
               prot_need & PAGE_WRITE ? MM_K_FOW :
300
               prot_need & PAGE_READ ? MM_K_FOR : -1);
301
    }
302

    
303
 exit:
304
    *pphys = phys;
305
    *pprot = prot;
306
    return ret;
307
}
308

    
309
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
310
{
311
    target_ulong phys;
312
    int prot, fail;
313

    
314
    fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
315
    return (fail >= 0 ? -1 : phys);
316
}
317

    
318
int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
319
                               int mmu_idx)
320
{
321
    target_ulong phys;
322
    int prot, fail;
323

    
324
    fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
325
    if (unlikely(fail >= 0)) {
326
        env->exception_index = EXCP_MMFAULT;
327
        env->trap_arg0 = addr;
328
        env->trap_arg1 = fail;
329
        env->trap_arg2 = (rw == 2 ? -1 : rw);
330
        return 1;
331
    }
332

    
333
    tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
334
                 prot, mmu_idx, TARGET_PAGE_SIZE);
335
    return 0;
336
}
337
#endif /* USER_ONLY */
338

    
339
void do_interrupt (CPUState *env)
340
{
341
    int i = env->exception_index;
342

    
343
    if (qemu_loglevel_mask(CPU_LOG_INT)) {
344
        static int count;
345
        const char *name = "<unknown>";
346

    
347
        switch (i) {
348
        case EXCP_RESET:
349
            name = "reset";
350
            break;
351
        case EXCP_MCHK:
352
            name = "mchk";
353
            break;
354
        case EXCP_SMP_INTERRUPT:
355
            name = "smp_interrupt";
356
            break;
357
        case EXCP_CLK_INTERRUPT:
358
            name = "clk_interrupt";
359
            break;
360
        case EXCP_DEV_INTERRUPT:
361
            name = "dev_interrupt";
362
            break;
363
        case EXCP_MMFAULT:
364
            name = "mmfault";
365
            break;
366
        case EXCP_UNALIGN:
367
            name = "unalign";
368
            break;
369
        case EXCP_OPCDEC:
370
            name = "opcdec";
371
            break;
372
        case EXCP_ARITH:
373
            name = "arith";
374
            break;
375
        case EXCP_FEN:
376
            name = "fen";
377
            break;
378
        case EXCP_CALL_PAL:
379
            name = "call_pal";
380
            break;
381
        case EXCP_STL_C:
382
            name = "stl_c";
383
            break;
384
        case EXCP_STQ_C:
385
            name = "stq_c";
386
            break;
387
        }
388
        qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
389
                 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
390
    }
391

    
392
    env->exception_index = -1;
393

    
394
#if !defined(CONFIG_USER_ONLY)
395
    switch (i) {
396
    case EXCP_RESET:
397
        i = 0x0000;
398
        break;
399
    case EXCP_MCHK:
400
        i = 0x0080;
401
        break;
402
    case EXCP_SMP_INTERRUPT:
403
        i = 0x0100;
404
        break;
405
    case EXCP_CLK_INTERRUPT:
406
        i = 0x0180;
407
        break;
408
    case EXCP_DEV_INTERRUPT:
409
        i = 0x0200;
410
        break;
411
    case EXCP_MMFAULT:
412
        i = 0x0280;
413
        break;
414
    case EXCP_UNALIGN:
415
        i = 0x0300;
416
        break;
417
    case EXCP_OPCDEC:
418
        i = 0x0380;
419
        break;
420
    case EXCP_ARITH:
421
        i = 0x0400;
422
        break;
423
    case EXCP_FEN:
424
        i = 0x0480;
425
        break;
426
    case EXCP_CALL_PAL:
427
        i = env->error_code;
428
        /* There are 64 entry points for both privileged and unprivileged,
429
           with bit 0x80 indicating unprivileged.  Each entry point gets
430
           64 bytes to do its job.  */
431
        if (i & 0x80) {
432
            i = 0x2000 + (i - 0x80) * 64;
433
        } else {
434
            i = 0x1000 + i * 64;
435
        }
436
        break;
437
    default:
438
        cpu_abort(env, "Unhandled CPU exception");
439
    }
440

    
441
    /* Remember where the exception happened.  Emulate real hardware in
442
       that the low bit of the PC indicates PALmode.  */
443
    env->exc_addr = env->pc | env->pal_mode;
444

    
445
    /* Continue execution at the PALcode entry point.  */
446
    env->pc = env->palbr + i;
447

    
448
    /* Switch to PALmode.  */
449
    if (!env->pal_mode) {
450
        env->pal_mode = 1;
451
        swap_shadow_regs(env);
452
    }
453
#endif /* !USER_ONLY */
454
}
455

    
456
void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
457
                     int flags)
458
{
459
    static const char *linux_reg_names[] = {
460
        "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
461
        "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
462
        "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
463
        "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
464
    };
465
    int i;
466

    
467
    cpu_fprintf(f, "     PC  " TARGET_FMT_lx "      PS  %02x\n",
468
                env->pc, env->ps);
469
    for (i = 0; i < 31; i++) {
470
        cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
471
                    linux_reg_names[i], env->ir[i]);
472
        if ((i % 3) == 2)
473
            cpu_fprintf(f, "\n");
474
    }
475

    
476
    cpu_fprintf(f, "lock_a   " TARGET_FMT_lx " lock_v   " TARGET_FMT_lx "\n",
477
                env->lock_addr, env->lock_value);
478

    
479
    for (i = 0; i < 31; i++) {
480
        cpu_fprintf(f, "FIR%02d    " TARGET_FMT_lx " ", i,
481
                    *((uint64_t *)(&env->fir[i])));
482
        if ((i % 3) == 2)
483
            cpu_fprintf(f, "\n");
484
    }
485
    cpu_fprintf(f, "\n");
486
}