mirror of
https://github.com/Azimer/Apollo64.git
synced 2025-04-02 10:31:54 -04:00
791 lines
No EOL
27 KiB
C++
791 lines
No EOL
27 KiB
C++
#define V_VSYNC
|
|
#define SITIME 500
|
|
#define PITIME 250
|
|
#define AITIME 510
|
|
//#define AITIME 350000
|
|
//#define AITIME 750000
|
|
//#define AITIME 930000
|
|
|
|
|
|
//#define SITIME (500 * incrementer)
|
|
//#define PITIME (data * 4 + 25) //((((float)(data+1) * 8.9) + 50)*incrementer)
|
|
//#define PITIME ((((float)(data+1) * 8.9) + 50)*incrementer)
|
|
//#define SITIME (100 * incrementer)
|
|
//#define RSPTIME 5//(1000 * CF)
|
|
//#define AITIME 5//(1000 * CF)
|
|
|
|
/**************************************************************************
|
|
* *
|
|
* Copyright (C) 2000, Eclipse Productions *
|
|
* *
|
|
* Offical Source code of the Apollo Project. DO NOT DISTRIBUTE! Any *
|
|
* unauthorized distribution of these files in any way, shape, or form *
|
|
* is a direct infringement on the copyrights entitled to Eclipse *
|
|
* Productions and will you will be prosecuted to the fullest extent of *
|
|
* the law. Have a nice day... ^_^ *
|
|
* *
|
|
*************************************************************************/
|
|
|
|
/**************************************************************************
|
|
*
|
|
* Revision History:
|
|
* Date: Comment:
|
|
* -----------------------------------------------------------------------
|
|
* 05-16-00 Initial Version (Andrew)
|
|
* 05-30-00 Memory Rewrite (Andrew)
|
|
* 06-02-00 Inline of Functions (Andrew)
|
|
* 06-20-00 Addition of AI,SP, and DP registers (Andrew)
|
|
* 11-01-01 Readded the scanline hack. ExciteBike wants it
|
|
*
|
|
**************************************************************************/
|
|
/**************************************************************************
|
|
*
|
|
* Notes:
|
|
*
|
|
* -Like the new memory system? Fast as fuck compared to the old. :-)
|
|
* -Memory is now inlined, for speed purposes. Now the only slow memory routine
|
|
* is CookData. This one needs some speedups and we got it all set. MSVC makes
|
|
* some real crap code for that function...
|
|
*
|
|
**************************************************************************/
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include "resource.h"
|
|
#include "WinMain.h"
|
|
#include "EmuMain.h"
|
|
#include "videodll.h"
|
|
#include "audiodll.h"
|
|
#include "cpumain.h"
|
|
|
|
u32 LastAudio;
|
|
|
|
#pragma warning( disable : 4244 ) // this disables a pointless warning i hate
|
|
#pragma warning( disable : 4035 ) // this disables a pointless warning i hate
|
|
|
|
#define MEM_ERROR(x,y) Debug(0,"%s %08X",x,y)
|
|
|
|
#define RSP_DLIST_EVENT 0x1
|
|
#define RSP_EVENT 0x2
|
|
#define SI_DMA_EVENT 0x3
|
|
#define PI_DMA_EVENT 0x4
|
|
#define AI_DMA_EVENT 0x5
|
|
|
|
void ScheduleEvent (u32 EventType, u32 Time, u32 size, void *extra);
|
|
void DoPifEmulation (u8* dest, u8* src); // TODO: Waiting for new memory
|
|
unsigned long GameSize;
|
|
|
|
u32 valloc = 0;
|
|
u8* rdram = NULL;
|
|
u8* ramRegs0 = NULL;
|
|
u8* ramRegs4 = NULL;
|
|
u8* ramRegs8 = NULL;
|
|
u8* RomMemory = NULL;
|
|
u8* idmem = NULL;
|
|
u8* SP = NULL;
|
|
u8* SP2 = NULL;
|
|
u8* DPC = NULL;
|
|
u8* DPS = NULL;
|
|
u8* MI = NULL;
|
|
u8* VI = NULL;
|
|
u8* AI = NULL;
|
|
u8* PI = NULL;
|
|
u8* RI = NULL;
|
|
u8* SI = NULL;
|
|
u8* pif = NULL;
|
|
u8* cartDom2 = NULL;
|
|
u8* cartDom1 = NULL;
|
|
u8* cartDom3 = NULL;
|
|
u8* cartDom4 = NULL;
|
|
DWORD *DVI; // Used for VI Hack
|
|
DWORD *DAI; // Used for AI temp fix
|
|
DWORD fsize=0;
|
|
|
|
extern char FlashRAM[0x20000]; // 1MBit in size
|
|
extern bool SRinUse; // SaveChips.cpp
|
|
extern bool FRinUse;
|
|
|
|
char FlashRAM_Buffer[128];
|
|
u32 FlashRAM_Offset = 0;
|
|
|
|
int rdramsize = 4*1024*1024;
|
|
|
|
void InitMem ( int memsize ) {
|
|
if ((valloc = (u32)VirtualAlloc(0,512*1024*1024,MEM_RESERVE,PAGE_READWRITE))!=NULL) {
|
|
Debug (0, "%08X used as memory base.", valloc);
|
|
} else {
|
|
Debug (1, "Page could not be allocated. Sorry, but don't try to run anything. It won't work");
|
|
return;
|
|
}
|
|
rdramsize = memsize;
|
|
rdram = (u8*)VirtualAlloc((void*)valloc, memsize+1, MEM_COMMIT,PAGE_READWRITE);
|
|
idmem = (u8*)VirtualAlloc((void*)(valloc+0x04000000), 0x2000, MEM_COMMIT,PAGE_READWRITE);
|
|
SP = (u8*)VirtualAlloc((void*)(valloc+0x04040000), 0x20, MEM_COMMIT,PAGE_READWRITE);
|
|
SP2 = (u8*)VirtualAlloc((void*)(valloc+0x04080000), 0x08, MEM_COMMIT,PAGE_READWRITE);
|
|
DPC = (u8*)VirtualAlloc((void*)(valloc+0x04100000), 0x10, MEM_COMMIT,PAGE_READWRITE);
|
|
DPS = (u8*)VirtualAlloc((void*)(valloc+0x04200000), 0x10, MEM_COMMIT,PAGE_READWRITE);
|
|
MI = (u8*)VirtualAlloc((void*)(valloc+0x04300000), 0x10, MEM_COMMIT,PAGE_READWRITE);
|
|
VI = (u8*)VirtualAlloc((void*)(valloc+0x04400000), 0x38, MEM_COMMIT,PAGE_READWRITE);
|
|
AI = (u8*)VirtualAlloc((void*)(valloc+0x04500000), 0x18, MEM_COMMIT,PAGE_READWRITE);
|
|
PI = (u8*)VirtualAlloc((void*)(valloc+0x04600000), 0x34, MEM_COMMIT,PAGE_READWRITE);
|
|
RI = (u8*)VirtualAlloc((void*)(valloc+0x04700000), 0x20, MEM_COMMIT,PAGE_READWRITE);
|
|
SI = (u8*)VirtualAlloc((void*)(valloc+0x04800000), 0x1C, MEM_COMMIT,PAGE_READWRITE);
|
|
ramRegs0= (u8*)VirtualAlloc((void*)(valloc+0x03F00000), 0x30, MEM_COMMIT,PAGE_READWRITE);
|
|
ramRegs4= (u8*)VirtualAlloc((void*)(valloc+0x03F04000), 0x30, MEM_COMMIT,PAGE_READWRITE);
|
|
ramRegs8= (u8*)VirtualAlloc((void*)(valloc+0x03F80000), 0x30, MEM_COMMIT,PAGE_READWRITE);
|
|
cartDom2= (u8*)VirtualAlloc((void*)(valloc+0x05000000), 0x10000, MEM_COMMIT,PAGE_READWRITE);
|
|
cartDom1= (u8*)VirtualAlloc((void*)(valloc+0x06000000), 0x10000, MEM_COMMIT,PAGE_READWRITE);
|
|
cartDom3= (u8*)VirtualAlloc((void*)(valloc+0x08000000), 0x20000, MEM_COMMIT,PAGE_READWRITE);
|
|
RomMemory=(u8*)VirtualAlloc((void*)(valloc+0x10000000), 0x10000, MEM_COMMIT,PAGE_READWRITE); // Just to make J's DLL work
|
|
cartDom4= (u8*)VirtualAlloc((void*)(valloc+0x1FD00000), 0x10000, MEM_COMMIT,PAGE_READWRITE);
|
|
pif = (u8*)VirtualAlloc((void*)(valloc+0x1FC00000), 0x800, MEM_COMMIT,PAGE_READWRITE);
|
|
|
|
// Added for VI Hack and AI fix
|
|
DVI = (u32 *)VI;
|
|
DAI = (u32 *)AI;
|
|
|
|
((u32*)MI)[1] = 0x01010101;
|
|
((u32*)DPC)[3] = 0;
|
|
}
|
|
|
|
u32 romsize;
|
|
|
|
void ChangeRDRAMSize (int memsize) {
|
|
if (memsize != rdramsize) {
|
|
VirtualFree((void*)valloc, rdramsize+1, MEM_DECOMMIT);
|
|
rdram = (u8*)VirtualAlloc((void*)valloc, memsize+1, MEM_COMMIT,PAGE_READWRITE);
|
|
rdramsize = memsize;
|
|
}
|
|
}
|
|
|
|
void MemoryAllocRom(u32 filesize) {
|
|
filesize = ((filesize + 0x1fffff)/0x200000)*0x400000;//bring it up to a even 2MB.
|
|
romsize = filesize;
|
|
VirtualFree((void*)(valloc+0x10000000), 64*1024*1024,MEM_DECOMMIT);
|
|
RomMemory= (u8*)VirtualAlloc((void*)(valloc+0x10000000), filesize, MEM_COMMIT,PAGE_READWRITE);
|
|
Debug (0, "Allocated %X bytes for ROM Image", filesize);
|
|
fsize = filesize;
|
|
}
|
|
|
|
void KillMemory(void) {
|
|
VirtualFree((void*)valloc, rdramsize+1, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x04000000), 0x2000, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x04040000), 0x20, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x04080000), 0x08, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x04100000), 0x10, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x04200000), 0x10, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x04300000), 0x10, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x04400000), 0x38, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x04500000), 0x18, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x04600000), 0x34, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x04700000), 0x20, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x04800000), 0x1C, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x1FC00000), 0x800, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x03F00000), 0x30, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x03F04000), 0x30, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x03F80000), 0x30, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x05000000), 1024*1024, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x06000000), 1024*1024, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x08000000), 0x20000, MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x10000000), 64*1024*1024,MEM_DECOMMIT);
|
|
VirtualFree((void*)(valloc+0x1FD00000), 1024*1024,MEM_DECOMMIT);
|
|
}
|
|
|
|
//Used for VI Hack..
|
|
u32 ailens = 0;
|
|
float AiFreq;
|
|
extern u32 VsyncTime;
|
|
extern int InterruptTime;
|
|
#define MMU_COUNT MmuRegs[9]
|
|
u32 ReadData (u32 addr) {
|
|
u32 retVal;
|
|
switch (addr & 0x00ffffff) {
|
|
case 0x00400010: // Current Scanline
|
|
retVal = ((u32*)returnMemPointer(addr))[0];
|
|
retVal+=0x80;
|
|
if (retVal > 512)
|
|
retVal = 0;
|
|
DVI[4] = retVal;
|
|
//Debug (0, "Scanline count: %i", retVal);
|
|
return retVal;
|
|
break;
|
|
case 0x00500000: {
|
|
Debug (0, "Read AI_DRAM_ADDR_REG = %08X", *(u32 *)(AI+0x00));
|
|
} break;
|
|
case 0x00500004: {
|
|
u32 GetLength ();
|
|
return GetLength ();
|
|
instructions = (VsyncTime - InterruptTime);
|
|
MMU_COUNT = instructions;
|
|
u32 retVal = snddll.AiReadLength ();
|
|
//((u32*)returnMemPointer(addr))[0] = retVal;
|
|
*(u32 *)(AI+0x04) = retVal;
|
|
// Debug (0, "Read AI_LEN_REG = %08X - %i", *(u32 *)(AI+0x04), retVal);
|
|
return retVal;
|
|
//return ((u32*)returnMemPointer(addr))[0] / 2;
|
|
}
|
|
/*
|
|
case 0x00500008: {
|
|
Debug (0, "Read AI_CONTROL_REG = %08X", *(u32 *)(AI+0x08));
|
|
} break;
|
|
*/
|
|
case 0x0050000C: {
|
|
u32 GetStatus ();
|
|
return GetStatus ();
|
|
// Debug (0, "Read AI_STATUS_REG = %08X", *(u32 *)(AI+0x0C));
|
|
} break;
|
|
/*
|
|
case 0x00500010: {
|
|
Debug (0, "Read AI_DACRATE_REG = %08X", *(u32 *)(AI+0x10));
|
|
} break;
|
|
case 0x00500014: {
|
|
Debug (0, "Read AI_BITRATE_REG = %08X", *(u32 *)(AI+0x14));
|
|
} break;
|
|
*/
|
|
default:
|
|
return ((u32*)returnMemPointer(addr))[0];
|
|
}
|
|
return ((u32*)returnMemPointer(addr))[0];
|
|
}
|
|
|
|
/*
|
|
CookData: This function is the hardware handler for the N64.
|
|
It takes the data, and uses it in a mimicing fashion, and returns
|
|
data in such a way the read functions to not have to be smart.
|
|
|
|
This function is far from complete.
|
|
*/
|
|
#define FLASH_NOOP 0
|
|
#define FLASH_ERASE 1
|
|
#define FLASH_WRITE 2
|
|
#define FLASH_STATUS 3
|
|
u32 FlashRAM_Mode = FLASH_NOOP;
|
|
|
|
|
|
u32 CookData(u32 addr, u32 data) {
|
|
u32 retVal;
|
|
if ((addr&0x1f000000) > 0x05000000) {
|
|
if ((addr & 0x1F000000) > 0x08020000)
|
|
return data;
|
|
if ((addr & 0x1fff0000) == 0x8000000)
|
|
return data;
|
|
if (FRinUse == false) {
|
|
((u32*)cartDom3)[0] = 0x00000000;
|
|
((u32*)cartDom3)[1] = 0x00000000;
|
|
Debug (0, "FlashRAM Detected!");
|
|
FRinUse = true;
|
|
SRinUse = false; // This save type dominates
|
|
FlashRAM_Mode = FLASH_NOOP;
|
|
}
|
|
//Debug (0, "Write to %08X - %08X", addr, data);
|
|
switch (data >> 24) {
|
|
case 0x4b: // Set Erase Block Mode (128 Byte - aligned )
|
|
FlashRAM_Mode = FLASH_ERASE;
|
|
FlashRAM_Offset = (data & 0xFFFF) * 128;
|
|
break;
|
|
|
|
case 0x78: // Second part of the Erase Block
|
|
((u32*)cartDom3)[0] = 0x11118008;
|
|
((u32*)cartDom3)[1] = 0x00c20000;
|
|
break;
|
|
|
|
// Init a FlashWrite
|
|
case 0xb4:
|
|
FlashRAM_Mode = FLASH_WRITE;
|
|
break;
|
|
|
|
// Sets the Block for the FlashWrite (128 Byte - aligned )
|
|
case 0xa5:
|
|
FlashRAM_Offset = (data & 0xFFFF) * 128;
|
|
((u32*)cartDom3)[0] = 0x11118004;
|
|
((u32*)cartDom3)[1] = 0x00c20000;
|
|
break;
|
|
|
|
case 0xD2: { // Flash RAM Execute
|
|
switch (FlashRAM_Mode) {
|
|
case FLASH_NOOP:
|
|
break;
|
|
case FLASH_ERASE:
|
|
memset(&FlashRAM[FlashRAM_Offset], 0xFF, 128);
|
|
break;
|
|
case FLASH_WRITE:
|
|
//Debug (0, "FlashRAM Write: %08X", FlashRAM_Offset);
|
|
memcpy(&FlashRAM[FlashRAM_Offset], &FlashRAM_Buffer[0], 128);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case 0xE1: { // Set FlashRAM Status
|
|
FlashRAM_Mode = FLASH_STATUS;
|
|
((u32*)cartDom3)[0] = 0x11118001;
|
|
((u32*)cartDom3)[1] = 0x00c20000;
|
|
}
|
|
break;
|
|
case 0xF0: // Set FlashRAM Read
|
|
FlashRAM_Mode = FLASH_NOOP;
|
|
FlashRAM_Offset = 0;
|
|
((u32*)cartDom3)[0] = 0x11118004;
|
|
((u32*)cartDom3)[1] = 0xf0000000;
|
|
break;
|
|
default:
|
|
FRinUse = false;
|
|
return data;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
switch (addr & 0x00ffffff) {
|
|
// case 0x00080000: break;//SP2
|
|
// case 0x00200000: break;//DPS
|
|
// case 0x00700000: break;//RI
|
|
case 0x00040008://SP DRAM->IDMEM
|
|
if (data+1) memcpy(&idmem[((u32*)SP)[0] & 0x1fff],returnMemPointer(((u32*)SP)[1]),(data+1)&0x1fff);
|
|
return data; break;
|
|
case 0x0004000C://SP IDMEM->DRAM
|
|
if (data+1) memcpy(returnMemPointer(((u32*)SP)[1]),&idmem[((u32*)SP)[0] & 0x1fff],(data+1)&0x1fff);
|
|
return data; break;
|
|
case 0x00040010://SP
|
|
retVal = ((u32*)SP)[4];
|
|
if (data & 0x1) retVal &= ~0x1;//clear and set halt
|
|
if (data & 0x2) retVal |= 0x1;
|
|
if (data & 0x4) retVal &= ~0x2;//clear broken
|
|
if (data & 0x8) CLEAR_INTR(SP_INTERRUPT);
|
|
if (data & 0x10) SET_INTR(SP_INTERRUPT);//clear and set interrupt
|
|
if (data & 0x20) retVal &= ~0x20;//clear and set sstep
|
|
if (data & 0x40) retVal |= 0x20;
|
|
if (data & 0x80) retVal &= ~0x40;//clear and set interrupt on break
|
|
if (data & 0x100) retVal |= 0x40;
|
|
if (data & 0x200) retVal &= ~0x80;//clear and set sig0
|
|
if (data & 0x400) retVal |= 0x80;
|
|
if (data & 0x800) retVal &= ~0x100;//clear and set sig1
|
|
if (data & 0x1000) retVal |= 0x100;
|
|
if (data & 0x2000)retVal &= ~0x200;//clear and set sig2
|
|
if (data & 0x4000) retVal |= 0x200;
|
|
if (data & 0x8000) retVal &= ~0x400;//clear and set sig3
|
|
if (data & 0x10000) retVal |= 0x400;
|
|
if (data & 0x20000) retVal &= ~0x800;//clear and set sig4
|
|
if (data & 0x40000) retVal |= 0x800;
|
|
if (data & 0x80000) retVal &= ~0x1000;//clear and set sig5
|
|
if (data & 0x100000) retVal |= 0x1000;
|
|
if (data & 0x200000) retVal &= ~0x2000;//clear and set sig6
|
|
if (data & 0x400000) retVal |= 0x2000;
|
|
if (data & 0x800000) retVal &= ~0x4000;//clear and set sig7
|
|
if (data & 0x1000000) retVal |= 0x4000;
|
|
//if (retVal >= 0x20)
|
|
// Debug (0, "SP Bits: %X", retVal);
|
|
if (!(retVal & 1))
|
|
SignalRSP (&retVal);
|
|
//ScheduleEvent (RSP_EVENT, RSPTIME, &((u32*)SP)[4]);
|
|
if (retVal & 0x80) {
|
|
InterruptNeeded |= SP_INTERRUPT;
|
|
retVal &= ~0x80;
|
|
}
|
|
return retVal; break;
|
|
case 0x0004001C://SP
|
|
// SPsema=0;
|
|
Debug (0, "SP Semaphore");
|
|
return 0; break;
|
|
case 0x00080004:
|
|
Debug (0, "SP BIST");
|
|
break;
|
|
case 0x00100000:
|
|
//Debug (0, "Written to the RDP_START_REG");
|
|
break;
|
|
case 0x00100004://DPC END
|
|
//Debug (0, "Written to the DPC_END_REG");
|
|
SignalRDP();
|
|
break;
|
|
case 0x00100008:
|
|
Debug (0, "Written to the DPC_CURRENT_REG");
|
|
break;
|
|
case 0x0010000C://DPC STATUS
|
|
//Debug (0, "Written to the DPC_STATUS_REG: %08X", data);
|
|
retVal = ((u32*)DPC)[3];
|
|
if (data & 0x1) retVal &= ~0x1;
|
|
if (data & 0x2) retVal |= 0x1;
|
|
if (data & 0x4) retVal &= ~0x2;
|
|
if (data & 0x8) retVal |= 0x2;
|
|
if (data & 0x10) retVal &= ~0x4;
|
|
if (data & 0x20) retVal |= 0x4;
|
|
if (data & 0x40) ((u32*)DPC)[7] = 0;
|
|
if (data & 0x80) ((u32*)DPC)[6] = 0;
|
|
if (data & 0x100) ((u32*)DPC)[5] = 0;
|
|
if (data & 0x200) ((u32*)DPC)[4] = 0;
|
|
return retVal;/* | 0x680;*/ break;
|
|
case 0x00100010:
|
|
Debug (0, "Written to the DPC_CLOCK_REG");
|
|
break;
|
|
case 0x00100014:
|
|
Debug (0, "Written to the DPC_BUFBUSY_REG");
|
|
break;
|
|
case 0x00100018:
|
|
Debug (0, "Written to the DPC_PIPEBUSY_REG");
|
|
break;
|
|
case 0x0010001C:
|
|
Debug (0, "Written to the DPC_TMEM_REG");
|
|
break;
|
|
case 0x00300000://MI
|
|
retVal = ((DWORD*)MI)[0];
|
|
if (data & 0x80) retVal &= ~0x80;
|
|
if (data & 0x100) retVal |= 0x80;
|
|
if (data & 0x200) retVal &= ~0x100;
|
|
if (data & 0x400) retVal |= 0x100;
|
|
if (data & 0x800) CLEAR_INTR(DP_INTERRUPT);
|
|
if (data & 0x1000) retVal &=~0x200;
|
|
if (data & 0x2000) retVal |=0x200;
|
|
return retVal; break;
|
|
case 0x00300008://MI
|
|
Debug (0, "This shouldn't happen: %08X", data);
|
|
return ((DWORD*)MI)[2];
|
|
break;
|
|
case 0x0030000C://MI
|
|
//Any write to this register causing an interrupt previously masked to come through
|
|
//will cause an interrupt.
|
|
retVal = ((DWORD*)MI)[3];
|
|
if (data & 0x2) retVal |= 0x1;
|
|
if (data & 0x8) retVal |= 0x2;
|
|
if (data & 0x20) retVal |= 0x4;
|
|
if (data & 0x80) retVal |= 0x8;
|
|
if (data & 0x200) retVal |= 0x10;
|
|
if (data & 0x800) retVal |= 0x20;
|
|
if (data & 0x1) retVal &= ~0x1;
|
|
if (data & 0x4) retVal &= ~0x2;
|
|
if (data & 0x10) retVal &= ~0x4;
|
|
if (data & 0x40) retVal &= ~0x8;
|
|
if (data & 0x100) retVal &= ~0x10;
|
|
if (data & 0x400) retVal &= ~0x20;
|
|
((DWORD*)MI)[3] = retVal;
|
|
if ((((u32*)MI)[3] & (((u32*)MI)[2]))) {
|
|
ScheduleEvent (0x6, 200, 0, NULL); // Delay the interrupt a bit
|
|
//InterruptNeeded |= ((u32*)MI)[2];
|
|
//CheckInterrupts(); // Enabling this causes flashes in Mario Party 2
|
|
}
|
|
//Debug (0, "MI[0xC] = %X", retVal);
|
|
return retVal; break;
|
|
case 0x00400000:// VI_STATUS
|
|
*(u32 *)(VI+0x0) = data;
|
|
gfxdll.ViStatusChanged ();
|
|
return data; break;
|
|
case 0x00400004:// Origin Changed
|
|
//Debug (0, "%08X: Origin Changed: %08X", pc, data);
|
|
break;
|
|
case 0x00400008:// VI_WIDTH
|
|
//Debug (0, "Width Changed: %08X", data);
|
|
*(u32 *)(VI+0x8) = data;
|
|
gfxdll.ViWidthChanged ();
|
|
return data; break;
|
|
case 0x00400010://VI
|
|
CLEAR_INTR(VI_INTERRUPT);
|
|
//Debug (0, "VI Clear");
|
|
return DVI[4]/*data*/; break;
|
|
case 0x00400018: {// VSYNC
|
|
/*
|
|
[21:45] <zilmar> VI_INTR_TIME = (VI_V_SYNC_REG + 1) * 1500;
|
|
[21:45] <zilmar> if ((VI_V_SYNC_REG % 1) != 0) {
|
|
[21:45] <zilmar> VI_INTR_TIME -= 38;
|
|
[21:45] <zilmar> }*/
|
|
#ifdef V_VSYNC
|
|
extern u32 VsyncTiming;
|
|
static u32 oldtiming=0;
|
|
//if (VsyncTiming == 625000)
|
|
// oldtiming = 0;
|
|
if (oldtiming != data) {
|
|
oldtiming = data;
|
|
VsyncTiming = (data + 1) * 1500;
|
|
if ((data % 0x1) != 0)
|
|
VsyncTiming -= 38;
|
|
// if (RegSettings.VSyncHack > 0)
|
|
// VsyncTiming /= RegSettings.VSyncHack;
|
|
Debug (0, "VsyncTiming is now %i", VsyncTiming);
|
|
//if (pr32 (0x8007CF30) == 0x504C0004) {
|
|
// if (pr32 (0x8007CF38) == 0x1000FFFF) { // HACK: Yoshi Story
|
|
// Debug (0, "Yoshi Story Hack inplace");
|
|
// pw32 (0x8007CF30, 0x00000000); // Yoshi Story Hack
|
|
// pw32 (0x8007CF38, 0x00000000); // Yoshi Story Hack
|
|
// }
|
|
//}
|
|
}
|
|
#endif
|
|
return data; break; }
|
|
case 0x00400030: { // Needed to Fix Zelda OOT 1.2
|
|
if (data == 0)
|
|
data = *(u32 *)(VI+0x30);
|
|
return data;
|
|
} break;
|
|
case 0x00400034: { // Needed to Fix Zelda OOT 1.2
|
|
if (data == 0)
|
|
data = *(u32 *)(VI+0x34);
|
|
return data;
|
|
} break;
|
|
|
|
case 0x00500000: { // W
|
|
//Debug (0, "Write AI_DRAM_ADDR_REG = %08X", data);
|
|
} break;
|
|
case 0x00500004: { // R/W
|
|
void SetLength (u32 data);
|
|
((u32*)AI)[1] = data;
|
|
instructions = (VsyncTime - InterruptTime);
|
|
MMU_COUNT = instructions;
|
|
// snddll.AiLenChanged();
|
|
SetLength (data);
|
|
ailens++;
|
|
return data;
|
|
// Debug (0, "Write AI_LEN_REG = %08X - %i", data, data);
|
|
/*if ((*(u32 *)(AI+0xC) & 1) == 0) // AI DMA Disabled
|
|
return data;*/
|
|
if (data) {//If there is no data, don't start playing...(duh)
|
|
((u32*)AI)[1] = data;
|
|
instructions = (VsyncTime - InterruptTime);
|
|
MMU_COUNT = instructions;
|
|
//ScheduleEvent (AI_DMA_EVENT, AITIME, 0, NULL);
|
|
snddll.AiLenChanged();
|
|
//((DWORD *)AI)[3] = 0xC0000000;
|
|
//dprintf ("$");
|
|
void GetNextInterrupt ();
|
|
GetNextInterrupt ();
|
|
//snddll.AiUpdate(FALSE);
|
|
}
|
|
return data;
|
|
} break;
|
|
case 0x00500008: { // W
|
|
Debug (0, "Write AI_CONTROL_REG = %08X", data);
|
|
} break;
|
|
case 0x0050000C: { // R/W
|
|
CLEAR_INTR(AI_INTERRUPT);
|
|
//Debug (0, "Write AI_STATUS_REG = %08X", data);
|
|
return *(u32 *)(AI+0xC);
|
|
} break;
|
|
|
|
case 0x00500010: { // W
|
|
extern u32 SystemType;
|
|
*(u32 *)(AI+0x10) = data;
|
|
instructions = (VsyncTime - InterruptTime);
|
|
MMU_COUNT = instructions;
|
|
if (snddll.AiDacrateChanged)
|
|
snddll.AiDacrateChanged(!SystemType);
|
|
if (SystemType == 1)
|
|
Debug (0, "Write AI_DACRATE_REG = %i - %f", data, (AiFreq = 48681812.0/(float)(data+1)));
|
|
else
|
|
Debug (0, "Write AI_DACRATE_REG = %i - %f", data, (AiFreq = 49656530.0/(float)(data+1)));
|
|
void SetFrequency (u32 data);
|
|
SetFrequency (AiFreq);
|
|
return data;
|
|
} break;
|
|
case 0x00500014: { // W
|
|
Debug (0, "Write AI_BITRATE_REG = %i", data+1);
|
|
} break;
|
|
|
|
/*
|
|
0x0450 0000 to 0x0450 0003 AI_DRAM_ADDR_REG
|
|
0x0450 0004 to 0x0450 0007 AI_LEN_REG
|
|
0x0450 0008 to 0x0450 000B AI_CONTROL_REG
|
|
0x0450 000C to 0x0450 000F AI_STATUS_REG
|
|
0x0450 0010 to 0x0450 0013 AI_DACRATE_REG
|
|
0x0450 0014 to 0x0450 0017 AI_BITRATE_REG*/
|
|
/*
|
|
case 0x00600000:
|
|
Debug (0, "%08X: DRAM Address: %08X", pc-4, data);
|
|
return data;
|
|
case 0x00600004:
|
|
Debug (0, "%08X: CART Address: %08X", pc-4, data);
|
|
return data;
|
|
*/
|
|
case 0x00600010://PI
|
|
if (data & 0x3) { CLEAR_INTR(PI_INTERRUPT); }
|
|
return ((u32 *)PI)[0x4]; break;
|
|
|
|
case 0x00600008: {//PI
|
|
u32 src = ((DWORD*)PI)[0];
|
|
u32 dst = ((DWORD*)PI)[1];
|
|
|
|
Debug (0, "%08X PI Transfer: (RDRAM)%08X -> (RROM)%08X with size %X", pc-4, ((DWORD*)PI)[0], ((DWORD*)PI)[1], data+1);
|
|
if ((dst >= 0x06000000) && (dst < 0x10000000)) {
|
|
u32 address = ((DWORD*)PI)[1] & 0x1FFFF;
|
|
if (FRinUse) {
|
|
Debug (0, "%08X PI Transfer: (RDRAM)%08X -> (FlashRAM Buffer)%08X with size %X", pc-4, ((DWORD*)PI)[0], ((DWORD*)PI)[1], data+1);
|
|
for (u32 x = 0; x <= data; x++) {
|
|
FlashRAM_Buffer[x^3] = *(u8 *)returnMemPointer((src+x)^3);
|
|
}
|
|
} else {
|
|
for (u32 x = 0; x <= data; x++) {
|
|
FlashRAM[(address+x)^3] = *(u8 *)returnMemPointer((src+x)^3);
|
|
}
|
|
if (SRinUse == false) {
|
|
SRinUse = true;
|
|
Debug (0, "SRAM Save Type Detected!");
|
|
}
|
|
}
|
|
}
|
|
((u32 *)PI)[0x4] |= 0x3;
|
|
ScheduleEvent (PI_DMA_EVENT, 0, 0, NULL);
|
|
//InterruptNeeded |= PI_INTERRUPT;
|
|
//SET_INTR(PI_INTERRUPT);
|
|
return data; break;
|
|
}
|
|
case 0x0060000C: { //PI
|
|
u32 dst = ((DWORD*)PI)[0];
|
|
u32 src = ((DWORD*)PI)[1];
|
|
static u32 DMAINFO[3];
|
|
//src &= 0x1fffffff;
|
|
// CF04DC30
|
|
//Debug (2, "%08X PI Transfer: (ROM)%08X -> (RDRAM)%08X with size %i\n", pc-4, ((DWORD*)PI)[1], ((DWORD*)PI)[0], data+1);
|
|
if ((src+data) < (0x10000000+fsize)) {
|
|
if ((src >= 0x08000000) && (src < 0x10000000)) {
|
|
u32 address = ((DWORD*)PI)[1] & 0x1FFFF;
|
|
if (FlashRAM_Mode == FLASH_STATUS) {
|
|
Debug (0, "%08X PI Transfer: (FlashRAM Status)%08X -> (RDRAM)%08X with size %X", pc-4, ((DWORD*)PI)[1], ((DWORD*)PI)[0], data+1);
|
|
for (u32 x = 0; x <= data; x++) {
|
|
*(u8 *)returnMemPointer((dst+x)^3) = *(u8 *)returnMemPointer((src+x)^3);
|
|
if (x < 8)
|
|
dprintf ("%02X", *(u8 *)returnMemPointer((src+x)^3));
|
|
}
|
|
} else {
|
|
if (SRinUse != true) {
|
|
address *= 2;
|
|
}
|
|
Debug (0, "%08X PI Transfer: (FlashRAM)%08X -> (RDRAM)%08X with size %X", pc-4, address, ((DWORD*)PI)[0], data+1);
|
|
for (u32 x = 0; x <= data; x++) {
|
|
*(u8 *)returnMemPointer((dst+x)^3) = FlashRAM[(address+x)^3];
|
|
//if (x < 8)
|
|
// dprintf ("%02X", *(u8 *)returnMemPointer((src+x)^3));
|
|
}
|
|
}
|
|
//dprintf ("\r\n");
|
|
//0F04DC30
|
|
((u32 *)PI)[0x4] |= 0x3;
|
|
ScheduleEvent (PI_DMA_EVENT, 0, 0, NULL);
|
|
} else if (src < 0x08000000) {
|
|
memset (returnMemPointer(dst), 0x00, data+1);
|
|
Debug (0, "%08X BADx PI Transfer: (ROM)%08X -> (RDRAM)%08X with size %X", pc-4, ((DWORD*)PI)[1], ((DWORD*)PI)[0], data+1);
|
|
((u32 *)PI)[4] &= ~0x3;
|
|
InterruptNeeded |= PI_INTERRUPT;
|
|
SET_INTR(PI_INTERRUPT);
|
|
return data;
|
|
} else {
|
|
static int dmahehe = 0;
|
|
DMAINFO[0] = dst;
|
|
DMAINFO[1] = src;
|
|
DMAINFO[2] = data;
|
|
((u32 *)PI)[0x4] |= 0x3;
|
|
ScheduleEvent (PI_DMA_EVENT, PITIME, sizeof(u32)*3, DMAINFO);
|
|
// Debug (0, "PI DMA %i", dmahehe);
|
|
dmahehe++;
|
|
}
|
|
//InterruptNeeded |= PI_INTERRUPT;
|
|
//SET_INTR(PI_INTERRUPT);
|
|
return data;
|
|
} else {
|
|
Debug (0, "%08X BAD PI Transfer: (ROM)%08X -> (RDRAM)%08X with size %X", pc-4, ((DWORD*)PI)[1], ((DWORD*)PI)[0], data+1);
|
|
//cpuIsDone = true;
|
|
//cpuIsReset = true;
|
|
memset (returnMemPointer(dst), 0x00, data+1);
|
|
((u32 *)PI)[0x4] |= 0x1;
|
|
ScheduleEvent (PI_DMA_EVENT, PITIME, 0, NULL);
|
|
//InterruptNeeded |= PI_INTERRUPT;
|
|
//SET_INTR(PI_INTERRUPT);
|
|
return data;
|
|
}
|
|
break;
|
|
} //*/
|
|
/*
|
|
case 0x00600008://PI
|
|
//Note: Incorrect emulation of all writes to register 2, case 8. A write here causes a RDRAM->ROM DMA.
|
|
//Debug (0, "%08X PI Transfer: (RDRAM)%08X -> (ROM)%08X with size %u", pc-4, ((DWORD*)PI)[0], ((DWORD*)PI)[1], data+1);
|
|
if ((((DWORD*)PI)[1] >= 0x08000000) && (((DWORD*)PI)[1] < 0x10000000)) {
|
|
u32 address = ((DWORD*)PI)[1] & 0x1FFFF;
|
|
if (FRinUse) {
|
|
//Debug (0, "FlashRAM Write DMA: %08X", ((DWORD*)PI)[1]);
|
|
memcpy(&FlashRAM_Buffer[0], returnMemPointer(((DWORD*)PI)[0]), data+1);
|
|
} else {
|
|
//Debug (0, "SRAM Write DMA: %08X", ((DWORD*)PI)[1]);
|
|
memcpy(&FlashRAM[address], returnMemPointer(((DWORD*)PI)[0]), data+1);
|
|
if (SRinUse == false) {
|
|
SRinUse = true;
|
|
Debug (0, "SRAM Save Type Detected!");
|
|
}
|
|
}
|
|
}
|
|
Debug (0, "%08X PI Transfer: (RDRAM)%08X -> (ROM)%08X with size %X", pc-4, ((DWORD*)PI)[0], ((DWORD*)PI)[1], data+1);
|
|
//MEM_ERROR("RDRAM->ROM",data);
|
|
InterruptNeeded |= PI_INTERRUPT;
|
|
SET_INTR(PI_INTERRUPT);
|
|
return data; break;
|
|
case 0x0060000C://PI
|
|
//if (((DWORD*)PI)[1] < 0x10000000)
|
|
//Debug (0, "%08X PI Transfer: (ROM)%08X -> (RDRAM)%08X with size %u", pc-4, ((DWORD*)PI)[1], ((DWORD*)PI)[0], data+1);
|
|
if ((((DWORD*)PI)[1]+data) < (0x10000000+fsize)) {
|
|
if ((((DWORD*)PI)[1] >= 0x08000000) && (((DWORD*)PI)[1] < 0x10000000)) {
|
|
u32 address = ((DWORD*)PI)[1] & 0x1FFFF;
|
|
if (FlashRAM_Mode == FLASH_STATUS) {
|
|
memcpy(returnMemPointer(((DWORD*)PI)[0]),returnMemPointer(((DWORD*)PI)[1]),data+1);
|
|
//Debug (0, "Flash RAM Status DMA: %08X", ((DWORD*)PI)[1]);
|
|
} else {
|
|
if (SRinUse == true) {
|
|
//Debug (0, "SRAM RAM Read DMA: %08X", ((DWORD*)PI)[1]);
|
|
} else {
|
|
address *= 2;
|
|
//Debug (0, "Flash RAM Read DMA: %08X", ((DWORD*)PI)[1]);
|
|
}
|
|
memcpy(returnMemPointer(((DWORD*)PI)[0]),&FlashRAM[address],data+1);
|
|
}
|
|
} else {
|
|
int exdst = (((DWORD*)PI)[0] & 3);
|
|
int exsrc = (((DWORD*)PI)[1] & 3);
|
|
if ((exdst || exsrc)) {
|
|
for (int x = 0; x <= data; x++) {
|
|
*(u8 *)returnMemPointer((((DWORD*)PI)[0]+x)^3) = *(u8 *)returnMemPointer((((DWORD*)PI)[1]+x)^3);
|
|
}
|
|
} else {
|
|
memcpy(returnMemPointer(((DWORD*)PI)[0]),returnMemPointer(((DWORD*)PI)[1]),data+1);
|
|
}
|
|
// memcpy(returnMemPointer(((DWORD*)PI)[0]),returnMemPointer(((DWORD*)PI)[1]),data+1);
|
|
}
|
|
//Debug (0, "%08X PI Transfer: (ROM)%08X -> (RDRAM)%08X with size %X", pc-4, ((DWORD*)PI)[1], ((DWORD*)PI)[0], data+1);
|
|
InterruptNeeded |= PI_INTERRUPT;
|
|
SET_INTR(PI_INTERRUPT);
|
|
return data;
|
|
} else {
|
|
Debug (0, "%08X BAD PI Transfer: (ROM)%08X -> (RDRAM)%08X with size %X", pc-4, ((DWORD*)PI)[1], ((DWORD*)PI)[0], data+1);
|
|
cpuIsDone = true;
|
|
cpuIsReset = true;
|
|
return data;
|
|
}
|
|
break;
|
|
//*/
|
|
extern u32 PiInterrupt, CountInterrupt, VsyncInterrupt;
|
|
extern u32 VsyncTime;
|
|
|
|
case 0x00800004://SI PIF2DRAM
|
|
DoPifEmulation ((u8*)returnMemPointer(ReadLong(0x04800000)), (u8*)returnMemPointer(0x1FC007C0));
|
|
//InterruptNeeded |= SI_INTERRUPT;
|
|
//SET_INTR(SI_INTERRUPT);
|
|
//pw32(0x04800018, 0x00001000);//SI_STATUS_REG = 0x00001000;
|
|
((u32 *)SI)[6] = 0x1001;
|
|
ScheduleEvent (SI_DMA_EVENT, SITIME, 0, NULL);
|
|
//PiInterrupt = instructions + 64;
|
|
//VsyncTime = MIN(MIN(CountInterrupt,PiInterrupt),VsyncInterrupt);
|
|
//Debug (0, "P2D: %08X, %08X", ReadLong(0x04800000), data);
|
|
return data; break;
|
|
case 0x00800010://SI DRAM2PIF
|
|
memcpy ((u8*)returnMemPointer(0x1FC007C0), (u8*)returnMemPointer(ReadLong(0x04800000)), 64);
|
|
//InterruptNeeded |= SI_INTERRUPT;
|
|
//SET_INTR(SI_INTERRUPT);
|
|
//pw32(0x04800018, 0x00001000);//SI_STATUS_REG = 0x00001000;
|
|
((u32 *)SI)[6] = 0x1001;
|
|
ScheduleEvent (SI_DMA_EVENT, SITIME, 0, NULL);
|
|
//PiInterrupt = instructions + 64;
|
|
//VsyncTime = MIN(MIN(CountInterrupt,PiInterrupt),VsyncInterrupt);
|
|
//Debug (0, "D2P: %08X, %08X", ReadLong(0x04800000), data);
|
|
return data; break;
|
|
case 0x00800018://SI STATUS REG
|
|
CLEAR_INTR(SI_INTERRUPT);
|
|
return (((u32 *)SI)[6] &= ~0x1000); break;
|
|
default: break;
|
|
}
|
|
return data;
|
|
} |