Statistics
| Branch: | Revision:

root / hw / m68k / mcf_intc.c @ 2c9b15ca

History | View | Annotate | Download (3.7 kB)

1 5fafdf24 ths
/*
2 20dcee94 pbrook
 * ColdFire Interrupt Controller emulation.
3 20dcee94 pbrook
 *
4 20dcee94 pbrook
 * Copyright (c) 2007 CodeSourcery.
5 20dcee94 pbrook
 *
6 8e31bf38 Matthew Fernandez
 * This code is licensed under the GPL
7 20dcee94 pbrook
 */
8 83c9f4ca Paolo Bonzini
#include "hw/hw.h"
9 0d09e41a Paolo Bonzini
#include "hw/m68k/mcf.h"
10 022c62cb Paolo Bonzini
#include "exec/address-spaces.h"
11 20dcee94 pbrook
12 20dcee94 pbrook
typedef struct {
13 663d9446 Benoît Canet
    MemoryRegion iomem;
14 20dcee94 pbrook
    uint64_t ipr;
15 20dcee94 pbrook
    uint64_t imr;
16 20dcee94 pbrook
    uint64_t ifr;
17 20dcee94 pbrook
    uint64_t enabled;
18 20dcee94 pbrook
    uint8_t icr[64];
19 9a6ee9fd Andreas Färber
    M68kCPU *cpu;
20 20dcee94 pbrook
    int active_vector;
21 20dcee94 pbrook
} mcf_intc_state;
22 20dcee94 pbrook
23 20dcee94 pbrook
static void mcf_intc_update(mcf_intc_state *s)
24 20dcee94 pbrook
{
25 20dcee94 pbrook
    uint64_t active;
26 20dcee94 pbrook
    int i;
27 20dcee94 pbrook
    int best;
28 20dcee94 pbrook
    int best_level;
29 20dcee94 pbrook
30 20dcee94 pbrook
    active = (s->ipr | s->ifr) & s->enabled & ~s->imr;
31 20dcee94 pbrook
    best_level = 0;
32 20dcee94 pbrook
    best = 64;
33 20dcee94 pbrook
    if (active) {
34 20dcee94 pbrook
        for (i = 0; i < 64; i++) {
35 20dcee94 pbrook
            if ((active & 1) != 0 && s->icr[i] >= best_level) {
36 20dcee94 pbrook
                best_level = s->icr[i];
37 20dcee94 pbrook
                best = i;
38 20dcee94 pbrook
            }
39 20dcee94 pbrook
            active >>= 1;
40 20dcee94 pbrook
        }
41 20dcee94 pbrook
    }
42 20dcee94 pbrook
    s->active_vector = ((best == 64) ? 24 : (best + 64));
43 cb3fb38e Andreas Färber
    m68k_set_irq_level(s->cpu, best_level, s->active_vector);
44 20dcee94 pbrook
}
45 20dcee94 pbrook
46 a8170e5e Avi Kivity
static uint64_t mcf_intc_read(void *opaque, hwaddr addr,
47 663d9446 Benoît Canet
                              unsigned size)
48 20dcee94 pbrook
{
49 20dcee94 pbrook
    int offset;
50 20dcee94 pbrook
    mcf_intc_state *s = (mcf_intc_state *)opaque;
51 20dcee94 pbrook
    offset = addr & 0xff;
52 20dcee94 pbrook
    if (offset >= 0x40 && offset < 0x80) {
53 20dcee94 pbrook
        return s->icr[offset - 0x40];
54 20dcee94 pbrook
    }
55 20dcee94 pbrook
    switch (offset) {
56 20dcee94 pbrook
    case 0x00:
57 20dcee94 pbrook
        return (uint32_t)(s->ipr >> 32);
58 20dcee94 pbrook
    case 0x04:
59 20dcee94 pbrook
        return (uint32_t)s->ipr;
60 20dcee94 pbrook
    case 0x08:
61 20dcee94 pbrook
        return (uint32_t)(s->imr >> 32);
62 20dcee94 pbrook
    case 0x0c:
63 20dcee94 pbrook
        return (uint32_t)s->imr;
64 20dcee94 pbrook
    case 0x10:
65 20dcee94 pbrook
        return (uint32_t)(s->ifr >> 32);
66 20dcee94 pbrook
    case 0x14:
67 20dcee94 pbrook
        return (uint32_t)s->ifr;
68 20dcee94 pbrook
    case 0xe0: /* SWIACK.  */
69 20dcee94 pbrook
        return s->active_vector;
70 20dcee94 pbrook
    case 0xe1: case 0xe2: case 0xe3: case 0xe4:
71 20dcee94 pbrook
    case 0xe5: case 0xe6: case 0xe7:
72 20dcee94 pbrook
        /* LnIACK */
73 2ac71179 Paul Brook
        hw_error("mcf_intc_read: LnIACK not implemented\n");
74 20dcee94 pbrook
    default:
75 20dcee94 pbrook
        return 0;
76 20dcee94 pbrook
    }
77 20dcee94 pbrook
}
78 20dcee94 pbrook
79 a8170e5e Avi Kivity
static void mcf_intc_write(void *opaque, hwaddr addr,
80 663d9446 Benoît Canet
                           uint64_t val, unsigned size)
81 20dcee94 pbrook
{
82 20dcee94 pbrook
    int offset;
83 20dcee94 pbrook
    mcf_intc_state *s = (mcf_intc_state *)opaque;
84 20dcee94 pbrook
    offset = addr & 0xff;
85 20dcee94 pbrook
    if (offset >= 0x40 && offset < 0x80) {
86 20dcee94 pbrook
        int n = offset - 0x40;
87 20dcee94 pbrook
        s->icr[n] = val;
88 20dcee94 pbrook
        if (val == 0)
89 20dcee94 pbrook
            s->enabled &= ~(1ull << n);
90 20dcee94 pbrook
        else
91 20dcee94 pbrook
            s->enabled |= (1ull << n);
92 20dcee94 pbrook
        mcf_intc_update(s);
93 20dcee94 pbrook
        return;
94 20dcee94 pbrook
    }
95 20dcee94 pbrook
    switch (offset) {
96 20dcee94 pbrook
    case 0x00: case 0x04:
97 20dcee94 pbrook
        /* Ignore IPR writes.  */
98 20dcee94 pbrook
        return;
99 20dcee94 pbrook
    case 0x08:
100 20dcee94 pbrook
        s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32);
101 20dcee94 pbrook
        break;
102 20dcee94 pbrook
    case 0x0c:
103 20dcee94 pbrook
        s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val;
104 20dcee94 pbrook
        break;
105 20dcee94 pbrook
    default:
106 2ac71179 Paul Brook
        hw_error("mcf_intc_write: Bad write offset %d\n", offset);
107 20dcee94 pbrook
        break;
108 20dcee94 pbrook
    }
109 20dcee94 pbrook
    mcf_intc_update(s);
110 20dcee94 pbrook
}
111 20dcee94 pbrook
112 20dcee94 pbrook
static void mcf_intc_set_irq(void *opaque, int irq, int level)
113 20dcee94 pbrook
{
114 20dcee94 pbrook
    mcf_intc_state *s = (mcf_intc_state *)opaque;
115 20dcee94 pbrook
    if (irq >= 64)
116 20dcee94 pbrook
        return;
117 20dcee94 pbrook
    if (level)
118 20dcee94 pbrook
        s->ipr |= 1ull << irq;
119 20dcee94 pbrook
    else
120 20dcee94 pbrook
        s->ipr &= ~(1ull << irq);
121 20dcee94 pbrook
    mcf_intc_update(s);
122 20dcee94 pbrook
}
123 20dcee94 pbrook
124 20dcee94 pbrook
static void mcf_intc_reset(mcf_intc_state *s)
125 20dcee94 pbrook
{
126 20dcee94 pbrook
    s->imr = ~0ull;
127 20dcee94 pbrook
    s->ipr = 0;
128 20dcee94 pbrook
    s->ifr = 0;
129 20dcee94 pbrook
    s->enabled = 0;
130 20dcee94 pbrook
    memset(s->icr, 0, 64);
131 20dcee94 pbrook
    s->active_vector = 24;
132 20dcee94 pbrook
}
133 20dcee94 pbrook
134 663d9446 Benoît Canet
static const MemoryRegionOps mcf_intc_ops = {
135 663d9446 Benoît Canet
    .read = mcf_intc_read,
136 663d9446 Benoît Canet
    .write = mcf_intc_write,
137 663d9446 Benoît Canet
    .endianness = DEVICE_NATIVE_ENDIAN,
138 20dcee94 pbrook
};
139 20dcee94 pbrook
140 663d9446 Benoît Canet
qemu_irq *mcf_intc_init(MemoryRegion *sysmem,
141 a8170e5e Avi Kivity
                        hwaddr base,
142 9a6ee9fd Andreas Färber
                        M68kCPU *cpu)
143 20dcee94 pbrook
{
144 20dcee94 pbrook
    mcf_intc_state *s;
145 20dcee94 pbrook
146 7267c094 Anthony Liguori
    s = g_malloc0(sizeof(mcf_intc_state));
147 9a6ee9fd Andreas Färber
    s->cpu = cpu;
148 20dcee94 pbrook
    mcf_intc_reset(s);
149 20dcee94 pbrook
150 2c9b15ca Paolo Bonzini
    memory_region_init_io(&s->iomem, NULL, &mcf_intc_ops, s, "mcf", 0x100);
151 663d9446 Benoît Canet
    memory_region_add_subregion(sysmem, base, &s->iomem);
152 20dcee94 pbrook
153 20dcee94 pbrook
    return qemu_allocate_irqs(mcf_intc_set_irq, s, 64);
154 20dcee94 pbrook
}