1 /*
2 * Copyright (C) 2005-2009 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * COMMENT: Grand Central Interrupt controller (used by MacPPC)
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "cpu.h"
36 #include "device.h"
37 #include "machine.h"
38 #include "memory.h"
39 #include "misc.h"
40
41
42 #define DEV_GC_LENGTH 0x100
43
44 struct gc_data {
45 struct interrupt cpu_irq;
46
47 uint32_t status_hi;
48 uint32_t status_lo;
49 uint32_t enable_hi;
50 uint32_t enable_lo;
51 };
52
53
gc_hi_interrupt_assert(struct interrupt * interrupt)54 void gc_hi_interrupt_assert(struct interrupt *interrupt)
55 {
56 struct gc_data *d = (struct gc_data *) interrupt->extra;
57 d->status_hi |= interrupt->line;
58 if (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi)
59 INTERRUPT_ASSERT(d->cpu_irq);
60 }
gc_hi_interrupt_deassert(struct interrupt * interrupt)61 void gc_hi_interrupt_deassert(struct interrupt *interrupt)
62 {
63 struct gc_data *d = (struct gc_data *) interrupt->extra;
64 d->status_hi &= ~interrupt->line;
65 if (!(d->status_lo & d->enable_lo || d->status_hi & d->enable_hi))
66 INTERRUPT_DEASSERT(d->cpu_irq);
67 }
gc_lo_interrupt_assert(struct interrupt * interrupt)68 void gc_lo_interrupt_assert(struct interrupt *interrupt)
69 {
70 struct gc_data *d = (struct gc_data *) interrupt->extra;
71 d->status_lo |= interrupt->line;
72 if (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi)
73 INTERRUPT_ASSERT(d->cpu_irq);
74 }
gc_lo_interrupt_deassert(struct interrupt * interrupt)75 void gc_lo_interrupt_deassert(struct interrupt *interrupt)
76 {
77 struct gc_data *d = (struct gc_data *) interrupt->extra;
78 d->status_lo &= ~interrupt->line;
79 if (!(d->status_lo & d->enable_lo || d->status_hi & d->enable_hi))
80 INTERRUPT_DEASSERT(d->cpu_irq);
81 }
82
83
DEVICE_ACCESS(gc)84 DEVICE_ACCESS(gc)
85 {
86 struct gc_data *d = (struct gc_data *) extra;
87 uint64_t idata = 0, odata = 0;
88
89 if (writeflag == MEM_WRITE)
90 idata = memory_readmax64(cpu, data, len);
91
92 switch (relative_addr) {
93
94 #if 0
95 #define INT_STATE_REG_H (interrupt_reg + 0x00)
96 #define INT_ENABLE_REG_H (interrupt_reg + 0x04)
97 #define INT_CLEAR_REG_H (interrupt_reg + 0x08)
98 #define INT_LEVEL_REG_H (interrupt_reg + 0x0c)
99 #define INT_STATE_REG_L (interrupt_reg + 0x10)
100 #define INT_ENABLE_REG_L (interrupt_reg + 0x14)
101 #define INT_CLEAR_REG_L (interrupt_reg + 0x18)
102 #define INT_LEVEL_REG_L (interrupt_reg + 0x1c)
103 #endif
104
105 case 0x10:
106 if (writeflag == MEM_READ)
107 odata = d->status_hi & d->enable_hi;
108 break;
109
110 case 0x14:
111 if (writeflag == MEM_READ)
112 odata = d->enable_hi;
113 else {
114 int old_assert = (d->status_lo & d->enable_lo
115 || d->status_hi & d->enable_hi);
116 int new_assert;
117 d->enable_hi = idata;
118
119 new_assert = (d->status_lo & d->enable_lo ||
120 d->status_hi & d->enable_hi);
121
122 if (old_assert && !new_assert)
123 INTERRUPT_DEASSERT(d->cpu_irq);
124 else if (!old_assert && new_assert)
125 INTERRUPT_ASSERT(d->cpu_irq);
126 }
127 break;
128
129 case 0x18:
130 if (writeflag == MEM_WRITE) {
131 int old_assert = (d->status_lo & d->enable_lo
132 || d->status_hi & d->enable_hi);
133 int new_assert;
134 d->status_hi &= ~idata;
135
136 new_assert = (d->status_lo & d->enable_lo ||
137 d->status_hi & d->enable_hi);
138
139 if (old_assert && !new_assert)
140 INTERRUPT_DEASSERT(d->cpu_irq);
141 else if (!old_assert && new_assert)
142 INTERRUPT_ASSERT(d->cpu_irq);
143 }
144 break;
145
146 case 0x20:
147 if (writeflag == MEM_READ)
148 odata = d->status_lo & d->enable_lo;
149 break;
150
151 case 0x24:
152 if (writeflag == MEM_READ)
153 odata = d->enable_lo;
154 else {
155 int old_assert = (d->status_lo & d->enable_lo
156 || d->status_hi & d->enable_hi);
157 int new_assert;
158 d->enable_lo = idata;
159
160 new_assert = (d->status_lo & d->enable_lo ||
161 d->status_hi & d->enable_hi);
162
163 if (old_assert && !new_assert)
164 INTERRUPT_DEASSERT(d->cpu_irq);
165 else if (!old_assert && new_assert)
166 INTERRUPT_ASSERT(d->cpu_irq);
167 }
168 break;
169
170 case 0x28:
171 if (writeflag == MEM_WRITE) {
172 int old_assert = (d->status_lo & d->enable_lo
173 || d->status_hi & d->enable_hi);
174 int new_assert;
175 d->status_lo &= ~idata;
176
177 new_assert = (d->status_lo & d->enable_lo ||
178 d->status_hi & d->enable_hi);
179
180 if (old_assert && !new_assert)
181 INTERRUPT_DEASSERT(d->cpu_irq);
182 else if (!old_assert && new_assert)
183 INTERRUPT_ASSERT(d->cpu_irq);
184 }
185 break;
186
187 case 0x1c:
188 case 0x2c:
189 /* Avoid a debug message. */
190 break;
191
192 default:if (writeflag == MEM_WRITE) {
193 fatal("[ gc: unimplemented write to "
194 "offset 0x%x: data=0x%x ]\n", (int)
195 relative_addr, (int)idata);
196 } else {
197 fatal("[ gc: unimplemented read from "
198 "offset 0x%x ]\n", (int)relative_addr);
199 }
200 }
201
202 if (writeflag == MEM_READ)
203 memory_writemax64(cpu, data, len, odata);
204
205 return 1;
206 }
207
208
DEVINIT(gc)209 DEVINIT(gc)
210 {
211 struct gc_data *d;
212 int i;
213
214 CHECK_ALLOCATION(d = (struct gc_data *) malloc(sizeof(struct gc_data)));
215 memset(d, 0, sizeof(struct gc_data));
216
217 /* Connect to the CPU interrupt pin: */
218 INTERRUPT_CONNECT(devinit->interrupt_path, d->cpu_irq);
219
220 /*
221 * Register the 64 Grand Central interrupts (32 lo, 32 hi):
222 */
223 for (i=0; i<32; i++) {
224 struct interrupt templ;
225 char n[300];
226 snprintf(n, sizeof(n), "%s.gc.lo.%i",
227 devinit->interrupt_path, i);
228 memset(&templ, 0, sizeof(templ));
229 templ.line = 1 << i;
230 templ.name = n;
231 templ.extra = d;
232 templ.interrupt_assert = gc_lo_interrupt_assert;
233 templ.interrupt_deassert = gc_lo_interrupt_deassert;
234 interrupt_handler_register(&templ);
235
236 snprintf(n, sizeof(n), "%s.gc.hi.%i",
237 devinit->interrupt_path, i);
238 memset(&templ, 0, sizeof(templ));
239 templ.line = 1 << i;
240 templ.name = n;
241 templ.extra = d;
242 templ.interrupt_assert = gc_hi_interrupt_assert;
243 templ.interrupt_deassert = gc_hi_interrupt_deassert;
244 interrupt_handler_register(&templ);
245 }
246
247 memory_device_register(devinit->machine->memory, "gc",
248 devinit->addr, DEV_GC_LENGTH, dev_gc_access, d, DM_DEFAULT, NULL);
249
250 return 1;
251 }
252
253