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