Statistics
| Branch: | Revision:

root / hw / openpic.c @ 0986ac3b

History | View | Annotate | Download (25.8 kB)

1
/*
2
 * OpenPIC emulation
3
 * 
4
 * Copyright (c) 2004 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
/*
25
 *
26
 * Based on OpenPic implementations:
27
 * - Intel GW80314 I/O compagnion chip developper's manual
28
 * - Motorola MPC8245 & MPC8540 user manuals.
29
 * - Motorola MCP750 (aka Raven) programmer manual.
30
 * - Motorola Harrier programmer manuel
31
 *
32
 * Serial interrupts, as implemented in Raven chipset are not supported yet.
33
 * 
34
 */
35
#include "vl.h"
36

    
37
//#define DEBUG_OPENPIC
38

    
39
#ifdef DEBUG_OPENPIC
40
#define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
41
#else
42
#define DPRINTF(fmt, args...) do { } while (0)
43
#endif
44
#define ERROR(fmr, args...) do { printf("ERROR: " fmr , ##args); } while (0)
45

    
46
#define USE_MPCxxx /* Intel model is broken, for now */
47

    
48
#if defined (USE_INTEL_GW80314)
49
/* Intel GW80314 I/O Companion chip */
50

    
51
#define MAX_CPU     4
52
#define MAX_IRQ    32
53
#define MAX_DBL     4
54
#define MAX_MBX     4
55
#define MAX_TMR     4
56
#define VECTOR_BITS 8
57
#define MAX_IPI     0
58

    
59
#define VID (0x00000000)
60

    
61
#define OPENPIC_LITTLE_ENDIAN 1
62
#define OPENPIC_BIG_ENDIAN    0
63

    
64
#elif defined(USE_MPCxxx)
65

    
66
#define MAX_CPU     2
67
#define MAX_IRQ    64
68
#define EXT_IRQ    48
69
#define MAX_DBL     0
70
#define MAX_MBX     0
71
#define MAX_TMR     4
72
#define VECTOR_BITS 8
73
#define MAX_IPI     4
74
#define VID         0x03 /* MPIC version ID */
75
#define VENI        0x00000000 /* Vendor ID */
76

    
77
enum {
78
    IRQ_IPVP = 0,
79
    IRQ_IDE,
80
};
81

    
82
#define OPENPIC_LITTLE_ENDIAN 1
83
#define OPENPIC_BIG_ENDIAN    0
84

    
85
#else
86
#error "Please select which OpenPic implementation is to be emulated"
87
#endif
88

    
89
#if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \
90
    (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN)
91
#define OPENPIC_SWAP
92
#endif
93

    
94
/* Interrupt definitions */
95
#define IRQ_FE     (EXT_IRQ)     /* Internal functional IRQ */
96
#define IRQ_ERR    (EXT_IRQ + 1) /* Error IRQ */
97
#define IRQ_TIM0   (EXT_IRQ + 2) /* First timer IRQ */
98
#if MAX_IPI > 0
99
#define IRQ_IPI0   (IRQ_TIM0 + MAX_TMR) /* First IPI IRQ */
100
#define IRQ_DBL0   (IRQ_IPI0 + (MAX_CPU * MAX_IPI)) /* First doorbell IRQ */
101
#else
102
#define IRQ_DBL0   (IRQ_TIM0 + MAX_TMR) /* First doorbell IRQ */
103
#define IRQ_MBX0   (IRQ_DBL0 + MAX_DBL) /* First mailbox IRQ */
104
#endif
105

    
106
#define BF_WIDTH(_bits_) \
107
(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
108

    
109
static inline void set_bit (uint32_t *field, int bit)
110
{
111
    field[bit >> 5] |= 1 << (bit & 0x1F);
112
}
113

    
114
static inline void reset_bit (uint32_t *field, int bit)
115
{
116
    field[bit >> 5] &= ~(1 << (bit & 0x1F));
117
}
118

    
119
static inline int test_bit (uint32_t *field, int bit)
120
{
121
    return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
122
}
123

    
124
enum {
125
    IRQ_EXTERNAL = 0x01,
126
    IRQ_INTERNAL = 0x02,
127
    IRQ_TIMER    = 0x04,
128
    IRQ_SPECIAL  = 0x08,
129
} IRQ_src_type;
130

    
131
typedef struct IRQ_queue_t {
132
    uint32_t queue[BF_WIDTH(MAX_IRQ)];
133
    int next;
134
    int priority;
135
} IRQ_queue_t;
136

    
137
typedef struct IRQ_src_t {
138
    uint32_t ipvp;  /* IRQ vector/priority register */
139
    uint32_t ide;   /* IRQ destination register */
140
    int type;
141
    int last_cpu;
142
    int pending;    /* TRUE if IRQ is pending */
143
} IRQ_src_t;
144

    
145
enum IPVP_bits {
146
    IPVP_MASK     = 31,
147
    IPVP_ACTIVITY = 30,
148
    IPVP_MODE     = 29,
149
    IPVP_POLARITY = 23,
150
    IPVP_SENSE    = 22,
151
};
152
#define IPVP_PRIORITY_MASK     (0x1F << 16)
153
#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
154
#define IPVP_VECTOR_MASK       ((1 << VECTOR_BITS) - 1)
155
#define IPVP_VECTOR(_ipvpr_)   ((_ipvpr_) & IPVP_VECTOR_MASK)
156

    
157
typedef struct IRQ_dst_t {
158
    uint32_t pctp; /* CPU current task priority */
159
    uint32_t pcsr; /* CPU sensitivity register */
160
    IRQ_queue_t raised;
161
    IRQ_queue_t servicing;
162
    CPUState *env;
163
} IRQ_dst_t;
164

    
165
struct openpic_t {
166
    PCIDevice pci_dev;
167
    int mem_index;
168
    /* Global registers */
169
    uint32_t frep; /* Feature reporting register */
170
    uint32_t glbc; /* Global configuration register  */
171
    uint32_t micr; /* MPIC interrupt configuration register */
172
    uint32_t veni; /* Vendor identification register */
173
    uint32_t spve; /* Spurious vector register */
174
    uint32_t tifr; /* Timer frequency reporting register */
175
    /* Source registers */
176
    IRQ_src_t src[MAX_IRQ];
177
    /* Local registers per output pin */
178
    IRQ_dst_t dst[MAX_CPU];
179
    int nb_cpus;
180
    /* Timer registers */
181
    struct {
182
        uint32_t ticc;  /* Global timer current count register */
183
        uint32_t tibc;  /* Global timer base count register */
184
    } timers[MAX_TMR];
185
#if MAX_DBL > 0
186
    /* Doorbell registers */
187
    uint32_t dar;        /* Doorbell activate register */
188
    struct {
189
        uint32_t dmr;    /* Doorbell messaging register */
190
    } doorbells[MAX_DBL];
191
#endif
192
#if MAX_MBX > 0
193
    /* Mailbox registers */
194
    struct {
195
        uint32_t mbr;    /* Mailbox register */
196
    } mailboxes[MAX_MAILBOXES];
197
#endif
198
};
199

    
200
static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
201
{
202
    set_bit(q->queue, n_IRQ);
203
}
204

    
205
static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
206
{
207
    reset_bit(q->queue, n_IRQ);
208
}
209

    
210
static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
211
{
212
    return test_bit(q->queue, n_IRQ);
213
}
214

    
215
static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
216
{
217
    int next, i;
218
    int priority;
219

    
220
    next = -1;
221
    priority = -1;
222
    for (i = 0; i < MAX_IRQ; i++) {
223
        if (IRQ_testbit(q, i)) {
224
            DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", 
225
                    i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
226
            if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
227
                next = i;
228
                priority = IPVP_PRIORITY(opp->src[i].ipvp);
229
            }
230
        }
231
    }
232
    q->next = next;
233
    q->priority = priority;
234
}
235

    
236
static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
237
{
238
    if (q->next == -1) {
239
        /* XXX: optimize */
240
        IRQ_check(opp, q);
241
    }
242

    
243
    return q->next;
244
}
245

    
246
static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
247
{
248
    IRQ_dst_t *dst;
249
    IRQ_src_t *src;
250
    int priority;
251

    
252
    dst = &opp->dst[n_CPU];
253
    src = &opp->src[n_IRQ];
254
    priority = IPVP_PRIORITY(src->ipvp);
255
    if (priority <= dst->pctp) {
256
        /* Too low priority */
257
        return;
258
    }
259
    if (IRQ_testbit(&dst->raised, n_IRQ)) {
260
        /* Interrupt miss */
261
        return;
262
    }
263
    set_bit(&src->ipvp, IPVP_ACTIVITY);
264
    IRQ_setbit(&dst->raised, n_IRQ);
265
    if (priority > dst->raised.priority) {
266
        IRQ_get_next(opp, &dst->raised);
267
        DPRINTF("Raise CPU IRQ\n");
268
        cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
269
    }
270
}
271

    
272
/* update pic state because registers for n_IRQ have changed value */
273
static void openpic_update_irq(openpic_t *opp, int n_IRQ)
274
{
275
    IRQ_src_t *src;
276
    int i;
277

    
278
    src = &opp->src[n_IRQ];
279

    
280
    if (!src->pending) {
281
        /* no irq pending */
282
        return;
283
    }
284
    if (test_bit(&src->ipvp, IPVP_MASK)) {
285
        /* Interrupt source is disabled */
286
        return;
287
    }
288
    if (IPVP_PRIORITY(src->ipvp) == 0) {
289
        /* Priority set to zero */
290
        return;
291
    }
292
    if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
293
        /* IRQ already active */
294
        return;
295
    }
296
    if (src->ide == 0x00000000) {
297
        /* No target */
298
        return;
299
    }
300

    
301
    if (!test_bit(&src->ipvp, IPVP_MODE) ||
302
        src->ide == (1 << src->last_cpu)) {
303
        /* Directed delivery mode */
304
        for (i = 0; i < opp->nb_cpus; i++) {
305
            if (test_bit(&src->ide, i))
306
                IRQ_local_pipe(opp, i, n_IRQ);
307
        }
308
    } else {
309
        /* Distributed delivery mode */
310
        /* XXX: incorrect code */
311
        for (i = src->last_cpu; i < src->last_cpu; i++) {
312
            if (i == MAX_IRQ)
313
                i = 0;
314
            if (test_bit(&src->ide, i)) {
315
                IRQ_local_pipe(opp, i, n_IRQ);
316
                src->last_cpu = i;
317
                break;
318
            }
319
        }
320
    }
321
}
322

    
323
void openpic_set_irq(void *opaque, int n_IRQ, int level)
324
{
325
    openpic_t *opp = opaque;
326
    IRQ_src_t *src;
327

    
328
    src = &opp->src[n_IRQ];
329
    DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", 
330
            n_IRQ, level, src->ipvp);
331
    if (test_bit(&src->ipvp, IPVP_SENSE)) {
332
        /* level-sensitive irq */
333
        src->pending = level;
334
        if (!level)
335
            reset_bit(&src->ipvp, IPVP_ACTIVITY);
336
    } else {
337
        /* edge-sensitive irq */
338
        if (level)
339
            src->pending = 1;
340
    }
341
    openpic_update_irq(opp, n_IRQ);
342
}
343

    
344
static void openpic_reset (openpic_t *opp)
345
{
346
    int i;
347

    
348
    opp->glbc = 0x80000000;
349
    /* Initialise controller registers */
350
    opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
351
    opp->veni = VENI;
352
    opp->spve = 0x000000FF;
353
    opp->tifr = 0x003F7A00;
354
    /* ? */
355
    opp->micr = 0x00000000;
356
    /* Initialise IRQ sources */
357
    for (i = 0; i < MAX_IRQ; i++) {
358
        opp->src[i].ipvp = 0xA0000000;
359
        opp->src[i].ide  = 0x00000000;
360
    }
361
    /* Initialise IRQ destinations */
362
    for (i = 0; i < opp->nb_cpus; i++) {
363
        opp->dst[i].pctp      = 0x0000000F;
364
        opp->dst[i].pcsr      = 0x00000000;
365
        memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
366
        memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
367
    }
368
    /* Initialise timers */
369
    for (i = 0; i < MAX_TMR; i++) {
370
        opp->timers[i].ticc = 0x00000000;
371
        opp->timers[i].tibc = 0x80000000;
372
    }
373
    /* Initialise doorbells */
374
#if MAX_DBL > 0
375
    opp->dar = 0x00000000;
376
    for (i = 0; i < MAX_DBL; i++) {
377
        opp->doorbells[i].dmr  = 0x00000000;
378
    }
379
#endif
380
    /* Initialise mailboxes */
381
#if MAX_MBX > 0
382
    for (i = 0; i < MAX_MBX; i++) { /* ? */
383
        opp->mailboxes[i].mbr   = 0x00000000;
384
    }
385
#endif
386
    /* Go out of RESET state */
387
    opp->glbc = 0x00000000;
388
}
389

    
390
static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
391
{
392
    uint32_t retval;
393

    
394
    switch (reg) {
395
    case IRQ_IPVP:
396
        retval = opp->src[n_IRQ].ipvp;
397
        break;
398
    case IRQ_IDE:
399
        retval = opp->src[n_IRQ].ide;
400
        break;
401
    }
402

    
403
    return retval;
404
}
405

    
406
static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
407
                                 uint32_t reg, uint32_t val)
408
{
409
    uint32_t tmp;
410

    
411
    switch (reg) {
412
    case IRQ_IPVP:
413
        /* NOTE: not fully accurate for special IRQs, but simple and
414
           sufficient */
415
        /* ACTIVITY bit is read-only */
416
        opp->src[n_IRQ].ipvp = 
417
            (opp->src[n_IRQ].ipvp & 0x40000000) |
418
            (val & 0x800F00FF);
419
        openpic_update_irq(opp, n_IRQ);
420
        DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", 
421
                n_IRQ, val, opp->src[n_IRQ].ipvp);
422
        break;
423
    case IRQ_IDE:
424
        tmp = val & 0xC0000000;
425
        tmp |= val & ((1 << MAX_CPU) - 1);
426
        opp->src[n_IRQ].ide = tmp;
427
        DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
428
        break;
429
    }
430
}
431

    
432
#if 0 // Code provision for Intel model
433
#if MAX_DBL > 0
434
static uint32_t read_doorbell_register (openpic_t *opp,
435
                                        int n_dbl, uint32_t offset)
436
{
437
    uint32_t retval;
438

439
    switch (offset) {
440
    case DBL_IPVP_OFFSET:
441
        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
442
        break;
443
    case DBL_IDE_OFFSET:
444
        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
445
        break;
446
    case DBL_DMR_OFFSET:
447
        retval = opp->doorbells[n_dbl].dmr;
448
        break;
449
    }
450

451
    return retval;
452
}
453
     
454
static void write_doorbell_register (penpic_t *opp, int n_dbl,
455
                                     uint32_t offset, uint32_t value)
456
{
457
    switch (offset) {
458
    case DBL_IVPR_OFFSET:
459
        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
460
        break;
461
    case DBL_IDE_OFFSET:
462
        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
463
        break;
464
    case DBL_DMR_OFFSET:
465
        opp->doorbells[n_dbl].dmr = value;
466
        break;
467
    }
468
}
469
#endif
470

    
471
#if MAX_MBX > 0
472
static uint32_t read_mailbox_register (openpic_t *opp,
473
                                       int n_mbx, uint32_t offset)
474
{
475
    uint32_t retval;
476

    
477
    switch (offset) {
478
    case MBX_MBR_OFFSET:
479
        retval = opp->mailboxes[n_mbx].mbr;
480
        break;
481
    case MBX_IVPR_OFFSET:
482
        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
483
        break;
484
    case MBX_DMR_OFFSET:
485
        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
486
        break;
487
    }
488

    
489
    return retval;
490
}
491

    
492
static void write_mailbox_register (openpic_t *opp, int n_mbx,
493
                                    uint32_t address, uint32_t value)
494
{
495
    switch (offset) {
496
    case MBX_MBR_OFFSET:
497
        opp->mailboxes[n_mbx].mbr = value;
498
        break;
499
    case MBX_IVPR_OFFSET:
500
        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
501
        break;
502
    case MBX_DMR_OFFSET:
503
        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
504
        break;
505
    }
506
}
507
#endif
508
#endif /* 0 : Code provision for Intel model */
509

    
510
static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
511
{
512
    openpic_t *opp = opaque;
513

    
514
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
515
    if (addr & 0xF)
516
        return;
517
#if defined OPENPIC_SWAP
518
    val = bswap32(val);
519
#endif
520
    addr &= 0xFF;
521
    switch (addr) {
522
    case 0x00: /* FREP */
523
        break;
524
    case 0x20: /* GLBC */
525
        if (val & 0x80000000)
526
            openpic_reset(opp);
527
        opp->glbc = val & ~0x80000000;
528
        break;
529
    case 0x80: /* VENI */
530
        break;
531
    case 0x90: /* PINT */
532
        /* XXX: Should be able to reset any CPU */
533
        if (val & 1) {
534
            DPRINTF("Reset CPU IRQ\n");
535
            //            cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);
536
        }
537
        break;
538
#if MAX_IPI > 0
539
    case 0xA0: /* IPI_IPVP */
540
    case 0xB0:
541
    case 0xC0:
542
    case 0xD0:
543
        {
544
            int idx;
545
            idx = (addr - 0xA0) >> 4;
546
            write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val);
547
        }
548
        break;
549
#endif
550
    case 0xE0: /* SPVE */
551
        opp->spve = val & 0x000000FF;
552
        break;
553
    case 0xF0: /* TIFR */
554
        opp->tifr = val;
555
        break;
556
    default:
557
        break;
558
    }
559
}
560

    
561
static uint32_t openpic_gbl_read (void *opaque, uint32_t addr)
562
{
563
    openpic_t *opp = opaque;
564
    uint32_t retval;
565

    
566
    DPRINTF("%s: addr %08x\n", __func__, addr);
567
    retval = 0xFFFFFFFF;
568
    if (addr & 0xF)
569
        return retval;
570
    addr &= 0xFF;
571
    switch (addr) {
572
    case 0x00: /* FREP */
573
        retval = opp->frep;
574
        break;
575
    case 0x20: /* GLBC */
576
        retval = opp->glbc;
577
        break;
578
    case 0x80: /* VENI */
579
        retval = opp->veni;
580
        break;
581
    case 0x90: /* PINT */
582
        retval = 0x00000000;
583
        break;
584
#if MAX_IPI > 0
585
    case 0xA0: /* IPI_IPVP */
586
    case 0xB0:
587
    case 0xC0:
588
    case 0xD0:
589
        {
590
            int idx;
591
            idx = (addr - 0xA0) >> 4;
592
            retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP);
593
        }
594
        break;
595
#endif
596
    case 0xE0: /* SPVE */
597
        retval = opp->spve;
598
        break;
599
    case 0xF0: /* TIFR */
600
        retval = opp->tifr;
601
        break;
602
    default:
603
        break;
604
    }
605
    DPRINTF("%s: => %08x\n", __func__, retval);
606
#if defined OPENPIC_SWAP
607
    retval = bswap32(retval);
608
#endif
609

    
610
    return retval;
611
}
612

    
613
static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
614
{
615
    openpic_t *opp = opaque;
616
    int idx;
617

    
618
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
619
    if (addr & 0xF)
620
        return;
621
#if defined OPENPIC_SWAP
622
    val = bswap32(val);
623
#endif
624
    addr -= 0x1100;
625
    addr &= 0xFFFF;
626
    idx = (addr & 0xFFF0) >> 6;
627
    addr = addr & 0x30;
628
    switch (addr) {
629
    case 0x00: /* TICC */
630
        break;
631
    case 0x10: /* TIBC */
632
        if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
633
            (val & 0x80000000) == 0 &&
634
            (opp->timers[idx].tibc & 0x80000000) != 0)
635
            opp->timers[idx].ticc &= ~0x80000000;
636
        opp->timers[idx].tibc = val;
637
        break;
638
    case 0x20: /* TIVP */
639
        write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val);
640
        break;
641
    case 0x30: /* TIDE */
642
        write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val);
643
        break;
644
    }
645
}
646

    
647
static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
648
{
649
    openpic_t *opp = opaque;
650
    uint32_t retval;
651
    int idx;
652

    
653
    DPRINTF("%s: addr %08x\n", __func__, addr);
654
    retval = 0xFFFFFFFF;
655
    if (addr & 0xF)
656
        return retval;
657
    addr -= 0x1100;
658
    addr &= 0xFFFF;
659
    idx = (addr & 0xFFF0) >> 6;
660
    addr = addr & 0x30;
661
    switch (addr) {
662
    case 0x00: /* TICC */
663
        retval = opp->timers[idx].ticc;
664
        break;
665
    case 0x10: /* TIBC */
666
        retval = opp->timers[idx].tibc;
667
        break;
668
    case 0x20: /* TIPV */
669
        retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP);
670
        break;
671
    case 0x30: /* TIDE */
672
        retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE);
673
        break;
674
    }
675
    DPRINTF("%s: => %08x\n", __func__, retval);
676
#if defined OPENPIC_SWAP
677
    retval = bswap32(retval);
678
#endif
679

    
680
    return retval;
681
}
682

    
683
static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
684
{
685
    openpic_t *opp = opaque;
686
    int idx;
687

    
688
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
689
    if (addr & 0xF)
690
        return;
691
#if defined OPENPIC_SWAP
692
    val = tswap32(val);
693
#endif
694
    addr = addr & 0xFFF0;
695
    idx = addr >> 5;
696
    if (addr & 0x10) {
697
        /* EXDE / IFEDE / IEEDE */
698
        write_IRQreg(opp, idx, IRQ_IDE, val);
699
    } else {
700
        /* EXVP / IFEVP / IEEVP */
701
        write_IRQreg(opp, idx, IRQ_IPVP, val);
702
    }
703
}
704

    
705
static uint32_t openpic_src_read (void *opaque, uint32_t addr)
706
{
707
    openpic_t *opp = opaque;
708
    uint32_t retval;
709
    int idx;
710

    
711
    DPRINTF("%s: addr %08x\n", __func__, addr);
712
    retval = 0xFFFFFFFF;
713
    if (addr & 0xF)
714
        return retval;
715
    addr = addr & 0xFFF0;
716
    idx = addr >> 5;
717
    if (addr & 0x10) {
718
        /* EXDE / IFEDE / IEEDE */
719
        retval = read_IRQreg(opp, idx, IRQ_IDE);
720
    } else {
721
        /* EXVP / IFEVP / IEEVP */
722
        retval = read_IRQreg(opp, idx, IRQ_IPVP);
723
    }
724
    DPRINTF("%s: => %08x\n", __func__, retval);
725
#if defined OPENPIC_SWAP
726
    retval = tswap32(retval);
727
#endif
728

    
729
    return retval;
730
}
731

    
732
static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
733
{
734
    openpic_t *opp = opaque;
735
    IRQ_src_t *src;
736
    IRQ_dst_t *dst;
737
    int idx, n_IRQ;
738

    
739
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
740
    if (addr & 0xF)
741
        return;
742
#if defined OPENPIC_SWAP
743
    val = bswap32(val);
744
#endif
745
    addr &= 0x1FFF0;
746
    idx = addr / 0x1000;
747
    dst = &opp->dst[idx];
748
    addr &= 0xFF0;
749
    switch (addr) {
750
#if MAX_IPI > 0
751
    case 0x40: /* PIPD */
752
    case 0x50:
753
    case 0x60:
754
    case 0x70:
755
        idx = (addr - 0x40) >> 4;
756
        write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val);
757
        openpic_set_irq(opp, IRQ_IPI0 + idx, 1);
758
        openpic_set_irq(opp, IRQ_IPI0 + idx, 0);
759
        break;
760
#endif
761
    case 0x80: /* PCTP */
762
        dst->pctp = val & 0x0000000F;
763
        break;
764
    case 0x90: /* WHOAMI */
765
        /* Read-only register */
766
        break;
767
    case 0xA0: /* PIAC */
768
        /* Read-only register */
769
        break;
770
    case 0xB0: /* PEOI */
771
        DPRINTF("PEOI\n");
772
        n_IRQ = IRQ_get_next(opp, &dst->servicing);
773
        IRQ_resetbit(&dst->servicing, n_IRQ);
774
        dst->servicing.next = -1;
775
        src = &opp->src[n_IRQ];
776
        /* Set up next servicing IRQ */
777
        IRQ_get_next(opp, &dst->servicing);
778
        /* Check queued interrupts. */
779
        n_IRQ = IRQ_get_next(opp, &dst->raised);
780
        if (n_IRQ != -1) {
781
            src = &opp->src[n_IRQ];
782
            if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
783
                DPRINTF("Raise CPU IRQ\n");
784
                cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
785
            }
786
        }
787
        break;
788
    default:
789
        break;
790
    }
791
}
792

    
793
static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
794
{
795
    openpic_t *opp = opaque;
796
    IRQ_src_t *src;
797
    IRQ_dst_t *dst;
798
    uint32_t retval;
799
    int idx, n_IRQ;
800
    
801
    DPRINTF("%s: addr %08x\n", __func__, addr);
802
    retval = 0xFFFFFFFF;
803
    if (addr & 0xF)
804
        return retval;
805
    addr &= 0x1FFF0;
806
    idx = addr / 0x1000;
807
    dst = &opp->dst[idx];
808
    addr &= 0xFF0;
809
    switch (addr) {
810
    case 0x80: /* PCTP */
811
        retval = dst->pctp;
812
        break;
813
    case 0x90: /* WHOAMI */
814
        retval = idx;
815
        break;
816
    case 0xA0: /* PIAC */
817
        n_IRQ = IRQ_get_next(opp, &dst->raised);
818
        DPRINTF("PIAC: irq=%d\n", n_IRQ);
819
        if (n_IRQ == -1) {
820
            /* No more interrupt pending */
821
            retval = opp->spve;
822
        } else {
823
            src = &opp->src[n_IRQ];
824
            if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
825
                !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
826
                /* - Spurious level-sensitive IRQ
827
                 * - Priorities has been changed
828
                 *   and the pending IRQ isn't allowed anymore
829
                 */
830
                reset_bit(&src->ipvp, IPVP_ACTIVITY);
831
                retval = IPVP_VECTOR(opp->spve);
832
            } else {
833
                /* IRQ enter servicing state */
834
                IRQ_setbit(&dst->servicing, n_IRQ);
835
                retval = IPVP_VECTOR(src->ipvp);
836
            }
837
            IRQ_resetbit(&dst->raised, n_IRQ);
838
            dst->raised.next = -1;
839
            if (!test_bit(&src->ipvp, IPVP_SENSE)) {
840
                /* edge-sensitive IRQ */
841
                reset_bit(&src->ipvp, IPVP_ACTIVITY);
842
                src->pending = 0;
843
            }
844
        }
845
        break;
846
    case 0xB0: /* PEOI */
847
        retval = 0;
848
        break;
849
#if MAX_IPI > 0
850
    case 0x40: /* IDE */
851
    case 0x50:
852
        idx = (addr - 0x40) >> 4;
853
        retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE);
854
        break;
855
#endif
856
    default:
857
        break;
858
    }
859
    DPRINTF("%s: => %08x\n", __func__, retval);
860
#if defined OPENPIC_SWAP
861
    retval= bswap32(retval);
862
#endif
863

    
864
    return retval;
865
}
866

    
867
static void openpic_buggy_write (void *opaque,
868
                                 target_phys_addr_t addr, uint32_t val)
869
{
870
    printf("Invalid OPENPIC write access !\n");
871
}
872

    
873
static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
874
{
875
    printf("Invalid OPENPIC read access !\n");
876

    
877
    return -1;
878
}
879

    
880
static void openpic_writel (void *opaque,
881
                            target_phys_addr_t addr, uint32_t val)
882
{
883
    openpic_t *opp = opaque;
884

    
885
    addr &= 0x3FFFF;
886
    DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
887
    if (addr < 0x1100) {
888
        /* Global registers */
889
        openpic_gbl_write(opp, addr, val);
890
    } else if (addr < 0x10000) {
891
        /* Timers registers */
892
        openpic_timer_write(opp, addr, val);
893
    } else if (addr < 0x20000) {
894
        /* Source registers */
895
        openpic_src_write(opp, addr, val);
896
    } else {
897
        /* CPU registers */
898
        openpic_cpu_write(opp, addr, val);
899
    }
900
}
901

    
902
static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
903
{
904
    openpic_t *opp = opaque;
905
    uint32_t retval;
906

    
907
    addr &= 0x3FFFF;
908
    DPRINTF("%s: offset %08x\n", __func__, (int)addr);
909
    if (addr < 0x1100) {
910
        /* Global registers */
911
        retval = openpic_gbl_read(opp, addr);
912
    } else if (addr < 0x10000) {
913
        /* Timers registers */
914
        retval = openpic_timer_read(opp, addr);
915
    } else if (addr < 0x20000) {
916
        /* Source registers */
917
        retval = openpic_src_read(opp, addr);
918
    } else {
919
        /* CPU registers */
920
        retval = openpic_cpu_read(opp, addr);
921
    }
922

    
923
    return retval;
924
}
925

    
926
static CPUWriteMemoryFunc *openpic_write[] = {
927
    &openpic_buggy_write,
928
    &openpic_buggy_write,
929
    &openpic_writel,
930
};
931

    
932
static CPUReadMemoryFunc *openpic_read[] = {
933
    &openpic_buggy_read,
934
    &openpic_buggy_read,
935
    &openpic_readl,
936
};
937

    
938
static void openpic_map(PCIDevice *pci_dev, int region_num, 
939
                        uint32_t addr, uint32_t size, int type)
940
{
941
    openpic_t *opp;
942

    
943
    DPRINTF("Map OpenPIC\n");
944
    opp = (openpic_t *)pci_dev;
945
    /* Global registers */
946
    DPRINTF("Register OPENPIC gbl   %08x => %08x\n",
947
            addr + 0x1000, addr + 0x1000 + 0x100);
948
    /* Timer registers */
949
    DPRINTF("Register OPENPIC timer %08x => %08x\n",
950
            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
951
    /* Interrupt source registers */
952
    DPRINTF("Register OPENPIC src   %08x => %08x\n",
953
            addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2));
954
    /* Per CPU registers */
955
    DPRINTF("Register OPENPIC dst   %08x => %08x\n",
956
            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
957
    cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
958
#if 0 // Don't implement ISU for now
959
    opp_io_memory = cpu_register_io_memory(0, openpic_src_read,
960
                                           openpic_src_write);
961
    cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
962
                                 opp_io_memory);
963
#endif
964
}
965

    
966
openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
967
                         CPUPPCState **envp)
968
{
969
    openpic_t *opp;
970
    uint8_t *pci_conf;
971
    int i, m;
972
    
973
    /* XXX: for now, only one CPU is supported */
974
    if (nb_cpus != 1)
975
        return NULL;
976
    if (bus) {
977
        opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
978
                                               -1, NULL, NULL);
979
        if (opp == NULL)
980
            return NULL;
981
        pci_conf = opp->pci_dev.config;
982
        pci_conf[0x00] = 0x14; // IBM MPIC2
983
        pci_conf[0x01] = 0x10;
984
        pci_conf[0x02] = 0xFF;
985
        pci_conf[0x03] = 0xFF;
986
        pci_conf[0x0a] = 0x80; // PIC
987
        pci_conf[0x0b] = 0x08;
988
        pci_conf[0x0e] = 0x00; // header_type
989
        pci_conf[0x3d] = 0x00; // no interrupt pin
990
        
991
        /* Register I/O spaces */
992
        pci_register_io_region((PCIDevice *)opp, 0, 0x40000,
993
                               PCI_ADDRESS_SPACE_MEM, &openpic_map);
994
    } else {
995
        opp = qemu_mallocz(sizeof(openpic_t));
996
    }
997

    
998
    opp->mem_index = cpu_register_io_memory(0, openpic_read,
999
                                            openpic_write, opp);
1000
    
1001
    //    isu_base &= 0xFFFC0000;
1002
    opp->nb_cpus = nb_cpus;
1003
    /* Set IRQ types */
1004
    for (i = 0; i < EXT_IRQ; i++) {
1005
        opp->src[i].type = IRQ_EXTERNAL;
1006
    }
1007
    for (; i < IRQ_TIM0; i++) {
1008
        opp->src[i].type = IRQ_SPECIAL;
1009
    }
1010
#if MAX_IPI > 0
1011
    m = IRQ_IPI0;
1012
#else
1013
    m = IRQ_DBL0;
1014
#endif
1015
    for (; i < m; i++) {
1016
        opp->src[i].type = IRQ_TIMER;
1017
    }
1018
    for (; i < MAX_IRQ; i++) {
1019
        opp->src[i].type = IRQ_INTERNAL;
1020
    }
1021
    for (i = 0; i < nb_cpus; i++)
1022
        opp->dst[i].env = envp[i];
1023
    openpic_reset(opp);
1024
    if (pmem_index)
1025
        *pmem_index = opp->mem_index;
1026
    return opp;
1027
}