mirror of
https://github.com/dborth/vbagx.git
synced 2024-11-01 16:35:11 +01:00
557 lines
14 KiB
C++
557 lines
14 KiB
C++
// -*- C++ -*-
|
|
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
|
// Copyright (C) 1999-2003 Forgotten
|
|
// Copyright (C) 2004 Forgotten and the VBA development team
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2, or(at your option)
|
|
// any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software Foundation,
|
|
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
#ifndef VBA_GBAinline_H
|
|
#define VBA_GBAinline_H
|
|
|
|
#include "System.h"
|
|
#include "Port.h"
|
|
#include "RTC.h"
|
|
#include "vmmem.h"
|
|
|
|
extern bool cpuSramEnabled;
|
|
extern bool cpuFlashEnabled;
|
|
extern bool cpuEEPROMEnabled;
|
|
extern bool cpuEEPROMSensorEnabled;
|
|
|
|
#define VM_USED 1
|
|
|
|
#define CPUReadByteQuickDef(addr) \
|
|
map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
|
|
|
|
#define CPUReadHalfWordQuickDef(addr) \
|
|
READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
|
|
|
|
#define CPUReadMemoryQuickDef(addr) \
|
|
READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
|
|
|
|
u8 inline CPUReadByteQuick( u32 addr )
|
|
{
|
|
switch(addr >> 24 )
|
|
{
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 12:
|
|
return VMRead8( addr & 0x1FFFFFF );
|
|
|
|
default:
|
|
return CPUReadByteQuickDef(addr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
u16 inline CPUReadHalfWordQuick( u32 addr )
|
|
{
|
|
switch(addr >> 24)
|
|
{
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 12:
|
|
return VMRead16( addr & 0x1FFFFFF );
|
|
default:
|
|
return CPUReadHalfWordQuickDef(addr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
u32 inline CPUReadMemoryQuick( u32 addr )
|
|
{
|
|
switch(addr >> 24)
|
|
{
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 12:
|
|
return VMRead32( addr & 0x1FFFFFF );
|
|
default:
|
|
return CPUReadMemoryQuickDef(addr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
inline u32 CPUReadMemory(u32 address)
|
|
{
|
|
|
|
#ifdef DEV_VERSION
|
|
if(address & 3)
|
|
{
|
|
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY)
|
|
{
|
|
log("Unaligned word read: %08x at %08x\n", address, armMode ?
|
|
armNextPC - 4 : armNextPC - 2);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
u32 value;
|
|
switch(address >> 24)
|
|
{
|
|
case 0:
|
|
if(reg[15].I >> 24)
|
|
{
|
|
if(address < 0x4000)
|
|
{
|
|
#ifdef DEV_VERSION
|
|
if(systemVerbose & VERBOSE_ILLEGAL_READ)
|
|
{
|
|
log("Illegal word read: %08x at %08x\n", address, armMode ?
|
|
armNextPC - 4 : armNextPC - 2);
|
|
}
|
|
#endif
|
|
|
|
value = READ32LE(((u32 *)&biosProtected));
|
|
}
|
|
else goto unreadable;
|
|
}
|
|
else
|
|
value = READ32LE(((u32 *)&bios[address & 0x3FFC]));
|
|
break;
|
|
case 2:
|
|
value = READ32LE(((u32 *)&workRAM[address & 0x3FFFC]));
|
|
break;
|
|
case 3:
|
|
value = READ32LE(((u32 *)&internalRAM[address & 0x7ffC]));
|
|
break;
|
|
case 4:
|
|
if((address < 0x4000400) && ioReadable[address & 0x3fc])
|
|
{
|
|
if(ioReadable[(address & 0x3fc) + 2])
|
|
value = READ32LE(((u32 *)&ioMem[address & 0x3fC]));
|
|
else
|
|
value = READ16LE(((u16 *)&ioMem[address & 0x3fc]));
|
|
}
|
|
else goto unreadable;
|
|
break;
|
|
case 5:
|
|
value = READ32LE(((u32 *)&paletteRAM[address & 0x3fC]));
|
|
break;
|
|
case 6:
|
|
value = READ32LE(((u32 *)&vram[address & 0x1fffc]));
|
|
break;
|
|
case 7:
|
|
value = READ32LE(((u32 *)&oam[address & 0x3FC]));
|
|
break;
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
/** Need NGC VM here **/
|
|
//value = READ32LE(((u32 *)&rom[address&0x1FFFFFC]));
|
|
value = VMRead32( address & 0x1FFFFFC );
|
|
break;
|
|
case 13:
|
|
if(cpuEEPROMEnabled)
|
|
// no need to swap this
|
|
return eepromRead(address);
|
|
goto unreadable;
|
|
case 14:
|
|
if(cpuFlashEnabled | cpuSramEnabled)
|
|
// no need to swap this
|
|
return flashRead(address);
|
|
// default
|
|
default:
|
|
unreadable:
|
|
#ifdef DEV_VERSION
|
|
if(systemVerbose & VERBOSE_ILLEGAL_READ)
|
|
{
|
|
log("Illegal word read: %08x at %08x\n", address, armMode ?
|
|
armNextPC - 4 : armNextPC - 2);
|
|
}
|
|
#endif
|
|
|
|
// if(ioMem[0x205] & 0x40) {
|
|
if(armState)
|
|
{
|
|
#if VM_USED
|
|
value = CPUReadMemoryQuick(reg[15].I);
|
|
#else
|
|
value = CPUReadMemoryQuickDef(reg[15].I);
|
|
#endif
|
|
//value = VMRead32(reg[15].I);
|
|
}
|
|
else
|
|
{
|
|
#if VM_USED
|
|
value = CPUReadHalfWordQuick(reg[15].I) |
|
|
CPUReadHalfWordQuick(reg[15].I) << 16;
|
|
#else
|
|
value = CPUReadHalfWordQuickDef(reg[15].I) |
|
|
CPUReadHalfWordQuickDef(reg[15].I) << 16;
|
|
#endif
|
|
//value = VMRead16(reg[15].I) | VMRead16(reg[15].I) << 16;
|
|
}
|
|
// } else {
|
|
// value = *((u32 *)&bios[address & 0x3ffc]);
|
|
// }
|
|
// return 0xFFFFFFFF;
|
|
}
|
|
|
|
if(address & 3)
|
|
{
|
|
#ifdef C_CORE
|
|
int shift = (address & 3) << 3;
|
|
value = (value >> shift) | (value << (32 - shift));
|
|
#else
|
|
#ifdef __GNUC__
|
|
asm("and $3, %%ecx;"
|
|
"shl $3 ,%%ecx;"
|
|
"ror %%cl, %0"
|
|
: "=r" (value)
|
|
: "r" (value), "c" (address));
|
|
#else
|
|
__asm {
|
|
mov ecx, address;
|
|
and ecx, 3;
|
|
shl ecx, 3;
|
|
ror [dword ptr value], cl;
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
return value;
|
|
}
|
|
|
|
extern u32 myROM[];
|
|
|
|
inline u32 CPUReadHalfWord(u32 address)
|
|
{
|
|
#ifdef DEV_VERSION
|
|
if(address & 1)
|
|
{
|
|
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY)
|
|
{
|
|
log("Unaligned halfword read: %08x at %08x\n", address, armMode ?
|
|
armNextPC - 4 : armNextPC - 2);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
u32 value;
|
|
|
|
switch(address >> 24)
|
|
{
|
|
case 0:
|
|
if (reg[15].I >> 24)
|
|
{
|
|
if(address < 0x4000)
|
|
{
|
|
#ifdef DEV_VERSION
|
|
if(systemVerbose & VERBOSE_ILLEGAL_READ)
|
|
{
|
|
log("Illegal halfword read: %08x at %08x\n", address, armMode ?
|
|
armNextPC - 4 : armNextPC - 2);
|
|
}
|
|
#endif
|
|
value = READ16LE(((u16 *)&biosProtected[address&2]));
|
|
}
|
|
else goto unreadable;
|
|
}
|
|
else
|
|
value = READ16LE(((u16 *)&bios[address & 0x3FFE]));
|
|
break;
|
|
case 2:
|
|
value = READ16LE(((u16 *)&workRAM[address & 0x3FFFE]));
|
|
break;
|
|
case 3:
|
|
value = READ16LE(((u16 *)&internalRAM[address & 0x7ffe]));
|
|
break;
|
|
case 4:
|
|
if((address < 0x4000400) && ioReadable[address & 0x3fe])
|
|
value = READ16LE(((u16 *)&ioMem[address & 0x3fe]));
|
|
else goto unreadable;
|
|
break;
|
|
case 5:
|
|
value = READ16LE(((u16 *)&paletteRAM[address & 0x3fe]));
|
|
break;
|
|
case 6:
|
|
value = READ16LE(((u16 *)&vram[address & 0x1fffe]));
|
|
break;
|
|
case 7:
|
|
value = READ16LE(((u16 *)&oam[address & 0x3fe]));
|
|
break;
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8)
|
|
value = rtcRead(address);
|
|
else
|
|
/** Need NGC VM Here **/
|
|
//value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE]));
|
|
value = VMRead16( address & 0x1FFFFFE );
|
|
break;
|
|
case 13:
|
|
if(cpuEEPROMEnabled)
|
|
// no need to swap this
|
|
return eepromRead(address);
|
|
goto unreadable;
|
|
case 14:
|
|
if(cpuFlashEnabled | cpuSramEnabled)
|
|
// no need to swap this
|
|
return flashRead(address);
|
|
// default
|
|
default:
|
|
unreadable:
|
|
#ifdef DEV_VERSION
|
|
if(systemVerbose & VERBOSE_ILLEGAL_READ)
|
|
{
|
|
log("Illegal halfword read: %08x at %08x\n", address, armMode ?
|
|
armNextPC - 4 : armNextPC - 2);
|
|
}
|
|
#endif
|
|
extern bool cpuDmaHack;
|
|
extern u32 cpuDmaLast;
|
|
extern int cpuDmaCount;
|
|
if(cpuDmaHack && cpuDmaCount)
|
|
{
|
|
value = (u16)cpuDmaLast;
|
|
}
|
|
else
|
|
{
|
|
if(armState)
|
|
{
|
|
#if VM_USED
|
|
value = CPUReadHalfWordQuick(reg[15].I + (address & 2));
|
|
#else
|
|
value = CPUReadHalfWordQuickDef(reg[15].I + (address & 2));
|
|
#endif
|
|
//value = VMRead16(reg[15].I + (address & 2));
|
|
}
|
|
else
|
|
{
|
|
#if VM_USED
|
|
value = CPUReadHalfWordQuick(reg[15].I);
|
|
#else
|
|
value = CPUReadHalfWordQuickDef(reg[15].I);
|
|
#endif
|
|
//value = VMRead16(reg[15].I);
|
|
}
|
|
}
|
|
// return value;
|
|
// if(address & 1)
|
|
// value = (value >> 8) | ((value & 0xFF) << 24);
|
|
// return 0xFFFF;
|
|
break;
|
|
}
|
|
|
|
if(address & 1)
|
|
{
|
|
value = (value >> 8) | (value << 24);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
inline u16 CPUReadHalfWordSigned(u32 address)
|
|
{
|
|
u16 value = CPUReadHalfWord(address);
|
|
if((address & 1))
|
|
value = (s8)value;
|
|
return value;
|
|
}
|
|
|
|
inline u8 CPUReadByte(u32 address)
|
|
{
|
|
switch(address >> 24)
|
|
{
|
|
case 0:
|
|
if (reg[15].I >> 24)
|
|
{
|
|
if(address < 0x4000)
|
|
{
|
|
#ifdef DEV_VERSION
|
|
if(systemVerbose & VERBOSE_ILLEGAL_READ)
|
|
{
|
|
log("Illegal byte read: %08x at %08x\n", address, armMode ?
|
|
armNextPC - 4 : armNextPC - 2);
|
|
}
|
|
#endif
|
|
return biosProtected[address & 3];
|
|
}
|
|
else goto unreadable;
|
|
}
|
|
return bios[address & 0x3FFF];
|
|
case 2:
|
|
return workRAM[address & 0x3FFFF];
|
|
case 3:
|
|
return internalRAM[address & 0x7fff];
|
|
case 4:
|
|
if((address < 0x4000400) && ioReadable[address & 0x3ff])
|
|
return ioMem[address & 0x3ff];
|
|
else goto unreadable;
|
|
case 5:
|
|
return paletteRAM[address & 0x3ff];
|
|
case 6:
|
|
return vram[address & 0x1ffff];
|
|
case 7:
|
|
return oam[address & 0x3ff];
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
/** Need NGC VM Here **/
|
|
//return rom[address & 0x1FFFFFF];
|
|
return VMRead8( address & 0x1FFFFFF );
|
|
case 13:
|
|
if(cpuEEPROMEnabled)
|
|
return eepromRead(address);
|
|
goto unreadable;
|
|
case 14:
|
|
if(cpuSramEnabled | cpuFlashEnabled)
|
|
return flashRead(address);
|
|
if(cpuEEPROMSensorEnabled)
|
|
{
|
|
switch(address & 0x00008f00)
|
|
{
|
|
case 0x8200:
|
|
return systemGetSensorX() & 255;
|
|
case 0x8300:
|
|
return (systemGetSensorX() >> 8)|0x80;
|
|
case 0x8400:
|
|
return systemGetSensorY() & 255;
|
|
case 0x8500:
|
|
return systemGetSensorY() >> 8;
|
|
}
|
|
}
|
|
// default
|
|
default:
|
|
unreadable:
|
|
#ifdef DEV_VERSION
|
|
if(systemVerbose & VERBOSE_ILLEGAL_READ)
|
|
{
|
|
log("Illegal byte read: %08x at %08x\n", address, armMode ?
|
|
armNextPC - 4 : armNextPC - 2);
|
|
}
|
|
#endif
|
|
|
|
if(armState)
|
|
{
|
|
#if VM_USED
|
|
return CPUReadByteQuick(reg[15].I+(address & 3));
|
|
#else
|
|
return CPUReadByteQuickDef(reg[15].I+(address & 3));
|
|
#endif
|
|
//return VMRead8(reg[15].I+(address & 3));
|
|
}
|
|
else
|
|
{
|
|
#if VM_USED
|
|
return CPUReadByteQuick(reg[15].I+(address & 1));
|
|
#else
|
|
return CPUReadByteQuickDef(reg[15].I+(address & 1));
|
|
#endif
|
|
//return VMRead8(reg[15].I+(address & 1));
|
|
}
|
|
// return 0xFF;
|
|
break;
|
|
}
|
|
}
|
|
|
|
inline void CPUWriteMemory(u32 address, u32 value)
|
|
{
|
|
#ifdef DEV_VERSION
|
|
if(address & 3)
|
|
{
|
|
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY)
|
|
{
|
|
log("Unaliagned word write: %08x to %08x from %08x\n",
|
|
value,
|
|
address,
|
|
armMode ? armNextPC - 4 : armNextPC - 2);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
switch(address >> 24)
|
|
{
|
|
case 0x02:
|
|
#ifdef SDL
|
|
if(*((u32 *)&freezeWorkRAM[address & 0x3FFFC]))
|
|
cheatsWriteMemory((u32 *)&workRAM[address & 0x3FFFC],
|
|
value,
|
|
*((u32 *)&freezeWorkRAM[address & 0x3FFFC]));
|
|
else
|
|
#endif
|
|
WRITE32LE(((u32 *)&workRAM[address & 0x3FFFC]), value);
|
|
break;
|
|
case 0x03:
|
|
#ifdef SDL
|
|
if(*((u32 *)&freezeInternalRAM[address & 0x7ffc]))
|
|
cheatsWriteMemory((u32 *)&internalRAM[address & 0x7FFC],
|
|
value,
|
|
*((u32 *)&freezeInternalRAM[address & 0x7ffc]));
|
|
else
|
|
#endif
|
|
WRITE32LE(((u32 *)&internalRAM[address & 0x7ffC]), value);
|
|
break;
|
|
case 0x04:
|
|
CPUUpdateRegister((address & 0x3FC), value & 0xFFFF);
|
|
CPUUpdateRegister((address & 0x3FC) + 2, (value >> 16));
|
|
break;
|
|
case 0x05:
|
|
WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value);
|
|
break;
|
|
case 0x06:
|
|
if(address & 0x10000)
|
|
WRITE32LE(((u32 *)&vram[address & 0x17ffc]), value);
|
|
else
|
|
WRITE32LE(((u32 *)&vram[address & 0x1fffc]), value);
|
|
break;
|
|
case 0x07:
|
|
WRITE32LE(((u32 *)&oam[address & 0x3fc]), value);
|
|
break;
|
|
case 0x0D:
|
|
if(cpuEEPROMEnabled)
|
|
{
|
|
eepromWrite(address, value);
|
|
break;
|
|
}
|
|
goto unwritable;
|
|
case 0x0E:
|
|
if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled)
|
|
{
|
|
(*cpuSaveGameFunc)(address, (u8)value);
|
|
break;
|
|
}
|
|
// default
|
|
default:
|
|
unwritable:
|
|
#ifdef DEV_VERSION
|
|
if(systemVerbose & VERBOSE_ILLEGAL_WRITE)
|
|
{
|
|
log("Illegal word write: %08x to %08x from %08x\n",
|
|
value,
|
|
address,
|
|
armMode ? armNextPC - 4 : armNextPC - 2);
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif //VBA_GBAinline_H
|