reupped untouched versions (pending proper migration of the sensor functions from VBA-GX

git-svn-id: https://svn.code.sf.net/p/vbam/code/trunk@923 a31d4220-a93d-0410-bf67-fe4944624d44
This commit is contained in:
squall-leonhart 2009-10-22 21:31:51 +00:00
parent 4aa84b20c8
commit 7d1e3e189a
8 changed files with 12165 additions and 8 deletions

92
src/System.h Normal file
View File

@ -0,0 +1,92 @@
#ifndef SYSTEM_H
#define SYSTEM_H
#include "common/Types.h"
#include <zlib.h>
class SoundDriver;
struct EmulatedSystem {
// main emulation function
void (*emuMain)(int);
// reset emulator
void (*emuReset)();
// clean up memory
void (*emuCleanUp)();
// load battery file
bool (*emuReadBattery)(const char *);
// write battery file
bool (*emuWriteBattery)(const char *);
// load state
bool (*emuReadState)(const char *);
// save state
bool (*emuWriteState)(const char *);
// load memory state (rewind)
bool (*emuReadMemState)(char *, int);
// write memory state (rewind)
bool (*emuWriteMemState)(char *, int);
// write PNG file
bool (*emuWritePNG)(const char *);
// write BMP file
bool (*emuWriteBMP)(const char *);
// emulator update CPSR (ARM only)
void (*emuUpdateCPSR)();
// emulator has debugger
bool emuHasDebugger;
// clock ticks to emulate
int emuCount;
};
extern void log(const char *,...);
extern bool systemPauseOnFrame();
extern void systemGbPrint(u8 *,int,int,int,int);
extern void systemScreenCapture(int);
extern void systemDrawScreen();
// updates the joystick data
extern bool systemReadJoypads();
// return information about the given joystick, -1 for default joystick
extern u32 systemReadJoypad(int);
extern u32 systemGetClock();
extern void systemMessage(int, const char *, ...);
extern void systemSetTitle(const char *);
extern SoundDriver * systemSoundInit();
extern void systemOnWriteDataToSoundBuffer(const u16 * finalWave, int length);
extern void systemOnSoundShutdown();
extern void systemScreenMessage(const char *);
extern void systemUpdateMotionSensor();
extern int systemGetSensorX();
extern int systemGetSensorY();
extern bool systemCanChangeSoundQuality();
extern void systemShowSpeed(int);
extern void system10Frames(int);
extern void systemFrame();
extern void systemGbBorderOn();
extern void Sm60FPS_Init();
extern bool Sm60FPS_CanSkipFrame();
extern void Sm60FPS_Sleep();
extern void DbgMsg(const char *msg, ...);
extern void winlog(const char *,...);
extern void (*dbgOutput)(const char *s, u32 addr);
extern void (*dbgSignal)(int sig,int number);
extern u16 systemColorMap16[0x10000];
extern u32 systemColorMap32[0x10000];
extern u16 systemGbPalette[24];
extern int systemRedShift;
extern int systemGreenShift;
extern int systemBlueShift;
extern int systemColorDepth;
extern int systemDebug;
extern int systemVerbose;
extern int systemFrameSkip;
extern int systemSaveUpdateCounter;
extern int systemSpeed;
#define SYSTEM_SAVE_UPDATED 30
#define SYSTEM_SAVE_NOT_UPDATED 0
#endif // SYSTEM_H

5435
src/gb/GB.cpp Normal file

File diff suppressed because it is too large Load Diff

1703
src/gb/gbMemory.cpp Normal file

File diff suppressed because it is too large Load Diff

3987
src/gba/GBA.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -103,22 +103,24 @@ union u8h
{
struct
{
/* 0*/ unsigned lo:4;
/* 4*/ unsigned hi:4;
/* 0*/ unsigned lo:4;
/* 4*/ unsigned hi:4;
} __attribute__ ((packed));
u8 val;
};
#else
#else
union u8h
{
#pragma pack(1)
struct
{
unsigned lo:4;
unsigned hi:4;};
__declspec(align(8)) struct
{
unsigned lo:2;
unsigned hi:2;
};
u8 val;
};
#endif
union TileEntry

717
src/gba/GBAinline.h Normal file
View File

@ -0,0 +1,717 @@
#ifndef GBAINLINE_H
#define GBAINLINE_H
#include "../System.h"
#include "../common/Port.h"
#include "RTC.h"
#include "Sound.h"
#include "agbprint.h"
extern const u32 objTilesAddress[3];
extern bool stopState;
extern bool holdState;
extern int holdType;
extern int cpuNextEvent;
extern bool cpuSramEnabled;
extern bool cpuFlashEnabled;
extern bool cpuEEPROMEnabled;
extern bool cpuEEPROMSensorEnabled;
extern bool cpuDmaHack;
extern u32 cpuDmaLast;
extern bool timer0On;
extern int timer0Ticks;
extern int timer0ClockReload;
extern bool timer1On;
extern int timer1Ticks;
extern int timer1ClockReload;
extern bool timer2On;
extern int timer2Ticks;
extern int timer2ClockReload;
extern bool timer3On;
extern int timer3Ticks;
extern int timer3ClockReload;
extern int cpuTotalTicks;
#define CPUReadByteQuick(addr) \
map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
#define CPUReadHalfWordQuick(addr) \
READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
#define CPUReadMemoryQuick(addr) \
READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
static inline u32 CPUReadMemory(u32 address)
{
#ifdef GBA_LOGGING
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 GBA_LOGGING
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:
address = (address & 0x1fffc);
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
{
value = 0;
break;
}
if ((address & 0x18000) == 0x18000)
address &= 0x17fff;
value = READ32LE(((u32 *)&vram[address]));
break;
case 7:
value = READ32LE(((u32 *)&oam[address & 0x3FC]));
break;
case 8:
case 9:
case 10:
case 11:
case 12:
value = READ32LE(((u32 *)&rom[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 GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal word read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2);
}
#endif
if(cpuDmaHack) {
value = cpuDmaLast;
} else {
if(armState) {
value = CPUReadMemoryQuick(reg[15].I);
} else {
value = CPUReadHalfWordQuick(reg[15].I) |
CPUReadHalfWordQuick(reg[15].I) << 16;
}
}
}
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[];
static inline u32 CPUReadHalfWord(u32 address)
{
#ifdef GBA_LOGGING
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 GBA_LOGGING
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]));
if (((address & 0x3fe)>0xFF) && ((address & 0x3fe)<0x10E))
{
if (((address & 0x3fe) == 0x100) && timer0On)
value = 0xFFFF - ((timer0Ticks-cpuTotalTicks) >> timer0ClockReload);
else
if (((address & 0x3fe) == 0x104) && timer1On && !(TM1CNT & 4))
value = 0xFFFF - ((timer1Ticks-cpuTotalTicks) >> timer1ClockReload);
else
if (((address & 0x3fe) == 0x108) && timer2On && !(TM2CNT & 4))
value = 0xFFFF - ((timer2Ticks-cpuTotalTicks) >> timer2ClockReload);
else
if (((address & 0x3fe) == 0x10C) && timer3On && !(TM3CNT & 4))
value = 0xFFFF - ((timer3Ticks-cpuTotalTicks) >> timer3ClockReload);
}
}
else goto unreadable;
break;
case 5:
value = READ16LE(((u16 *)&paletteRAM[address & 0x3fe]));
break;
case 6:
address = (address & 0x1fffe);
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
{
value = 0;
break;
}
if ((address & 0x18000) == 0x18000)
address &= 0x17fff;
value = READ16LE(((u16 *)&vram[address]));
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
value = READ16LE(((u16 *)&rom[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 GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal halfword read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2);
}
#endif
if(cpuDmaHack) {
value = cpuDmaLast & 0xFFFF;
} else {
if(armState) {
value = CPUReadHalfWordQuick(reg[15].I + (address & 2));
} else {
value = CPUReadHalfWordQuick(reg[15].I);
}
}
break;
}
if(address & 1) {
value = (value >> 8) | (value << 24);
}
return value;
}
static inline u16 CPUReadHalfWordSigned(u32 address)
{
u16 value = CPUReadHalfWord(address);
if((address & 1))
value = (s8)value;
return value;
}
static inline u8 CPUReadByte(u32 address)
{
switch(address >> 24) {
case 0:
if (reg[15].I >> 24) {
if(address < 0x4000) {
#ifdef GBA_LOGGING
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:
address = (address & 0x1ffff);
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
return 0;
if ((address & 0x18000) == 0x18000)
address &= 0x17fff;
return vram[address];
case 7:
return oam[address & 0x3ff];
case 8:
case 9:
case 10:
case 11:
case 12:
return rom[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 GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal byte read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2);
}
#endif
if(cpuDmaHack) {
return cpuDmaLast & 0xFF;
} else {
if(armState) {
return CPUReadByteQuick(reg[15].I+(address & 3));
} else {
return CPUReadByteQuick(reg[15].I+(address & 1));
}
}
break;
}
}
static inline void CPUWriteMemory(u32 address, u32 value)
{
#ifdef GBA_LOGGING
if(address & 3) {
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
log("Unaligned word write: %08x to %08x from %08x\n",
value,
address,
armMode ? armNextPC - 4 : armNextPC - 2);
}
}
#endif
switch(address >> 24) {
case 0x02:
#ifdef BKPT_SUPPORT
if(*((u32 *)&freezeWorkRAM[address & 0x3FFFC]))
cheatsWriteMemory(address & 0x203FFFC,
value);
else
#endif
WRITE32LE(((u32 *)&workRAM[address & 0x3FFFC]), value);
break;
case 0x03:
#ifdef BKPT_SUPPORT
if(*((u32 *)&freezeInternalRAM[address & 0x7ffc]))
cheatsWriteMemory(address & 0x3007FFC,
value);
else
#endif
WRITE32LE(((u32 *)&internalRAM[address & 0x7ffC]), value);
break;
case 0x04:
if(address < 0x4000400) {
CPUUpdateRegister((address & 0x3FC), value & 0xFFFF);
CPUUpdateRegister((address & 0x3FC) + 2, (value >> 16));
} else goto unwritable;
break;
case 0x05:
#ifdef BKPT_SUPPORT
if(*((u32 *)&freezePRAM[address & 0x3fc]))
cheatsWriteMemory(address & 0x70003FC,
value);
else
#endif
WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value);
break;
case 0x06:
address = (address & 0x1fffc);
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
return;
if ((address & 0x18000) == 0x18000)
address &= 0x17fff;
#ifdef BKPT_SUPPORT
if(*((u32 *)&freezeVRAM[address]))
cheatsWriteMemory(address + 0x06000000, value);
else
#endif
WRITE32LE(((u32 *)&vram[address]), value);
break;
case 0x07:
#ifdef BKPT_SUPPORT
if(*((u32 *)&freezeOAM[address & 0x3fc]))
cheatsWriteMemory(address & 0x70003FC,
value);
else
#endif
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 GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
log("Illegal word write: %08x to %08x from %08x\n",
value,
address,
armMode ? armNextPC - 4 : armNextPC - 2);
}
#endif
break;
}
}
static inline void CPUWriteHalfWord(u32 address, u16 value)
{
#ifdef GBA_LOGGING
if(address & 1) {
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
log("Unaligned halfword write: %04x to %08x from %08x\n",
value,
address,
armMode ? armNextPC - 4 : armNextPC - 2);
}
}
#endif
switch(address >> 24) {
case 2:
#ifdef BKPT_SUPPORT
if(*((u16 *)&freezeWorkRAM[address & 0x3FFFE]))
cheatsWriteHalfWord(address & 0x203FFFE,
value);
else
#endif
WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]),value);
break;
case 3:
#ifdef BKPT_SUPPORT
if(*((u16 *)&freezeInternalRAM[address & 0x7ffe]))
cheatsWriteHalfWord(address & 0x3007ffe,
value);
else
#endif
WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value);
break;
case 4:
if(address < 0x4000400)
CPUUpdateRegister(address & 0x3fe, value);
else goto unwritable;
break;
case 5:
#ifdef BKPT_SUPPORT
if(*((u16 *)&freezePRAM[address & 0x03fe]))
cheatsWriteHalfWord(address & 0x70003fe,
value);
else
#endif
WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
break;
case 6:
address = (address & 0x1fffe);
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
return;
if ((address & 0x18000) == 0x18000)
address &= 0x17fff;
#ifdef BKPT_SUPPORT
if(*((u16 *)&freezeVRAM[address]))
cheatsWriteHalfWord(address + 0x06000000,
value);
else
#endif
WRITE16LE(((u16 *)&vram[address]), value);
break;
case 7:
#ifdef BKPT_SUPPORT
if(*((u16 *)&freezeOAM[address & 0x03fe]))
cheatsWriteHalfWord(address & 0x70003fe,
value);
else
#endif
WRITE16LE(((u16 *)&oam[address & 0x3fe]), value);
break;
case 8:
case 9:
if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) {
if(!rtcWrite(address, value))
goto unwritable;
} else if(!agbPrintWrite(address, value)) goto unwritable;
break;
case 13:
if(cpuEEPROMEnabled) {
eepromWrite(address, (u8)value);
break;
}
goto unwritable;
case 14:
if((!eepromInUse) | cpuSramEnabled | cpuFlashEnabled) {
(*cpuSaveGameFunc)(address, (u8)value);
break;
}
goto unwritable;
default:
unwritable:
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
log("Illegal halfword write: %04x to %08x from %08x\n",
value,
address,
armMode ? armNextPC - 4 : armNextPC - 2);
}
#endif
break;
}
}
static inline void CPUWriteByte(u32 address, u8 b)
{
switch(address >> 24) {
case 2:
#ifdef BKPT_SUPPORT
if(freezeWorkRAM[address & 0x3FFFF])
cheatsWriteByte(address & 0x203FFFF, b);
else
#endif
workRAM[address & 0x3FFFF] = b;
break;
case 3:
#ifdef BKPT_SUPPORT
if(freezeInternalRAM[address & 0x7fff])
cheatsWriteByte(address & 0x3007fff, b);
else
#endif
internalRAM[address & 0x7fff] = b;
break;
case 4:
if(address < 0x4000400) {
switch(address & 0x3FF) {
case 0x60:
case 0x61:
case 0x62:
case 0x63:
case 0x64:
case 0x65:
case 0x68:
case 0x69:
case 0x6c:
case 0x6d:
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x78:
case 0x79:
case 0x7c:
case 0x7d:
case 0x80:
case 0x81:
case 0x84:
case 0x85:
case 0x90:
case 0x91:
case 0x92:
case 0x93:
case 0x94:
case 0x95:
case 0x96:
case 0x97:
case 0x98:
case 0x99:
case 0x9a:
case 0x9b:
case 0x9c:
case 0x9d:
case 0x9e:
case 0x9f:
soundEvent(address&0xFF, b);
break;
case 0x301: // HALTCNT, undocumented
if(b == 0x80)
stopState = true;
holdState = 1;
holdType = -1;
cpuNextEvent = cpuTotalTicks;
break;
default: // every other register
u32 lowerBits = address & 0x3fe;
if(address & 1) {
CPUUpdateRegister(lowerBits, (READ16LE(&ioMem[lowerBits]) & 0x00FF) | (b << 8));
} else {
CPUUpdateRegister(lowerBits, (READ16LE(&ioMem[lowerBits]) & 0xFF00) | b);
}
}
break;
} else goto unwritable;
break;
case 5:
// no need to switch
*((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b;
break;
case 6:
address = (address & 0x1fffe);
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
return;
if ((address & 0x18000) == 0x18000)
address &= 0x17fff;
// no need to switch
// byte writes to OBJ VRAM are ignored
if ((address) < objTilesAddress[((DISPCNT&7)+1)>>2])
{
#ifdef BKPT_SUPPORT
if(freezeVRAM[address])
cheatsWriteByte(address + 0x06000000, b);
else
#endif
*((u16 *)&vram[address]) = (b << 8) | b;
}
break;
case 7:
// no need to switch
// byte writes to OAM are ignored
// *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b;
break;
case 13:
if(cpuEEPROMEnabled) {
eepromWrite(address, b);
break;
}
goto unwritable;
case 14:
if ((saveType != 5) && ((!eepromInUse) | cpuSramEnabled | cpuFlashEnabled)) {
//if(!cpuEEPROMEnabled && (cpuSramEnabled | cpuFlashEnabled)) {
(*cpuSaveGameFunc)(address, b);
break;
}
// default
default:
unwritable:
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
log("Illegal byte write: %02x to %08x from %08x\n",
b,
address,
armMode ? armNextPC - 4 : armNextPC -2 );
}
#endif
break;
}
}
#endif // GBAINLINE_H

208
src/gba/RTC.cpp Normal file
View File

@ -0,0 +1,208 @@
#include "../System.h"
#include "GBA.h"
#include "Globals.h"
#include "../common/Port.h"
#include "../Util.h"
#include "../NLS.h"
#include <time.h>
#include <memory.h>
enum RTCSTATE { IDLE, COMMAND, DATA, READDATA };
typedef struct {
u8 byte0;
u8 byte1;
u8 byte2;
u8 command;
int dataLen;
int bits;
RTCSTATE state;
u8 data[12];
// reserved variables for future
u8 reserved[12];
bool reserved2;
u32 reserved3;
} RTCCLOCKDATA;
static RTCCLOCKDATA rtcClockData;
static bool rtcEnabled = false;
void rtcEnable(bool e)
{
rtcEnabled = e;
}
bool rtcIsEnabled()
{
return rtcEnabled;
}
u16 rtcRead(u32 address)
{
if(rtcEnabled) {
switch(address){
case 0x80000c8:
return rtcClockData.byte2;
break;
case 0x80000c6:
return rtcClockData.byte1;
break;
case 0x80000c4:
return rtcClockData.byte0;
break;
}
}
return READ16LE((&rom[address & 0x1FFFFFE]));
}
static u8 toBCD(u8 value)
{
value = value % 100;
int l = value % 10;
int h = value / 10;
return h * 16 + l;
}
bool rtcWrite(u32 address, u16 value)
{
if(!rtcEnabled)
return false;
if(address == 0x80000c8) {
rtcClockData.byte2 = (u8)value; // enable ?
} else if(address == 0x80000c6) {
rtcClockData.byte1 = (u8)value; // read/write
} else if(address == 0x80000c4) {
if(rtcClockData.byte2 & 1) {
if(rtcClockData.state == IDLE && rtcClockData.byte0 == 1 && value == 5) {
rtcClockData.state = COMMAND;
rtcClockData.bits = 0;
rtcClockData.command = 0;
} else if(!(rtcClockData.byte0 & 1) && (value & 1)) { // bit transfer
rtcClockData.byte0 = (u8)value;
switch(rtcClockData.state) {
case COMMAND:
rtcClockData.command |= ((value & 2) >> 1) << (7-rtcClockData.bits);
rtcClockData.bits++;
if(rtcClockData.bits == 8) {
rtcClockData.bits = 0;
switch(rtcClockData.command) {
case 0x60:
// not sure what this command does but it doesn't take parameters
// maybe it is a reset or stop
rtcClockData.state = IDLE;
rtcClockData.bits = 0;
break;
case 0x62:
// this sets the control state but not sure what those values are
rtcClockData.state = READDATA;
rtcClockData.dataLen = 1;
break;
case 0x63:
rtcClockData.dataLen = 1;
rtcClockData.data[0] = 0x40;
rtcClockData.state = DATA;
break;
case 0x64:
break;
case 0x65:
{
struct tm *newtime;
time_t long_time;
time( &long_time ); /* Get time as long integer. */
newtime = localtime( &long_time ); /* Convert to local time. */
rtcClockData.dataLen = 7;
rtcClockData.data[0] = toBCD(newtime->tm_year);
rtcClockData.data[1] = toBCD(newtime->tm_mon+1);
rtcClockData.data[2] = toBCD(newtime->tm_mday);
rtcClockData.data[3] = toBCD(newtime->tm_wday);
rtcClockData.data[4] = toBCD(newtime->tm_hour);
rtcClockData.data[5] = toBCD(newtime->tm_min);
rtcClockData.data[6] = toBCD(newtime->tm_sec);
rtcClockData.state = DATA;
}
break;
case 0x67:
{
struct tm *newtime;
time_t long_time;
time( &long_time ); /* Get time as long integer. */
newtime = localtime( &long_time ); /* Convert to local time. */
rtcClockData.dataLen = 3;
rtcClockData.data[0] = toBCD(newtime->tm_hour);
rtcClockData.data[1] = toBCD(newtime->tm_min);
rtcClockData.data[2] = toBCD(newtime->tm_sec);
rtcClockData.state = DATA;
}
break;
default:
systemMessage(0, N_("Unknown RTC command %02x"), rtcClockData.command);
rtcClockData.state = IDLE;
break;
}
}
break;
case DATA:
if(rtcClockData.byte1 & 2) {
} else {
rtcClockData.byte0 = (rtcClockData.byte0 & ~2) |
((rtcClockData.data[rtcClockData.bits >> 3] >>
(rtcClockData.bits & 7)) & 1)*2;
rtcClockData.bits++;
if(rtcClockData.bits == 8*rtcClockData.dataLen) {
rtcClockData.bits = 0;
rtcClockData.state = IDLE;
}
}
break;
case READDATA:
if(!(rtcClockData.byte1 & 2)) {
} else {
rtcClockData.data[rtcClockData.bits >> 3] =
(rtcClockData.data[rtcClockData.bits >> 3] >> 1) |
((value << 6) & 128);
rtcClockData.bits++;
if(rtcClockData.bits == 8*rtcClockData.dataLen) {
rtcClockData.bits = 0;
rtcClockData.state = IDLE;
}
}
break;
default:
break;
}
} else
rtcClockData.byte0 = (u8)value;
}
}
return true;
}
void rtcReset()
{
memset(&rtcClockData, 0, sizeof(rtcClockData));
rtcClockData.byte0 = 0;
rtcClockData.byte1 = 0;
rtcClockData.byte2 = 0;
rtcClockData.command = 0;
rtcClockData.dataLen = 0;
rtcClockData.bits = 0;
rtcClockData.state = IDLE;
}
void rtcSaveGame(gzFile gzFile)
{
utilGzWrite(gzFile, &rtcClockData, sizeof(rtcClockData));
}
void rtcReadGame(gzFile gzFile)
{
utilGzRead(gzFile, &rtcClockData, sizeof(rtcClockData));
}

13
src/gba/RTC.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef RTC_H
#define RTC_H
u16 rtcRead(u32 address);
bool rtcWrite(u32 address, u16 value);
void rtcEnable(bool);
bool rtcIsEnabled();
void rtcReset();
void rtcReadGame(gzFile gzFile);
void rtcSaveGame(gzFile gzFile);
#endif // RTC_H