📄 dma.cpp
字号:
/* * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. * * (c) Copyright 1996 - 2001 Gary Henderson (gary@daniver.demon.co.uk) and * Jerremy Koot (jkoot@snes9x.com) * * Super FX C emulator code * (c) Copyright 1997 - 1999 Ivar (Ivar@snes9x.com) and * Gary Henderson. * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. * * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson. * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_. * C4 C code (c) Copyright 2001 Gary Henderson (gary@daniver.demon.co.uk). * * DOS port code contains the works of other authors. See headers in * individual files. * * Snes9x homepage: www.snes9x.com * * Permission to use, copy, modify and distribute Snes9x in both binary and * source form, for non-commercial purposes, is hereby granted without fee, * providing that this license information and copyright notice appear with * all copies and any derived work. * * This software is provided 'as-is', without any express or implied * warranty. In no event shall the authors be held liable for any damages * arising from the use of this software. * * Snes9x is freeware for PERSONAL USE only. Commercial users should * seek permission of the copyright holders first. Commercial use includes * charging money for Snes9x or software derived from Snes9x. * * The copyright holders request that bug fixes and improvements to the code * should be forwarded to them so everyone can benefit from the modifications * in future versions. * * Super NES and Super Nintendo Entertainment System are trademarks of * Nintendo Co., Limited and its subsidiary companies. */#include "snes9x.h"#include "memmap.h"#include "ppu.h"#include "cpuexec.h"#include "missing.h"#include "dma.h"#include "apu.h"#include "gfx.h"#include "sa1.h"extern int HDMA_ModeByteCounts [8];extern uint8 *HDMAMemPointers [8];extern uint8 *HDMABasePointers [8];/**********************************************************************************************//* S9xDoDMA() *//* This function preforms the general dma transfer *//**********************************************************************************************/void S9xDoDMA (uint8 Channel){ uint8 Work; if (Channel > 7 || CPU.InDMA) return; CPU.InDMA = TRUE; bool8 in_sa1_dma = FALSE; SDMA *d = &DMA[Channel]; int count = d->TransferBytes; if (count == 0) count = 0x10000; int inc = d->AAddressFixed ? 0 : (!d->AAddressDecrement ? 1 : -1); switch (d->BAddress) { case 0x18: case 0x19: if (IPPU.RenderThisFrame) FLUSH_REDRAW (); if (Settings.SDD1 && d->AAddressFixed && Memory.BlockIsROM [((d->ABank << 16) + d->AAddress) >> 12]) { inc = !d->AAddressDecrement ? 1 : -1;// if (d->BAddress == 0x18 && Settings.SDD1 && d->AAddressFixed)// {// printf ("%02x%04x, count: %d\n", d->ABank, d->AAddress, d->TransferBytes);#if 0 uint8 *base = GetBasePointer ((d->ABank << 16) + d->AAddress) + d->AAddress; for (int i = 0; i < 16; i++) printf ("%02x ", *base++); printf ("\n");#endif } break; } if (d->BAddress == 0x18 && SA1.in_char_dma && (d->ABank & 0xf0) == 0x40) { // Perform packed bitmap to PPU character format conversion on the // data before transmitting it to V-RAM via-DMA. int num_chars = 1 << ((Memory.FillRAM [0x2231] >> 2) & 7); int depth = (Memory.FillRAM [0x2231] & 3) == 0 ? 8 : (Memory.FillRAM [0x2231] & 3) == 1 ? 4 : 2; int bytes_per_char = 8 * depth; int bytes_per_line = depth * num_chars; int char_line_bytes = bytes_per_char * num_chars; uint32 addr = (d->AAddress / char_line_bytes) * char_line_bytes; uint8 *base = GetBasePointer ((d->ABank << 16) + addr) + addr; uint8 *buffer = &Memory.ROM [CMemory::MAX_ROM_SIZE - 0x10000]; uint8 *p = buffer; uint32 inc = char_line_bytes - (d->AAddress % char_line_bytes); uint32 char_count = inc / bytes_per_char; in_sa1_dma = TRUE; //printf ("%08x,", base); fflush (stdout);//printf ("depth = %d, count = %d, bytes_per_char = %d, bytes_per_line = %d, num_chars = %d, char_line_bytes = %d\n",//depth, count, bytes_per_char, bytes_per_line, num_chars, char_line_bytes); int i; switch (depth) { case 2: 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) * 2; for (uint32 j = 0; j < char_count && p - buffer < count; j++, line += 2) { uint8 *q = line; for (int l = 0; l < 8; l++, q += bytes_per_line) { for (int b = 0; b < 2; b++) { uint8 r = *(q + b); *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1); *(p + 0) = (*(p + 0) << 1) | ((r >> 2) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 3) & 1); *(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1); *(p + 0) = (*(p + 0) << 1) | ((r >> 6) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 7) & 1); } p += 2; } } } break; case 4: 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) * 4; for (uint32 j = 0; j < char_count && p - buffer < count; j++, line += 4) { uint8 *q = line; for (int l = 0; l < 8; l++, q += bytes_per_line) { for (int b = 0; b < 4; 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 + 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) 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) sprintf (String, "%s CGRAM: %02X (%x)", String, PPU.CGADD, PPU.CGFLIP); else if (d->BAddress == 0x04) sprintf (String, "%s OBJADDR: %04X", String, PPU.OAMAddr); S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String); }#endif if (!d->TransferDirection) {#ifdef VAR_CYCLES CPU.Cycles += 8 * count;#else CPU.Cycles += count + (count >> 2);#endif 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 (inc > 0) d->AAddress += count; else if (inc < 0) d->AAddress -= count; if (d->TransferMode == 0 || d->TransferMode == 2) { switch (d->BAddress) { case 0x04: do { Work = *(base + p); REGISTER_2104(Work); p += inc; CHECK_SOUND(); } while (--count > 0); break; case 0x18: IPPU.FirstVRAMRead = TRUE; 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: IPPU.FirstVRAMRead = TRUE; 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 IPPU.FirstVRAMRead = TRUE; 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -