📄 dma.cpp
字号:
*(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1); *(p + 16) = (*(p + 16) << 1) | ((r >> 6) & 1); *(p + 17) = (*(p + 17) << 1) | ((r >> 7) & 1); } p += 2; } p += 32 - 16; } } break; case 8: for (i = 0; i < count; i += inc, base += char_line_bytes, inc = char_line_bytes, char_count = num_chars) { uint8 *line = base + (num_chars - char_count) * 8; for (uint32 j = 0; j < char_count && p - buffer < count; j++, line += 8) { uint8 *q = line; for (int l = 0; l < 8; l++, q += bytes_per_line) { for (int b = 0; b < 8; b++) { uint8 r = *(q + b); *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1); *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1); *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1); *(p + 32) = (*(p + 32) << 1) | ((r >> 4) & 1); *(p + 33) = (*(p + 33) << 1) | ((r >> 5) & 1); *(p + 48) = (*(p + 48) << 1) | ((r >> 6) & 1); *(p + 49) = (*(p + 49) << 1) | ((r >> 7) & 1); } p += 2; } p += 64 - 16; } } break; } } #ifdef DEBUGGER if (Settings.TraceDMA) { sprintf (String, "DMA[%d]: %s Mode: %d 0x%02X%04X->0x21%02X Bytes: %d (%s) V-Line:%ld", Channel, d->TransferDirection ? "read" : "write", d->TransferMode, d->ABank, d->AAddress, d->BAddress, d->TransferBytes, d->AAddressFixed ? "fixed" : (d->AAddressDecrement ? "dec" : "inc"), CPU.V_Counter); if (d->BAddress == 0x18 || d->BAddress == 0x19 || d->BAddress == 0x39 || d->BAddress == 0x3a) sprintf (String, "%s VRAM: %04X (%d,%d) %s", String, PPU.VMA.Address, PPU.VMA.Increment, PPU.VMA.FullGraphicCount, PPU.VMA.High ? "word" : "byte"); else if (d->BAddress == 0x22 || d->BAddress == 0x3b) sprintf (String, "%s CGRAM: %02X (%x)", String, PPU.CGADD, PPU.CGFLIP); else if (d->BAddress == 0x04 || d->BAddress == 0x38) sprintf (String, "%s OBJADDR: %04X", String, PPU.OAMAddr); S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String); }#endif if (!d->TransferDirection) { /* XXX: DMA is potentially broken here for cases where we DMA across * XXX: memmap boundries. A possible solution would be to re-call * XXX: GetBasePointer whenever we cross a boundry, and when * XXX: GetBasePointer returns (0) to take the 'slow path' and use * XXX: S9xGetByte instead of *base. GetBasePointer() would want to * XXX: return (0) for MAP_PPU and whatever else is a register range * XXX: rather than a RAM/ROM block, and we'd want to detect MAP_PPU * XXX: (or specifically, Address Bus B addresses $2100-$21FF in * XXX: banks $00-$3F) specially and treat it as MAP_NONE (since * XXX: PPU->PPU transfers don't work). */ //reflects extra cycle used by DMA CPU.Cycles += SLOW_ONE_CYCLE * (count+1); S9xUpdateAPUTimer(); uint8 *base = GetBasePointer ((d->ABank << 16) + d->AAddress); uint16 p = d->AAddress; if (!base) base = Memory.ROM; if (in_sa1_dma) { base = &Memory.ROM [CMemory::MAX_ROM_SIZE - 0x10000]; p = 0; } if (in_sdd1_dma) { base = in_sdd1_dma; p = 0; } if(spc7110_dma) { base=spc7110_dma; p = 0; } if (inc > 0) d->AAddress += count; else if (inc < 0) d->AAddress -= count; if (d->TransferMode == 0 || d->TransferMode == 2 || d->TransferMode == 6) { switch (d->BAddress) { case 0x04: do { Work = *(base + p); REGISTER_2104(Work); p += inc; CHECK_SOUND(); } while (--count > 0); break; case 0x18:#ifndef CORRECT_VRAM_READS IPPU.FirstVRAMRead = TRUE;#endif if (!PPU.VMA.FullGraphicCount) { do { Work = *(base + p); REGISTER_2118_linear(Work); p += inc; CHECK_SOUND(); } while (--count > 0); } else { do { Work = *(base + p); REGISTER_2118_tile(Work); p += inc; CHECK_SOUND(); } while (--count > 0); } break; case 0x19:#ifndef CORRECT_VRAM_READS IPPU.FirstVRAMRead = TRUE;#endif if (!PPU.VMA.FullGraphicCount) { do { Work = *(base + p); REGISTER_2119_linear(Work); p += inc; CHECK_SOUND(); } while (--count > 0); } else { do { Work = *(base + p); REGISTER_2119_tile(Work); p += inc; CHECK_SOUND(); } while (--count > 0); } break; case 0x22: do { Work = *(base + p); REGISTER_2122(Work); p += inc; CHECK_SOUND(); } while (--count > 0); break; case 0x80: do { Work = *(base + p); REGISTER_2180(Work); p += inc; CHECK_SOUND(); } while (--count > 0); break; default: do { Work = *(base + p); S9xSetPPU (Work, 0x2100 + d->BAddress); p += inc; CHECK_SOUND(); } while (--count > 0); break; } } else if (d->TransferMode == 1 || d->TransferMode == 5) { if (d->BAddress == 0x18) { // Write to V-RAM#ifndef CORRECT_VRAM_READS IPPU.FirstVRAMRead = TRUE;#endif if (!PPU.VMA.FullGraphicCount) { while (count > 1) { Work = *(base + p); REGISTER_2118_linear(Work); p += inc; Work = *(base + p); REGISTER_2119_linear(Work); p += inc; CHECK_SOUND(); count -= 2; } if (count == 1) { Work = *(base + p); REGISTER_2118_linear(Work); p += inc; } } else { while (count > 1) { Work = *(base + p); REGISTER_2118_tile(Work); p += inc; Work = *(base + p); REGISTER_2119_tile(Work); p += inc; CHECK_SOUND(); count -= 2; } if (count == 1) { Work = *(base + p); REGISTER_2118_tile(Work); p += inc; } } } else { // DMA mode 1 general case while (count > 1) { Work = *(base + p); S9xSetPPU (Work, 0x2100 + d->BAddress); p += inc; Work = *(base + p); S9xSetPPU (Work, 0x2101 + d->BAddress); p += inc; CHECK_SOUND(); count -= 2; } if (count == 1) { Work = *(base + p); S9xSetPPU (Work, 0x2100 + d->BAddress); p += inc; } } } else if (d->TransferMode == 3 || d->TransferMode == 7) { do { Work = *(base + p); S9xSetPPU (Work, 0x2100 + d->BAddress); p += inc; if (count <= 1) break; Work = *(base + p); S9xSetPPU (Work, 0x2100 + d->BAddress); p += inc; if (count <= 2) break; Work = *(base + p); S9xSetPPU (Work, 0x2101 + d->BAddress); p += inc; if (count <= 3) break; Work = *(base + p); S9xSetPPU (Work, 0x2101 + d->BAddress); p += inc; CHECK_SOUND(); count -= 4; } while (count > 0); } else if (d->TransferMode == 4) { do { Work = *(base + p); S9xSetPPU (Work, 0x2100 + d->BAddress); p += inc; if (count <= 1) break; Work = *(base + p); S9xSetPPU (Work, 0x2101 + d->BAddress); p += inc; if (count <= 2) break; Work = *(base + p); S9xSetPPU (Work, 0x2102 + d->BAddress); p += inc; if (count <= 3) break; Work = *(base + p); S9xSetPPU (Work, 0x2103 + d->BAddress); p += inc; CHECK_SOUND(); count -= 4; } while (count > 0); } else {#ifdef DEBUGGER // if (Settings.TraceDMA) { sprintf (String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel); S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String); }#endif } } else { /* XXX: DMA is potentially broken here for cases where the dest is * XXX: in the Address Bus B range. Note that this bad dest may not * XXX: cover the whole range of the DMA though, if we transfer * XXX: 65536 bytes only 256 of them may be Address Bus B. */ do { switch (d->TransferMode) { case 0: case 2: case 6: Work = S9xGetPPU (0x2100 + d->BAddress); S9xSetByte (Work, (d->ABank << 16) + d->AAddress); d->AAddress += inc; --count; break; case 1: case 5: Work = S9xGetPPU (0x2100 + d->BAddress); S9xSetByte (Work, (d->ABank << 16) + d->AAddress); d->AAddress += inc; if (!--count) break; Work = S9xGetPPU (0x2101 + d->BAddress); S9xSetByte (Work, (d->ABank << 16) + d->AAddress); d->AAddress += inc; count--; break; case 3: case 7: Work = S9xGetPPU (0x2100 + d->BAddress); S9xSetByte (Work, (d->ABank << 16) + d->AAddress); d->AAddress += inc; if (!--count) break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -