Statistics
| Branch: | Revision:

root / target-alpha / helper.c @ ee0dc6d3

History | View | Annotate | Download (13.1 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 ret = 0;
31
    int flags, mask;
32

    
33
    flags = env->fp_status.float_exception_flags;
34
    ret |= (uint64_t) flags << 52;
35
    if (flags)
36
        ret |= FPCR_SUM;
37
    env->ipr[IPR_EXC_SUM] &= ~0x3E;
38
    env->ipr[IPR_EXC_SUM] |= flags << 1;
39

    
40
    mask = env->fp_status.float_exception_mask;
41
    if (mask & float_flag_invalid)
42
        ret |= FPCR_INVD;
43
    if (mask & float_flag_divbyzero)
44
        ret |= FPCR_DZED;
45
    if (mask & float_flag_overflow)
46
        ret |= FPCR_OVFD;
47
    if (mask & float_flag_underflow)
48
        ret |= FPCR_UNFD;
49
    if (mask & float_flag_inexact)
50
        ret |= FPCR_INED;
51

    
52
    switch (env->fp_status.float_rounding_mode) {
53
    case float_round_nearest_even:
54
        ret |= 2ULL << FPCR_DYN_SHIFT;
55
        break;
56
    case float_round_down:
57
        ret |= 1ULL << FPCR_DYN_SHIFT;
58
        break;
59
    case float_round_up:
60
        ret |= 3ULL << FPCR_DYN_SHIFT;
61
        break;
62
    case float_round_to_zero:
63
        break;
64
    }
65
    return ret;
66
}
67

    
68
void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
69
{
70
    int round_mode, mask;
71

    
72
    set_float_exception_flags((val >> 52) & 0x3F, &env->fp_status);
73

    
74
    mask = 0;
75
    if (val & FPCR_INVD)
76
        mask |= float_flag_invalid;
77
    if (val & FPCR_DZED)
78
        mask |= float_flag_divbyzero;
79
    if (val & FPCR_OVFD)
80
        mask |= float_flag_overflow;
81
    if (val & FPCR_UNFD)
82
        mask |= float_flag_underflow;
83
    if (val & FPCR_INED)
84
        mask |= float_flag_inexact;
85
    env->fp_status.float_exception_mask = mask;
86

    
87
    switch ((val >> FPCR_DYN_SHIFT) & 3) {
88
    case 0:
89
        round_mode = float_round_to_zero;
90
        break;
91
    case 1:
92
        round_mode = float_round_down;
93
        break;
94
    case 2:
95
        round_mode = float_round_nearest_even;
96
        break;
97
    case 3:
98
    default: /* this avoids a gcc (< 4.4) warning */
99
        round_mode = float_round_up;
100
        break;
101
    }
102
    set_float_rounding_mode(round_mode, &env->fp_status);
103
}
104

    
105
#if defined(CONFIG_USER_ONLY)
106

    
107
int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
108
                                int mmu_idx, int is_softmmu)
109
{
110
    if (rw == 2)
111
        env->exception_index = EXCP_ITB_MISS;
112
    else
113
        env->exception_index = EXCP_DFAULT;
114
    env->ipr[IPR_EXC_ADDR] = address;
115

    
116
    return 1;
117
}
118

    
119
target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
120
{
121
    return addr;
122
}
123

    
124
void do_interrupt (CPUState *env)
125
{
126
    env->exception_index = -1;
127
}
128

    
129
#else
130

    
131
target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
132
{
133
    return -1;
134
}
135

    
136
int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
137
                                int mmu_idx, int is_softmmu)
138
{
139
    uint32_t opc;
140

    
141
    if (rw == 2) {
142
        /* Instruction translation buffer miss */
143
        env->exception_index = EXCP_ITB_MISS;
144
    } else {
145
        if (env->ipr[IPR_EXC_ADDR] & 1)
146
            env->exception_index = EXCP_DTB_MISS_PAL;
147
        else
148
            env->exception_index = EXCP_DTB_MISS_NATIVE;
149
        opc = (ldl_code(env->pc) >> 21) << 4;
150
        if (rw) {
151
            opc |= 0x9;
152
        } else {
153
            opc |= 0x4;
154
        }
155
        env->ipr[IPR_MM_STAT] = opc;
156
    }
157

    
158
    return 1;
159
}
160

    
161
int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
162
{
163
    uint64_t hwpcb;
164
    int ret = 0;
165

    
166
    hwpcb = env->ipr[IPR_PCBB];
167
    switch (iprn) {
168
    case IPR_ASN:
169
        if (env->features & FEATURE_ASN)
170
            *valp = env->ipr[IPR_ASN];
171
        else
172
            *valp = 0;
173
        break;
174
    case IPR_ASTEN:
175
        *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60;
176
        break;
177
    case IPR_ASTSR:
178
        *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60;
179
        break;
180
    case IPR_DATFX:
181
        /* Write only */
182
        ret = -1;
183
        break;
184
    case IPR_ESP:
185
        if (env->features & FEATURE_SPS)
186
            *valp = env->ipr[IPR_ESP];
187
        else
188
            *valp = ldq_raw(hwpcb + 8);
189
        break;
190
    case IPR_FEN:
191
        *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63;
192
        break;
193
    case IPR_IPIR:
194
        /* Write-only */
195
        ret = -1;
196
        break;
197
    case IPR_IPL:
198
        *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
199
        break;
200
    case IPR_KSP:
201
        if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
202
            ret = -1;
203
        } else {
204
            if (env->features & FEATURE_SPS)
205
                *valp = env->ipr[IPR_KSP];
206
            else
207
                *valp = ldq_raw(hwpcb + 0);
208
        }
209
        break;
210
    case IPR_MCES:
211
        *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59;
212
        break;
213
    case IPR_PERFMON:
214
        /* Implementation specific */
215
        *valp = 0;
216
        break;
217
    case IPR_PCBB:
218
        *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16;
219
        break;
220
    case IPR_PRBR:
221
        *valp = env->ipr[IPR_PRBR];
222
        break;
223
    case IPR_PTBR:
224
        *valp = env->ipr[IPR_PTBR];
225
        break;
226
    case IPR_SCBB:
227
        *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]);
228
        break;
229
    case IPR_SIRR:
230
        /* Write-only */
231
        ret = -1;
232
        break;
233
    case IPR_SISR:
234
        *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]);
235
    case IPR_SSP:
236
        if (env->features & FEATURE_SPS)
237
            *valp = env->ipr[IPR_SSP];
238
        else
239
            *valp = ldq_raw(hwpcb + 16);
240
        break;
241
    case IPR_SYSPTBR:
242
        if (env->features & FEATURE_VIRBND)
243
            *valp = env->ipr[IPR_SYSPTBR];
244
        else
245
            ret = -1;
246
        break;
247
    case IPR_TBCHK:
248
        if ((env->features & FEATURE_TBCHK)) {
249
            /* XXX: TODO */
250
            *valp = 0;
251
            ret = -1;
252
        } else {
253
            ret = -1;
254
        }
255
        break;
256
    case IPR_TBIA:
257
        /* Write-only */
258
        ret = -1;
259
        break;
260
    case IPR_TBIAP:
261
        /* Write-only */
262
        ret = -1;
263
        break;
264
    case IPR_TBIS:
265
        /* Write-only */
266
        ret = -1;
267
        break;
268
    case IPR_TBISD:
269
        /* Write-only */
270
        ret = -1;
271
        break;
272
    case IPR_TBISI:
273
        /* Write-only */
274
        ret = -1;
275
        break;
276
    case IPR_USP:
277
        if (env->features & FEATURE_SPS)
278
            *valp = env->ipr[IPR_USP];
279
        else
280
            *valp = ldq_raw(hwpcb + 24);
281
        break;
282
    case IPR_VIRBND:
283
        if (env->features & FEATURE_VIRBND)
284
            *valp = env->ipr[IPR_VIRBND];
285
        else
286
            ret = -1;
287
        break;
288
    case IPR_VPTB:
289
        *valp = env->ipr[IPR_VPTB];
290
        break;
291
    case IPR_WHAMI:
292
        *valp = env->ipr[IPR_WHAMI];
293
        break;
294
    default:
295
        /* Invalid */
296
        ret = -1;
297
        break;
298
    }
299

    
300
    return ret;
301
}
302

    
303
int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
304
{
305
    uint64_t hwpcb, tmp64;
306
    uint8_t tmp8;
307
    int ret = 0;
308

    
309
    hwpcb = env->ipr[IPR_PCBB];
310
    switch (iprn) {
311
    case IPR_ASN:
312
        /* Read-only */
313
        ret = -1;
314
        break;
315
    case IPR_ASTEN:
316
        tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4;
317
        *oldvalp = tmp8;
318
        tmp8 &= val & 0xF;
319
        tmp8 |= (val >> 4) & 0xF;
320
        env->ipr[IPR_ASTEN] &= ~0xF;
321
        env->ipr[IPR_ASTEN] |= tmp8;
322
        ret = 1;
323
        break;
324
    case IPR_ASTSR:
325
        tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4;
326
        *oldvalp = tmp8;
327
        tmp8 &= val & 0xF;
328
        tmp8 |= (val >> 4) & 0xF;
329
        env->ipr[IPR_ASTSR] &= ~0xF;
330
        env->ipr[IPR_ASTSR] |= tmp8;
331
        ret = 1;
332
    case IPR_DATFX:
333
        env->ipr[IPR_DATFX] &= ~0x1;
334
        env->ipr[IPR_DATFX] |= val & 1;
335
        tmp64 = ldq_raw(hwpcb + 56);
336
        tmp64 &= ~0x8000000000000000ULL;
337
        tmp64 |= (val & 1) << 63;
338
        stq_raw(hwpcb + 56, tmp64);
339
        break;
340
    case IPR_ESP:
341
        if (env->features & FEATURE_SPS)
342
            env->ipr[IPR_ESP] = val;
343
        else
344
            stq_raw(hwpcb + 8, val);
345
        break;
346
    case IPR_FEN:
347
        env->ipr[IPR_FEN] = val & 1;
348
        tmp64 = ldq_raw(hwpcb + 56);
349
        tmp64 &= ~1;
350
        tmp64 |= val & 1;
351
        stq_raw(hwpcb + 56, tmp64);
352
        break;
353
    case IPR_IPIR:
354
        /* XXX: TODO: Send IRQ to CPU #ir[16] */
355
        break;
356
    case IPR_IPL:
357
        *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
358
        env->ipr[IPR_IPL] &= ~0x1F;
359
        env->ipr[IPR_IPL] |= val & 0x1F;
360
        /* XXX: may issue an interrupt or ASR _now_ */
361
        ret = 1;
362
        break;
363
    case IPR_KSP:
364
        if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
365
            ret = -1;
366
        } else {
367
            if (env->features & FEATURE_SPS)
368
                env->ipr[IPR_KSP] = val;
369
            else
370
                stq_raw(hwpcb + 0, val);
371
        }
372
        break;
373
    case IPR_MCES:
374
        env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18);
375
        env->ipr[IPR_MCES] |= val & 0x18;
376
        break;
377
    case IPR_PERFMON:
378
        /* Implementation specific */
379
        *oldvalp = 0;
380
        ret = 1;
381
        break;
382
    case IPR_PCBB:
383
        /* Read-only */
384
        ret = -1;
385
        break;
386
    case IPR_PRBR:
387
        env->ipr[IPR_PRBR] = val;
388
        break;
389
    case IPR_PTBR:
390
        /* Read-only */
391
        ret = -1;
392
        break;
393
    case IPR_SCBB:
394
        env->ipr[IPR_SCBB] = (uint32_t)val;
395
        break;
396
    case IPR_SIRR:
397
        if (val & 0xF) {
398
            env->ipr[IPR_SISR] |= 1 << (val & 0xF);
399
            /* XXX: request a software interrupt _now_ */
400
        }
401
        break;
402
    case IPR_SISR:
403
        /* Read-only */
404
        ret = -1;
405
        break;
406
    case IPR_SSP:
407
        if (env->features & FEATURE_SPS)
408
            env->ipr[IPR_SSP] = val;
409
        else
410
            stq_raw(hwpcb + 16, val);
411
        break;
412
    case IPR_SYSPTBR:
413
        if (env->features & FEATURE_VIRBND)
414
            env->ipr[IPR_SYSPTBR] = val;
415
        else
416
            ret = -1;
417
    case IPR_TBCHK:
418
        /* Read-only */
419
        ret = -1;
420
        break;
421
    case IPR_TBIA:
422
        tlb_flush(env, 1);
423
        break;
424
    case IPR_TBIAP:
425
        tlb_flush(env, 1);
426
        break;
427
    case IPR_TBIS:
428
        tlb_flush_page(env, val);
429
        break;
430
    case IPR_TBISD:
431
        tlb_flush_page(env, val);
432
        break;
433
    case IPR_TBISI:
434
        tlb_flush_page(env, val);
435
        break;
436
    case IPR_USP:
437
        if (env->features & FEATURE_SPS)
438
            env->ipr[IPR_USP] = val;
439
        else
440
            stq_raw(hwpcb + 24, val);
441
        break;
442
    case IPR_VIRBND:
443
        if (env->features & FEATURE_VIRBND)
444
            env->ipr[IPR_VIRBND] = val;
445
        else
446
            ret = -1;
447
        break;
448
    case IPR_VPTB:
449
        env->ipr[IPR_VPTB] = val;
450
        break;
451
    case IPR_WHAMI:
452
        /* Read-only */
453
        ret = -1;
454
        break;
455
    default:
456
        /* Invalid */
457
        ret = -1;
458
        break;
459
    }
460

    
461
    return ret;
462
}
463

    
464
void do_interrupt (CPUState *env)
465
{
466
    int excp;
467

    
468
    env->ipr[IPR_EXC_ADDR] = env->pc | 1;
469
    excp = env->exception_index;
470
    env->exception_index = -1;
471
    env->error_code = 0;
472
    /* XXX: disable interrupts and memory mapping */
473
    if (env->ipr[IPR_PAL_BASE] != -1ULL) {
474
        /* We use native PALcode */
475
        env->pc = env->ipr[IPR_PAL_BASE] + excp;
476
    } else {
477
        /* We use emulated PALcode */
478
        call_pal(env);
479
        /* Emulate REI */
480
        env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
481
        env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
482
        /* XXX: re-enable interrupts and memory mapping */
483
    }
484
}
485
#endif
486

    
487
void cpu_dump_state (CPUState *env, FILE *f,
488
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
489
                     int flags)
490
{
491
    static const char *linux_reg_names[] = {
492
        "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
493
        "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
494
        "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
495
        "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
496
    };
497
    int i;
498

    
499
    cpu_fprintf(f, "     PC  " TARGET_FMT_lx "      PS  " TARGET_FMT_lx "\n",
500
                env->pc, env->ps);
501
    for (i = 0; i < 31; i++) {
502
        cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
503
                    linux_reg_names[i], env->ir[i]);
504
        if ((i % 3) == 2)
505
            cpu_fprintf(f, "\n");
506
    }
507
    cpu_fprintf(f, "\n");
508
    for (i = 0; i < 31; i++) {
509
        cpu_fprintf(f, "FIR%02d    " TARGET_FMT_lx " ", i,
510
                    *((uint64_t *)(&env->fir[i])));
511
        if ((i % 3) == 2)
512
            cpu_fprintf(f, "\n");
513
    }
514
    cpu_fprintf(f, "\nlock     " TARGET_FMT_lx "\n", env->lock);
515
}