const char* reios_locate_ip() { if (libGDR_GetDiscType() == GdRom) { base_fad = 45150; descrambl = false; } else { u8 ses[6]; libGDR_GetSessionInfo(ses, 0); libGDR_GetSessionInfo(ses, ses[2]); base_fad = (ses[3] << 16) | (ses[4] << 8) | (ses[5] << 0); descrambl = true; } printf("reios: loading ip.bin from FAD: %d\n", base_fad); libGDR_ReadSector(GetMemPtr(0x8c008000, 0), base_fad, 16, 2048); memset(reios_bootfile, 0, sizeof(reios_bootfile)); memcpy(reios_bootfile, GetMemPtr(0x8c008060, 0), 16); printf("reios: bootfile is '%s'\n", reios_bootfile); for (int i = 15; i >= 0; i--) { if (reios_bootfile[i] != ' ') break; reios_bootfile[i] = 0; } return reios_bootfile; }
// Core 1 Input is "CDDA mode" - Source audio data is 32 bits. // PS2 note: Very! few PS2 games use this mode. Some PSX games used it, however no // *known* PS2 game does since it was likely only available if the game was recorded to CD // media (ie, not available in DVD mode, which almost all PS2 games use). Plus PS2 games // generally prefer to use ADPCM streaming audio since they need as much storage space as // possible for FMVs and high-def textures. // StereoOut32 V_Core::ReadInput_HiFi() { InputPosRead &= ~1; // //#ifdef PCM24_S1_INTERLEAVE // StereoOut32 retval( // *((s32*)(ADMATempBuffer+(InputPosRead<<1))), // *((s32*)(ADMATempBuffer+(InputPosRead<<1)+2)) // ); //#else // StereoOut32 retval( // (s32&)(ADMATempBuffer[InputPosRead]), // (s32&)(ADMATempBuffer[InputPosRead+0x200]) // ); //#endif StereoOut32 retval( (s32&)(*GetMemPtr(0x2000 + (Index<<10) + InputPosRead)), (s32&)(*GetMemPtr(0x2200 + (Index<<10) + InputPosRead)) ); if( Index == 1 ) { // CDDA Mode: // give 30 bit data (SndOut downsamples the rest of the way) // HACKFIX: 28 bits seems better according to rama. I should take some time and do some // bitcounting on this one. --air retval.Left >>= 4; retval.Right >>= 4; }
bool reios_locate_bootfile(const char* bootfile) { u32 data_len = 2048 * 1024; u8* temp = new u8[data_len]; libGDR_ReadSector(temp, base_fad + 16, 1, 2048); if (memcmp(temp, "\001CD001\001", 7) == 0) { printf("reios: iso9660 PVD found\n"); u32 lba = read_u32bi(&temp[156 + 2]); //make sure to use big endian u32 len = read_u32bi(&temp[156 + 10]); //make sure to use big endian data_len = ((len + 2047) / 2048) *2048; printf("reios: iso9660 root_directory, FAD: %d, len: %d\n", 150 + lba, data_len); libGDR_ReadSector(temp, 150 + lba, data_len/2048, 2048); } else { libGDR_ReadSector(temp, base_fad + 16, data_len / 2048, 2048); } for (int i = 0; i < (data_len-20); i++) { if (memcmp(temp+i, bootfile, strlen(bootfile)) == 0) { printf("Found %s at %06X\n", bootfile, i); u32 lba = read_u32bi(&temp[i - 33 + 2]); //make sure to use big endian u32 len = read_u32bi(&temp[i - 33 + 10]); //make sure to use big endian printf("filename len: %d\n", temp[i - 1]); printf("file LBA: %d\n", lba); printf("file LEN: %d\n", len); if (descrambl) descrambl_file(lba + 150, len, GetMemPtr(0x8c010000, 0)); else libGDR_ReadSector(GetMemPtr(0x8c010000, 0), lba + 150, (len + 2047) / 2048, 2048); #if 0 if (false) { FILE* f = fopen("z:\\1stboot.bin", "wb"); fwrite(GetMemPtr(0x8c010000, 0), 1, len, f); fclose(f); } #endif delete[] temp; bootfile_inited = true; return true; } } delete[] temp; return false; }
void reios_boot() { //setup syscalls //find boot file //boot it memset(GetMemPtr(0x8C000000, 0), 0xFF, 64 * 1024); setup_syscall(hook_addr(&reios_sys_system), dc_bios_syscall_system); setup_syscall(hook_addr(&reios_sys_font), dc_bios_syscall_font); setup_syscall(hook_addr(&reios_sys_flashrom), dc_bios_syscall_flashrom); setup_syscall(hook_addr(&reios_sys_gd), dc_bios_syscall_gd); setup_syscall(hook_addr(&reios_sys_misc), dc_bios_syscall_misc); WriteMem32(dc_bios_entrypoint_gd_do_bioscall, REIOS_OPCODE); //Infinitive loop for arm ! WriteMem32(0x80800000, 0xEAFFFFFE); if (settings.reios.ElfFile.size()) { if (!reios_loadElf(settings.reios.ElfFile)) { msgboxf("Failed to open %s\n", MBX_ICONERROR, settings.reios.ElfFile.c_str()); } reios_setup_state(0x8C010000); } else { const char* bootfile = reios_locate_ip(); if (!bootfile || !reios_locate_bootfile(bootfile)) msgboxf("Failed to locate bootfile", MBX_ICONERROR); reios_setup_state(0xac008300); } }
bool reios_init(u8* rom, u8* flash) { printf("reios: Init\n"); biosrom = rom; flashrom = flash; memset(rom, 0xEA, 2048 * 1024); memset(GetMemPtr(0x8C000000, 0), 0, RAM_SIZE); u16* rom16 = (u16*)rom; rom16[0] = REIOS_OPCODE; register_hook(0xA0000000, reios_boot); register_hook(0x8C001000, reios_sys_system); register_hook(0x8C001002, reios_sys_font); register_hook(0x8C001004, reios_sys_flashrom); register_hook(0x8C001006, reios_sys_gd); register_hook(0x8C001008, reios_sys_misc); register_hook(dc_bios_entrypoint_gd_do_bioscall, &gd_do_bioscall); return true; }
static void reios_boot(void) { printf("-----------------\n"); printf("REIOS: Booting up\n"); printf("-----------------\n"); //setup syscalls //find boot file //boot it memset(GetMemPtr(0x8C000000, 0), 0xFF, 64 * 1024); setup_syscall(hook_addr(&reios_sys_system), dc_bios_syscall_system); setup_syscall(hook_addr(&reios_sys_font), dc_bios_syscall_font); setup_syscall(hook_addr(&reios_sys_flashrom), dc_bios_syscall_flashrom); setup_syscall(hook_addr(&reios_sys_gd), dc_bios_syscall_gd); setup_syscall(hook_addr(&reios_sys_misc), dc_bios_syscall_misc); WriteMem32(dc_bios_entrypoint_gd_do_bioscall, REIOS_OPCODE); //Infinitive loop for arm ! WriteMem32(0x80800000, 0xEAFFFFFE); if (settings.reios.ElfFile.size()) { if (!reios_loadElf(settings.reios.ElfFile)) msgboxf("Failed to open %s\n", MBX_ICONERROR, settings.reios.ElfFile.c_str()); reios_setup_state(0x8C010000); } else { if (DC_PLATFORM == DC_PLATFORM_DREAMCAST) { if (!bootfile_inited) msgboxf("Failed to locate bootfile", MBX_ICONERROR); reios_setup_state(0xac008300); } else { verify(DC_PLATFORM == DC_PLATFORM_NAOMI); u32* sz = (u32*)naomi_cart_GetPtr(0x368, 4); if (!sz) { msgboxf("Naomi boot failure", MBX_ICONERROR); } int size = *sz; verify(size < RAM_SIZE && naomi_cart_GetPtr(size - 1, 1) && "Invalid cart size"); WriteMemBlock_nommu_ptr(0x0c020000, (u32*)naomi_cart_GetPtr(0, size), size); reios_setuo_naomi(0x0c021000); } } }
void V_Core::AutoDMAReadBuffer(int mode) //mode: 0= split stereo; 1 = do not split stereo { #ifndef ENABLE_NEW_IOPDMA_SPU2 int spos = ((InputPosRead+0xff)&0x100); //starting position of the free buffer LogAutoDMA( Index ? ADMA7LogFile : ADMA4LogFile ); // HACKFIX!! DMAPtr can be invalid after a savestate load, so the savestate just forces it // to NULL and we ignore it here. (used to work in old VM editions of PCSX2 with fixed // addressing, but new PCSX2s have dynamic memory addressing). if(mode) { if( DMAPtr != NULL ) //memcpy((ADMATempBuffer+(spos<<1)),DMAPtr+InputDataProgress,0x400); memcpy(GetMemPtr(0x2000+(Index<<10)+spos),DMAPtr+InputDataProgress,0x400); MADR+=0x400; InputDataLeft-=0x200; InputDataProgress+=0x200; } else { if( DMAPtr != NULL ) //memcpy((ADMATempBuffer+spos),DMAPtr+InputDataProgress,0x200); memcpy(GetMemPtr(0x2000+(Index<<10)+spos),DMAPtr+InputDataProgress,0x200); MADR+=0x200; InputDataLeft-=0x100; InputDataProgress+=0x100; if( DMAPtr != NULL ) //memcpy((ADMATempBuffer+spos+0x200),DMAPtr+InputDataProgress,0x200); memcpy(GetMemPtr(0x2200+(Index<<10)+spos),DMAPtr+InputDataProgress,0x200); MADR+=0x200; InputDataLeft-=0x100; InputDataProgress+=0x100; } // See ReadInput at mixer.cpp for explanation on the commented out lines // #endif }
bool reios_loadElf(const string& elf) { FILE* f = fopen(elf.c_str(), "rb"); if (!f) { return false; } fseek(f, 0, SEEK_END); size_t size = ftell(f); if (size > 16 * 1024 * 1024) { return false; } void* elfFile = malloc(size); memset(elfFile, 0, size); fseek(f, 0, SEEK_SET); fread(elfFile, 1, size, f); fclose(f); int i; bool phys = false; if (elf_checkFile(elfFile) != 0) { free(elfFile); return false; } for (i = 0; i < elf_getNumProgramHeaders(elfFile); i++) { /* Load that section */ uint64_t dest, src; size_t len; if (phys) { dest = elf_getProgramHeaderPaddr(elfFile, i); } else { dest = elf_getProgramHeaderVaddr(elfFile, i); } len = elf_getProgramHeaderFileSize(elfFile, i); src = (uint64_t)(uintptr_t)elfFile + elf_getProgramHeaderOffset(elfFile, i); u8* ptr = GetMemPtr(dest, len); memcpy((void*)ptr, (void*)(uintptr_t)src, len); ptr += len; memset((void*)ptr, 0, elf_getProgramHeaderMemorySize(elfFile, i) - len); } return true; }
// writes a signed value to the SPU2 ram // Invalidates the ADPCM cache in the process. __forceinline void spu2M_Write( u32 addr, s16 value ) { // Make sure the cache is invalidated: // (note to self : addr address WORDs, not bytes) addr &= 0xfffff; if( addr >= SPU2_DYN_MEMLINE ) { const int cacheIdx = addr / pcm_WordsPerBlock; pcm_cache_data[cacheIdx].Validated = false; if(MsgToConsole()) ConLog( "* SPU2-X: PcmCache Block Clear at 0x%x (cacheIdx=0x%x)\n", addr, cacheIdx); } *GetMemPtr( addr ) = value; }
const char* reios_locate_ip(void) { char ip_bin[256]; if (libGDR_GetDiscType() == GdRom) { base_fad = 45150; descrambl = false; } else { u8 ses[6]; libGDR_GetSessionInfo(ses, 0); libGDR_GetSessionInfo(ses, ses[2]); base_fad = (ses[3] << 16) | (ses[4] << 8) | (ses[5] << 0); descrambl = true; } libGDR_ReadSector(GetMemPtr(0x8c008000, 0), base_fad, 256, 2048); memset(ip_bin, 0, sizeof(ip_bin)); memcpy(ip_bin, GetMemPtr(0x8c008000, 0), 256); memcpy(&reios_hardware_id[0], &ip_bin[0], 16 * sizeof(char)); memcpy(&reios_maker_id[0], &ip_bin[16], 16 * sizeof(char)); memcpy(&reios_device_info[0], &ip_bin[32], 16 * sizeof(char)); memcpy(&reios_area_symbols[0], &ip_bin[48], 8 * sizeof(char)); memcpy(&reios_peripherals[0], &ip_bin[56], 8 * sizeof(char)); memcpy(&reios_product_number[0], &ip_bin[64], 10 * sizeof(char)); memcpy(&reios_product_version[0], &ip_bin[74], 6 * sizeof(char)); memcpy(&reios_releasedate[0], &ip_bin[80], 16 * sizeof(char)); memcpy(&reios_boot_filename[0], &ip_bin[96], 16 * sizeof(char)); memcpy(&reios_software_company[0], &ip_bin[112], 16 * sizeof(char)); memcpy(&reios_software_name[0], &ip_bin[128], 128 * sizeof(char)); printf("reios: IP.bin is '%s'\n", ip_bin); printf("reios: Hardware ID is: %s\n", reios_hardware_id); printf("reios: Maker ID is: %s\n", reios_maker_id); printf("reios: Device info is: %s\n", reios_device_info); printf("reios: Area symbols is: %s\n", reios_area_symbols); printf("reios: Peripherals is: %s\n", reios_peripherals); printf("reios: Product number is: %s\n", reios_product_number); printf("reios: Product version is: %s\n", reios_product_version); printf("reios: Release date is: %s\n", reios_releasedate); printf("reios: Boot filename is: %s\n", reios_boot_filename); printf("reios: Software company is: %s\n", reios_software_company); printf("reios: Software name is: %s\n", reios_software_name); printf("reios: loading ip.bin from FAD: %d\n", base_fad); libGDR_ReadSector(GetMemPtr(0x8c008000, 0), base_fad, 16, 2048); memset(reios_bootfile, 0, sizeof(reios_bootfile)); memcpy(reios_bootfile, GetMemPtr(0x8c008060, 0), 16); printf("reios: bootfile is '%s'\n", reios_bootfile); for (int i = 15; i >= 0; i--) { if (reios_bootfile[i] != ' ') break; reios_bootfile[i] = 0; } return reios_bootfile; }
s32 V_Core::NewDmaWrite(u32* data, u32 bytesLeft, u32* bytesProcessed) { #ifdef ENABLE_NEW_IOPDMA_SPU2 bool DmaStarting = !DmaStarted; DmaStarted = true; if(bytesLeft<2) { // execute interrupt code early NewDmaInterrupt(); *bytesProcessed = bytesLeft; return 0; } if( IsDevBuild ) { DebugCores[Index].lastsize = bytesLeft; DebugCores[Index].dmaFlag = 1; } TSA &= ~7; bool adma_enable = ((AutoDMACtrl&(Index+1))==(Index+1)); if(adma_enable) { TSA&=0x1fff; if(MsgAutoDMA() && DmaStarting) ConLog("* SPU2-X: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n", GetDmaIndexChar(), bytesLeft<<1, TSA, DMABits, AutoDMACtrl, (~Regs.ATTR)&0x7fff); u32 processed = 0; while((AutoDmaFree>0)&&(bytesLeft>=0x400)) { // copy block LogAutoDMA( Index ? ADMA7LogFile : ADMA4LogFile ); // HACKFIX!! DMAPtr can be invalid after a savestate load, so the savestate just forces it // to NULL and we ignore it here. (used to work in old VM editions of PCSX2 with fixed // addressing, but new PCSX2s have dynamic memory addressing). s16* mptr = (s16*)data; if(false)//(mode) { //memcpy((ADMATempBuffer+(InputPosWrite<<1)),mptr,0x400); memcpy(GetMemPtr(0x2000+(Index<<10)+InputPosWrite),mptr,0x400); mptr+=0x200; // Flag interrupt? If IRQA occurs between start and dest, flag it. // Important: Test both core IRQ settings for either DMA! u32 dummyTSA = 0x2000+(Index<<10)+InputPosWrite; u32 dummyTDA = 0x2000+(Index<<10)+InputPosWrite+0x200; for( int i=0; i<2; i++ ) { if( Cores[i].IRQEnable && (Cores[i].IRQA >= dummyTSA) && (Cores[i].IRQA < dummyTDA) ) { SetIrqCall(i); } } } else { //memcpy((ADMATempBuffer+InputPosWrite),mptr,0x200); memcpy(GetMemPtr(0x2000+(Index<<10)+InputPosWrite),mptr,0x200); mptr+=0x100; // Flag interrupt? If IRQA occurs between start and dest, flag it. // Important: Test both core IRQ settings for either DMA! u32 dummyTSA = 0x2000+(Index<<10)+InputPosWrite; u32 dummyTDA = 0x2000+(Index<<10)+InputPosWrite+0x100; for( int i=0; i<2; i++ ) { if( Cores[i].IRQEnable && (Cores[i].IRQA >= dummyTSA) && (Cores[i].IRQA < dummyTDA) ) { SetIrqCall(i); } } //memcpy((ADMATempBuffer+InputPosWrite+0x200),mptr,0x200); memcpy(GetMemPtr(0x2200+(Index<<10)+InputPosWrite),mptr,0x200); mptr+=0x100; // Flag interrupt? If IRQA occurs between start and dest, flag it. // Important: Test both core IRQ settings for either DMA! dummyTSA = 0x2200+(Index<<10)+InputPosWrite; dummyTDA = 0x2200+(Index<<10)+InputPosWrite+0x100; for( int i=0; i<2; i++ ) { if( Cores[i].IRQEnable && (Cores[i].IRQA >= dummyTSA) && (Cores[i].IRQA < dummyTDA) ) { SetIrqCall(i); } } } // See ReadInput at mixer.cpp for explanation on the commented out lines // InputPosWrite = (InputPosWrite + 0x100) & 0x1ff; AutoDmaFree -= 0x200; processed += 0x400; bytesLeft -= 0x400; } if(processed==0) { *bytesProcessed = 0; return 768*15; // pause a bit } else { *bytesProcessed = processed; return 0; // auto pause } } else { if(MsgDMA() && DmaStarting) ConLog("* SPU2-X: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n", GetDmaIndexChar(),bytesLeft,TSA,DMABits,AutoDMACtrl,(~Regs.ATTR)&0x7fff); if(bytesLeft> 2048) bytesLeft = 2048; // TODO: Sliced transfers? PlainDMAWrite((u16*)data,bytesLeft/2); } Regs.STATX &= ~0x80; Regs.STATX |= 0x400; #endif *bytesProcessed = bytesLeft; return 0; }
s32 V_Core::NewDmaRead(u32* data, u32 bytesLeft, u32* bytesProcessed) { #ifdef ENABLE_NEW_IOPDMA_SPU2 bool DmaStarting = !DmaStarted; DmaStarted = true; TSA &= 0xffff8; u16* pMem = (u16*)data; u32 buff1end = TSA + bytesLeft; u32 buff2end = 0; if( buff1end > 0x100000 ) { buff2end = buff1end - 0x100000; buff1end = 0x100000; } const u32 buff1size = (buff1end-TSA); memcpy( pMem, GetMemPtr( TSA ), buff1size*2 ); // Note on TSA's position after our copy finishes: // IRQA should be measured by the end of the writepos+0x20. But the TDA // should be written back at the precise endpoint of the xfer. if( buff2end > 0 ) { // second branch needs cleared: // It starts at the beginning of memory and moves forward to buff2end memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 ); TDA = (buff2end+0x20) & 0xfffff; // Flag interrupt? If IRQA occurs between start and dest, flag it. // Important: Test both core IRQ settings for either DMA! // Note: Because this buffer wraps, we use || instead of && for( int i=0; i<2; i++ ) { if( Cores[i].IRQEnable && (Cores[i].IRQA >= TSA) || (Cores[i].IRQA < TDA) ) { SetIrqCall(i); } } } else { // Buffer doesn't wrap/overflow! // Just set the TDA and check for an IRQ... TDA = (buff1end + 0x20) & 0xfffff; // Flag interrupt? If IRQA occurs between start and dest, flag it. // Important: Test both core IRQ settings for either DMA! for( int i=0; i<2; i++ ) { if( Cores[i].IRQEnable && (Cores[i].IRQA >= TSA) && (Cores[i].IRQA < TDA) ) { SetIrqCall(i); } } } TSA = TDA & 0xFFFFF; Regs.STATX &= ~0x80; Regs.STATX |= 0x400; #endif *bytesProcessed = bytesLeft; return 0; }
void V_Core::DoDMAread(u16* pMem, u32 size) { #ifndef ENABLE_NEW_IOPDMA_SPU2 TSA &= 0xffff8; u32 buff1end = TSA + size; u32 buff2end = 0; if( buff1end > 0x100000 ) { buff2end = buff1end - 0x100000; buff1end = 0x100000; } const u32 buff1size = (buff1end-TSA); memcpy( pMem, GetMemPtr( TSA ), buff1size*2 ); // Note on TSA's position after our copy finishes: // IRQA should be measured by the end of the writepos+0x20. But the TDA // should be written back at the precise endpoint of the xfer. if( buff2end > 0 ) { // second branch needs cleared: // It starts at the beginning of memory and moves forward to buff2end memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 ); TDA = (buff2end+0x20) & 0xfffff; // Flag interrupt? If IRQA occurs between start and dest, flag it. // Important: Test both core IRQ settings for either DMA! // Note: Because this buffer wraps, we use || instead of && for( int i=0; i<2; i++ ) { if ((Cores[i].IRQEnable && (Cores[i].IRQA >= TSA)) || (Cores[i].IRQA < TDA)) { SetIrqCall(i); } } } else { // Buffer doesn't wrap/overflow! // Just set the TDA and check for an IRQ... TDA = (buff1end + 0x20) & 0xfffff; // Flag interrupt? If IRQA occurs between start and dest, flag it. // Important: Test both core IRQ settings for either DMA! for( int i=0; i<2; i++ ) { if( Cores[i].IRQEnable && (Cores[i].IRQA >= TSA) && (Cores[i].IRQA < TDA) ) { SetIrqCall(i); } } } TSA = TDA & 0xFFFFF; DMAICounter = size; Regs.STATX &= ~0x80; //Regs.ATTR |= 0x30; TADR = MADR + (size<<1); #endif }
void V_Core::PlainDMAWrite(u16 *pMem, u32 size) { // Perform an alignment check. // Not really important. Everything should work regardless, // but it could be indicative of an emulation foopah elsewhere. #if 0 uptr pa = ((uptr)pMem)&7; uptr pm = TSA&0x7; if( pa ) { fprintf(stderr, "* SPU2 DMA Write > Missaligned SOURCE! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, TSA, TDA, size); } if( pm ) { fprintf(stderr, "* SPU2 DMA Write > Missaligned TARGET! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, TSA, TDA, size ); } #endif if(Index==0) DMA4LogWrite(pMem,size<<1); else DMA7LogWrite(pMem,size<<1); TSA &= 0xfffff; u32 buff1end = TSA + size; u32 buff2end=0; if( buff1end > 0x100000 ) { buff2end = buff1end - 0x100000; buff1end = 0x100000; } const int cacheIdxStart = TSA / pcm_WordsPerBlock; const int cacheIdxEnd = (buff1end+pcm_WordsPerBlock-1) / pcm_WordsPerBlock; PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart]; PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd]; do { cacheLine->Validated = false; cacheLine++; } while ( cacheLine != &cacheEnd ); //ConLog( "* SPU2-X: Cache Clear Range! TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n", // TSA, buff1end, flagTSA, flagTDA, clearLen ); // First Branch needs cleared: // It starts at TSA and goes to buff1end. const u32 buff1size = (buff1end-TSA); memcpy( GetMemPtr( TSA ), pMem, buff1size*2 ); if( buff2end > 0 ) { // second branch needs copied: // It starts at the beginning of memory and moves forward to buff2end // endpoint cache should be irrelevant, since it's almost certainly dynamic // memory below 0x2800 (registers and such) //const u32 endpt2 = (buff2end + roundUp) / indexer_scalar; //memset( pcm_cache_flags, 0, endpt2 ); // Emulation Grayarea: Should addresses wrap around to zero, or wrap around to // 0x2800? Hard to know for sure (almost no games depend on this) memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 ); TDA = (buff2end+1) & 0xfffff; // Flag interrupt? If IRQA occurs between start and dest, flag it. // Important: Test both core IRQ settings for either DMA! // Note: Because this buffer wraps, we use || instead of && #if NO_BIOS_HACKFIX for( int i=0; i<2; i++ ) { // Note: (start is inclusive, dest exclusive -- fixes DMC1 FMVs) if ((Cores[i].IRQEnable && (Cores[i].IRQA >= TSA)) || (Cores[i].IRQA < TDA)) { //ConLog("DMAwrite Core %d: IRQ Called (IRQ passed). IRQA = %x Cycles = %d\n", i, Cores[i].IRQA, Cycles ); SetIrqCall(i); } } #else if ((IRQEnable && (IRQA >= TSA)) || (IRQA < TDA)) { SetIrqCall(Index); } #endif } else { // Buffer doesn't wrap/overflow! // Just set the TDA and check for an IRQ... TDA = buff1end; // Flag interrupt? If IRQA occurs between start and dest, flag it. // Important: Test both core IRQ settings for either DMA! #if NO_BIOS_HACKFIX for( int i=0; i<2; i++ ) { // Note: (start is inclusive, dest exclusive -- fixes DMC1 FMVs) if( Cores[i].IRQEnable && (Cores[i].IRQA >= TSA) && (Cores[i].IRQA < TDA) ) { //ConLog("DMAwrite Core %d: IRQ Called (IRQ passed). IRQA = %x Cycles = %d\n", i, Cores[i].IRQA, Cycles ); SetIrqCall(i); } } #else if( IRQEnable && (IRQA >= TSA) && (IRQA < TDA) ) { SetIrqCall(Index); } #endif } TSA = TDA & 0xFFFF0; DMAICounter = size; TADR = MADR + (size<<1); }
void SPU2readDMA(int core, u16* pMem, u32 size) { if(hasPtr) TimeUpdate(*cPtr); Cores[core].TSA &= 0xffff8; u32 buff1end = Cores[core].TSA + size; u32 buff2end = 0; if( buff1end > 0x100000 ) { buff2end = buff1end - 0x100000; buff1end = 0x100000; } const u32 buff1size = (buff1end-Cores[core].TSA); memcpy( pMem, GetMemPtr( Cores[core].TSA ), buff1size*2 ); if( buff2end > 0 ) { // second branch needs cleared: // It starts at the beginning of memory and moves forward to buff2end memcpy( &pMem[buff1size], GetMemPtr( 0 ), buff2end*2 ); Cores[core].TDA = (buff2end+0x20) & 0xfffff; for( int i=0; i<2; i++ ) { if(Cores[i].IRQEnable) { // Flag interrupt? // If IRQA occurs between start and dest, flag it. // Since the buffer wraps, the conditional might seem odd, but it works. if( ( Cores[i].IRQA >= Cores[core].TSA ) || ( Cores[i].IRQA <= Cores[core].TDA ) ) { Spdif.Info=4<<i; SetIrqCall(); } } } } else { // Buffer doesn't wrap/overflow! // Just set the TDA and check for an IRQ... Cores[core].TDA = buff1end; for( int i=0; i<2; i++ ) { if(Cores[i].IRQEnable) { // Flag interrupt? // If IRQA occurs between start and dest, flag it: if( ( Cores[i].IRQA >= Cores[i].TSA ) && ( Cores[i].IRQA <= Cores[i].TDA+0x1f ) ) { Spdif.Info=4<<i; SetIrqCall(); } } } } Cores[core].TSA=Cores[core].TDA & 0xFFFFF; Cores[core].DMAICounter=size; Cores[core].Regs.STATX &= ~0x80; //Cores[core].Regs.ATTR |= 0x30; Cores[core].TADR=Cores[core].MADR+(size<<1); }
void DoDMAWrite(int core,u16 *pMem,u32 size) { // Perform an alignment check. // Not really important. Everything should work regardless, // but it could be indicative of an emulation foopah elsewhere. #if 0 uptr pa = ((uptr)pMem)&7; uptr pm = Cores[core].TSA&0x7; if( pa ) { fprintf(stderr, "* SPU2 DMA Write > Missaligned SOURCE! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size); } if( pm ) { fprintf(stderr, "* SPU2 DMA Write > Missaligned TARGET! Core: %d TSA: 0x%x TDA: 0x%x Size: 0x%x\n", core, Cores[core].TSA, Cores[core].TDA, size ); } #endif if(core==0) DMA4LogWrite(pMem,size<<1); else DMA7LogWrite(pMem,size<<1); if(MsgDMA()) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff); Cores[core].TSA &= 0xfffff; u32 buff1end = Cores[core].TSA + size; u32 buff2end=0; if( buff1end > 0x100000 ) { buff2end = buff1end - 0x100000; buff1end = 0x100000; } const int cacheIdxStart = Cores[core].TSA / pcm_WordsPerBlock; const int cacheIdxEnd = (buff1end+pcm_WordsPerBlock-1) / pcm_WordsPerBlock; PcmCacheEntry* cacheLine = &pcm_cache_data[cacheIdxStart]; PcmCacheEntry& cacheEnd = pcm_cache_data[cacheIdxEnd]; do { cacheLine->Validated = false; cacheLine++; } while ( cacheLine != &cacheEnd ); #if 0 // Pcm Cache Invalidation! // It's a requirement that we mask bits for the blocks that are written to *only*, // because doing anything else can cause the cache to fail, thanks to the progressive // nature of the SPU2's ADPCM encoding. (the same thing that makes it impossible // to use SSE optimizations on it). u8* cache = (u8*)pcm_cache_flags; // Step 1: Clear bits in the front remainder. const int pcmTSA = Cores[core].TSA / pcm_WordsPerBlock; const int pcmTDA = buff1end / pcm_WordsPerBlock; const int remFront = pcmTSA & 31; const int remBack = ((buff1end+pcm_WordsPerBlock-1)/pcm_WordsPerBlock) & 31; // round up to get the end remainder int flagTSA = pcmTSA / 32; if( remFront ) { // need to clear some upper bits of this u32 uint mask = (1ul<<remFront)-1; cache[flagTSA++] &= mask; } // Step 2: Clear the middle run const int flagClearLen = pcmTDA-pcmTSA; memset( &cache[flagTSA], 0, flagClearLen ); // Step 3: Clear bits in the end remainder. if( remBack ) { // need to clear some lower bits in this u32 uint mask = ~(1ul<<remBack)-1; cache[flagTSA + flagClearLen] &= mask; } #endif //ConLog( " * SPU2 : Cache Clear Range! TSA=0x%x, TDA=0x%x (low8=0x%x, high8=0x%x, len=0x%x)\n", // Cores[core].TSA, buff1end, flagTSA, flagTDA, clearLen ); // First Branch needs cleared: // It starts at TSA and goes to buff1end. const u32 buff1size = (buff1end-Cores[core].TSA); memcpy( GetMemPtr( Cores[core].TSA ), pMem, buff1size*2 ); if( buff2end > 0 ) { // second branch needs copied: // It starts at the beginning of memory and moves forward to buff2end // endpoint cache should be irrelevant, since it's almost certainly dynamic // memory below 0x2800 (registers and such) //const u32 endpt2 = (buff2end + roundUp) / indexer_scalar; //memset( pcm_cache_flags, 0, endpt2 ); memcpy( GetMemPtr( 0 ), &pMem[buff1size], buff2end*2 ); Cores[core].TDA = (buff2end+1) & 0xfffff; if(Cores[core].IRQEnable) { // Flag interrupt? // If IRQA occurs between start and dest, flag it. // Since the buffer wraps, the conditional might seem odd, but it works. if( ( Cores[core].IRQA >= Cores[core].TSA ) || ( Cores[core].IRQA <= Cores[core].TDA ) ) { Spdif.Info=4<<core; SetIrqCall(); } } } else { // Buffer doesn't wrap/overflow! // Just set the TDA and check for an IRQ... Cores[core].TDA = buff1end; if(Cores[core].IRQEnable) { // Flag interrupt? // If IRQA occurs between start and dest, flag it: if( ( Cores[core].IRQA >= Cores[core].TSA ) && ( Cores[core].IRQA <= Cores[core].TDA ) ) { Spdif.Info=4<<core; SetIrqCall(); } } } Cores[core].TSA=Cores[core].TDA&0xFFFF0; Cores[core].DMAICounter=size; Cores[core].TADR=Cores[core].MADR+(size<<1); }
__forceinline s16 spu2M_Read( u32 addr ) { return *GetMemPtr( addr & 0xfffff ); }
void DMAC_Ch2St(void) { u32 chcr = DMAC_CHCR(2).full; u32 dmaor = DMAC_DMAOR.full; u32 dmatcr = DMAC_DMATCR(2); u32 src = DMAC_SAR(2); u32 dst = SB_C2DSTAT; u32 len = SB_C2DLEN ; if(0x8201 != (dmaor &DMAOR_MASK)) { printf("\n!\tDMAC: DMAOR has invalid settings (%X) !\n", dmaor); return; } if (len & 0x1F) { printf("\n!\tDMAC: SB_C2DLEN has invalid size (%X) !\n", len); return; } // printf(">>\tDMAC: Ch2 DMA SRC=%X DST=%X LEN=%X\n", src, dst, len ); // Direct DList DMA (Ch2) // Texture DMA if((dst >= 0x10000000) && (dst <= 0x10FFFFFF)) { u32 p_addr=src & RAM_MASK; //GetMemPtr perhaps ? it's not good to use the mem arrays directly while(len) { if ((p_addr+len)>RAM_SIZE) { u32 *sys_buf=(u32 *)GetMemPtr(src,len);//(&mem_b[src&RAM_MASK]); u32 new_len=RAM_SIZE-p_addr; TAWrite(dst,sys_buf,(new_len/32)); len-=new_len; src+=new_len; } else { u32 *sys_buf=(u32 *)GetMemPtr(src,len);//(&mem_b[src&RAM_MASK]); TAWrite(dst,sys_buf,(len/32)); src+=len; break; } } } // If SB_C2DSTAT reg is inrange from 0x11000000 to 0x11FFFFE0, set 1 in SB_LMMODE0 reg. else if((dst >= 0x11000000) && (dst <= 0x11FFFFE0)) { //printf(">>\tDMAC: TEX LNMODE0 Ch2 DMA SRC=%X DST=%X LEN=%X | LN(%X::%X)\n", src, dst, len, *pSB_LMMODE0, *pSB_LMMODE1 ); dst=(dst&0xFFFFFF) |0xa4000000; u32 p_addr=src & RAM_MASK; while(len) { if ((p_addr+len)>RAM_SIZE) { u32 new_len=RAM_SIZE-p_addr; WriteMemBlock_nommu_dma(dst,src,new_len); len-=new_len; src+=new_len; dst+=new_len; } else { WriteMemBlock_nommu_dma(dst,src,len); src+=len; break; } } } // If SB_C2DSTAT reg is in range from 0x13000000 to 0x13FFFFE0, set 1 in SB_LMMODE1 reg. else if((dst >= 0x13000000) && (dst <= 0x13FFFFE0)) { die(".\tPVR DList DMA LNMODE1\n\n"); src+=len; } else { printf("\n!\tDMAC: SB_C2DSTAT has invalid address (%X) !\n", dst); src+=len; } // Setup some of the regs so it thinks we've finished DMA DMAC_SAR(2) = (src); DMAC_CHCR(2).full &= 0xFFFFFFFE; DMAC_DMATCR(2) = 0x00000000; SB_C2DST = 0x00000000; SB_C2DLEN = 0x00000000; SB_C2DSTAT = (src ); // The DMA end interrupt flag (SB_ISTNRM - bit 19: DTDE2INT) is set to "1." //-> fixed , holly_PVR_DMA is for different use now (fixed the interrupts enum too) asic_RaiseInterruptWait(holly_CH2_DMA); }
void reios_sys_flashrom() { debugf("reios_sys_flashrom\n"); u32 cmd = Sh4cntx.r[7]; u32 flashrom_info[][2] = { { 0 * 1024, 8 * 1024 }, { 8 * 1024, 8 * 1024 }, { 16 * 1024, 16 * 1024 }, { 32 * 1024, 32 * 1024 }, { 64 * 1024, 64 * 1024 }, }; switch (cmd) { case 0: // FLASHROM_INFO { /* r4 = partition number(0 - 4) r5 = pointer to two 32 bit integers to receive the result. The first will be the offset of the partition start, in bytes from the start of the flashrom. The second will be the size of the partition, in bytes. #define FLASHROM_PT_SYSTEM 0 /< \brief Factory settings (read-only, 8K) #define FLASHROM_PT_RESERVED 1 /< \brief reserved (all 0s, 8K) #define FLASHROM_PT_BLOCK_1 2 /< \brief Block allocated (16K) #define FLASHROM_PT_SETTINGS 3 /< \brief Game settings (block allocated, 32K) #define FLASHROM_PT_BLOCK_2 4 /< \brief Block allocated (64K) */ u32 part = Sh4cntx.r[4]; u32 dest = Sh4cntx.r[5]; u32* pDst = (u32*)GetMemPtr(dest, 8); if (part <= 4) { pDst[0] = flashrom_info[part][0]; pDst[1] = flashrom_info[part][1]; Sh4cntx.r[0] = 0; } else { Sh4cntx.r[0] = -1; } } break; case 1: //FLASHROM_READ { /* r4 = read start position, in bytes from the start of the flashrom r5 = pointer to destination buffer r6 = number of bytes to read */ u32 offs = Sh4cntx.r[4]; u32 dest = Sh4cntx.r[5]; u32 size = Sh4cntx.r[6]; memcpy(GetMemPtr(dest, size), flashrom + offs, size); Sh4cntx.r[0] = size; } break; case 2: //FLASHROM_WRITE { /* r4 = write start position, in bytes from the start of the flashrom r5 = pointer to source buffer r6 = number of bytes to write */ u32 offs = Sh4cntx.r[4]; u32 src = Sh4cntx.r[5]; u32 size = Sh4cntx.r[6]; u8* pSrc = GetMemPtr(src, size); for (int i = 0; i < size; i++) { flashrom[offs + i] &= pSrc[i]; } } break; case 3: //FLASHROM_DELETE { u32 offs = Sh4cntx.r[4]; u32 dest = Sh4cntx.r[5]; u32 part = 5; for (int i = 0; i <= 4; i++) { if (offs >= flashrom_info[i][0] && offs < (flashrom_info[i][0] + flashrom_info[i][1])) { part = i; break; } } if (part <= 4) { memset(flashrom + flashrom_info[part][0], 0xFF, flashrom_info[part][1]); Sh4cntx.r[0] = 0; } else { Sh4cntx.r[0] = -1; } } break; default: printf("reios_sys_flashrom: not handled, %d\n", cmd); } }
bool MemPEFile::LoadFile( const wchar_t* szFileName, ULONG cbAdditionalBytes, MEMFILE_ACCESS AccessMask ) { m_Access = AccessMask; m_strFileName = szFileName; DWORD dwFileAccess = 0; DWORD dwPageAccess = 0; DWORD dwFileMapAccess = 0; switch ( AccessMask ) { case MA_READ: dwFileAccess = GENERIC_READ; dwPageAccess = PAGE_READONLY; dwFileMapAccess = FILE_MAP_READ; break; case MA_WRITE: dwFileAccess = GENERIC_WRITE; dwPageAccess = PAGE_READWRITE; dwFileMapAccess = FILE_MAP_WRITE; break; case MA_ALL: dwFileAccess = GENERIC_READ | GENERIC_WRITE; dwPageAccess = PAGE_READWRITE; dwFileMapAccess = FILE_MAP_READ | FILE_MAP_WRITE; break; default: throw std::logic_error( "invalid access mask passed" ); } m_hFile = CreateFile( szFileName, dwFileAccess, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL ); if( m_hFile == INVALID_HANDLE_VALUE ) { return false; } LARGE_INTEGER FileSize = {0,0}; FileSize.LowPart = GetFileSize( m_hFile, reinterpret_cast<LPDWORD>( &FileSize.HighPart ) ); if ( FileSize.LowPart == INVALID_FILE_SIZE ) { return false; } FileSize.QuadPart += cbAdditionalBytes; m_hFileMap = CreateFileMapping( m_hFile, NULL, dwPageAccess | SEC_RESERVE, FileSize.HighPart, FileSize.LowPart, 0); if( m_hFileMap == NULL ) { CloseHandle(m_hFile); return false; } m_pFileMap = reinterpret_cast<ULONG_PTR>( MapViewOfFile( m_hFileMap, dwFileMapAccess, 0, 0, 0 ) ); if( m_pFileMap == NULL ) { CloseHandle(m_hFileMap); CloseHandle(m_hFile); return false; } Reset( GetMemPtr() ); return true; }