// 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; }
static void dma_si_read(struct si_controller* si) { int i; if (si->regs[SI_PIF_ADDR_RD64B_REG] != 0x1FC007C0) { DebugMessage(M64MSG_ERROR, "dma_si_read(): unknown SI use"); return; } update_pif_read(si); for (i = 0; i < PIF_RAM_SIZE; i += 4) { si->ri->rdram.dram[(si->regs[SI_DRAM_ADDR_REG]+i)/4] = sl(*(uint32_t*)(&si->pif.ram[i])); } cp0_update_count(); if (g_delay_si) { add_interupt_event(SI_INT, /*0x100*/0x900); } else { si->regs[SI_STATUS_REG] |= 0x1000; // INTERRUPT signal_rcp_interrupt(si->r4300, MI_INTR_SI); } }
static void dma_si_write(struct si_controller* si) { int i; if (si->regs[SI_PIF_ADDR_WR64B_REG] != 0x1FC007C0) { DebugMessage(si->r4300->state, M64MSG_ERROR, "dma_si_write(): unknown SI use"); si->r4300->state->stop=1; } for (i = 0; i < PIF_RAM_SIZE; i += 4) { *((uint32_t*)(&si->pif.ram[i])) = sl(si->ri->rdram.dram[(si->regs[SI_DRAM_ADDR_REG]+i)/4]); } if (si->r4300->state->enable_trimming_mode) { for (i = 0; i < PIF_RAM_SIZE; i += 4) { unsigned int ram_address = si->regs[SI_DRAM_ADDR_REG] + i; if (!bit_array_test(si->r4300->state->barray_ram_written_first, ram_address / 4)) bit_array_set(si->r4300->state->barray_ram_read, ram_address / 4); } } update_pif_write(si); update_count(si->r4300->state); if (si->r4300->state->g_delay_si) { add_interupt_event(si->r4300->state, SI_INT, /*0x100*/0x900); } else { si->regs[SI_STATUS_REG] |= 0x1000; // INTERRUPT signal_rcp_interrupt(si->r4300, MI_INTR_SI); } }
int write_dpc_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct rdp_core* dp = (struct rdp_core*)opaque; uint32_t reg = dpc_reg(address); switch(reg) { case DPC_STATUS_REG: if (update_dpc_status(dp, value & mask) != 0) do_SP_Task(dp->sp); case DPC_CURRENT_REG: case DPC_CLOCK_REG: case DPC_BUFBUSY_REG: case DPC_PIPEBUSY_REG: case DPC_TMEM_REG: return 0; } masked_write(&dp->dpc_regs[reg], value, mask); switch(reg) { case DPC_START_REG: dp->dpc_regs[DPC_CURRENT_REG] = dp->dpc_regs[DPC_START_REG]; break; case DPC_END_REG: gfx.processRDPList(); signal_rcp_interrupt(dp->r4300, MI_INTR_DP); break; } return 0; }
void sp_set_status(UINT32 status) { if (status & 0x1) { cpunum_set_input_line(1, INPUT_LINE_HALT, ASSERT_LINE); rsp_sp_status |= SP_STATUS_HALT; } if (status & 0x2) { rsp_sp_status |= SP_STATUS_BROKE; if (rsp_sp_status & SP_STATUS_INT_ON_BRK) { signal_rcp_interrupt(SP_INTERRUPT); } } }
// Advances the controller by one clock cycle. void ai_cycle(struct ai_controller *ai) { if (likely(ai->counter-- != 0)) return; // DMA engine is finishing up with one entry. if (ai->fifo_count > 0) { struct bus_controller *bus; memcpy(&bus, ai, sizeof(bus)); signal_rcp_interrupt(bus->vr4300, MI_INTR_AI); ai->fifo_ri = (ai->fifo_ri == 1) ? 0 : 1; ai->regs[AI_STATUS_REG] &= ~0xC0000001; ai->counter = 0xFFFFFFFFU; ai->fifo_count--; if (ai->fifo_count > 0) ai_dma(ai); } }
static void sp_set_status(UINT32 status) { if (status & 0x1) { //cpu_trigger(6789); cpunum_set_input_line(1, INPUT_LINE_HALT, ASSERT_LINE); cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_HALT); //rsp_sp_status |= SP_STATUS_HALT; } if (status & 0x2) { //rsp_sp_status |= SP_STATUS_BROKE; cpunum_set_info_int(1, CPUINFO_INT_REGISTER + RSP_SR, cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) | RSP_STATUS_BROKE); if (cpunum_get_info_int(1, CPUINFO_INT_REGISTER + RSP_SR) & RSP_STATUS_INTR_BREAK) { signal_rcp_interrupt(SP_INTERRUPT); } } }
// Advances the controller by one clock cycle. void pi_cycle_(struct pi_controller *pi) { // DMA engine is finishing up with one entry. if (pi->bytes_to_copy > 0) { uint32_t bytes = pi->bytes_to_copy; // XXX: Defer actual movement of bytes until... now. // This is a giant hack; bytes should be DMA'd slowly. // Also, why the heck does the OR do? I know the & // clears the busy bit, but... pi->is_dma_read ? pi_dma_read(pi) : pi_dma_write(pi); pi->regs[PI_DRAM_ADDR_REG] += bytes; pi->regs[PI_CART_ADDR_REG] += bytes; pi->regs[PI_STATUS_REG] &= ~0x1; pi->regs[PI_STATUS_REG] |= 0x8; signal_rcp_interrupt(pi->bus->vr4300, MI_INTR_PI); pi->bytes_to_copy = 0; return; } }
static INTERRUPT_GEN( n64_vblank ) { signal_rcp_interrupt(device->machine, VI_INTERRUPT); }
// Performs an (instantaneous) DMA. void ai_dma(struct ai_controller *ai) { struct bus_controller *bus; // Shove things into the audio context, slide the window. memcpy(&bus, ai, sizeof(bus)); // Need to raise an interrupt when the DMA engine // is doing the last 8-byte data bus transfer... if (likely(ai->fifo[ai->fifo_ri].length > 0)) { unsigned freq = (double) NTSC_DAC_FREQ / (ai->regs[AI_DACRATE_REG] + 1); unsigned samples = ai->fifo[ai->fifo_ri].length / 4;// - 1; // Shovel things into the audio context. uint8_t buf[0x40000]; unsigned i; ALuint buffer; ALint val; alGetSourcei(ai->ctx.source, AL_BUFFERS_PROCESSED, &val); if (val) { for (i = 0; i < ai->fifo[ai->fifo_ri].length / 4; i++) { uint32_t word; // Byteswap audio buffer to native format. // TODO: Can we specify endian-ness somehow? memcpy(&word, bus->ri->ram + (ai->fifo[ ai->fifo_ri].address + sizeof(word) * i), sizeof(word)); word = byteswap_32(word); memcpy(buf + sizeof(word) * i, &word, sizeof(word)); } alSourceUnqueueBuffers(ai->ctx.source, 1, &buffer); alBufferData(buffer, AL_FORMAT_STEREO16, buf, ai->fifo[ai->fifo_ri].length, 44100 /* ai->ctx.frequency */); alSourceQueueBuffers(ai->ctx.source, 1, &buffer); alGetSourcei(ai->ctx.source, AL_SOURCE_STATE, &val); if(val != AL_PLAYING) alSourcePlay(ai->ctx.source); if (alGetError() != AL_NO_ERROR) { fprintf(stderr, "OpenAL is angry!\n"); exit(255); } } ai->counter = (62500000.0 / freq) * samples; //printf("Wait %lu cycles to raise interrupt.\n", ai->counter); } // If the length was zero, just interrupt now? else { signal_rcp_interrupt(bus->vr4300, MI_INTR_AI); ai->fifo_ri = (ai->fifo_ri == 1) ? 0 : 1; ai->regs[AI_STATUS_REG] &= ~0x80000001; ai->counter = 0xFFFFFFFFU; ai->fifo_count--; } if (ai->fifo_count > 0) ai->regs[AI_STATUS_REG] |= 0x40000000; }
static void update_sp_status(struct rsp_core* sp, uint32_t w) { /* clear / set halt */ if (w & 0x1) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_HALT; if (w & 0x2) sp->regs[SP_STATUS_REG] |= SP_STATUS_HALT; /* clear broke */ if (w & 0x4) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_BROKE; /* clear SP interrupt */ if (w & 0x8) { clear_rcp_interrupt(sp->r4300, MI_INTR_SP); } /* set SP interrupt */ if (w & 0x10) { signal_rcp_interrupt(sp->r4300, MI_INTR_SP); } /* clear / set single step */ if (w & 0x20) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SSTEP; if (w & 0x40) sp->regs[SP_STATUS_REG] |= SP_STATUS_SSTEP; /* clear / set interrupt on break */ if (w & 0x80) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_INTR_BREAK; if (w & 0x100) sp->regs[SP_STATUS_REG] |= SP_STATUS_INTR_BREAK; /* clear / set signal 0 */ if (w & 0x200) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG0; if (w & 0x400) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG0; /* clear / set signal 1 */ if (w & 0x800) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG1; if (w & 0x1000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG1; /* clear / set signal 2 */ if (w & 0x2000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG2; if (w & 0x4000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG2; /* clear / set signal 3 */ if (w & 0x8000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG3; if (w & 0x10000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG3; /* clear / set signal 4 */ if (w & 0x20000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG4; if (w & 0x40000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG4; /* clear / set signal 5 */ if (w & 0x80000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG5; if (w & 0x100000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG5; /* clear / set signal 6 */ if (w & 0x200000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG6; if (w & 0x400000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG6; /* clear / set signal 7 */ if (w & 0x800000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG7; if (w & 0x1000000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG7; //if (get_event(SP_INT)) return; if (!(w & 0x1) && !(w & 0x4)) return; if (!(sp->regs[SP_STATUS_REG] & (SP_STATUS_HALT | SP_STATUS_BROKE))) do_SP_Task(sp); }
static INTERRUPT_GEN( n64_vblank ) { signal_rcp_interrupt(VI_INTERRUPT); }
static void update_sp_status(struct rsp_core* sp, uint32_t w) { /* clear / set halt */ if (w & 0x1) sp->regs[SP_STATUS_REG] &= ~0x1; if (w & 0x2) sp->regs[SP_STATUS_REG] |= 0x1; /* clear broke */ if (w & 0x4) sp->regs[SP_STATUS_REG] &= ~0x2; /* clear SP interrupt */ if (w & 0x8) { clear_rcp_interrupt(sp->r4300, MI_INTR_SP); } /* set SP interrupt */ if (w & 0x10) { signal_rcp_interrupt(sp->r4300, MI_INTR_SP); } /* clear / set single step */ if (w & 0x20) sp->regs[SP_STATUS_REG] &= ~0x20; if (w & 0x40) sp->regs[SP_STATUS_REG] |= 0x20; /* clear / set interrupt on break */ if (w & 0x80) sp->regs[SP_STATUS_REG] &= ~0x40; if (w & 0x100) sp->regs[SP_STATUS_REG] |= 0x40; /* clear / set signal 0 */ if (w & 0x200) sp->regs[SP_STATUS_REG] &= ~0x80; if (w & 0x400) sp->regs[SP_STATUS_REG] |= 0x80; /* clear / set signal 1 */ if (w & 0x800) sp->regs[SP_STATUS_REG] &= ~0x100; if (w & 0x1000) sp->regs[SP_STATUS_REG] |= 0x100; /* clear / set signal 2 */ if (w & 0x2000) sp->regs[SP_STATUS_REG] &= ~0x200; if (w & 0x4000) sp->regs[SP_STATUS_REG] |= 0x200; /* clear / set signal 3 */ if (w & 0x8000) sp->regs[SP_STATUS_REG] &= ~0x400; if (w & 0x10000) sp->regs[SP_STATUS_REG] |= 0x400; /* clear / set signal 4 */ if (w & 0x20000) sp->regs[SP_STATUS_REG] &= ~0x800; if (w & 0x40000) sp->regs[SP_STATUS_REG] |= 0x800; /* clear / set signal 5 */ if (w & 0x80000) sp->regs[SP_STATUS_REG] &= ~0x1000; if (w & 0x100000) sp->regs[SP_STATUS_REG] |= 0x1000; /* clear / set signal 6 */ if (w & 0x200000) sp->regs[SP_STATUS_REG] &= ~0x2000; if (w & 0x400000) sp->regs[SP_STATUS_REG] |= 0x2000; /* clear / set signal 7 */ if (w & 0x800000) sp->regs[SP_STATUS_REG] &= ~0x4000; if (w & 0x1000000) sp->regs[SP_STATUS_REG] |= 0x4000; //if (get_event(SP_INT)) return; if (!(w & 0x1) && !(w & 0x4)) return; if (!(sp->regs[SP_STATUS_REG] & 0x3)) // !halt && !broke do_SP_Task(sp); }