Statistics
| Branch: | Revision:

root / hw / ppc.c @ a750fc0b

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

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

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

    
160
void ppc6xx_irq_init (CPUState *env)
161
{
162
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6);
163
}
164

    
165
/* PowerPC 970 internal IRQ controller */
166
static void ppc970_set_irq (void *opaque, int pin, int level)
167
{
168
    CPUState *env = opaque;
169
    int cur_level;
170

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

    
282
void ppc970_irq_init (CPUState *env)
283
{
284
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, 7);
285
}
286

    
287
/* PowerPC 405 internal IRQ controller */
288
static void ppc405_set_irq (void *opaque, int pin, int level)
289
{
290
    CPUState *env = opaque;
291
    int cur_level;
292

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

    
401
void ppc405_irq_init (CPUState *env)
402
{
403
    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc405_set_irq, env, 7);
404
}
405

    
406
/*****************************************************************************/
407
/* PowerPC time base and decrementer emulation */
408
struct ppc_tb_t {
409
    /* Time base management */
410
    int64_t  tb_offset;    /* Compensation               */
411
    uint32_t tb_freq;      /* TB frequency               */
412
    /* Decrementer management */
413
    uint64_t decr_next;    /* Tick for next decr interrupt  */
414
    struct QEMUTimer *decr_timer;
415
    void *opaque;
416
};
417

    
418
static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
419
{
420
    /* TB time in tb periods */
421
    return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
422
                    tb_env->tb_freq, ticks_per_sec);
423
}
424

    
425
uint32_t cpu_ppc_load_tbl (CPUState *env)
426
{
427
    ppc_tb_t *tb_env = env->tb_env;
428
    uint64_t tb;
429

    
430
    tb = cpu_ppc_get_tb(tb_env);
431
#ifdef PPC_DEBUG_TB
432
    {
433
        static int last_time;
434
        int now;
435
        now = time(NULL);
436
        if (last_time != now) {
437
            last_time = now;
438
            if (loglevel != 0) {
439
                fprintf(logfile, "%s: tb=0x%016lx %d %08lx\n",
440
                        __func__, tb, now, tb_env->tb_offset);
441
            }
442
        }
443
    }
444
#endif
445

    
446
    return tb & 0xFFFFFFFF;
447
}
448

    
449
uint32_t cpu_ppc_load_tbu (CPUState *env)
450
{
451
    ppc_tb_t *tb_env = env->tb_env;
452
    uint64_t tb;
453

    
454
    tb = cpu_ppc_get_tb(tb_env);
455
#if defined(PPC_DEBUG_TB)
456
    if (loglevel != 0) {
457
        fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
458
    }
459
#endif
460

    
461
    return tb >> 32;
462
}
463

    
464
static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value)
465
{
466
    tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
467
        - qemu_get_clock(vm_clock);
468
#ifdef PPC_DEBUG_TB
469
    if (loglevel != 0) {
470
        fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value,
471
                tb_env->tb_offset);
472
    }
473
#endif
474
}
475

    
476
void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
477
{
478
    ppc_tb_t *tb_env = env->tb_env;
479

    
480
    cpu_ppc_store_tb(tb_env,
481
                     ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
482
}
483

    
484
void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
485
{
486
    ppc_tb_t *tb_env = env->tb_env;
487

    
488
    cpu_ppc_store_tb(tb_env,
489
                     ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value);
490
}
491

    
492
uint32_t cpu_ppc_load_decr (CPUState *env)
493
{
494
    ppc_tb_t *tb_env = env->tb_env;
495
    uint32_t decr;
496
    int64_t diff;
497

    
498
    diff = tb_env->decr_next - qemu_get_clock(vm_clock);
499
    if (diff >= 0)
500
        decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
501
    else
502
        decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec);
503
#if defined(PPC_DEBUG_TB)
504
    if (loglevel != 0) {
505
        fprintf(logfile, "%s: 0x%08x\n", __func__, decr);
506
    }
507
#endif
508

    
509
    return decr;
510
}
511

    
512
/* When decrementer expires,
513
 * all we need to do is generate or queue a CPU exception
514
 */
515
static inline void cpu_ppc_decr_excp (CPUState *env)
516
{
517
    /* Raise it */
518
#ifdef PPC_DEBUG_TB
519
    if (loglevel != 0) {
520
        fprintf(logfile, "raise decrementer exception\n");
521
    }
522
#endif
523
    ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
524
}
525

    
526
static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
527
                                 uint32_t value, int is_excp)
528
{
529
    ppc_tb_t *tb_env = env->tb_env;
530
    uint64_t now, next;
531

    
532
#ifdef PPC_DEBUG_TB
533
    if (loglevel != 0) {
534
        fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value);
535
    }
536
#endif
537
    now = qemu_get_clock(vm_clock);
538
    next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq);
539
    if (is_excp)
540
        next += tb_env->decr_next - now;
541
    if (next == now)
542
        next++;
543
    tb_env->decr_next = next;
544
    /* Adjust timer */
545
    qemu_mod_timer(tb_env->decr_timer, next);
546
    /* If we set a negative value and the decrementer was positive,
547
     * raise an exception.
548
     */
549
    if ((value & 0x80000000) && !(decr & 0x80000000))
550
        cpu_ppc_decr_excp(env);
551
}
552

    
553
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
554
{
555
    _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
556
}
557

    
558
static void cpu_ppc_decr_cb (void *opaque)
559
{
560
    _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
561
}
562

    
563
static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
564
{
565
    CPUState *env = opaque;
566
    ppc_tb_t *tb_env = env->tb_env;
567

    
568
    tb_env->tb_freq = freq;
569
    /* There is a bug in Linux 2.4 kernels:
570
     * if a decrementer exception is pending when it enables msr_ee at startup,
571
     * it's not ready to handle it...
572
     */
573
    _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
574
}
575

    
576
/* Set up (once) timebase frequency (in Hz) */
577
clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
578
{
579
    ppc_tb_t *tb_env;
580

    
581
    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
582
    if (tb_env == NULL)
583
        return NULL;
584
    env->tb_env = tb_env;
585
    /* Create new timer */
586
    tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
587
    cpu_ppc_set_tb_clk(env, freq);
588

    
589
    return &cpu_ppc_set_tb_clk;
590
}
591

    
592
/* Specific helpers for POWER & PowerPC 601 RTC */
593
clk_setup_cb cpu_ppc601_rtc_init (CPUState *env)
594
{
595
    return cpu_ppc_tb_init(env, 7812500);
596
}
597

    
598
void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
599
__attribute__ (( alias ("cpu_ppc_store_tbu") ));
600

    
601
uint32_t cpu_ppc601_load_rtcu (CPUState *env)
602
__attribute__ (( alias ("cpu_ppc_load_tbu") ));
603

    
604
void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
605
{
606
    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
607
}
608

    
609
uint32_t cpu_ppc601_load_rtcl (CPUState *env)
610
{
611
    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
612
}
613

    
614
/*****************************************************************************/
615
/* Embedded PowerPC timers */
616

    
617
/* PIT, FIT & WDT */
618
typedef struct ppcemb_timer_t ppcemb_timer_t;
619
struct ppcemb_timer_t {
620
    uint64_t pit_reload;  /* PIT auto-reload value        */
621
    uint64_t fit_next;    /* Tick for next FIT interrupt  */
622
    struct QEMUTimer *fit_timer;
623
    uint64_t wdt_next;    /* Tick for next WDT interrupt  */
624
    struct QEMUTimer *wdt_timer;
625
};
626

    
627
/* Fixed interval timer */
628
static void cpu_4xx_fit_cb (void *opaque)
629
{
630
    CPUState *env;
631
    ppc_tb_t *tb_env;
632
    ppcemb_timer_t *ppcemb_timer;
633
    uint64_t now, next;
634

    
635
    env = opaque;
636
    tb_env = env->tb_env;
637
    ppcemb_timer = tb_env->opaque;
638
    now = qemu_get_clock(vm_clock);
639
    switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
640
    case 0:
641
        next = 1 << 9;
642
        break;
643
    case 1:
644
        next = 1 << 13;
645
        break;
646
    case 2:
647
        next = 1 << 17;
648
        break;
649
    case 3:
650
        next = 1 << 21;
651
        break;
652
    default:
653
        /* Cannot occur, but makes gcc happy */
654
        return;
655
    }
656
    next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
657
    if (next == now)
658
        next++;
659
    qemu_mod_timer(ppcemb_timer->fit_timer, next);
660
    env->spr[SPR_40x_TSR] |= 1 << 26;
661
    if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
662
        ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
663
#ifdef PPC_DEBUG_TB
664
    if (loglevel != 0) {
665
        fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__,
666
                (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
667
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
668
    }
669
#endif
670
}
671

    
672
/* Programmable interval timer */
673
static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
674
{
675
    ppcemb_timer_t *ppcemb_timer;
676
    uint64_t now, next;
677

    
678
    ppcemb_timer = tb_env->opaque;
679
    if (ppcemb_timer->pit_reload <= 1 ||
680
        !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
681
        (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
682
        /* Stop PIT */
683
#ifdef PPC_DEBUG_TB
684
        if (loglevel != 0) {
685
            fprintf(logfile, "%s: stop PIT\n", __func__);
686
        }
687
#endif
688
        qemu_del_timer(tb_env->decr_timer);
689
    } else {
690
#ifdef PPC_DEBUG_TB
691
        if (loglevel != 0) {
692
            fprintf(logfile, "%s: start PIT 0x" REGX "\n",
693
                    __func__, ppcemb_timer->pit_reload);
694
        }
695
#endif
696
        now = qemu_get_clock(vm_clock);
697
        next = now + muldiv64(ppcemb_timer->pit_reload,
698
                              ticks_per_sec, tb_env->tb_freq);
699
        if (is_excp)
700
            next += tb_env->decr_next - now;
701
        if (next == now)
702
            next++;
703
        qemu_mod_timer(tb_env->decr_timer, next);
704
        tb_env->decr_next = next;
705
    }
706
}
707

    
708
static void cpu_4xx_pit_cb (void *opaque)
709
{
710
    CPUState *env;
711
    ppc_tb_t *tb_env;
712
    ppcemb_timer_t *ppcemb_timer;
713

    
714
    env = opaque;
715
    tb_env = env->tb_env;
716
    ppcemb_timer = tb_env->opaque;
717
    env->spr[SPR_40x_TSR] |= 1 << 27;
718
    if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
719
        ppc_set_irq(env, PPC_INTERRUPT_PIT, 1);
720
    start_stop_pit(env, tb_env, 1);
721
#ifdef PPC_DEBUG_TB
722
    if (loglevel != 0) {
723
        fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " "
724
                "%016" PRIx64 "\n", __func__,
725
                (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
726
                (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
727
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
728
                ppcemb_timer->pit_reload);
729
    }
730
#endif
731
}
732

    
733
/* Watchdog timer */
734
static void cpu_4xx_wdt_cb (void *opaque)
735
{
736
    CPUState *env;
737
    ppc_tb_t *tb_env;
738
    ppcemb_timer_t *ppcemb_timer;
739
    uint64_t now, next;
740

    
741
    env = opaque;
742
    tb_env = env->tb_env;
743
    ppcemb_timer = tb_env->opaque;
744
    now = qemu_get_clock(vm_clock);
745
    switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
746
    case 0:
747
        next = 1 << 17;
748
        break;
749
    case 1:
750
        next = 1 << 21;
751
        break;
752
    case 2:
753
        next = 1 << 25;
754
        break;
755
    case 3:
756
        next = 1 << 29;
757
        break;
758
    default:
759
        /* Cannot occur, but makes gcc happy */
760
        return;
761
    }
762
    next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
763
    if (next == now)
764
        next++;
765
#ifdef PPC_DEBUG_TB
766
    if (loglevel != 0) {
767
        fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__,
768
                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
769
    }
770
#endif
771
    switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
772
    case 0x0:
773
    case 0x1:
774
        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
775
        ppcemb_timer->wdt_next = next;
776
        env->spr[SPR_40x_TSR] |= 1 << 31;
777
        break;
778
    case 0x2:
779
        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
780
        ppcemb_timer->wdt_next = next;
781
        env->spr[SPR_40x_TSR] |= 1 << 30;
782
        if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
783
            ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
784
        break;
785
    case 0x3:
786
        env->spr[SPR_40x_TSR] &= ~0x30000000;
787
        env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
788
        switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
789
        case 0x0:
790
            /* No reset */
791
            break;
792
        case 0x1: /* Core reset */
793
            ppc40x_core_reset(env);
794
            break;
795
        case 0x2: /* Chip reset */
796
            ppc40x_chip_reset(env);
797
            break;
798
        case 0x3: /* System reset */
799
            ppc40x_system_reset(env);
800
            break;
801
        }
802
    }
803
}
804

    
805
void store_40x_pit (CPUState *env, target_ulong val)
806
{
807
    ppc_tb_t *tb_env;
808
    ppcemb_timer_t *ppcemb_timer;
809

    
810
    tb_env = env->tb_env;
811
    ppcemb_timer = tb_env->opaque;
812
#ifdef PPC_DEBUG_TB
813
    if (loglevel != 0) {
814
        fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer);
815
    }
816
#endif
817
    ppcemb_timer->pit_reload = val;
818
    start_stop_pit(env, tb_env, 0);
819
}
820

    
821
target_ulong load_40x_pit (CPUState *env)
822
{
823
    return cpu_ppc_load_decr(env);
824
}
825

    
826
void store_booke_tsr (CPUState *env, target_ulong val)
827
{
828
#ifdef PPC_DEBUG_TB
829
    if (loglevel != 0) {
830
        fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
831
    }
832
#endif
833
    env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
834
    if (val & 0x80000000)
835
        ppc_set_irq(env, PPC_INTERRUPT_PIT, 0);
836
}
837

    
838
void store_booke_tcr (CPUState *env, target_ulong val)
839
{
840
    ppc_tb_t *tb_env;
841

    
842
    tb_env = env->tb_env;
843
#ifdef PPC_DEBUG_TB
844
    if (loglevel != 0) {
845
        fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
846
    }
847
#endif
848
    env->spr[SPR_40x_TCR] = val & 0xFFC00000;
849
    start_stop_pit(env, tb_env, 1);
850
    cpu_4xx_wdt_cb(env);
851
}
852

    
853
static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
854
{
855
    CPUState *env = opaque;
856
    ppc_tb_t *tb_env = env->tb_env;
857

    
858
#ifdef PPC_DEBUG_TB
859
    if (loglevel != 0) {
860
        fprintf(logfile, "%s set new frequency to %u\n", __func__, freq);
861
    }
862
#endif
863
    tb_env->tb_freq = freq;
864
    /* XXX: we should also update all timers */
865
}
866

    
867
clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
868
{
869
    ppc_tb_t *tb_env;
870
    ppcemb_timer_t *ppcemb_timer;
871

    
872
    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
873
    if (tb_env == NULL) {
874
        return NULL;
875
    }
876
    env->tb_env = tb_env;
877
    ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
878
    tb_env->tb_freq = freq;
879
    tb_env->opaque = ppcemb_timer;
880
#ifdef PPC_DEBUG_TB
881
    if (loglevel != 0) {
882
        fprintf(logfile, "%s %p %p %p\n", __func__, tb_env, ppcemb_timer,
883
                &ppc_emb_set_tb_clk);
884
    }
885
#endif
886
    if (ppcemb_timer != NULL) {
887
        /* We use decr timer for PIT */
888
        tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env);
889
        ppcemb_timer->fit_timer =
890
            qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
891
        ppcemb_timer->wdt_timer =
892
            qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
893
    }
894

    
895
    return &ppc_emb_set_tb_clk;
896
}
897

    
898
/*****************************************************************************/
899
/* Embedded PowerPC Device Control Registers */
900
typedef struct ppc_dcrn_t ppc_dcrn_t;
901
struct ppc_dcrn_t {
902
    dcr_read_cb dcr_read;
903
    dcr_write_cb dcr_write;
904
    void *opaque;
905
};
906

    
907
/* XXX: on 460, DCR addresses are 32 bits wide,
908
 *      using DCRIPR to get the 22 upper bits of the DCR address
909
 */
910
#define DCRN_NB 1024
911
struct ppc_dcr_t {
912
    ppc_dcrn_t dcrn[DCRN_NB];
913
    int (*read_error)(int dcrn);
914
    int (*write_error)(int dcrn);
915
};
916

    
917
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
918
{
919
    ppc_dcrn_t *dcr;
920

    
921
    if (dcrn < 0 || dcrn >= DCRN_NB)
922
        goto error;
923
    dcr = &dcr_env->dcrn[dcrn];
924
    if (dcr->dcr_read == NULL)
925
        goto error;
926
    *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
927

    
928
    return 0;
929

    
930
 error:
931
    if (dcr_env->read_error != NULL)
932
        return (*dcr_env->read_error)(dcrn);
933

    
934
    return -1;
935
}
936

    
937
int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
938
{
939
    ppc_dcrn_t *dcr;
940

    
941
    if (dcrn < 0 || dcrn >= DCRN_NB)
942
        goto error;
943
    dcr = &dcr_env->dcrn[dcrn];
944
    if (dcr->dcr_write == NULL)
945
        goto error;
946
    (*dcr->dcr_write)(dcr->opaque, dcrn, val);
947

    
948
    return 0;
949

    
950
 error:
951
    if (dcr_env->write_error != NULL)
952
        return (*dcr_env->write_error)(dcrn);
953

    
954
    return -1;
955
}
956

    
957
int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
958
                      dcr_read_cb dcr_read, dcr_write_cb dcr_write)
959
{
960
    ppc_dcr_t *dcr_env;
961
    ppc_dcrn_t *dcr;
962

    
963
    dcr_env = env->dcr_env;
964
    if (dcr_env == NULL)
965
        return -1;
966
    if (dcrn < 0 || dcrn >= DCRN_NB)
967
        return -1;
968
    dcr = &dcr_env->dcrn[dcrn];
969
    if (dcr->opaque != NULL ||
970
        dcr->dcr_read != NULL ||
971
        dcr->dcr_write != NULL)
972
        return -1;
973
    dcr->opaque = opaque;
974
    dcr->dcr_read = dcr_read;
975
    dcr->dcr_write = dcr_write;
976

    
977
    return 0;
978
}
979

    
980
int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn),
981
                  int (*write_error)(int dcrn))
982
{
983
    ppc_dcr_t *dcr_env;
984

    
985
    dcr_env = qemu_mallocz(sizeof(ppc_dcr_t));
986
    if (dcr_env == NULL)
987
        return -1;
988
    dcr_env->read_error = read_error;
989
    dcr_env->write_error = write_error;
990
    env->dcr_env = dcr_env;
991

    
992
    return 0;
993
}
994

    
995

    
996
#if 0
997
/*****************************************************************************/
998
/* Handle system reset (for now, just stop emulation) */
999
void cpu_ppc_reset (CPUState *env)
1000
{
1001
    printf("Reset asked... Stop emulation\n");
1002
    abort();
1003
}
1004
#endif
1005

    
1006
/*****************************************************************************/
1007
/* Debug port */
1008
void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
1009
{
1010
    addr &= 0xF;
1011
    switch (addr) {
1012
    case 0:
1013
        printf("%c", val);
1014
        break;
1015
    case 1:
1016
        printf("\n");
1017
        fflush(stdout);
1018
        break;
1019
    case 2:
1020
        printf("Set loglevel to %04x\n", val);
1021
        cpu_set_log(val | 0x100);
1022
        break;
1023
    }
1024
}
1025

    
1026
/*****************************************************************************/
1027
/* NVRAM helpers */
1028
void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
1029
{
1030
    m48t59_write(nvram, addr, value);
1031
}
1032

    
1033
uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
1034
{
1035
    return m48t59_read(nvram, addr);
1036
}
1037

    
1038
void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
1039
{
1040
    m48t59_write(nvram, addr, value >> 8);
1041
    m48t59_write(nvram, addr + 1, value & 0xFF);
1042
}
1043

    
1044
uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
1045
{
1046
    uint16_t tmp;
1047

    
1048
    tmp = m48t59_read(nvram, addr) << 8;
1049
    tmp |= m48t59_read(nvram, addr + 1);
1050
    return tmp;
1051
}
1052

    
1053
void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
1054
{
1055
    m48t59_write(nvram, addr, value >> 24);
1056
    m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
1057
    m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
1058
    m48t59_write(nvram, addr + 3, value & 0xFF);
1059
}
1060

    
1061
uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
1062
{
1063
    uint32_t tmp;
1064

    
1065
    tmp = m48t59_read(nvram, addr) << 24;
1066
    tmp |= m48t59_read(nvram, addr + 1) << 16;
1067
    tmp |= m48t59_read(nvram, addr + 2) << 8;
1068
    tmp |= m48t59_read(nvram, addr + 3);
1069

    
1070
    return tmp;
1071
}
1072

    
1073
void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
1074
                       const unsigned char *str, uint32_t max)
1075
{
1076
    int i;
1077

    
1078
    for (i = 0; i < max && str[i] != '\0'; i++) {
1079
        m48t59_write(nvram, addr + i, str[i]);
1080
    }
1081
    m48t59_write(nvram, addr + max - 1, '\0');
1082
}
1083

    
1084
int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
1085
{
1086
    int i;
1087

    
1088
    memset(dst, 0, max);
1089
    for (i = 0; i < max; i++) {
1090
        dst[i] = NVRAM_get_byte(nvram, addr + i);
1091
        if (dst[i] == '\0')
1092
            break;
1093
    }
1094

    
1095
    return i;
1096
}
1097

    
1098
static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
1099
{
1100
    uint16_t tmp;
1101
    uint16_t pd, pd1, pd2;
1102

    
1103
    tmp = prev >> 8;
1104
    pd = prev ^ value;
1105
    pd1 = pd & 0x000F;
1106
    pd2 = ((pd >> 4) & 0x000F) ^ pd1;
1107
    tmp ^= (pd1 << 3) | (pd1 << 8);
1108
    tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
1109

    
1110
    return tmp;
1111
}
1112

    
1113
uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
1114
{
1115
    uint32_t i;
1116
    uint16_t crc = 0xFFFF;
1117
    int odd;
1118

    
1119
    odd = count & 1;
1120
    count &= ~1;
1121
    for (i = 0; i != count; i++) {
1122
        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
1123
    }
1124
    if (odd) {
1125
        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
1126
    }
1127

    
1128
    return crc;
1129
}
1130

    
1131
#define CMDLINE_ADDR 0x017ff000
1132

    
1133
int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
1134
                          const unsigned char *arch,
1135
                          uint32_t RAM_size, int boot_device,
1136
                          uint32_t kernel_image, uint32_t kernel_size,
1137
                          const char *cmdline,
1138
                          uint32_t initrd_image, uint32_t initrd_size,
1139
                          uint32_t NVRAM_image,
1140
                          int width, int height, int depth)
1141
{
1142
    uint16_t crc;
1143

    
1144
    /* Set parameters for Open Hack'Ware BIOS */
1145
    NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
1146
    NVRAM_set_lword(nvram,  0x10, 0x00000002); /* structure v2 */
1147
    NVRAM_set_word(nvram,   0x14, NVRAM_size);
1148
    NVRAM_set_string(nvram, 0x20, arch, 16);
1149
    NVRAM_set_lword(nvram,  0x30, RAM_size);
1150
    NVRAM_set_byte(nvram,   0x34, boot_device);
1151
    NVRAM_set_lword(nvram,  0x38, kernel_image);
1152
    NVRAM_set_lword(nvram,  0x3C, kernel_size);
1153
    if (cmdline) {
1154
        /* XXX: put the cmdline in NVRAM too ? */
1155
        strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
1156
        NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
1157
        NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
1158
    } else {
1159
        NVRAM_set_lword(nvram,  0x40, 0);
1160
        NVRAM_set_lword(nvram,  0x44, 0);
1161
    }
1162
    NVRAM_set_lword(nvram,  0x48, initrd_image);
1163
    NVRAM_set_lword(nvram,  0x4C, initrd_size);
1164
    NVRAM_set_lword(nvram,  0x50, NVRAM_image);
1165

    
1166
    NVRAM_set_word(nvram,   0x54, width);
1167
    NVRAM_set_word(nvram,   0x56, height);
1168
    NVRAM_set_word(nvram,   0x58, depth);
1169
    crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
1170
    NVRAM_set_word(nvram,  0xFC, crc);
1171

    
1172
    return 0;
1173
}