// Writes a word to the PI MMIO register space. int write_pi_regs(void *opaque, uint32_t address, uint32_t word, uint32_t dqm) { struct pi_controller *pi = (struct pi_controller *) opaque; unsigned offset = address - PI_REGS_BASE_ADDRESS; enum pi_register reg = (offset >> 2); debug_mmio_write(pi, pi_register_mnemonics[reg], word, dqm); if (reg == PI_STATUS_REG) { if (word & 0x1) pi->regs[reg] = 0; if (word & 0x2) { clear_rcp_interrupt(pi->bus->vr4300, MI_INTR_PI); pi->regs[reg] &= ~0x8; } } else { pi->regs[reg] &= ~dqm; pi->regs[reg] |= word; if (reg == PI_CART_ADDR_REG) dd_pi_write(pi->bus->dd, word); else if (reg == PI_WR_LEN_REG) { if (pi->regs[PI_DRAM_ADDR_REG] == 0xFFFFFFFF) { pi->regs[PI_STATUS_REG] &= ~0x1; pi->regs[PI_STATUS_REG] |= 0x8; signal_rcp_interrupt(pi->bus->vr4300, MI_INTR_PI); return 0; } pi->bytes_to_copy = (pi->regs[PI_WR_LEN_REG] & 0xFFFFFF) + 1; pi->counter = pi->bytes_to_copy / 2 + 100; // Assume ~2 bytes/clock? pi->regs[PI_STATUS_REG] |= 0x9; // I'm busy! pi->is_dma_read = false; } else if (reg == PI_RD_LEN_REG) { if (pi->regs[PI_DRAM_ADDR_REG] == 0xFFFFFFFF) { pi->regs[PI_STATUS_REG] &= ~0x1; pi->regs[PI_STATUS_REG] |= 0x8; signal_rcp_interrupt(pi->bus->vr4300, MI_INTR_PI); return 0; } pi->bytes_to_copy = (pi->regs[PI_RD_LEN_REG] & 0xFFFFFF) + 1; pi->counter = pi->bytes_to_copy / 2 + 100; // Assume ~2 bytes/clock? pi->regs[PI_STATUS_REG] |= 0x9; // I'm busy! pi->is_dma_read = true; } } return 0; }
// Writes a word to the AI MMIO register space. int write_ai_regs(void *opaque, uint32_t address, uint32_t word, uint32_t dqm) { struct ai_controller *ai = (struct ai_controller *) opaque; unsigned offset = address - AI_REGS_BASE_ADDRESS; enum ai_register reg = (offset >> 2); debug_mmio_write(ai, ai_register_mnemonics[reg], word, dqm); if (reg == AI_DRAM_ADDR_REG) ai->regs[AI_DRAM_ADDR_REG] = word & 0xFFFFF8; else if (reg == AI_LEN_REG) { ai->regs[AI_LEN_REG] = word & 0x3FFF8; if (ai->fifo_count == 2) return 0; // Fill the next FIFO entry in the DMA engine. ai->fifo[ai->fifo_wi].address = ai->regs[AI_DRAM_ADDR_REG]; ai->fifo[ai->fifo_wi].length = ai->regs[AI_LEN_REG]; ai->fifo_wi = (ai->fifo_wi == 1) ? 0 : 1; ai->fifo_count++; if (ai->fifo_count == 2) ai->regs[AI_STATUS_REG] |= 0x80000001U; // If we're not DMA-ing already, start DMA engine. if (!(ai->regs[AI_STATUS_REG] & 0x40000000U)) ai_dma(ai); } else if (reg == AI_STATUS_REG) { struct bus_controller *bus; memcpy(&bus, ai, sizeof(bus)); clear_rcp_interrupt(bus->vr4300, MI_INTR_AI); } else if (reg == AI_DACRATE_REG) { ai->regs[AI_DACRATE_REG] = word & 0x3FFF; ai->ctx.frequency = (double) NTSC_DAC_FREQ / (ai->regs[AI_DACRATE_REG] + 1); } else if (reg == AI_BITRATE_REG) ai->regs[AI_BITRATE_REG] = word & 0xF; else ai->regs[reg] = word; return 0; }
// Writes a word to the MI MMIO register space. int write_mi_regs(void *opaque, uint32_t address, uint32_t word, uint32_t dqm) { struct vr4300 *vr4300 = (struct vr4300 *) opaque; uint32_t offset = address - MI_REGS_BASE_ADDRESS; enum mi_register reg = (offset >> 2); uint32_t result; debug_mmio_write(mi, mi_register_mnemonics[reg], word, dqm); // Change mode settings? if (reg == MI_INIT_MODE_REG) { result = word & 0x3FF; if (word & 0x0080) result &= ~MI_INIT_MODE; else if (word & 0x0100) result |= MI_INIT_MODE; if (word & 0x0200) result &= ~MI_EBUS_TEST_MODE; else if (word & 0x0400) result |= MI_EBUS_TEST_MODE; if (word & 0x0800) { vr4300->mi_regs[MI_INTR_REG] &= ~MI_INTR_DP; check_for_interrupts(vr4300); // TODO/FIXME: ??? } if (word & 0x1000) result &= ~MI_RDRAM_REG_MODE; else if (word & 0x2000) result |= MI_RDRAM_REG_MODE; vr4300->mi_regs[MI_INIT_MODE_REG] = result; } // Change interrupt mask? else if (reg == MI_INTR_MASK_REG) { if (word & 0x0001) vr4300->mi_regs[MI_INTR_MASK_REG] &= ~MI_INTR_SP; else if (word & 0x0002) vr4300->mi_regs[MI_INTR_MASK_REG] |= MI_INTR_SP; if (word & 0x0004) vr4300->mi_regs[MI_INTR_MASK_REG] &= ~MI_INTR_SI; else if (word & 0x0008) vr4300->mi_regs[MI_INTR_MASK_REG] |= MI_INTR_SI; if (word & 0x0010) vr4300->mi_regs[MI_INTR_MASK_REG] &= ~MI_INTR_AI; else if (word & 0x0020) vr4300->mi_regs[MI_INTR_MASK_REG] |= MI_INTR_AI; if (word & 0x0040) vr4300->mi_regs[MI_INTR_MASK_REG] &= ~MI_INTR_VI; else if (word & 0x0080) vr4300->mi_regs[MI_INTR_MASK_REG] |= MI_INTR_VI; if (word & 0x0100) vr4300->mi_regs[MI_INTR_MASK_REG] &= ~MI_INTR_PI; else if (word & 0x0200) vr4300->mi_regs[MI_INTR_MASK_REG] |= MI_INTR_PI; if (word & 0x0400) vr4300->mi_regs[MI_INTR_MASK_REG] &= ~MI_INTR_DP; else if (word & 0x0800) vr4300->mi_regs[MI_INTR_MASK_REG] |= MI_INTR_DP; check_for_interrupts(vr4300); // TODO/FIXME: ??? } else { vr4300->mi_regs[reg] &= ~dqm; vr4300->mi_regs[reg] |= word; } return 0; }