Statistics
| Branch: | Revision:

root / hw / ppc.c @ dbdd2506

History | View | Annotate | Download (39.6 kB)

1
/*
2
 * QEMU generic PowerPC hardware System Emulator
3
 *
4
 * Copyright (c) 2003-2007 Jocelyn Mayer
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "vl.h"
25
#include "m48t59.h"
26

    
27
//#define PPC_DEBUG_IRQ
28
//#define PPC_DEBUG_TB
29

    
30
extern FILE *logfile;
31
extern int loglevel;
32

    
33
static void cpu_ppc_tb_stop (CPUState *env);
34
static void cpu_ppc_tb_start (CPUState *env);
35

    
36
static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
37
{
38
    if (level) {
39
        env->pending_interrupts |= 1 << n_IRQ;
40
        cpu_interrupt(env, CPU_INTERRUPT_HARD);
41
    } else {
42
        env->pending_interrupts &= ~(1 << n_IRQ);
43
        if (env->pending_interrupts == 0)
44
            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
45
    }
46
#if defined(PPC_DEBUG_IRQ)
47
    if (loglevel & CPU_LOG_INT) {
48
        fprintf(logfile, "%s: %p n_IRQ %d level %d => pending %08x req %08x\n",
49
                __func__, env, n_IRQ, level,
50
                env->pending_interrupts, env->interrupt_request);
51
    }
52
#endif
53
}
54

    
55
/* PowerPC 6xx / 7xx internal IRQ controller */
56
static void ppc6xx_set_irq (void *opaque, int pin, int level)
57
{
58
    CPUState *env = opaque;
59
    int cur_level;
60

    
61
#if defined(PPC_DEBUG_IRQ)
62
    if (loglevel & CPU_LOG_INT) {
63
        fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
64
                env, pin, level);
65
    }
66
#endif
67
    cur_level = (env->irq_input_state >> pin) & 1;
68
    /* Don't generate spurious events */
69
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
70
        switch (pin) {
71
        case PPC6xx_INPUT_TBEN:
72
            /* Level sensitive - active high */
73
#if defined(PPC_DEBUG_IRQ)
74
            if (loglevel & CPU_LOG_INT) {
75
                fprintf(logfile, "%s: %s the time base\n",
76
                        __func__, level ? "start" : "stop");
77
            }
78
#endif
79
            if (level) {
80
                cpu_ppc_tb_start(env);
81
            } else {
82
                cpu_ppc_tb_stop(env);
83
            }
84
        case PPC6xx_INPUT_INT:
85
            /* Level sensitive - active high */
86
#if defined(PPC_DEBUG_IRQ)
87
            if (loglevel & CPU_LOG_INT) {
88
                fprintf(logfile, "%s: set the external IRQ state to %d\n",
89
                        __func__, level);
90
            }
91
#endif
92
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
93
            break;
94
        case PPC6xx_INPUT_SMI:
95
            /* Level sensitive - active high */
96
#if defined(PPC_DEBUG_IRQ)
97
            if (loglevel & CPU_LOG_INT) {
98
                fprintf(logfile, "%s: set the SMI IRQ state to %d\n",
99
                        __func__, level);
100
            }
101
#endif
102
            ppc_set_irq(env, PPC_INTERRUPT_SMI, level);
103
            break;
104
        case PPC6xx_INPUT_MCP:
105
            /* Negative edge sensitive */
106
            /* XXX: TODO: actual reaction may depends on HID0 status
107
             *            603/604/740/750: check HID0[EMCP]
108
             */
109
            if (cur_level == 1 && level == 0) {
110
#if defined(PPC_DEBUG_IRQ)
111
                if (loglevel & CPU_LOG_INT) {
112
                    fprintf(logfile, "%s: raise machine check state\n",
113
                            __func__);
114
                }
115
#endif
116
                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
117
            }
118
            break;
119
        case PPC6xx_INPUT_CKSTP_IN:
120
            /* Level sensitive - active low */
121
            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
122
            /* XXX: Note that the only way to restart the CPU is to reset it */
123
            if (level) {
124
#if defined(PPC_DEBUG_IRQ)
125
                if (loglevel & CPU_LOG_INT) {
126
                    fprintf(logfile, "%s: stop the CPU\n", __func__);
127
                }
128
#endif
129
                env->halted = 1;
130
            }
131
            break;
132
        case PPC6xx_INPUT_HRESET:
133
            /* Level sensitive - active low */
134
            if (level) {
135
#if 0 // XXX: TOFIX
136
#if defined(PPC_DEBUG_IRQ)
137
                if (loglevel & CPU_LOG_INT) {
138
                    fprintf(logfile, "%s: reset the CPU\n", __func__);
139
                }
140
#endif
141
                cpu_reset(env);
142
#endif
143
            }
144
            break;
145
        case PPC6xx_INPUT_SRESET:
146
#if defined(PPC_DEBUG_IRQ)
147
            if (loglevel & CPU_LOG_INT) {
148
                fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
149
                        __func__, level);
150
            }
151
#endif
152
            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
153
            break;
154
        default:
155
            /* Unknown pin - do nothing */
156
#if defined(PPC_DEBUG_IRQ)
157
            if (loglevel & CPU_LOG_INT) {
158
                fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
159
            }
160
#endif
161
            return;
162
        }
163
        if (level)
164
            env->irq_input_state |= 1 << pin;
165
        else
166
            env->irq_input_state &= ~(1 << pin);
167
    }
168
}
169

    
170
void ppc6xx_irq_init (CPUState *env)
171
{
172
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6);
173
}
174

    
175
#if defined(TARGET_PPC64)
176
/* PowerPC 970 internal IRQ controller */
177
static void ppc970_set_irq (void *opaque, int pin, int level)
178
{
179
    CPUState *env = opaque;
180
    int cur_level;
181

    
182
#if defined(PPC_DEBUG_IRQ)
183
    if (loglevel & CPU_LOG_INT) {
184
        fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
185
                env, pin, level);
186
    }
187
#endif
188
    cur_level = (env->irq_input_state >> pin) & 1;
189
    /* Don't generate spurious events */
190
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
191
        switch (pin) {
192
        case PPC970_INPUT_INT:
193
            /* Level sensitive - active high */
194
#if defined(PPC_DEBUG_IRQ)
195
            if (loglevel & CPU_LOG_INT) {
196
                fprintf(logfile, "%s: set the external IRQ state to %d\n",
197
                        __func__, level);
198
            }
199
#endif
200
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
201
            break;
202
        case PPC970_INPUT_THINT:
203
            /* Level sensitive - active high */
204
#if defined(PPC_DEBUG_IRQ)
205
            if (loglevel & CPU_LOG_INT) {
206
                fprintf(logfile, "%s: set the SMI IRQ state to %d\n", __func__,
207
                        level);
208
            }
209
#endif
210
            ppc_set_irq(env, PPC_INTERRUPT_THERM, level);
211
            break;
212
        case PPC970_INPUT_MCP:
213
            /* Negative edge sensitive */
214
            /* XXX: TODO: actual reaction may depends on HID0 status
215
             *            603/604/740/750: check HID0[EMCP]
216
             */
217
            if (cur_level == 1 && level == 0) {
218
#if defined(PPC_DEBUG_IRQ)
219
                if (loglevel & CPU_LOG_INT) {
220
                    fprintf(logfile, "%s: raise machine check state\n",
221
                            __func__);
222
                }
223
#endif
224
                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
225
            }
226
            break;
227
        case PPC970_INPUT_CKSTP:
228
            /* Level sensitive - active low */
229
            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
230
            if (level) {
231
#if defined(PPC_DEBUG_IRQ)
232
                if (loglevel & CPU_LOG_INT) {
233
                    fprintf(logfile, "%s: stop the CPU\n", __func__);
234
                }
235
#endif
236
                env->halted = 1;
237
            } else {
238
#if defined(PPC_DEBUG_IRQ)
239
                if (loglevel & CPU_LOG_INT) {
240
                    fprintf(logfile, "%s: restart the CPU\n", __func__);
241
                }
242
#endif
243
                env->halted = 0;
244
            }
245
            break;
246
        case PPC970_INPUT_HRESET:
247
            /* Level sensitive - active low */
248
            if (level) {
249
#if 0 // XXX: TOFIX
250
#if defined(PPC_DEBUG_IRQ)
251
                if (loglevel & CPU_LOG_INT) {
252
                    fprintf(logfile, "%s: reset the CPU\n", __func__);
253
                }
254
#endif
255
                cpu_reset(env);
256
#endif
257
            }
258
            break;
259
        case PPC970_INPUT_SRESET:
260
#if defined(PPC_DEBUG_IRQ)
261
            if (loglevel & CPU_LOG_INT) {
262
                fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
263
                        __func__, level);
264
            }
265
#endif
266
            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
267
            break;
268
        case PPC970_INPUT_TBEN:
269
#if defined(PPC_DEBUG_IRQ)
270
            if (loglevel & CPU_LOG_INT) {
271
                fprintf(logfile, "%s: set the TBEN state to %d\n", __func__,
272
                        level);
273
            }
274
#endif
275
            /* XXX: TODO */
276
            break;
277
        default:
278
            /* Unknown pin - do nothing */
279
#if defined(PPC_DEBUG_IRQ)
280
            if (loglevel & CPU_LOG_INT) {
281
                fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
282
            }
283
#endif
284
            return;
285
        }
286
        if (level)
287
            env->irq_input_state |= 1 << pin;
288
        else
289
            env->irq_input_state &= ~(1 << pin);
290
    }
291
}
292

    
293
void ppc970_irq_init (CPUState *env)
294
{
295
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, 7);
296
}
297
#endif /* defined(TARGET_PPC64) */
298

    
299
/* PowerPC 40x internal IRQ controller */
300
static void ppc40x_set_irq (void *opaque, int pin, int level)
301
{
302
    CPUState *env = opaque;
303
    int cur_level;
304

    
305
#if defined(PPC_DEBUG_IRQ)
306
    if (loglevel & CPU_LOG_INT) {
307
        fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
308
                env, pin, level);
309
    }
310
#endif
311
    cur_level = (env->irq_input_state >> pin) & 1;
312
    /* Don't generate spurious events */
313
    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
314
        switch (pin) {
315
        case PPC40x_INPUT_RESET_SYS:
316
            if (level) {
317
#if defined(PPC_DEBUG_IRQ)
318
                if (loglevel & CPU_LOG_INT) {
319
                    fprintf(logfile, "%s: reset the PowerPC system\n",
320
                            __func__);
321
                }
322
#endif
323
                ppc40x_system_reset(env);
324
            }
325
            break;
326
        case PPC40x_INPUT_RESET_CHIP:
327
            if (level) {
328
#if defined(PPC_DEBUG_IRQ)
329
                if (loglevel & CPU_LOG_INT) {
330
                    fprintf(logfile, "%s: reset the PowerPC chip\n", __func__);
331
                }
332
#endif
333
                ppc40x_chip_reset(env);
334
            }
335
            break;
336
        case PPC40x_INPUT_RESET_CORE:
337
            /* XXX: TODO: update DBSR[MRR] */
338
            if (level) {
339
#if defined(PPC_DEBUG_IRQ)
340
                if (loglevel & CPU_LOG_INT) {
341
                    fprintf(logfile, "%s: reset the PowerPC core\n", __func__);
342
                }
343
#endif
344
                ppc40x_core_reset(env);
345
            }
346
            break;
347
        case PPC40x_INPUT_CINT:
348
            /* Level sensitive - active high */
349
#if defined(PPC_DEBUG_IRQ)
350
            if (loglevel & CPU_LOG_INT) {
351
                fprintf(logfile, "%s: set the critical IRQ state to %d\n",
352
                        __func__, level);
353
            }
354
#endif
355
            ppc_set_irq(env, PPC_INTERRUPT_CEXT, level);
356
            break;
357
        case PPC40x_INPUT_INT:
358
            /* Level sensitive - active high */
359
#if defined(PPC_DEBUG_IRQ)
360
            if (loglevel & CPU_LOG_INT) {
361
                fprintf(logfile, "%s: set the external IRQ state to %d\n",
362
                        __func__, level);
363
            }
364
#endif
365
            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
366
            break;
367
        case PPC40x_INPUT_HALT:
368
            /* Level sensitive - active low */
369
            if (level) {
370
#if defined(PPC_DEBUG_IRQ)
371
                if (loglevel & CPU_LOG_INT) {
372
                    fprintf(logfile, "%s: stop the CPU\n", __func__);
373
                }
374
#endif
375
                env->halted = 1;
376
            } else {
377
#if defined(PPC_DEBUG_IRQ)
378
                if (loglevel & CPU_LOG_INT) {
379
                    fprintf(logfile, "%s: restart the CPU\n", __func__);
380
                }
381
#endif
382
                env->halted = 0;
383
            }
384
            break;
385
        case PPC40x_INPUT_DEBUG:
386
            /* Level sensitive - active high */
387
#if defined(PPC_DEBUG_IRQ)
388
            if (loglevel & CPU_LOG_INT) {
389
                fprintf(logfile, "%s: set the debug pin state to %d\n",
390
                        __func__, level);
391
            }
392
#endif
393
            ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level);
394
            break;
395
        default:
396
            /* Unknown pin - do nothing */
397
#if defined(PPC_DEBUG_IRQ)
398
            if (loglevel & CPU_LOG_INT) {
399
                fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
400
            }
401
#endif
402
            return;
403
        }
404
        if (level)
405
            env->irq_input_state |= 1 << pin;
406
        else
407
            env->irq_input_state &= ~(1 << pin);
408
    }
409
}
410

    
411
void ppc40x_irq_init (CPUState *env)
412
{
413
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
414
                                                  env, PPC40x_INPUT_NB);
415
}
416

    
417
/*****************************************************************************/
418
/* PowerPC time base and decrementer emulation */
419
struct ppc_tb_t {
420
    /* Time base management */
421
    int64_t  tb_offset;    /* Compensation                    */
422
    int64_t  atb_offset;   /* Compensation                    */
423
    uint32_t tb_freq;      /* TB frequency                    */
424
    /* Decrementer management */
425
    uint64_t decr_next;    /* Tick for next decr interrupt    */
426
    uint32_t decr_freq;    /* decrementer frequency           */
427
    struct QEMUTimer *decr_timer;
428
#if defined(TARGET_PPC64H)
429
    /* Hypervisor decrementer management */
430
    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
431
    struct QEMUTimer *hdecr_timer;
432
    uint64_t purr_load;
433
    uint64_t purr_start;
434
#endif
435
    void *opaque;
436
};
437

    
438
static always_inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, uint64_t vmclk,
439
                                              int64_t tb_offset)
440
{
441
    /* TB time in tb periods */
442
    return muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec) + tb_offset;
443
}
444

    
445
uint32_t cpu_ppc_load_tbl (CPUState *env)
446
{
447
    ppc_tb_t *tb_env = env->tb_env;
448
    uint64_t tb;
449

    
450
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
451
#if defined(PPC_DEBUG_TB)
452
    if (loglevel != 0) {
453
        fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
454
    }
455
#endif
456

    
457
    return tb & 0xFFFFFFFF;
458
}
459

    
460
static always_inline uint32_t _cpu_ppc_load_tbu (CPUState *env)
461
{
462
    ppc_tb_t *tb_env = env->tb_env;
463
    uint64_t tb;
464

    
465
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
466
#if defined(PPC_DEBUG_TB)
467
    if (loglevel != 0) {
468
        fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
469
    }
470
#endif
471

    
472
    return tb >> 32;
473
}
474

    
475
uint32_t cpu_ppc_load_tbu (CPUState *env)
476
{
477
    return _cpu_ppc_load_tbu(env);
478
}
479

    
480
static always_inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t vmclk,
481
                                            int64_t *tb_offsetp,
482
                                            uint64_t value)
483
{
484
    *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec);
485
#ifdef PPC_DEBUG_TB
486
    if (loglevel != 0) {
487
        fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value,
488
                *tb_offsetp);
489
    }
490
#endif
491
}
492

    
493
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
494
{
495
    ppc_tb_t *tb_env = env->tb_env;
496
    uint64_t tb;
497

    
498
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
499
    tb &= 0xFFFFFFFF00000000ULL;
500
    cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
501
                     &tb_env->tb_offset, tb | (uint64_t)value);
502
}
503

    
504
static always_inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value)
505
{
506
    ppc_tb_t *tb_env = env->tb_env;
507
    uint64_t tb;
508

    
509
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);
510
    tb &= 0x00000000FFFFFFFFULL;
511
    cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
512
                     &tb_env->tb_offset, ((uint64_t)value << 32) | tb);
513
}
514

    
515
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
516
{
517
    _cpu_ppc_store_tbu(env, value);
518
}
519

    
520
uint32_t cpu_ppc_load_atbl (CPUState *env)
521
{
522
    ppc_tb_t *tb_env = env->tb_env;
523
    uint64_t tb;
524

    
525
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
526
#if defined(PPC_DEBUG_TB)
527
    if (loglevel != 0) {
528
        fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
529
    }
530
#endif
531

    
532
    return tb & 0xFFFFFFFF;
533
}
534

    
535
uint32_t cpu_ppc_load_atbu (CPUState *env)
536
{
537
    ppc_tb_t *tb_env = env->tb_env;
538
    uint64_t tb;
539

    
540
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
541
#if defined(PPC_DEBUG_TB)
542
    if (loglevel != 0) {
543
        fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
544
    }
545
#endif
546

    
547
    return tb >> 32;
548
}
549

    
550
void cpu_ppc_store_atbl (CPUState *env, uint32_t value)
551
{
552
    ppc_tb_t *tb_env = env->tb_env;
553
    uint64_t tb;
554

    
555
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
556
    tb &= 0xFFFFFFFF00000000ULL;
557
    cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
558
                     &tb_env->atb_offset, tb | (uint64_t)value);
559
}
560

    
561
void cpu_ppc_store_atbu (CPUState *env, uint32_t value)
562
{
563
    ppc_tb_t *tb_env = env->tb_env;
564
    uint64_t tb;
565

    
566
    tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset);
567
    tb &= 0x00000000FFFFFFFFULL;
568
    cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock),
569
                     &tb_env->atb_offset, ((uint64_t)value << 32) | tb);
570
}
571

    
572
static void cpu_ppc_tb_stop (CPUState *env)
573
{
574
    ppc_tb_t *tb_env = env->tb_env;
575
    uint64_t tb, atb, vmclk;
576

    
577
    /* If the time base is already frozen, do nothing */
578
    if (tb_env->tb_freq != 0) {
579
        vmclk = qemu_get_clock(vm_clock);
580
        /* Get the time base */
581
        tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
582
        /* Get the alternate time base */
583
        atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset);
584
        /* Store the time base value (ie compute the current offset) */
585
        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
586
        /* Store the alternate time base value (compute the current offset) */
587
        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
588
        /* Set the time base frequency to zero */
589
        tb_env->tb_freq = 0;
590
        /* Now, the time bases are frozen to tb_offset / atb_offset value */
591
    }
592
}
593

    
594
static void cpu_ppc_tb_start (CPUState *env)
595
{
596
    ppc_tb_t *tb_env = env->tb_env;
597
    uint64_t tb, atb, vmclk;
598
    
599
    /* If the time base is not frozen, do nothing */
600
    if (tb_env->tb_freq == 0) {
601
        vmclk = qemu_get_clock(vm_clock);
602
        /* Get the time base from tb_offset */
603
        tb = tb_env->tb_offset;
604
        /* Get the alternate time base from atb_offset */
605
        atb = tb_env->atb_offset;
606
        /* Restore the tb frequency from the decrementer frequency */
607
        tb_env->tb_freq = tb_env->decr_freq;
608
        /* Store the time base value */
609
        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb);
610
        /* Store the alternate time base value */
611
        cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb);
612
    }
613
}
614

    
615
static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env,
616
                                                  uint64_t *next)
617
{
618
    ppc_tb_t *tb_env = env->tb_env;
619
    uint32_t decr;
620
    int64_t diff;
621

    
622
    diff = tb_env->decr_next - qemu_get_clock(vm_clock);
623
    if (diff >= 0)
624
        decr = muldiv64(diff, tb_env->decr_freq, ticks_per_sec);
625
    else
626
        decr = -muldiv64(-diff, tb_env->decr_freq, ticks_per_sec);
627
#if defined(PPC_DEBUG_TB)
628
    if (loglevel != 0) {
629
        fprintf(logfile, "%s: 0x%08x\n", __func__, decr);
630
    }
631
#endif
632

    
633
    return decr;
634
}
635

    
636
uint32_t cpu_ppc_load_decr (CPUState *env)
637
{
638
    ppc_tb_t *tb_env = env->tb_env;
639

    
640
    return _cpu_ppc_load_decr(env, &tb_env->decr_next);
641
}
642

    
643
#if defined(TARGET_PPC64H)
644
uint32_t cpu_ppc_load_hdecr (CPUState *env)
645
{
646
    ppc_tb_t *tb_env = env->tb_env;
647

    
648
    return _cpu_ppc_load_decr(env, &tb_env->hdecr_next);
649
}
650

    
651
uint64_t cpu_ppc_load_purr (CPUState *env)
652
{
653
    ppc_tb_t *tb_env = env->tb_env;
654
    uint64_t diff;
655

    
656
    diff = qemu_get_clock(vm_clock) - tb_env->purr_start;
657

    
658
    return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
659
}
660
#endif /* defined(TARGET_PPC64H) */
661

    
662
/* When decrementer expires,
663
 * all we need to do is generate or queue a CPU exception
664
 */
665
static always_inline void cpu_ppc_decr_excp (CPUState *env)
666
{
667
    /* Raise it */
668
#ifdef PPC_DEBUG_TB
669
    if (loglevel != 0) {
670
        fprintf(logfile, "raise decrementer exception\n");
671
    }
672
#endif
673
    ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
674
}
675

    
676
static always_inline void cpu_ppc_hdecr_excp (CPUState *env)
677
{
678
    /* Raise it */
679
#ifdef PPC_DEBUG_TB
680
    if (loglevel != 0) {
681
        fprintf(logfile, "raise decrementer exception\n");
682
    }
683
#endif
684
    ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1);
685
}
686

    
687
static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp,
688
                                  struct QEMUTimer *timer,
689
                                  void (*raise_excp)(CPUState *),
690
                                  uint32_t decr, uint32_t value,
691
                                  int is_excp)
692
{
693
    ppc_tb_t *tb_env = env->tb_env;
694
    uint64_t now, next;
695

    
696
#ifdef PPC_DEBUG_TB
697
    if (loglevel != 0) {
698
        fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value);
699
    }
700
#endif
701
    now = qemu_get_clock(vm_clock);
702
    next = now + muldiv64(value, ticks_per_sec, tb_env->decr_freq);
703
    if (is_excp)
704
        next += *nextp - now;
705
    if (next == now)
706
        next++;
707
    *nextp = next;
708
    /* Adjust timer */
709
    qemu_mod_timer(timer, next);
710
    /* If we set a negative value and the decrementer was positive,
711
     * raise an exception.
712
     */
713
    if ((value & 0x80000000) && !(decr & 0x80000000))
714
        (*raise_excp)(env);
715
}
716

    
717
static always_inline void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
718
                                               uint32_t value, int is_excp)
719
{
720
    ppc_tb_t *tb_env = env->tb_env;
721

    
722
    __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer,
723
                         &cpu_ppc_decr_excp, decr, value, is_excp);
724
}
725

    
726
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
727
{
728
    _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
729
}
730

    
731
static void cpu_ppc_decr_cb (void *opaque)
732
{
733
    _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
734
}
735

    
736
#if defined(TARGET_PPC64H)
737
static always_inline void _cpu_ppc_store_hdecr (CPUState *env, uint32_t hdecr,
738
                                                uint32_t value, int is_excp)
739
{
740
    ppc_tb_t *tb_env = env->tb_env;
741

    
742
    __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer,
743
                         &cpu_ppc_hdecr_excp, hdecr, value, is_excp);
744
}
745

    
746
void cpu_ppc_store_hdecr (CPUState *env, uint32_t value)
747
{
748
    _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0);
749
}
750

    
751
static void cpu_ppc_hdecr_cb (void *opaque)
752
{
753
    _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1);
754
}
755

    
756
void cpu_ppc_store_purr (CPUState *env, uint64_t value)
757
{
758
    ppc_tb_t *tb_env = env->tb_env;
759

    
760
    tb_env->purr_load = value;
761
    tb_env->purr_start = qemu_get_clock(vm_clock);
762
}
763
#endif /* defined(TARGET_PPC64H) */
764

    
765
static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
766
{
767
    CPUState *env = opaque;
768
    ppc_tb_t *tb_env = env->tb_env;
769

    
770
    tb_env->tb_freq = freq;
771
    tb_env->decr_freq = freq;
772
    /* There is a bug in Linux 2.4 kernels:
773
     * if a decrementer exception is pending when it enables msr_ee at startup,
774
     * it's not ready to handle it...
775
     */
776
    _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
777
#if defined(TARGET_PPC64H)
778
    _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
779
    cpu_ppc_store_purr(env, 0x0000000000000000ULL);
780
#endif /* defined(TARGET_PPC64H) */
781
}
782

    
783
/* Set up (once) timebase frequency (in Hz) */
784
clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
785
{
786
    ppc_tb_t *tb_env;
787

    
788
    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
789
    if (tb_env == NULL)
790
        return NULL;
791
    env->tb_env = tb_env;
792
    /* Create new timer */
793
    tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
794
#if defined(TARGET_PPC64H)
795
    tb_env->hdecr_timer = qemu_new_timer(vm_clock, &cpu_ppc_hdecr_cb, env);
796
#endif /* defined(TARGET_PPC64H) */
797
    cpu_ppc_set_tb_clk(env, freq);
798

    
799
    return &cpu_ppc_set_tb_clk;
800
}
801

    
802
/* Specific helpers for POWER & PowerPC 601 RTC */
803
clk_setup_cb cpu_ppc601_rtc_init (CPUState *env)
804
{
805
    return cpu_ppc_tb_init(env, 7812500);
806
}
807

    
808
void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
809
{
810
    _cpu_ppc_store_tbu(env, value);
811
}
812

    
813
uint32_t cpu_ppc601_load_rtcu (CPUState *env)
814
{
815
    return _cpu_ppc_load_tbu(env);
816
}
817

    
818
void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
819
{
820
    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
821
}
822

    
823
uint32_t cpu_ppc601_load_rtcl (CPUState *env)
824
{
825
    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
826
}
827

    
828
/*****************************************************************************/
829
/* Embedded PowerPC timers */
830

    
831
/* PIT, FIT & WDT */
832
typedef struct ppcemb_timer_t ppcemb_timer_t;
833
struct ppcemb_timer_t {
834
    uint64_t pit_reload;  /* PIT auto-reload value        */
835
    uint64_t fit_next;    /* Tick for next FIT interrupt  */
836
    struct QEMUTimer *fit_timer;
837
    uint64_t wdt_next;    /* Tick for next WDT interrupt  */
838
    struct QEMUTimer *wdt_timer;
839
};
840

    
841
/* Fixed interval timer */
842
static void cpu_4xx_fit_cb (void *opaque)
843
{
844
    CPUState *env;
845
    ppc_tb_t *tb_env;
846
    ppcemb_timer_t *ppcemb_timer;
847
    uint64_t now, next;
848

    
849
    env = opaque;
850
    tb_env = env->tb_env;
851
    ppcemb_timer = tb_env->opaque;
852
    now = qemu_get_clock(vm_clock);
853
    switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
854
    case 0:
855
        next = 1 << 9;
856
        break;
857
    case 1:
858
        next = 1 << 13;
859
        break;
860
    case 2:
861
        next = 1 << 17;
862
        break;
863
    case 3:
864
        next = 1 << 21;
865
        break;
866
    default:
867
        /* Cannot occur, but makes gcc happy */
868
        return;
869
    }
870
    next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
871
    if (next == now)
872
        next++;
873
    qemu_mod_timer(ppcemb_timer->fit_timer, next);
874
    env->spr[SPR_40x_TSR] |= 1 << 26;
875
    if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
876
        ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
877
#ifdef PPC_DEBUG_TB
878
    if (loglevel != 0) {
879
        fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__,
880
                (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
881
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
882
    }
883
#endif
884
}
885

    
886
/* Programmable interval timer */
887
static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
888
{
889
    ppcemb_timer_t *ppcemb_timer;
890
    uint64_t now, next;
891

    
892
    ppcemb_timer = tb_env->opaque;
893
    if (ppcemb_timer->pit_reload <= 1 ||
894
        !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
895
        (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
896
        /* Stop PIT */
897
#ifdef PPC_DEBUG_TB
898
        if (loglevel != 0) {
899
            fprintf(logfile, "%s: stop PIT\n", __func__);
900
        }
901
#endif
902
        qemu_del_timer(tb_env->decr_timer);
903
    } else {
904
#ifdef PPC_DEBUG_TB
905
        if (loglevel != 0) {
906
            fprintf(logfile, "%s: start PIT 0x" REGX "\n",
907
                    __func__, ppcemb_timer->pit_reload);
908
        }
909
#endif
910
        now = qemu_get_clock(vm_clock);
911
        next = now + muldiv64(ppcemb_timer->pit_reload,
912
                              ticks_per_sec, tb_env->decr_freq);
913
        if (is_excp)
914
            next += tb_env->decr_next - now;
915
        if (next == now)
916
            next++;
917
        qemu_mod_timer(tb_env->decr_timer, next);
918
        tb_env->decr_next = next;
919
    }
920
}
921

    
922
static void cpu_4xx_pit_cb (void *opaque)
923
{
924
    CPUState *env;
925
    ppc_tb_t *tb_env;
926
    ppcemb_timer_t *ppcemb_timer;
927

    
928
    env = opaque;
929
    tb_env = env->tb_env;
930
    ppcemb_timer = tb_env->opaque;
931
    env->spr[SPR_40x_TSR] |= 1 << 27;
932
    if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
933
        ppc_set_irq(env, PPC_INTERRUPT_PIT, 1);
934
    start_stop_pit(env, tb_env, 1);
935
#ifdef PPC_DEBUG_TB
936
    if (loglevel != 0) {
937
        fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " "
938
                "%016" PRIx64 "\n", __func__,
939
                (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
940
                (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
941
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
942
                ppcemb_timer->pit_reload);
943
    }
944
#endif
945
}
946

    
947
/* Watchdog timer */
948
static void cpu_4xx_wdt_cb (void *opaque)
949
{
950
    CPUState *env;
951
    ppc_tb_t *tb_env;
952
    ppcemb_timer_t *ppcemb_timer;
953
    uint64_t now, next;
954

    
955
    env = opaque;
956
    tb_env = env->tb_env;
957
    ppcemb_timer = tb_env->opaque;
958
    now = qemu_get_clock(vm_clock);
959
    switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
960
    case 0:
961
        next = 1 << 17;
962
        break;
963
    case 1:
964
        next = 1 << 21;
965
        break;
966
    case 2:
967
        next = 1 << 25;
968
        break;
969
    case 3:
970
        next = 1 << 29;
971
        break;
972
    default:
973
        /* Cannot occur, but makes gcc happy */
974
        return;
975
    }
976
    next = now + muldiv64(next, ticks_per_sec, tb_env->decr_freq);
977
    if (next == now)
978
        next++;
979
#ifdef PPC_DEBUG_TB
980
    if (loglevel != 0) {
981
        fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__,
982
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
983
    }
984
#endif
985
    switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
986
    case 0x0:
987
    case 0x1:
988
        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
989
        ppcemb_timer->wdt_next = next;
990
        env->spr[SPR_40x_TSR] |= 1 << 31;
991
        break;
992
    case 0x2:
993
        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
994
        ppcemb_timer->wdt_next = next;
995
        env->spr[SPR_40x_TSR] |= 1 << 30;
996
        if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
997
            ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
998
        break;
999
    case 0x3:
1000
        env->spr[SPR_40x_TSR] &= ~0x30000000;
1001
        env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
1002
        switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
1003
        case 0x0:
1004
            /* No reset */
1005
            break;
1006
        case 0x1: /* Core reset */
1007
            ppc40x_core_reset(env);
1008
            break;
1009
        case 0x2: /* Chip reset */
1010
            ppc40x_chip_reset(env);
1011
            break;
1012
        case 0x3: /* System reset */
1013
            ppc40x_system_reset(env);
1014
            break;
1015
        }
1016
    }
1017
}
1018

    
1019
void store_40x_pit (CPUState *env, target_ulong val)
1020
{
1021
    ppc_tb_t *tb_env;
1022
    ppcemb_timer_t *ppcemb_timer;
1023

    
1024
    tb_env = env->tb_env;
1025
    ppcemb_timer = tb_env->opaque;
1026
#ifdef PPC_DEBUG_TB
1027
    if (loglevel != 0) {
1028
        fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer);
1029
    }
1030
#endif
1031
    ppcemb_timer->pit_reload = val;
1032
    start_stop_pit(env, tb_env, 0);
1033
}
1034

    
1035
target_ulong load_40x_pit (CPUState *env)
1036
{
1037
    return cpu_ppc_load_decr(env);
1038
}
1039

    
1040
void store_booke_tsr (CPUState *env, target_ulong val)
1041
{
1042
#ifdef PPC_DEBUG_TB
1043
    if (loglevel != 0) {
1044
        fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
1045
    }
1046
#endif
1047
    env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
1048
    if (val & 0x80000000)
1049
        ppc_set_irq(env, PPC_INTERRUPT_PIT, 0);
1050
}
1051

    
1052
void store_booke_tcr (CPUState *env, target_ulong val)
1053
{
1054
    ppc_tb_t *tb_env;
1055

    
1056
    tb_env = env->tb_env;
1057
#ifdef PPC_DEBUG_TB
1058
    if (loglevel != 0) {
1059
        fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
1060
    }
1061
#endif
1062
    env->spr[SPR_40x_TCR] = val & 0xFFC00000;
1063
    start_stop_pit(env, tb_env, 1);
1064
    cpu_4xx_wdt_cb(env);
1065
}
1066

    
1067
static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
1068
{
1069
    CPUState *env = opaque;
1070
    ppc_tb_t *tb_env = env->tb_env;
1071

    
1072
#ifdef PPC_DEBUG_TB
1073
    if (loglevel != 0) {
1074
        fprintf(logfile, "%s set new frequency to %u\n", __func__, freq);
1075
    }
1076
#endif
1077
    tb_env->tb_freq = freq;
1078
    tb_env->decr_freq = freq;
1079
    /* XXX: we should also update all timers */
1080
}
1081

    
1082
clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
1083
{
1084
    ppc_tb_t *tb_env;
1085
    ppcemb_timer_t *ppcemb_timer;
1086

    
1087
    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
1088
    if (tb_env == NULL) {
1089
        return NULL;
1090
    }
1091
    env->tb_env = tb_env;
1092
    ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
1093
    tb_env->tb_freq = freq;
1094
    tb_env->decr_freq = freq;
1095
    tb_env->opaque = ppcemb_timer;
1096
#ifdef PPC_DEBUG_TB
1097
    if (loglevel != 0) {
1098
        fprintf(logfile, "%s %p %p %p\n", __func__, tb_env, ppcemb_timer,
1099
                &ppc_emb_set_tb_clk);
1100
    }
1101
#endif
1102
    if (ppcemb_timer != NULL) {
1103
        /* We use decr timer for PIT */
1104
        tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env);
1105
        ppcemb_timer->fit_timer =
1106
            qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
1107
        ppcemb_timer->wdt_timer =
1108
            qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
1109
    }
1110

    
1111
    return &ppc_emb_set_tb_clk;
1112
}
1113

    
1114
/*****************************************************************************/
1115
/* Embedded PowerPC Device Control Registers */
1116
typedef struct ppc_dcrn_t ppc_dcrn_t;
1117
struct ppc_dcrn_t {
1118
    dcr_read_cb dcr_read;
1119
    dcr_write_cb dcr_write;
1120
    void *opaque;
1121
};
1122

    
1123
/* XXX: on 460, DCR addresses are 32 bits wide,
1124
 *      using DCRIPR to get the 22 upper bits of the DCR address
1125
 */
1126
#define DCRN_NB 1024
1127
struct ppc_dcr_t {
1128
    ppc_dcrn_t dcrn[DCRN_NB];
1129
    int (*read_error)(int dcrn);
1130
    int (*write_error)(int dcrn);
1131
};
1132

    
1133
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
1134
{
1135
    ppc_dcrn_t *dcr;
1136

    
1137
    if (dcrn < 0 || dcrn >= DCRN_NB)
1138
        goto error;
1139
    dcr = &dcr_env->dcrn[dcrn];
1140
    if (dcr->dcr_read == NULL)
1141
        goto error;
1142
    *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
1143

    
1144
    return 0;
1145

    
1146
 error:
1147
    if (dcr_env->read_error != NULL)
1148
        return (*dcr_env->read_error)(dcrn);
1149

    
1150
    return -1;
1151
}
1152

    
1153
int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
1154
{
1155
    ppc_dcrn_t *dcr;
1156

    
1157
    if (dcrn < 0 || dcrn >= DCRN_NB)
1158
        goto error;
1159
    dcr = &dcr_env->dcrn[dcrn];
1160
    if (dcr->dcr_write == NULL)
1161
        goto error;
1162
    (*dcr->dcr_write)(dcr->opaque, dcrn, val);
1163

    
1164
    return 0;
1165

    
1166
 error:
1167
    if (dcr_env->write_error != NULL)
1168
        return (*dcr_env->write_error)(dcrn);
1169

    
1170
    return -1;
1171
}
1172

    
1173
int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
1174
                      dcr_read_cb dcr_read, dcr_write_cb dcr_write)
1175
{
1176
    ppc_dcr_t *dcr_env;
1177
    ppc_dcrn_t *dcr;
1178

    
1179
    dcr_env = env->dcr_env;
1180
    if (dcr_env == NULL)
1181
        return -1;
1182
    if (dcrn < 0 || dcrn >= DCRN_NB)
1183
        return -1;
1184
    dcr = &dcr_env->dcrn[dcrn];
1185
    if (dcr->opaque != NULL ||
1186
        dcr->dcr_read != NULL ||
1187
        dcr->dcr_write != NULL)
1188
        return -1;
1189
    dcr->opaque = opaque;
1190
    dcr->dcr_read = dcr_read;
1191
    dcr->dcr_write = dcr_write;
1192

    
1193
    return 0;
1194
}
1195

    
1196
int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn),
1197
                  int (*write_error)(int dcrn))
1198
{
1199
    ppc_dcr_t *dcr_env;
1200

    
1201
    dcr_env = qemu_mallocz(sizeof(ppc_dcr_t));
1202
    if (dcr_env == NULL)
1203
        return -1;
1204
    dcr_env->read_error = read_error;
1205
    dcr_env->write_error = write_error;
1206
    env->dcr_env = dcr_env;
1207

    
1208
    return 0;
1209
}
1210

    
1211
#if 0
1212
/*****************************************************************************/
1213
/* Handle system reset (for now, just stop emulation) */
1214
void cpu_ppc_reset (CPUState *env)
1215
{
1216
    printf("Reset asked... Stop emulation\n");
1217
    abort();
1218
}
1219
#endif
1220

    
1221
/*****************************************************************************/
1222
/* Debug port */
1223
void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
1224
{
1225
    addr &= 0xF;
1226
    switch (addr) {
1227
    case 0:
1228
        printf("%c", val);
1229
        break;
1230
    case 1:
1231
        printf("\n");
1232
        fflush(stdout);
1233
        break;
1234
    case 2:
1235
        printf("Set loglevel to %04x\n", val);
1236
        cpu_set_log(val | 0x100);
1237
        break;
1238
    }
1239
}
1240

    
1241
/*****************************************************************************/
1242
/* NVRAM helpers */
1243
void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
1244
{
1245
    m48t59_write(nvram, addr, value);
1246
}
1247

    
1248
uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
1249
{
1250
    return m48t59_read(nvram, addr);
1251
}
1252

    
1253
void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
1254
{
1255
    m48t59_write(nvram, addr, value >> 8);
1256
    m48t59_write(nvram, addr + 1, value & 0xFF);
1257
}
1258

    
1259
uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
1260
{
1261
    uint16_t tmp;
1262

    
1263
    tmp = m48t59_read(nvram, addr) << 8;
1264
    tmp |= m48t59_read(nvram, addr + 1);
1265
    return tmp;
1266
}
1267

    
1268
void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
1269
{
1270
    m48t59_write(nvram, addr, value >> 24);
1271
    m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
1272
    m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
1273
    m48t59_write(nvram, addr + 3, value & 0xFF);
1274
}
1275

    
1276
uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
1277
{
1278
    uint32_t tmp;
1279

    
1280
    tmp = m48t59_read(nvram, addr) << 24;
1281
    tmp |= m48t59_read(nvram, addr + 1) << 16;
1282
    tmp |= m48t59_read(nvram, addr + 2) << 8;
1283
    tmp |= m48t59_read(nvram, addr + 3);
1284

    
1285
    return tmp;
1286
}
1287

    
1288
void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
1289
                       const unsigned char *str, uint32_t max)
1290
{
1291
    int i;
1292

    
1293
    for (i = 0; i < max && str[i] != '\0'; i++) {
1294
        m48t59_write(nvram, addr + i, str[i]);
1295
    }
1296
    m48t59_write(nvram, addr + max - 1, '\0');
1297
}
1298

    
1299
int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
1300
{
1301
    int i;
1302

    
1303
    memset(dst, 0, max);
1304
    for (i = 0; i < max; i++) {
1305
        dst[i] = NVRAM_get_byte(nvram, addr + i);
1306
        if (dst[i] == '\0')
1307
            break;
1308
    }
1309

    
1310
    return i;
1311
}
1312

    
1313
static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
1314
{
1315
    uint16_t tmp;
1316
    uint16_t pd, pd1, pd2;
1317

    
1318
    tmp = prev >> 8;
1319
    pd = prev ^ value;
1320
    pd1 = pd & 0x000F;
1321
    pd2 = ((pd >> 4) & 0x000F) ^ pd1;
1322
    tmp ^= (pd1 << 3) | (pd1 << 8);
1323
    tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
1324

    
1325
    return tmp;
1326
}
1327

    
1328
uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
1329
{
1330
    uint32_t i;
1331
    uint16_t crc = 0xFFFF;
1332
    int odd;
1333

    
1334
    odd = count & 1;
1335
    count &= ~1;
1336
    for (i = 0; i != count; i++) {
1337
        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
1338
    }
1339
    if (odd) {
1340
        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
1341
    }
1342

    
1343
    return crc;
1344
}
1345

    
1346
#define CMDLINE_ADDR 0x017ff000
1347

    
1348
int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
1349
                          const unsigned char *arch,
1350
                          uint32_t RAM_size, int boot_device,
1351
                          uint32_t kernel_image, uint32_t kernel_size,
1352
                          const char *cmdline,
1353
                          uint32_t initrd_image, uint32_t initrd_size,
1354
                          uint32_t NVRAM_image,
1355
                          int width, int height, int depth)
1356
{
1357
    uint16_t crc;
1358

    
1359
    /* Set parameters for Open Hack'Ware BIOS */
1360
    NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
1361
    NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
1362
    NVRAM_set_word(nvram,   0x14, NVRAM_size);
1363
    NVRAM_set_string(nvram, 0x20, arch, 16);
1364
    NVRAM_set_lword(nvram,  0x30, RAM_size);
1365
    NVRAM_set_byte(nvram,   0x34, boot_device);
1366
    NVRAM_set_lword(nvram,  0x38, kernel_image);
1367
    NVRAM_set_lword(nvram,  0x3C, kernel_size);
1368
    if (cmdline) {
1369
        /* XXX: put the cmdline in NVRAM too ? */
1370
        strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
1371
        NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
1372
        NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
1373
    } else {
1374
        NVRAM_set_lword(nvram,  0x40, 0);
1375
        NVRAM_set_lword(nvram,  0x44, 0);
1376
    }
1377
    NVRAM_set_lword(nvram,  0x48, initrd_image);
1378
    NVRAM_set_lword(nvram,  0x4C, initrd_size);
1379
    NVRAM_set_lword(nvram,  0x50, NVRAM_image);
1380

    
1381
    NVRAM_set_word(nvram,   0x54, width);
1382
    NVRAM_set_word(nvram,   0x56, height);
1383
    NVRAM_set_word(nvram,   0x58, depth);
1384
    crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
1385
    NVRAM_set_word(nvram,  0xFC, crc);
1386

    
1387
    return 0;
1388
}