root / hw / alpha_typhoon.c @ a8170e5e
History | View | Annotate | Download (23.3 kB)
1 |
/*
|
---|---|
2 |
* DEC 21272 (TSUNAMI/TYPHOON) chipset emulation.
|
3 |
*
|
4 |
* Written by Richard Henderson.
|
5 |
*
|
6 |
* This work is licensed under the GNU GPL license version 2 or later.
|
7 |
*/
|
8 |
|
9 |
#include "cpu.h" |
10 |
#include "exec-all.h" |
11 |
#include "hw.h" |
12 |
#include "devices.h" |
13 |
#include "sysemu.h" |
14 |
#include "alpha_sys.h" |
15 |
#include "exec-memory.h" |
16 |
|
17 |
|
18 |
#define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost" |
19 |
|
20 |
typedef struct TyphoonCchip { |
21 |
MemoryRegion region; |
22 |
uint64_t misc; |
23 |
uint64_t drir; |
24 |
uint64_t dim[4];
|
25 |
uint32_t iic[4];
|
26 |
CPUAlphaState *cpu[4];
|
27 |
} TyphoonCchip; |
28 |
|
29 |
typedef struct TyphoonWindow { |
30 |
uint32_t base_addr; |
31 |
uint32_t mask; |
32 |
uint32_t translated_base_pfn; |
33 |
} TyphoonWindow; |
34 |
|
35 |
typedef struct TyphoonPchip { |
36 |
MemoryRegion region; |
37 |
MemoryRegion reg_iack; |
38 |
MemoryRegion reg_mem; |
39 |
MemoryRegion reg_io; |
40 |
MemoryRegion reg_conf; |
41 |
uint64_t ctl; |
42 |
TyphoonWindow win[4];
|
43 |
} TyphoonPchip; |
44 |
|
45 |
#define TYPHOON_PCI_HOST_BRIDGE(obj) \
|
46 |
OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE) |
47 |
|
48 |
typedef struct TyphoonState { |
49 |
PCIHostState parent_obj; |
50 |
|
51 |
TyphoonCchip cchip; |
52 |
TyphoonPchip pchip; |
53 |
MemoryRegion dchip_region; |
54 |
MemoryRegion ram_region; |
55 |
|
56 |
/* QEMU emulation state. */
|
57 |
uint32_t latch_tmp; |
58 |
} TyphoonState; |
59 |
|
60 |
/* Called when one of DRIR or DIM changes. */
|
61 |
static void cpu_irq_change(CPUAlphaState *env, uint64_t req) |
62 |
{ |
63 |
/* If there are any non-masked interrupts, tell the cpu. */
|
64 |
if (env) {
|
65 |
if (req) {
|
66 |
cpu_interrupt(env, CPU_INTERRUPT_HARD); |
67 |
} else {
|
68 |
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); |
69 |
} |
70 |
} |
71 |
} |
72 |
|
73 |
static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size) |
74 |
{ |
75 |
CPUAlphaState *env = cpu_single_env; |
76 |
TyphoonState *s = opaque; |
77 |
uint64_t ret = 0;
|
78 |
|
79 |
if (addr & 4) { |
80 |
return s->latch_tmp;
|
81 |
} |
82 |
|
83 |
switch (addr) {
|
84 |
case 0x0000: |
85 |
/* CSC: Cchip System Configuration Register. */
|
86 |
/* All sorts of data here; probably the only thing relevant is
|
87 |
PIP<14> Pchip 1 Present = 0. */
|
88 |
break;
|
89 |
|
90 |
case 0x0040: |
91 |
/* MTR: Memory Timing Register. */
|
92 |
/* All sorts of stuff related to real DRAM. */
|
93 |
break;
|
94 |
|
95 |
case 0x0080: |
96 |
/* MISC: Miscellaneous Register. */
|
97 |
ret = s->cchip.misc | (env->cpu_index & 3);
|
98 |
break;
|
99 |
|
100 |
case 0x00c0: |
101 |
/* MPD: Memory Presence Detect Register. */
|
102 |
break;
|
103 |
|
104 |
case 0x0100: /* AAR0 */ |
105 |
case 0x0140: /* AAR1 */ |
106 |
case 0x0180: /* AAR2 */ |
107 |
case 0x01c0: /* AAR3 */ |
108 |
/* AAR: Array Address Register. */
|
109 |
/* All sorts of information about DRAM. */
|
110 |
break;
|
111 |
|
112 |
case 0x0200: |
113 |
/* DIM0: Device Interrupt Mask Register, CPU0. */
|
114 |
ret = s->cchip.dim[0];
|
115 |
break;
|
116 |
case 0x0240: |
117 |
/* DIM1: Device Interrupt Mask Register, CPU1. */
|
118 |
ret = s->cchip.dim[1];
|
119 |
break;
|
120 |
case 0x0280: |
121 |
/* DIR0: Device Interrupt Request Register, CPU0. */
|
122 |
ret = s->cchip.dim[0] & s->cchip.drir;
|
123 |
break;
|
124 |
case 0x02c0: |
125 |
/* DIR1: Device Interrupt Request Register, CPU1. */
|
126 |
ret = s->cchip.dim[1] & s->cchip.drir;
|
127 |
break;
|
128 |
case 0x0300: |
129 |
/* DRIR: Device Raw Interrupt Request Register. */
|
130 |
ret = s->cchip.drir; |
131 |
break;
|
132 |
|
133 |
case 0x0340: |
134 |
/* PRBEN: Probe Enable Register. */
|
135 |
break;
|
136 |
|
137 |
case 0x0380: |
138 |
/* IIC0: Interval Ignore Count Register, CPU0. */
|
139 |
ret = s->cchip.iic[0];
|
140 |
break;
|
141 |
case 0x03c0: |
142 |
/* IIC1: Interval Ignore Count Register, CPU1. */
|
143 |
ret = s->cchip.iic[1];
|
144 |
break;
|
145 |
|
146 |
case 0x0400: /* MPR0 */ |
147 |
case 0x0440: /* MPR1 */ |
148 |
case 0x0480: /* MPR2 */ |
149 |
case 0x04c0: /* MPR3 */ |
150 |
/* MPR: Memory Programming Register. */
|
151 |
break;
|
152 |
|
153 |
case 0x0580: |
154 |
/* TTR: TIGbus Timing Register. */
|
155 |
/* All sorts of stuff related to interrupt delivery timings. */
|
156 |
break;
|
157 |
case 0x05c0: |
158 |
/* TDR: TIGbug Device Timing Register. */
|
159 |
break;
|
160 |
|
161 |
case 0x0600: |
162 |
/* DIM2: Device Interrupt Mask Register, CPU2. */
|
163 |
ret = s->cchip.dim[2];
|
164 |
break;
|
165 |
case 0x0640: |
166 |
/* DIM3: Device Interrupt Mask Register, CPU3. */
|
167 |
ret = s->cchip.dim[3];
|
168 |
break;
|
169 |
case 0x0680: |
170 |
/* DIR2: Device Interrupt Request Register, CPU2. */
|
171 |
ret = s->cchip.dim[2] & s->cchip.drir;
|
172 |
break;
|
173 |
case 0x06c0: |
174 |
/* DIR3: Device Interrupt Request Register, CPU3. */
|
175 |
ret = s->cchip.dim[3] & s->cchip.drir;
|
176 |
break;
|
177 |
|
178 |
case 0x0700: |
179 |
/* IIC2: Interval Ignore Count Register, CPU2. */
|
180 |
ret = s->cchip.iic[2];
|
181 |
break;
|
182 |
case 0x0740: |
183 |
/* IIC3: Interval Ignore Count Register, CPU3. */
|
184 |
ret = s->cchip.iic[3];
|
185 |
break;
|
186 |
|
187 |
case 0x0780: |
188 |
/* PWR: Power Management Control. */
|
189 |
break;
|
190 |
|
191 |
case 0x0c00: /* CMONCTLA */ |
192 |
case 0x0c40: /* CMONCTLB */ |
193 |
case 0x0c80: /* CMONCNT01 */ |
194 |
case 0x0cc0: /* CMONCNT23 */ |
195 |
break;
|
196 |
|
197 |
default:
|
198 |
cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size); |
199 |
return -1; |
200 |
} |
201 |
|
202 |
s->latch_tmp = ret >> 32;
|
203 |
return ret;
|
204 |
} |
205 |
|
206 |
static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size) |
207 |
{ |
208 |
/* Skip this. It's all related to DRAM timing and setup. */
|
209 |
return 0; |
210 |
} |
211 |
|
212 |
static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size) |
213 |
{ |
214 |
TyphoonState *s = opaque; |
215 |
uint64_t ret = 0;
|
216 |
|
217 |
if (addr & 4) { |
218 |
return s->latch_tmp;
|
219 |
} |
220 |
|
221 |
switch (addr) {
|
222 |
case 0x0000: |
223 |
/* WSBA0: Window Space Base Address Register. */
|
224 |
ret = s->pchip.win[0].base_addr;
|
225 |
break;
|
226 |
case 0x0040: |
227 |
/* WSBA1 */
|
228 |
ret = s->pchip.win[1].base_addr;
|
229 |
break;
|
230 |
case 0x0080: |
231 |
/* WSBA2 */
|
232 |
ret = s->pchip.win[2].base_addr;
|
233 |
break;
|
234 |
case 0x00c0: |
235 |
/* WSBA3 */
|
236 |
ret = s->pchip.win[3].base_addr;
|
237 |
break;
|
238 |
|
239 |
case 0x0100: |
240 |
/* WSM0: Window Space Mask Register. */
|
241 |
ret = s->pchip.win[0].mask;
|
242 |
break;
|
243 |
case 0x0140: |
244 |
/* WSM1 */
|
245 |
ret = s->pchip.win[1].mask;
|
246 |
break;
|
247 |
case 0x0180: |
248 |
/* WSM2 */
|
249 |
ret = s->pchip.win[2].mask;
|
250 |
break;
|
251 |
case 0x01c0: |
252 |
/* WSM3 */
|
253 |
ret = s->pchip.win[3].mask;
|
254 |
break;
|
255 |
|
256 |
case 0x0200: |
257 |
/* TBA0: Translated Base Address Register. */
|
258 |
ret = (uint64_t)s->pchip.win[0].translated_base_pfn << 10; |
259 |
break;
|
260 |
case 0x0240: |
261 |
/* TBA1 */
|
262 |
ret = (uint64_t)s->pchip.win[1].translated_base_pfn << 10; |
263 |
break;
|
264 |
case 0x0280: |
265 |
/* TBA2 */
|
266 |
ret = (uint64_t)s->pchip.win[2].translated_base_pfn << 10; |
267 |
break;
|
268 |
case 0x02c0: |
269 |
/* TBA3 */
|
270 |
ret = (uint64_t)s->pchip.win[3].translated_base_pfn << 10; |
271 |
break;
|
272 |
|
273 |
case 0x0300: |
274 |
/* PCTL: Pchip Control Register. */
|
275 |
ret = s->pchip.ctl; |
276 |
break;
|
277 |
case 0x0340: |
278 |
/* PLAT: Pchip Master Latency Register. */
|
279 |
break;
|
280 |
case 0x03c0: |
281 |
/* PERROR: Pchip Error Register. */
|
282 |
break;
|
283 |
case 0x0400: |
284 |
/* PERRMASK: Pchip Error Mask Register. */
|
285 |
break;
|
286 |
case 0x0440: |
287 |
/* PERRSET: Pchip Error Set Register. */
|
288 |
break;
|
289 |
case 0x0480: |
290 |
/* TLBIV: Translation Buffer Invalidate Virtual Register (WO). */
|
291 |
break;
|
292 |
case 0x04c0: |
293 |
/* TLBIA: Translation Buffer Invalidate All Register (WO). */
|
294 |
break;
|
295 |
case 0x0500: /* PMONCTL */ |
296 |
case 0x0540: /* PMONCNT */ |
297 |
case 0x0800: /* SPRST */ |
298 |
break;
|
299 |
|
300 |
default:
|
301 |
cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size); |
302 |
return -1; |
303 |
} |
304 |
|
305 |
s->latch_tmp = ret >> 32;
|
306 |
return ret;
|
307 |
} |
308 |
|
309 |
static void cchip_write(void *opaque, hwaddr addr, |
310 |
uint64_t v32, unsigned size)
|
311 |
{ |
312 |
TyphoonState *s = opaque; |
313 |
uint64_t val, oldval, newval; |
314 |
|
315 |
if (addr & 4) { |
316 |
val = v32 << 32 | s->latch_tmp;
|
317 |
addr ^= 4;
|
318 |
} else {
|
319 |
s->latch_tmp = v32; |
320 |
return;
|
321 |
} |
322 |
|
323 |
switch (addr) {
|
324 |
case 0x0000: |
325 |
/* CSC: Cchip System Configuration Register. */
|
326 |
/* All sorts of data here; nothing relevant RW. */
|
327 |
break;
|
328 |
|
329 |
case 0x0040: |
330 |
/* MTR: Memory Timing Register. */
|
331 |
/* All sorts of stuff related to real DRAM. */
|
332 |
break;
|
333 |
|
334 |
case 0x0080: |
335 |
/* MISC: Miscellaneous Register. */
|
336 |
newval = oldval = s->cchip.misc; |
337 |
newval &= ~(val & 0x10000ff0); /* W1C fields */ |
338 |
if (val & 0x100000) { |
339 |
newval &= ~0xff0000ull; /* ACL clears ABT and ABW */ |
340 |
} else {
|
341 |
newval |= val & 0x00f00000; /* ABT field is W1S */ |
342 |
if ((newval & 0xf0000) == 0) { |
343 |
newval |= val & 0xf0000; /* ABW field is W1S iff zero */ |
344 |
} |
345 |
} |
346 |
newval |= (val & 0xf000) >> 4; /* IPREQ field sets IPINTR. */ |
347 |
|
348 |
newval &= ~0xf0000000000ull; /* WO and RW fields */ |
349 |
newval |= val & 0xf0000000000ull;
|
350 |
s->cchip.misc = newval; |
351 |
|
352 |
/* Pass on changes to IPI and ITI state. */
|
353 |
if ((newval ^ oldval) & 0xff0) { |
354 |
int i;
|
355 |
for (i = 0; i < 4; ++i) { |
356 |
CPUAlphaState *env = s->cchip.cpu[i]; |
357 |
if (env) {
|
358 |
/* IPI can be either cleared or set by the write. */
|
359 |
if (newval & (1 << (i + 8))) { |
360 |
cpu_interrupt(env, CPU_INTERRUPT_SMP); |
361 |
} else {
|
362 |
cpu_reset_interrupt(env, CPU_INTERRUPT_SMP); |
363 |
} |
364 |
|
365 |
/* ITI can only be cleared by the write. */
|
366 |
if ((newval & (1 << (i + 4))) == 0) { |
367 |
cpu_reset_interrupt(env, CPU_INTERRUPT_TIMER); |
368 |
} |
369 |
} |
370 |
} |
371 |
} |
372 |
break;
|
373 |
|
374 |
case 0x00c0: |
375 |
/* MPD: Memory Presence Detect Register. */
|
376 |
break;
|
377 |
|
378 |
case 0x0100: /* AAR0 */ |
379 |
case 0x0140: /* AAR1 */ |
380 |
case 0x0180: /* AAR2 */ |
381 |
case 0x01c0: /* AAR3 */ |
382 |
/* AAR: Array Address Register. */
|
383 |
/* All sorts of information about DRAM. */
|
384 |
break;
|
385 |
|
386 |
case 0x0200: /* DIM0 */ |
387 |
/* DIM: Device Interrupt Mask Register, CPU0. */
|
388 |
s->cchip.dim[0] = val;
|
389 |
cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
|
390 |
break;
|
391 |
case 0x0240: /* DIM1 */ |
392 |
/* DIM: Device Interrupt Mask Register, CPU1. */
|
393 |
s->cchip.dim[0] = val;
|
394 |
cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
|
395 |
break;
|
396 |
|
397 |
case 0x0280: /* DIR0 (RO) */ |
398 |
case 0x02c0: /* DIR1 (RO) */ |
399 |
case 0x0300: /* DRIR (RO) */ |
400 |
break;
|
401 |
|
402 |
case 0x0340: |
403 |
/* PRBEN: Probe Enable Register. */
|
404 |
break;
|
405 |
|
406 |
case 0x0380: /* IIC0 */ |
407 |
s->cchip.iic[0] = val & 0xffffff; |
408 |
break;
|
409 |
case 0x03c0: /* IIC1 */ |
410 |
s->cchip.iic[1] = val & 0xffffff; |
411 |
break;
|
412 |
|
413 |
case 0x0400: /* MPR0 */ |
414 |
case 0x0440: /* MPR1 */ |
415 |
case 0x0480: /* MPR2 */ |
416 |
case 0x04c0: /* MPR3 */ |
417 |
/* MPR: Memory Programming Register. */
|
418 |
break;
|
419 |
|
420 |
case 0x0580: |
421 |
/* TTR: TIGbus Timing Register. */
|
422 |
/* All sorts of stuff related to interrupt delivery timings. */
|
423 |
break;
|
424 |
case 0x05c0: |
425 |
/* TDR: TIGbug Device Timing Register. */
|
426 |
break;
|
427 |
|
428 |
case 0x0600: |
429 |
/* DIM2: Device Interrupt Mask Register, CPU2. */
|
430 |
s->cchip.dim[2] = val;
|
431 |
cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
|
432 |
break;
|
433 |
case 0x0640: |
434 |
/* DIM3: Device Interrupt Mask Register, CPU3. */
|
435 |
s->cchip.dim[3] = val;
|
436 |
cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
|
437 |
break;
|
438 |
|
439 |
case 0x0680: /* DIR2 (RO) */ |
440 |
case 0x06c0: /* DIR3 (RO) */ |
441 |
break;
|
442 |
|
443 |
case 0x0700: /* IIC2 */ |
444 |
s->cchip.iic[2] = val & 0xffffff; |
445 |
break;
|
446 |
case 0x0740: /* IIC3 */ |
447 |
s->cchip.iic[3] = val & 0xffffff; |
448 |
break;
|
449 |
|
450 |
case 0x0780: |
451 |
/* PWR: Power Management Control. */
|
452 |
break;
|
453 |
|
454 |
case 0x0c00: /* CMONCTLA */ |
455 |
case 0x0c40: /* CMONCTLB */ |
456 |
case 0x0c80: /* CMONCNT01 */ |
457 |
case 0x0cc0: /* CMONCNT23 */ |
458 |
break;
|
459 |
|
460 |
default:
|
461 |
cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size); |
462 |
return;
|
463 |
} |
464 |
} |
465 |
|
466 |
static void dchip_write(void *opaque, hwaddr addr, |
467 |
uint64_t val, unsigned size)
|
468 |
{ |
469 |
/* Skip this. It's all related to DRAM timing and setup. */
|
470 |
} |
471 |
|
472 |
static void pchip_write(void *opaque, hwaddr addr, |
473 |
uint64_t v32, unsigned size)
|
474 |
{ |
475 |
TyphoonState *s = opaque; |
476 |
uint64_t val, oldval; |
477 |
|
478 |
if (addr & 4) { |
479 |
val = v32 << 32 | s->latch_tmp;
|
480 |
addr ^= 4;
|
481 |
} else {
|
482 |
s->latch_tmp = v32; |
483 |
return;
|
484 |
} |
485 |
|
486 |
switch (addr) {
|
487 |
case 0x0000: |
488 |
/* WSBA0: Window Space Base Address Register. */
|
489 |
s->pchip.win[0].base_addr = val;
|
490 |
break;
|
491 |
case 0x0040: |
492 |
/* WSBA1 */
|
493 |
s->pchip.win[1].base_addr = val;
|
494 |
break;
|
495 |
case 0x0080: |
496 |
/* WSBA2 */
|
497 |
s->pchip.win[2].base_addr = val;
|
498 |
break;
|
499 |
case 0x00c0: |
500 |
/* WSBA3 */
|
501 |
s->pchip.win[3].base_addr = val;
|
502 |
break;
|
503 |
|
504 |
case 0x0100: |
505 |
/* WSM0: Window Space Mask Register. */
|
506 |
s->pchip.win[0].mask = val;
|
507 |
break;
|
508 |
case 0x0140: |
509 |
/* WSM1 */
|
510 |
s->pchip.win[1].mask = val;
|
511 |
break;
|
512 |
case 0x0180: |
513 |
/* WSM2 */
|
514 |
s->pchip.win[2].mask = val;
|
515 |
break;
|
516 |
case 0x01c0: |
517 |
/* WSM3 */
|
518 |
s->pchip.win[3].mask = val;
|
519 |
break;
|
520 |
|
521 |
case 0x0200: |
522 |
/* TBA0: Translated Base Address Register. */
|
523 |
s->pchip.win[0].translated_base_pfn = val >> 10; |
524 |
break;
|
525 |
case 0x0240: |
526 |
/* TBA1 */
|
527 |
s->pchip.win[1].translated_base_pfn = val >> 10; |
528 |
break;
|
529 |
case 0x0280: |
530 |
/* TBA2 */
|
531 |
s->pchip.win[2].translated_base_pfn = val >> 10; |
532 |
break;
|
533 |
case 0x02c0: |
534 |
/* TBA3 */
|
535 |
s->pchip.win[3].translated_base_pfn = val >> 10; |
536 |
break;
|
537 |
|
538 |
case 0x0300: |
539 |
/* PCTL: Pchip Control Register. */
|
540 |
oldval = s->pchip.ctl; |
541 |
oldval &= ~0x00001cff0fc7ffull; /* RW fields */ |
542 |
oldval |= val & 0x00001cff0fc7ffull;
|
543 |
|
544 |
s->pchip.ctl = oldval; |
545 |
break;
|
546 |
|
547 |
case 0x0340: |
548 |
/* PLAT: Pchip Master Latency Register. */
|
549 |
break;
|
550 |
case 0x03c0: |
551 |
/* PERROR: Pchip Error Register. */
|
552 |
break;
|
553 |
case 0x0400: |
554 |
/* PERRMASK: Pchip Error Mask Register. */
|
555 |
break;
|
556 |
case 0x0440: |
557 |
/* PERRSET: Pchip Error Set Register. */
|
558 |
break;
|
559 |
|
560 |
case 0x0480: |
561 |
/* TLBIV: Translation Buffer Invalidate Virtual Register. */
|
562 |
break;
|
563 |
|
564 |
case 0x04c0: |
565 |
/* TLBIA: Translation Buffer Invalidate All Register (WO). */
|
566 |
break;
|
567 |
|
568 |
case 0x0500: |
569 |
/* PMONCTL */
|
570 |
case 0x0540: |
571 |
/* PMONCNT */
|
572 |
case 0x0800: |
573 |
/* SPRST */
|
574 |
break;
|
575 |
|
576 |
default:
|
577 |
cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size); |
578 |
return;
|
579 |
} |
580 |
} |
581 |
|
582 |
static const MemoryRegionOps cchip_ops = { |
583 |
.read = cchip_read, |
584 |
.write = cchip_write, |
585 |
.endianness = DEVICE_LITTLE_ENDIAN, |
586 |
.valid = { |
587 |
.min_access_size = 4, /* ??? Should be 8. */ |
588 |
.max_access_size = 8,
|
589 |
}, |
590 |
.impl = { |
591 |
.min_access_size = 4,
|
592 |
.max_access_size = 4,
|
593 |
}, |
594 |
}; |
595 |
|
596 |
static const MemoryRegionOps dchip_ops = { |
597 |
.read = dchip_read, |
598 |
.write = dchip_write, |
599 |
.endianness = DEVICE_LITTLE_ENDIAN, |
600 |
.valid = { |
601 |
.min_access_size = 4, /* ??? Should be 8. */ |
602 |
.max_access_size = 8,
|
603 |
}, |
604 |
.impl = { |
605 |
.min_access_size = 4,
|
606 |
.max_access_size = 8,
|
607 |
}, |
608 |
}; |
609 |
|
610 |
static const MemoryRegionOps pchip_ops = { |
611 |
.read = pchip_read, |
612 |
.write = pchip_write, |
613 |
.endianness = DEVICE_LITTLE_ENDIAN, |
614 |
.valid = { |
615 |
.min_access_size = 4, /* ??? Should be 8. */ |
616 |
.max_access_size = 8,
|
617 |
}, |
618 |
.impl = { |
619 |
.min_access_size = 4,
|
620 |
.max_access_size = 4,
|
621 |
}, |
622 |
}; |
623 |
|
624 |
static void typhoon_set_irq(void *opaque, int irq, int level) |
625 |
{ |
626 |
TyphoonState *s = opaque; |
627 |
uint64_t drir; |
628 |
int i;
|
629 |
|
630 |
/* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL. */
|
631 |
drir = s->cchip.drir; |
632 |
if (level) {
|
633 |
drir |= 1ull << irq;
|
634 |
} else {
|
635 |
drir &= ~(1ull << irq);
|
636 |
} |
637 |
s->cchip.drir = drir; |
638 |
|
639 |
for (i = 0; i < 4; ++i) { |
640 |
cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir); |
641 |
} |
642 |
} |
643 |
|
644 |
static void typhoon_set_isa_irq(void *opaque, int irq, int level) |
645 |
{ |
646 |
typhoon_set_irq(opaque, 55, level);
|
647 |
} |
648 |
|
649 |
static void typhoon_set_timer_irq(void *opaque, int irq, int level) |
650 |
{ |
651 |
TyphoonState *s = opaque; |
652 |
int i;
|
653 |
|
654 |
/* Thankfully, the mc146818rtc code doesn't track the IRQ state,
|
655 |
and so we don't have to worry about missing interrupts just
|
656 |
because we never actually ACK the interrupt. Just ignore any
|
657 |
case of the interrupt level going low. */
|
658 |
if (level == 0) { |
659 |
return;
|
660 |
} |
661 |
|
662 |
/* Deliver the interrupt to each CPU, considering each CPU's IIC. */
|
663 |
for (i = 0; i < 4; ++i) { |
664 |
CPUAlphaState *env = s->cchip.cpu[i]; |
665 |
if (env) {
|
666 |
uint32_t iic = s->cchip.iic[i]; |
667 |
|
668 |
/* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
|
669 |
Bit 24 is the OverFlow bit, RO, and set when the count
|
670 |
decrements past 0. When is OF cleared? My guess is that
|
671 |
OF is actually cleared when the IIC is written, and that
|
672 |
the ICNT field always decrements. At least, that's an
|
673 |
interpretation that makes sense, and "allows the CPU to
|
674 |
determine exactly how mant interval timer ticks were
|
675 |
skipped". At least within the next 4M ticks... */
|
676 |
|
677 |
iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000); |
678 |
s->cchip.iic[i] = iic; |
679 |
|
680 |
if (iic & 0x1000000) { |
681 |
/* Set the ITI bit for this cpu. */
|
682 |
s->cchip.misc |= 1 << (i + 4); |
683 |
/* And signal the interrupt. */
|
684 |
cpu_interrupt(env, CPU_INTERRUPT_TIMER); |
685 |
} |
686 |
} |
687 |
} |
688 |
} |
689 |
|
690 |
static void typhoon_alarm_timer(void *opaque) |
691 |
{ |
692 |
TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
|
693 |
int cpu = (uintptr_t)opaque & 3; |
694 |
|
695 |
/* Set the ITI bit for this cpu. */
|
696 |
s->cchip.misc |= 1 << (cpu + 4); |
697 |
cpu_interrupt(s->cchip.cpu[cpu], CPU_INTERRUPT_TIMER); |
698 |
} |
699 |
|
700 |
PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, |
701 |
qemu_irq *p_rtc_irq, |
702 |
CPUAlphaState *cpus[4], pci_map_irq_fn sys_map_irq)
|
703 |
{ |
704 |
const uint64_t MB = 1024 * 1024; |
705 |
const uint64_t GB = 1024 * MB; |
706 |
MemoryRegion *addr_space = get_system_memory(); |
707 |
MemoryRegion *addr_space_io = get_system_io(); |
708 |
DeviceState *dev; |
709 |
TyphoonState *s; |
710 |
PCIHostState *phb; |
711 |
PCIBus *b; |
712 |
int i;
|
713 |
|
714 |
dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE);
|
715 |
qdev_init_nofail(dev); |
716 |
|
717 |
s = TYPHOON_PCI_HOST_BRIDGE(dev); |
718 |
phb = PCI_HOST_BRIDGE(dev); |
719 |
|
720 |
/* Remember the CPUs so that we can deliver interrupts to them. */
|
721 |
for (i = 0; i < 4; i++) { |
722 |
CPUAlphaState *env = cpus[i]; |
723 |
s->cchip.cpu[i] = env; |
724 |
if (env) {
|
725 |
env->alarm_timer = qemu_new_timer_ns(rtc_clock, |
726 |
typhoon_alarm_timer, |
727 |
(void *)((uintptr_t)s + i));
|
728 |
} |
729 |
} |
730 |
|
731 |
*p_rtc_irq = *qemu_allocate_irqs(typhoon_set_timer_irq, s, 1);
|
732 |
|
733 |
/* Main memory region, 0x00.0000.0000. Real hardware supports 32GB,
|
734 |
but the address space hole reserved at this point is 8TB. */
|
735 |
memory_region_init_ram(&s->ram_region, "ram", ram_size);
|
736 |
vmstate_register_ram_global(&s->ram_region); |
737 |
memory_region_add_subregion(addr_space, 0, &s->ram_region);
|
738 |
|
739 |
/* TIGbus, 0x801.0000.0000, 1GB. */
|
740 |
/* ??? The TIGbus is used for delivering interrupts, and access to
|
741 |
the flash ROM. I'm not sure that we need to implement it at all. */
|
742 |
|
743 |
/* Pchip0 CSRs, 0x801.8000.0000, 256MB. */
|
744 |
memory_region_init_io(&s->pchip.region, &pchip_ops, s, "pchip0", 256*MB); |
745 |
memory_region_add_subregion(addr_space, 0x80180000000ULL,
|
746 |
&s->pchip.region); |
747 |
|
748 |
/* Cchip CSRs, 0x801.A000.0000, 256MB. */
|
749 |
memory_region_init_io(&s->cchip.region, &cchip_ops, s, "cchip0", 256*MB); |
750 |
memory_region_add_subregion(addr_space, 0x801a0000000ULL,
|
751 |
&s->cchip.region); |
752 |
|
753 |
/* Dchip CSRs, 0x801.B000.0000, 256MB. */
|
754 |
memory_region_init_io(&s->dchip_region, &dchip_ops, s, "dchip0", 256*MB); |
755 |
memory_region_add_subregion(addr_space, 0x801b0000000ULL,
|
756 |
&s->dchip_region); |
757 |
|
758 |
/* Pchip0 PCI memory, 0x800.0000.0000, 4GB. */
|
759 |
memory_region_init(&s->pchip.reg_mem, "pci0-mem", 4*GB); |
760 |
memory_region_add_subregion(addr_space, 0x80000000000ULL,
|
761 |
&s->pchip.reg_mem); |
762 |
|
763 |
/* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB. */
|
764 |
/* ??? Ideally we drop the "system" i/o space on the floor and give the
|
765 |
PCI subsystem the full address space reserved by the chipset.
|
766 |
We can't do that until the MEM and IO paths in memory.c are unified. */
|
767 |
memory_region_init_io(&s->pchip.reg_io, &alpha_pci_bw_io_ops, NULL,
|
768 |
"pci0-io", 32*MB); |
769 |
memory_region_add_subregion(addr_space, 0x801fc000000ULL,
|
770 |
&s->pchip.reg_io); |
771 |
|
772 |
b = pci_register_bus(dev, "pci",
|
773 |
typhoon_set_irq, sys_map_irq, s, |
774 |
&s->pchip.reg_mem, addr_space_io, 0, 64); |
775 |
phb->bus = b; |
776 |
|
777 |
/* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */
|
778 |
memory_region_init_io(&s->pchip.reg_iack, &alpha_pci_iack_ops, b, |
779 |
"pci0-iack", 64*MB); |
780 |
memory_region_add_subregion(addr_space, 0x801f8000000ULL,
|
781 |
&s->pchip.reg_iack); |
782 |
|
783 |
/* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB. */
|
784 |
memory_region_init_io(&s->pchip.reg_conf, &alpha_pci_conf1_ops, b, |
785 |
"pci0-conf", 16*MB); |
786 |
memory_region_add_subregion(addr_space, 0x801fe000000ULL,
|
787 |
&s->pchip.reg_conf); |
788 |
|
789 |
/* For the record, these are the mappings for the second PCI bus.
|
790 |
We can get away with not implementing them because we indicate
|
791 |
via the Cchip.CSC<PIP> bit that Pchip1 is not present. */
|
792 |
/* Pchip1 PCI memory, 0x802.0000.0000, 4GB. */
|
793 |
/* Pchip1 CSRs, 0x802.8000.0000, 256MB. */
|
794 |
/* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB. */
|
795 |
/* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB. */
|
796 |
/* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB. */
|
797 |
|
798 |
/* Init the ISA bus. */
|
799 |
/* ??? Technically there should be a cy82c693ub pci-isa bridge. */
|
800 |
{ |
801 |
qemu_irq isa_pci_irq, *isa_irqs; |
802 |
|
803 |
*isa_bus = isa_bus_new(NULL, addr_space_io);
|
804 |
isa_pci_irq = *qemu_allocate_irqs(typhoon_set_isa_irq, s, 1);
|
805 |
isa_irqs = i8259_init(*isa_bus, isa_pci_irq); |
806 |
isa_bus_irqs(*isa_bus, isa_irqs); |
807 |
} |
808 |
|
809 |
return b;
|
810 |
} |
811 |
|
812 |
static int typhoon_pcihost_init(SysBusDevice *dev) |
813 |
{ |
814 |
return 0; |
815 |
} |
816 |
|
817 |
static void typhoon_pcihost_class_init(ObjectClass *klass, void *data) |
818 |
{ |
819 |
DeviceClass *dc = DEVICE_CLASS(klass); |
820 |
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
821 |
|
822 |
k->init = typhoon_pcihost_init; |
823 |
dc->no_user = 1;
|
824 |
} |
825 |
|
826 |
static const TypeInfo typhoon_pcihost_info = { |
827 |
.name = TYPE_TYPHOON_PCI_HOST_BRIDGE, |
828 |
.parent = TYPE_PCI_HOST_BRIDGE, |
829 |
.instance_size = sizeof(TyphoonState),
|
830 |
.class_init = typhoon_pcihost_class_init, |
831 |
}; |
832 |
|
833 |
static void typhoon_register_types(void) |
834 |
{ |
835 |
type_register_static(&typhoon_pcihost_info); |
836 |
} |
837 |
|
838 |
type_init(typhoon_register_types) |