static inline bool8 addCyclesInDMA (uint8 dma_channel) { // Add 8 cycles per byte, sync APU, and do HC related events. // If HDMA was done in S9xDoHEventProcessing(), check if it used the same channel as DMA. ADD_CYCLES(SLOW_ONE_CYCLE); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); if (CPU.HDMARanInDMA & (1 << dma_channel)) { CPU.HDMARanInDMA = 0; #ifdef DEBUGGER printf("HDMA and DMA use the same channel %d!\n", dma_channel); #endif // If HDMA triggers in the middle of DMA transfer and it uses the same channel, // it kills the DMA transfer immediately. $43x2 and $43x5 stop updating. return (FALSE); } CPU.HDMARanInDMA = 0; return (TRUE); }
int get_indexed(struct _memory *memory, struct _table_6809 *table, char *instruction, uint32_t address, int *cycles_min, int *cycles_max) { const char *name[] = { "x", "y", "u", "s" }; uint8_t post_byte = READ_RAM(address); int reg = (post_byte >> 5) & 0x3; if ((post_byte & 0x9f) == 0x84) { // ,R non-indirect sprintf(instruction, "%s ,%s", table->instr, name[reg]); return 0; } else if ((post_byte & 0x9f) == 0x94) { // [,R] indirect sprintf(instruction, "%s [,%s]", table->instr, name[reg]); ADD_CYCLES(3); return 0; } else if ((post_byte & 0x80) == 0x00) { // 5 bit offset, R non-indirect int8_t offset = post_byte & 0x1f; if ((offset & 0x10) != 0) { offset |= 0xe0; } sprintf(instruction, "%s %d,%s", table->instr, offset, name[reg]); ADD_CYCLES(1); return 0; } else if ((post_byte & 0x9f) == 0x88) { // 8 bit offset, R non-indirect int8_t offset = READ_RAM(address + 1); sprintf(instruction, "%s %d,%s", table->instr, offset, name[reg]); ADD_CYCLES(1); return 1; } else if ((post_byte & 0x9f) == 0x98) { // [8 bit offset, R] indirect int8_t offset = READ_RAM(address + 1); sprintf(instruction, "%s [%d,%s]", table->instr, offset, name[reg]); ADD_CYCLES(4); return 1; } else if ((post_byte & 0x9f) == 0x89) { // 16 bit offset, R non-indirect int16_t offset = READ_RAM16(address + 1); sprintf(instruction, "%s %d,%s", table->instr, offset, name[reg]); ADD_CYCLES(4); return 2; } else if ((post_byte & 0x9f) == 0x99) { // [16 bit offset, R] indirect int16_t offset = READ_RAM16(address + 1); sprintf(instruction, "%s [%d,%s]", table->instr, offset, name[reg]); ADD_CYCLES(7); return 2; } else if ((post_byte & 0x9f) == 0x86) { // A,R non-indirect sprintf(instruction, "%s a,%s", table->instr, name[reg]); ADD_CYCLES(1); return 0; } else if ((post_byte & 0x9f) == 0x96) { // [A,R] non-indirect sprintf(instruction, "%s [a,%s]", table->instr, name[reg]); ADD_CYCLES(4); return 0; } else if ((post_byte & 0x9f) == 0x85) { // B,R non-indirect sprintf(instruction, "%s b,%s", table->instr, name[reg]); ADD_CYCLES(1); return 0; } else if ((post_byte & 0x9f) == 0x95) { // [B,R] indirect sprintf(instruction, "%s [b,%s]", table->instr, name[reg]); ADD_CYCLES(4); return 0; } else if ((post_byte & 0x9f) == 0x8b) { // D,R non-indirect sprintf(instruction, "%s d,%s", table->instr, name[reg]); ADD_CYCLES(4); return 0; } else if ((post_byte & 0x9f) == 0x9b) { // [D,R] non-indirect sprintf(instruction, "%s [d,%s]", table->instr, name[reg]); ADD_CYCLES(7); return 0; } else if ((post_byte & 0x9f) == 0x80) { // ,R+ non-indirect sprintf(instruction, "%s ,%s+", table->instr, name[reg]); ADD_CYCLES(2); return 0; } else if ((post_byte & 0x9f) == 0x81) { // ,R++ non-indirect sprintf(instruction, "%s ,%s++", table->instr, name[reg]); ADD_CYCLES(3); return 0; } else if ((post_byte & 0x9f) == 0x91) { // [,R++] indirect sprintf(instruction, "%s [,%s++]", table->instr, name[reg]); ADD_CYCLES(6); return 0; } else if ((post_byte & 0x9f) == 0x82) { // ,-R non-indirect sprintf(instruction, "%s ,-%s", table->instr, name[reg]); ADD_CYCLES(2); return 0; } else if ((post_byte & 0x9f) == 0x83) { // ,--R non-indirect sprintf(instruction, "%s ,--%s", table->instr, name[reg]); ADD_CYCLES(3); return 0; } else if ((post_byte & 0x9f) == 0x93) { // [,--R] indirect sprintf(instruction, "%s [,--%s]", table->instr, name[reg]); ADD_CYCLES(6); return 0; } else if ((post_byte & 0x9f) == 0x8c) { // 8 bit offset, PCR non-indirect int8_t offset = READ_RAM(address + 1); sprintf(instruction, "%s %d,pc", table->instr, offset); ADD_CYCLES(1); return 1; } else if ((post_byte & 0x9f) == 0x9c) { // [8 bit offset, PCR] indirect int8_t offset = READ_RAM(address + 1); sprintf(instruction, "%s [%d,pc]", table->instr, offset); ADD_CYCLES(4); return 1; } else if ((post_byte & 0x9f) == 0x8d) { // 16 bit offset, PCR non-indirect int16_t offset = READ_RAM16(address + 1); sprintf(instruction, "%s %d,pc", table->instr, offset); ADD_CYCLES(5); return 2; } else if ((post_byte & 0x9f) == 0x9d) { // [16 bit offset, PCR] non-indirect int16_t offset = READ_RAM16(address + 1); sprintf(instruction, "%s [%d,pc]", table->instr, offset); ADD_CYCLES(8); return 2; } else if ((post_byte & 0x9f) == 0x9f) { // [16 bit offset] non-indirect int16_t offset = READ_RAM16(address + 1); sprintf(instruction, "%s [0x%04x]", table->instr, offset); ADD_CYCLES(5); return 2; } strcpy(instruction, "???"); return 0; }
bool8 S9xDoDMA (uint8 Channel) { CPU.InDMA = TRUE; CPU.InDMAorHDMA = TRUE; CPU.CurrentDMAorHDMAChannel = Channel; SDMA *d = &DMA[Channel]; // Check invalid DMA first if ((d->ABank == 0x7E || d->ABank == 0x7F) && d->BAddress == 0x80 && !d->ReverseTransfer) { // Attempting a DMA from WRAM to $2180 will not work, WRAM will not be written. // Attempting a DMA from $2180 to WRAM will similarly not work, // the value written is (initially) the OpenBus value. // In either case, the address in $2181-3 is not incremented. // Does an invalid DMA actually take time? // I'd say yes, since 'invalid' is probably just the WRAM chip // not being able to read and write itself at the same time // And no, PPU.WRAM should not be updated. int32 c = d->TransferBytes; // Writing $0000 to $43x5 actually results in a transfer of $10000 bytes, not 0. if (c == 0) c = 0x10000; // 8 cycles per channel ADD_CYCLES(SLOW_ONE_CYCLE); // 8 cycles per byte while (c) { d->TransferBytes--; d->AAddress++; c--; if (!addCyclesInDMA(Channel)) { CPU.InDMA = FALSE; CPU.InDMAorHDMA = FALSE; CPU.CurrentDMAorHDMAChannel = -1; return (FALSE); } } #ifdef DEBUGGER if (Settings.TraceDMA) { sprintf(String, "DMA[%d]: WRAM Bank:%02X->$2180", Channel, d->ABank); S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String); } #endif CPU.InDMA = FALSE; CPU.InDMAorHDMA = FALSE; CPU.CurrentDMAorHDMAChannel = -1; return (TRUE); } // Prepare for accessing $2118-2119 switch (d->BAddress) { case 0x18: case 0x19: if (IPPU.RenderThisFrame) FLUSH_REDRAW(); break; } int32 inc = d->AAddressFixed ? 0 : (!d->AAddressDecrement ? 1 : -1); int32 count = d->TransferBytes; // Writing $0000 to $43x5 actually results in a transfer of $10000 bytes, not 0. if (count == 0) count = 0x10000; // Prepare for custom chip DMA // S-DD1 uint8 *in_sdd1_dma = NULL; if (Settings.SDD1) { if (d->AAddressFixed && Memory.FillRAM[0x4801] > 0) { // XXX: Should probably verify that we're DMAing from ROM? // And somewhere we should make sure we're not running across a mapping boundary too. // Hacky support for pre-decompressed S-DD1 data inc = !d->AAddressDecrement ? 1 : -1; uint8 *in_ptr = S9xGetBasePointer(((d->ABank << 16) | d->AAddress)); if (in_ptr) { in_ptr += d->AAddress; SDD1_decompress(sdd1_decode_buffer, in_ptr, d->TransferBytes); } #ifdef DEBUGGER else { sprintf(String, "S-DD1: DMA from non-block address $%02X:%04X", d->ABank, d->AAddress); S9xMessage(S9X_WARNING, S9X_DMA_TRACE, String); } #endif in_sdd1_dma = sdd1_decode_buffer; } Memory.FillRAM[0x4801] = 0; } // SPC7110 uint8 *spc7110_dma = NULL; if (Settings.SPC7110) { if (d->AAddress == 0x4800 || d->ABank == 0x50) { spc7110_dma = new uint8[d->TransferBytes]; for (int i = 0; i < d->TransferBytes; i++) spc7110_dma[i] = s7emu.decomp.read(); int32 icount = s7emu.r4809 | (s7emu.r480a << 8); icount -= d->TransferBytes; s7emu.r4809 = icount & 0x00ff; s7emu.r480a = (icount & 0xff00) >> 8; inc = 1; d->AAddress -= count; } }