static void cchip_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { TyphoonState *s = opaque; uint64_t oldval, newval; switch (addr) { case 0x0000: /* CSC: Cchip System Configuration Register. */ /* All sorts of data here; nothing relevant RW. */ break; case 0x0040: /* MTR: Memory Timing Register. */ /* All sorts of stuff related to real DRAM. */ break; case 0x0080: /* MISC: Miscellaneous Register. */ newval = oldval = s->cchip.misc; newval &= ~(val & 0x10000ff0); /* W1C fields */ if (val & 0x100000) { newval &= ~0xff0000ull; /* ACL clears ABT and ABW */ } else { newval |= val & 0x00f00000; /* ABT field is W1S */ if ((newval & 0xf0000) == 0) { newval |= val & 0xf0000; /* ABW field is W1S iff zero */ } } newval |= (val & 0xf000) >> 4; /* IPREQ field sets IPINTR. */ newval &= ~0xf0000000000ull; /* WO and RW fields */ newval |= val & 0xf0000000000ull; s->cchip.misc = newval; /* Pass on changes to IPI and ITI state. */ if ((newval ^ oldval) & 0xff0) { int i; for (i = 0; i < 4; ++i) { AlphaCPU *cpu = s->cchip.cpu[i]; if (cpu != NULL) { CPUState *cs = CPU(cpu); /* IPI can be either cleared or set by the write. */ if (newval & (1 << (i + 8))) { cpu_interrupt(cs, CPU_INTERRUPT_SMP); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP); } /* ITI can only be cleared by the write. */ if ((newval & (1 << (i + 4))) == 0) { cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER); } } } } break; case 0x00c0: /* MPD: Memory Presence Detect Register. */ break; case 0x0100: /* AAR0 */ case 0x0140: /* AAR1 */ case 0x0180: /* AAR2 */ case 0x01c0: /* AAR3 */ /* AAR: Array Address Register. */ /* All sorts of information about DRAM. */ break; case 0x0200: /* DIM0 */ /* DIM: Device Interrupt Mask Register, CPU0. */ s->cchip.dim[0] = val; cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir); break; case 0x0240: /* DIM1 */ /* DIM: Device Interrupt Mask Register, CPU1. */ s->cchip.dim[0] = val; cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir); break; case 0x0280: /* DIR0 (RO) */ case 0x02c0: /* DIR1 (RO) */ case 0x0300: /* DRIR (RO) */ break; case 0x0340: /* PRBEN: Probe Enable Register. */ break; case 0x0380: /* IIC0 */ s->cchip.iic[0] = val & 0xffffff; break; case 0x03c0: /* IIC1 */ s->cchip.iic[1] = val & 0xffffff; break; case 0x0400: /* MPR0 */ case 0x0440: /* MPR1 */ case 0x0480: /* MPR2 */ case 0x04c0: /* MPR3 */ /* MPR: Memory Programming Register. */ break; case 0x0580: /* TTR: TIGbus Timing Register. */ /* All sorts of stuff related to interrupt delivery timings. */ break; case 0x05c0: /* TDR: TIGbug Device Timing Register. */ break; case 0x0600: /* DIM2: Device Interrupt Mask Register, CPU2. */ s->cchip.dim[2] = val; cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir); break; case 0x0640: /* DIM3: Device Interrupt Mask Register, CPU3. */ s->cchip.dim[3] = val; cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir); break; case 0x0680: /* DIR2 (RO) */ case 0x06c0: /* DIR3 (RO) */ break; case 0x0700: /* IIC2 */ s->cchip.iic[2] = val & 0xffffff; break; case 0x0740: /* IIC3 */ s->cchip.iic[3] = val & 0xffffff; break; case 0x0780: /* PWR: Power Management Control. */ break; case 0x0c00: /* CMONCTLA */ case 0x0c40: /* CMONCTLB */ case 0x0c80: /* CMONCNT01 */ case 0x0cc0: /* CMONCNT23 */ break; default: cpu_unassigned_access(current_cpu, addr, true, false, 0, size); return; } }