From c711145d1d120606656865fa5cdcb8d47eb51daf Mon Sep 17 00:00:00 2001 From: dborth Date: Mon, 22 Sep 2008 23:00:10 +0000 Subject: [PATCH] upgrade core, fix frameskipping bug --- Makefile.gc | 12 +- Makefile.wii | 12 +- readme.txt | 12 +- source/ngc/vbasupport.cpp | 26 +- source/ngc/vmmem.cpp | 36 +- source/vba/CheatSearch.cpp | 691 ++- source/vba/CheatSearch.h | 148 +- source/vba/Cheats.cpp | 4732 +++++++++------ source/vba/Cheats.h | 110 +- source/vba/EEprom.cpp | 420 +- source/vba/EEprom.h | 78 +- source/vba/Flash.cpp | 563 +- source/vba/Flash.h | 69 +- source/vba/GBA.cpp | 4361 -------------- source/vba/GBAinline.h | 556 -- source/vba/Gfx.h | 1809 ------ source/vba/Globals.cpp | 276 +- source/vba/Globals.h | 302 +- source/vba/Mode0.cpp | 1161 ++-- source/vba/Mode1.cpp | 1075 ++-- source/vba/Mode2.cpp | 996 ++-- source/vba/Mode3.cpp | 840 ++- source/vba/Mode4.cpp | 834 ++- source/vba/Mode5.cpp | 840 ++- source/vba/NLS.h | 126 +- source/vba/Port.h | 152 +- source/vba/RTC.cpp | 472 +- source/vba/RTC.h | 62 +- source/vba/Sound.cpp | 1936 +++--- source/vba/Sound.h | 166 +- source/vba/Sram.cpp | 71 +- source/vba/Sram.h | 53 +- source/vba/System.h | 262 +- source/vba/Text.cpp | 180 - source/vba/Text.h | 21 - source/vba/Util.cpp | 2217 ++++--- source/vba/Util.h | 29 +- source/vba/admame.cpp | 2043 ++++--- source/vba/agb/GBA-arm.cpp | 2967 ++++++++++ source/vba/agb/GBA-thumb.cpp | 2343 ++++++++ source/vba/agb/GBA.cpp | 3994 +++++++++++++ source/vba/{ => agb}/GBA.h | 313 +- source/vba/{Gfx.cpp => agb/GBAGfx.cpp} | 94 +- source/vba/agb/GBAGfx.h | 1601 +++++ source/vba/agb/GBAcpu.h | 302 + source/vba/agb/GBAinline.h | 738 +++ source/vba/{ => agb}/agbprint.cpp | 204 +- source/vba/{ => agb}/agbprint.h | 54 +- source/vba/arm-new.h | 7472 ------------------------ source/vba/armdis.cpp | 1551 +++-- source/vba/armdis.h | 66 +- source/vba/bilinear.cpp | 432 -- source/vba/bios.cpp | 2458 ++++---- source/vba/bios.h | 93 +- source/vba/{gb => dmg}/GB.cpp | 8 +- source/vba/{gb => dmg}/GB.h | 0 source/vba/{gb => dmg}/gbCheats.cpp | 0 source/vba/{gb => dmg}/gbCheats.h | 0 source/vba/{gb => dmg}/gbCodes.h | 0 source/vba/{gb => dmg}/gbCodesCB.h | 0 source/vba/{gb => dmg}/gbDis.cpp | 0 source/vba/{gb => dmg}/gbGfx.cpp | 2 +- source/vba/{gb => dmg}/gbGlobals.cpp | 2 +- source/vba/{gb => dmg}/gbGlobals.h | 0 source/vba/{gb => dmg}/gbMemory.cpp | 2 +- source/vba/{gb => dmg}/gbMemory.h | 0 source/vba/{gb => dmg}/gbPrinter.cpp | 2 +- source/vba/{gb => dmg}/gbPrinter.h | 0 source/vba/{gb => dmg}/gbSGB.cpp | 0 source/vba/{gb => dmg}/gbSGB.h | 0 source/vba/{gb => dmg}/gbSound.cpp | 0 source/vba/{gb => dmg}/gbSound.h | 0 source/vba/elf.cpp | 6242 ++++++++++---------- source/vba/elf.h | 594 +- source/vba/exprNode.h | 69 - source/vba/getopt.c | 1061 ---- source/vba/getopt.h | 142 - source/vba/getopt1.c | 191 - source/vba/interframe.cpp | 1224 ++-- source/vba/interp.h | 600 +- source/vba/pixel.cpp | 307 +- source/vba/simple2x.cpp | 112 - source/vba/thumb.h | 2474 -------- 83 files changed, 29032 insertions(+), 36431 deletions(-) delete mode 100644 source/vba/GBA.cpp delete mode 100644 source/vba/GBAinline.h delete mode 100644 source/vba/Gfx.h delete mode 100644 source/vba/Text.cpp delete mode 100644 source/vba/Text.h create mode 100644 source/vba/agb/GBA-arm.cpp create mode 100644 source/vba/agb/GBA-thumb.cpp create mode 100644 source/vba/agb/GBA.cpp rename source/vba/{ => agb}/GBA.h (72%) rename source/vba/{Gfx.cpp => agb/GBAGfx.cpp} (85%) create mode 100644 source/vba/agb/GBAGfx.h create mode 100644 source/vba/agb/GBAcpu.h create mode 100644 source/vba/agb/GBAinline.h rename source/vba/{ => agb}/agbprint.cpp (61%) rename source/vba/{ => agb}/agbprint.h (97%) delete mode 100644 source/vba/arm-new.h delete mode 100644 source/vba/bilinear.cpp rename source/vba/{gb => dmg}/GB.cpp (99%) rename source/vba/{gb => dmg}/GB.h (100%) rename source/vba/{gb => dmg}/gbCheats.cpp (100%) rename source/vba/{gb => dmg}/gbCheats.h (100%) rename source/vba/{gb => dmg}/gbCodes.h (100%) rename source/vba/{gb => dmg}/gbCodesCB.h (100%) rename source/vba/{gb => dmg}/gbDis.cpp (100%) rename source/vba/{gb => dmg}/gbGfx.cpp (99%) rename source/vba/{gb => dmg}/gbGlobals.cpp (98%) rename source/vba/{gb => dmg}/gbGlobals.h (100%) rename source/vba/{gb => dmg}/gbMemory.cpp (99%) rename source/vba/{gb => dmg}/gbMemory.h (100%) rename source/vba/{gb => dmg}/gbPrinter.cpp (99%) rename source/vba/{gb => dmg}/gbPrinter.h (100%) rename source/vba/{gb => dmg}/gbSGB.cpp (100%) rename source/vba/{gb => dmg}/gbSGB.h (100%) rename source/vba/{gb => dmg}/gbSound.cpp (100%) rename source/vba/{gb => dmg}/gbSound.h (100%) delete mode 100644 source/vba/exprNode.h delete mode 100644 source/vba/getopt.c delete mode 100644 source/vba/getopt.h delete mode 100644 source/vba/getopt1.c delete mode 100644 source/vba/simple2x.cpp delete mode 100644 source/vba/thumb.h diff --git a/Makefile.gc b/Makefile.gc index 03728e3..278fc54 100644 --- a/Makefile.gc +++ b/Makefile.gc @@ -18,17 +18,17 @@ include $(DEVKITPPC)/gamecube_rules TARGET := vbagx_gc TARGETDIR := executables BUILD := build_gc -SOURCES := source/vba source/vba/gb source/ngc -INCLUDES := source/vba source/vba/gb source/ngc +SOURCES := source/vba source/vba/agb source/vba/dmg source/ngc +INCLUDES := source/vba source/ngc #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) -maltivec \ - -DNGC -DWORDS_BIGENDIAN -DC_CORE \ - -DCHANFFS -DSDL -DHAVE_ZUTIL_H -CXXFLAGS = -save-temps -Xassembler -aln=$@.lst $(CFLAGS) +CFLAGS = -g -O3 -Wall $(MACHDEP) $(INCLUDE) \ + -DNGC -DWORDS_BIGENDIAN -DC_CORE -DFINAL_VERSION \ + -DSDL -DNO_PNG -DHAVE_ZUTIL_H +CXXFLAGS = $(CFLAGS) LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map -Wl,--cref #--------------------------------------------------------------------------------- diff --git a/Makefile.wii b/Makefile.wii index 43f8219..1d1b2b8 100644 --- a/Makefile.wii +++ b/Makefile.wii @@ -18,17 +18,17 @@ include $(DEVKITPPC)/wii_rules TARGET := vbagx_wii TARGETDIR := executables BUILD := build_wii -SOURCES := source/vba source/vba/gb source/ngc -INCLUDES := source/vba source/vba/gb source/ngc +SOURCES := source/vba source/vba/agb source/vba/dmg source/ngc +INCLUDES := source/vba source/ngc #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) -maltivec \ - -DNGC -DWORDS_BIGENDIAN -DC_CORE \ - -DCHANFFS -DSDL -DHAVE_ZUTIL_H -CXXFLAGS = -save-temps -Xassembler -aln=$@.lst $(CFLAGS) +CFLAGS = -g -O3 -Wall $(MACHDEP) $(INCLUDE) \ + -DNGC -DWORDS_BIGENDIAN -DC_CORE -DFINAL_VERSION \ + -DSDL -DNO_PNG -DHAVE_ZUTIL_H +CXXFLAGS = $(CFLAGS) LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map -Wl,--cref #--------------------------------------------------------------------------------- diff --git a/readme.txt b/readme.txt index 64b2504..53196ec 100644 --- a/readme.txt +++ b/readme.txt @@ -1,7 +1,7 @@ ¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤ - Visual Boy Advance GX - - Version 1.0.1 + Version 1.0.2 (Under GPL License) ¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤ @@ -22,6 +22,16 @@ With it you can play GBA/Game Boy Color/Game Boy games on your Wii/GameCube. |0O×øo· UPDATE HISTORY ·oø×O0| `¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' +[What's New 1.0.2] +* New core! The core is a modified version of VBA-M and VBA 1.80 beta 3 +* Better emulation speeds. Should now be nearly full speed all the time +* Turbo speed feature. Mapped to right C-stick (classic controller & + Gamecube controller), and A+B for wiimote +* Controller mapping preferences bug fixed. Your preferences will reset + automatically to correct any problems in your preferences file +* Fix a frameskipping bug +* Some tweaks behind the scenes + [What's New 1.0.1] * GBA games now run at full speed * Menu improvements, with spiffy new background - thanks brakken! diff --git a/source/ngc/vbasupport.cpp b/source/ngc/vbasupport.cpp index f2ca93f..9adff10 100644 --- a/source/ngc/vbasupport.cpp +++ b/source/ngc/vbasupport.cpp @@ -13,23 +13,21 @@ #include #include -#include "GBA.h" -#include "agbprint.h" +#include "agb/GBA.h" +#include "agb/agbprint.h" #include "Flash.h" #include "Port.h" #include "RTC.h" #include "Sound.h" -#include "Text.h" #include "unzip.h" #include "Util.h" -#include "gb/GB.h" -#include "gb/gbGlobals.h" +#include "dmg/GB.h" +#include "dmg/gbGlobals.h" #include "vba.h" #include "fileop.h" #include "audio.h" #include "vmmem.h" -#include "pal60.h" #include "input.h" #include "video.h" #include "menudraw.h" @@ -44,9 +42,6 @@ static tb_t start, now; u32 loadtimeradjust; -int throttle = 100; -u32 throttleLastTime = 0; - static u32 autoFrameSkipLastTime = 0; static int frameskipadjust = 0; @@ -122,7 +117,7 @@ bool systemPauseOnFrame() { return false; } - +/* void GC_Sleep(u32 dwMiliseconds) { int nVBlanks = (dwMiliseconds / 16); @@ -131,7 +126,7 @@ void GC_Sleep(u32 dwMiliseconds) VIDEO_WaitVSync(); } } - +*/ void system10Frames(int rate) { if ( cartridgeType == 1 ) @@ -181,8 +176,8 @@ void system10Frames(int rate) ****************************************************************************/ void systemGbPrint(u8 *data,int pages,int feed,int palette, int contrast) {} -void debuggerOutput(char *, u32) {} -void (*dbgOutput)(char *, u32) = debuggerOutput; +void debuggerOutput(const char *s, u32 addr) {} +void (*dbgOutput)(const char *s, u32 addr) = debuggerOutput; void systemMessage(int num, const char *msg, ...) {} /**************************************************************************** @@ -397,7 +392,7 @@ int loadVBAROM(char filename[]) } // Set defaults - flashSetSize(0x10000); + flashSetSize(0x20000); // 128K saves rtcEnable(true); agbPrintEnable(false); soundOffFlag = false; @@ -425,6 +420,9 @@ int loadVBAROM(char filename[]) emulating = 1; + // reset frameskip variables + autoFrameSkipLastTime = frameskipadjust = systemFrameSkip = 0; + // Start system clock mftb(&start); diff --git a/source/ngc/vmmem.cpp b/source/ngc/vmmem.cpp index 6ad3ef6..271eba8 100644 --- a/source/ngc/vmmem.cpp +++ b/source/ngc/vmmem.cpp @@ -17,7 +17,7 @@ #include #include -#include "GBA.h" +#include "agb/GBA.h" #include "Globals.h" #include "Util.h" #include "Port.h" @@ -104,20 +104,16 @@ static void VMClose( void ) int VMCPULoadROM( char *filename ) { int res=0; - char temp[512]; + //char temp[512]; VMClose(); VMAllocGBA(); GBAROMSize = 0; - sprintf(temp,"Filename %s\n", filename); - //WaitPrompt(temp); - romfile = gen_fopen(filename, "rb"); if ( romfile == NULL ) { WaitPrompt((char*) "Error opening file!"); - //while(1); VMClose(); return 0; } @@ -126,7 +122,7 @@ int VMCPULoadROM( char *filename ) GBAROMSize = ftell(romfile); fseek(romfile, 0, SEEK_SET); - sprintf(temp,"ROM Size %dMb (%dMBit)", GBAROMSize/1024/1024,(GBAROMSize*8)/1024/1024); + //sprintf(temp,"ROM Size %dMb (%dMBit)", GBAROMSize/1024/1024,(GBAROMSize*8)/1024/1024); //WaitPrompt(temp); rom = (u8 *)MEM2Storage; @@ -137,7 +133,8 @@ int VMCPULoadROM( char *filename ) if ( (u32)res != GBAROMSize ) { WaitPrompt((char*) "Error reading file!"); - while(1); + VMClose(); + return 0; } strcpy( romfilename, filename ); @@ -208,7 +205,7 @@ u8 VMRead8( u32 address ) #include #include -#include "GBA.h" +#include "agb/GBA.h" #include "Globals.h" #include "Util.h" #include "Port.h" @@ -389,13 +386,12 @@ int VMCPULoadROM( char *filename ) loadtimeradjust = useVM = GBAROMSize = 0; - printf("Filename %s\n", filename); + //printf("Filename %s\n", filename); romfile = gen_fopen(filename, "rb"); if ( romfile == NULL ) { WaitPrompt((char*) "Error opening file!"); - while(1); VMClose(); return 0; } @@ -408,7 +404,8 @@ int VMCPULoadROM( char *filename ) { sprintf(msg, "Error reading file! %i \n",res); WaitPrompt(msg); - while(1); + VMClose(); + return 0; } fseek(romfile, 0, SEEK_END); @@ -446,7 +443,8 @@ static void VMNewPage( int pageid ) { sprintf(msg, "Seek error! - Offset %08x %d\n", pageid << VMSHIFTBITS, res); WaitPrompt(msg); - while(1); + VMClose(); + return; } VMAllocate( pageid ); @@ -456,7 +454,8 @@ static void VMNewPage( int pageid ) { sprintf(msg, "Error reading! %d bytes only\n", res); WaitPrompt(msg); - while(1); + VMClose(); + return; } mftb(&end); @@ -516,7 +515,8 @@ u32 VMRead32( u32 address ) default: sprintf(msg, "VM32 : Unknown page type! (%d) [%d]", vmpage[pageid].pagetype, pageid); WaitPrompt(msg); - while(1); + VMClose(); + return 0; } /* Can never get here ... but stops gcc bitchin' */ @@ -555,7 +555,8 @@ u16 VMRead16( u32 address ) default: WaitPrompt((char*) "VM16 : Unknown page type!"); - while(1); + VMClose(); + return 0; } /* Can never get here ... but stops gcc bitchin' */ @@ -594,7 +595,8 @@ u8 VMRead8( u32 address ) default: WaitPrompt((char*) "VM8 : Unknown page type!"); - while(1); + VMClose(); + return 0; } /* Can never get here ... but stops gcc bitchin' */ diff --git a/source/vba/CheatSearch.cpp b/source/vba/CheatSearch.cpp index da460de..c5280b1 100644 --- a/source/vba/CheatSearch.cpp +++ b/source/vba/CheatSearch.cpp @@ -1,362 +1,329 @@ -// 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. - -#include -#include - -#include "CheatSearch.h" - -CheatSearchBlock cheatSearchBlocks[4]; - -CheatSearchData cheatSearchData = { - 0, - cheatSearchBlocks - }; - -static bool cheatSearchEQ(u32 a, u32 b) -{ - return a == b; -} - -static bool cheatSearchNE(u32 a, u32 b) -{ - return a != b; -} - -static bool cheatSearchLT(u32 a, u32 b) -{ - return a < b; -} - -static bool cheatSearchLE(u32 a, u32 b) -{ - return a <= b; -} - -static bool cheatSearchGT(u32 a, u32 b) -{ - return a > b; -} - -static bool cheatSearchGE(u32 a, u32 b) -{ - return a >= b; -} - -static bool cheatSearchSignedEQ(s32 a, s32 b) -{ - return a == b; -} - -static bool cheatSearchSignedNE(s32 a, s32 b) -{ - return a != b; -} - -static bool cheatSearchSignedLT(s32 a, s32 b) -{ - return a < b; -} - -static bool cheatSearchSignedLE(s32 a, s32 b) -{ - return a <= b; -} - -static bool cheatSearchSignedGT(s32 a, s32 b) -{ - return a > b; -} - -static bool cheatSearchSignedGE(s32 a, s32 b) -{ - return a >= b; -} - -static bool (*cheatSearchFunc[])(u32,u32) = { - cheatSearchEQ, - cheatSearchNE, - cheatSearchLT, - cheatSearchLE, - cheatSearchGT, - cheatSearchGE - }; - -static bool (*cheatSearchSignedFunc[])(s32,s32) = { - cheatSearchSignedEQ, - cheatSearchSignedNE, - cheatSearchSignedLT, - cheatSearchSignedLE, - cheatSearchSignedGT, - cheatSearchSignedGE - }; - -void cheatSearchCleanup(CheatSearchData *cs) -{ - int count = cs->count; - - for(int i = 0; i < count; i++) - { - free(cs->blocks[i].saved); - free(cs->blocks[i].bits); - } - cs->count = 0; -} - -void cheatSearchStart(const CheatSearchData *cs) -{ - int count = cs->count; - - for(int i = 0; i < count; i++) - { - CheatSearchBlock *block = &cs->blocks[i]; - - memset(block->bits, 0xff, block->size >> 3); - memcpy(block->saved, block->data, block->size); - } -} - -s32 cheatSearchSignedRead(u8 *data, int off, int size) -{ - u32 res = data[off++]; - - switch(size) - { - case BITS_8: - res <<= 24; - return ((s32)res) >> 24; - case BITS_16: - res |= ((u32)data[off++])<<8; - res <<= 16; - return ((s32)res) >> 16; - case BITS_32: - res |= ((u32)data[off++])<<8; - res |= ((u32)data[off++])<<16; - res |= ((u32)data[off++])<<24; - return (s32)res; - } - return (s32)res; -} - -u32 cheatSearchRead(u8 *data, int off, int size) -{ - u32 res = data[off++]; - if(size == BITS_16) - res |= ((u32)data[off++])<<8; - else if(size == BITS_32) - { - res |= ((u32)data[off++])<<8; - res |= ((u32)data[off++])<<16; - res |= ((u32)data[off++])<<24; - } - return res; -} - -void cheatSearch(const CheatSearchData *cs, int compare, int size, - bool isSigned) -{ - if(compare < 0 || compare > SEARCH_GE) - return; - int inc = 1; - if(size == BITS_16) - inc = 2; - else if(size == BITS_32) - inc = 4; - - if(isSigned) - { - bool (*func)(s32,s32) = cheatSearchSignedFunc[compare]; - - for(int i = 0; i < cs->count; i++) - { - CheatSearchBlock *block = &cs->blocks[i]; - int size2 = block->size; - u8 *bits = block->bits; - u8 *data = block->data; - u8 *saved = block->saved; - - for(int j = 0; j < size2; j += inc) - { - if(IS_BIT_SET(bits, j)) - { - s32 a = cheatSearchSignedRead(data, j, size); - s32 b = cheatSearchSignedRead(saved,j, size); - - if(!func(a, b)) - { - CLEAR_BIT(bits, j); - if(size == BITS_16) - CLEAR_BIT(bits, j+1); - if(size == BITS_32) - { - CLEAR_BIT(bits, j+2); - CLEAR_BIT(bits, j+3); - } - } - } - } - } - } - else - { - bool (*func)(u32,u32) = cheatSearchFunc[compare]; - - for(int i = 0; i < cs->count; i++) - { - CheatSearchBlock *block = &cs->blocks[i]; - int size2 = block->size; - u8 *bits = block->bits; - u8 *data = block->data; - u8 *saved = block->saved; - - for(int j = 0; j < size2; j += inc) - { - if(IS_BIT_SET(bits, j)) - { - u32 a = cheatSearchRead(data, j, size); - u32 b = cheatSearchRead(saved,j, size); - - if(!func(a, b)) - { - CLEAR_BIT(bits, j); - if(size == BITS_16) - CLEAR_BIT(bits, j+1); - if(size == BITS_32) - { - CLEAR_BIT(bits, j+2); - CLEAR_BIT(bits, j+3); - } - } - } - } - } - } -} - -void cheatSearchValue(const CheatSearchData *cs, int compare, int size, - bool isSigned, u32 value) -{ - if(compare < 0 || compare > SEARCH_GE) - return; - int inc = 1; - if(size == BITS_16) - inc = 2; - else if(size == BITS_32) - inc = 4; - - if(isSigned) - { - bool (*func)(s32,s32) = cheatSearchSignedFunc[compare]; - - for(int i = 0; i < cs->count; i++) - { - CheatSearchBlock *block = &cs->blocks[i]; - int size2 = block->size; - u8 *bits = block->bits; - u8 *data = block->data; - - for(int j = 0; j < size2; j += inc) - { - if(IS_BIT_SET(bits, j)) - { - s32 a = cheatSearchSignedRead(data, j, size); - s32 b = (s32)value; - - if(!func(a, b)) - { - CLEAR_BIT(bits, j); - if(size == BITS_16) - CLEAR_BIT(bits, j+1); - if(size == BITS_32) - { - CLEAR_BIT(bits, j+2); - CLEAR_BIT(bits, j+3); - } - } - } - } - } - } - else - { - bool (*func)(u32,u32) = cheatSearchFunc[compare]; - - for(int i = 0; i < cs->count; i++) - { - CheatSearchBlock *block = &cs->blocks[i]; - int size2 = block->size; - u8 *bits = block->bits; - u8 *data = block->data; - - for(int j = 0; j < size2; j += inc) - { - if(IS_BIT_SET(bits, j)) - { - u32 a = cheatSearchRead(data, j, size); - - if(!func(a, value)) - { - CLEAR_BIT(bits, j); - if(size == BITS_16) - CLEAR_BIT(bits, j+1); - if(size == BITS_32) - { - CLEAR_BIT(bits, j+2); - CLEAR_BIT(bits, j+3); - } - } - } - } - } - } -} - -int cheatSearchGetCount(const CheatSearchData *cs, int size) -{ - int res = 0; - int inc = 1; - if(size == BITS_16) - inc = 2; - else if(size == BITS_32) - inc = 4; - - for(int i = 0; i < cs->count; i++) - { - CheatSearchBlock *block = &cs->blocks[i]; - - int size2 = block->size; - u8 *bits = block->bits; - for(int j = 0; j < size2; j += inc) - { - if(IS_BIT_SET(bits, j)) - res++; - } - } - return res; -} - -void cheatSearchUpdateValues(const CheatSearchData *cs) -{ - for(int i = 0; i < cs->count; i++) - { - CheatSearchBlock *block = &cs->blocks[i]; - - memcpy(block->saved, block->data, block->size); - } -} - +// 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. + +#include +#include + +#include "CheatSearch.h" + +CheatSearchBlock cheatSearchBlocks[4]; + +CheatSearchData cheatSearchData = { + 0, + cheatSearchBlocks +}; + +static bool cheatSearchEQ(u32 a, u32 b) +{ + return a == b; +} + +static bool cheatSearchNE(u32 a, u32 b) +{ + return a != b; +} + +static bool cheatSearchLT(u32 a, u32 b) +{ + return a < b; +} + +static bool cheatSearchLE(u32 a, u32 b) +{ + return a <= b; +} + +static bool cheatSearchGT(u32 a, u32 b) +{ + return a > b; +} + +static bool cheatSearchGE(u32 a, u32 b) +{ + return a >= b; +} + +static bool cheatSearchSignedEQ(s32 a, s32 b) +{ + return a == b; +} + +static bool cheatSearchSignedNE(s32 a, s32 b) +{ + return a != b; +} + +static bool cheatSearchSignedLT(s32 a, s32 b) +{ + return a < b; +} + +static bool cheatSearchSignedLE(s32 a, s32 b) +{ + return a <= b; +} + +static bool cheatSearchSignedGT(s32 a, s32 b) +{ + return a > b; +} + +static bool cheatSearchSignedGE(s32 a, s32 b) +{ + return a >= b; +} + +static bool (*cheatSearchFunc[])(u32,u32) = { + cheatSearchEQ, + cheatSearchNE, + cheatSearchLT, + cheatSearchLE, + cheatSearchGT, + cheatSearchGE +}; + +static bool (*cheatSearchSignedFunc[])(s32,s32) = { + cheatSearchSignedEQ, + cheatSearchSignedNE, + cheatSearchSignedLT, + cheatSearchSignedLE, + cheatSearchSignedGT, + cheatSearchSignedGE +}; + +void cheatSearchCleanup(CheatSearchData *cs) +{ + int count = cs->count; + + for(int i = 0; i < count; i++) { + free(cs->blocks[i].saved); + free(cs->blocks[i].bits); + } + cs->count = 0; +} + +void cheatSearchStart(const CheatSearchData *cs) +{ + int count = cs->count; + + for(int i = 0; i < count; i++) { + CheatSearchBlock *block = &cs->blocks[i]; + + memset(block->bits, 0xff, block->size >> 3); + memcpy(block->saved, block->data, block->size); + } +} + +s32 cheatSearchSignedRead(u8 *data, int off, int size) +{ + u32 res = data[off++]; + + switch(size) { + case BITS_8: + res <<= 24; + return ((s32)res) >> 24; + case BITS_16: + res |= ((u32)data[off++])<<8; + res <<= 16; + return ((s32)res) >> 16; + case BITS_32: + res |= ((u32)data[off++])<<8; + res |= ((u32)data[off++])<<16; + res |= ((u32)data[off++])<<24; + return (s32)res; + } + return (s32)res; +} + +u32 cheatSearchRead(u8 *data, int off, int size) +{ + u32 res = data[off++]; + if(size == BITS_16) + res |= ((u32)data[off++])<<8; + else if(size == BITS_32) { + res |= ((u32)data[off++])<<8; + res |= ((u32)data[off++])<<16; + res |= ((u32)data[off++])<<24; + } + return res; +} + +void cheatSearch(const CheatSearchData *cs, int compare, int size, + bool isSigned) +{ + if(compare < 0 || compare > SEARCH_GE) + return; + int inc = 1; + if(size == BITS_16) + inc = 2; + else if(size == BITS_32) + inc = 4; + + if(isSigned) { + bool (*func)(s32,s32) = cheatSearchSignedFunc[compare]; + + for(int i = 0; i < cs->count; i++) { + CheatSearchBlock *block = &cs->blocks[i]; + int size2 = block->size; + u8 *bits = block->bits; + u8 *data = block->data; + u8 *saved = block->saved; + + for(int j = 0; j < size2; j += inc) { + if(IS_BIT_SET(bits, j)) { + s32 a = cheatSearchSignedRead(data, j, size); + s32 b = cheatSearchSignedRead(saved,j, size); + + if(!func(a, b)) { + CLEAR_BIT(bits, j); + if(size == BITS_16) + CLEAR_BIT(bits, j+1); + if(size == BITS_32) { + CLEAR_BIT(bits, j+2); + CLEAR_BIT(bits, j+3); + } + } + } + } + } + } else { + bool (*func)(u32,u32) = cheatSearchFunc[compare]; + + for(int i = 0; i < cs->count; i++) { + CheatSearchBlock *block = &cs->blocks[i]; + int size2 = block->size; + u8 *bits = block->bits; + u8 *data = block->data; + u8 *saved = block->saved; + + for(int j = 0; j < size2; j += inc) { + if(IS_BIT_SET(bits, j)) { + u32 a = cheatSearchRead(data, j, size); + u32 b = cheatSearchRead(saved,j, size); + + if(!func(a, b)) { + CLEAR_BIT(bits, j); + if(size == BITS_16) + CLEAR_BIT(bits, j+1); + if(size == BITS_32) { + CLEAR_BIT(bits, j+2); + CLEAR_BIT(bits, j+3); + } + } + } + } + } + } +} + +void cheatSearchValue(const CheatSearchData *cs, int compare, int size, + bool isSigned, u32 value) +{ + if(compare < 0 || compare > SEARCH_GE) + return; + int inc = 1; + if(size == BITS_16) + inc = 2; + else if(size == BITS_32) + inc = 4; + + if(isSigned) { + bool (*func)(s32,s32) = cheatSearchSignedFunc[compare]; + + for(int i = 0; i < cs->count; i++) { + CheatSearchBlock *block = &cs->blocks[i]; + int size2 = block->size; + u8 *bits = block->bits; + u8 *data = block->data; + + for(int j = 0; j < size2; j += inc) { + if(IS_BIT_SET(bits, j)) { + s32 a = cheatSearchSignedRead(data, j, size); + s32 b = (s32)value; + + if(!func(a, b)) { + CLEAR_BIT(bits, j); + if(size == BITS_16) + CLEAR_BIT(bits, j+1); + if(size == BITS_32) { + CLEAR_BIT(bits, j+2); + CLEAR_BIT(bits, j+3); + } + } + } + } + } + } else { + bool (*func)(u32,u32) = cheatSearchFunc[compare]; + + for(int i = 0; i < cs->count; i++) { + CheatSearchBlock *block = &cs->blocks[i]; + int size2 = block->size; + u8 *bits = block->bits; + u8 *data = block->data; + + for(int j = 0; j < size2; j += inc) { + if(IS_BIT_SET(bits, j)) { + u32 a = cheatSearchRead(data, j, size); + + if(!func(a, value)) { + CLEAR_BIT(bits, j); + if(size == BITS_16) + CLEAR_BIT(bits, j+1); + if(size == BITS_32) { + CLEAR_BIT(bits, j+2); + CLEAR_BIT(bits, j+3); + } + } + } + } + } + } +} + +int cheatSearchGetCount(const CheatSearchData *cs, int size) +{ + int res = 0; + int inc = 1; + if(size == BITS_16) + inc = 2; + else if(size == BITS_32) + inc = 4; + + for(int i = 0; i < cs->count; i++) { + CheatSearchBlock *block = &cs->blocks[i]; + + int size2 = block->size; + u8 *bits = block->bits; + for(int j = 0; j < size2; j += inc) { + if(IS_BIT_SET(bits, j)) + res++; + } + } + return res; +} + +void cheatSearchUpdateValues(const CheatSearchData *cs) +{ + for(int i = 0; i < cs->count; i++) { + CheatSearchBlock *block = &cs->blocks[i]; + + memcpy(block->saved, block->data, block->size); + } +} + diff --git a/source/vba/CheatSearch.h b/source/vba/CheatSearch.h index 5b833cb..43a68c4 100644 --- a/source/vba/CheatSearch.h +++ b/source/vba/CheatSearch.h @@ -1,75 +1,73 @@ -// -*- 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_CHEATSEARCH_H -#define VBA_CHEATSEARCH_H - -#include "System.h" - -struct CheatSearchBlock - { - int size; - u32 offset; - u8 *bits; - u8 *data; - u8 *saved; - }; - -struct CheatSearchData - { - int count; - CheatSearchBlock *blocks; - }; - -enum { - SEARCH_EQ, - SEARCH_NE, - SEARCH_LT, - SEARCH_LE, - SEARCH_GT, - SEARCH_GE -}; - -enum { - BITS_8, - BITS_16, - BITS_32 -}; - -#define SET_BIT(bits,off) \ - (bits)[(off) >> 3] |= (1 << ((off) & 7)) - -#define CLEAR_BIT(bits, off) \ - (bits)[(off) >> 3] &= ~(1 << ((off) & 7)) - -#define IS_BIT_SET(bits, off) \ - (bits)[(off) >> 3] & (1 << ((off) & 7)) - -extern CheatSearchData cheatSearchData; -extern void cheatSearchCleanup(CheatSearchData *cs); -extern void cheatSearchStart(const CheatSearchData *cs); -extern void cheatSearch(const CheatSearchData *cs, int compare, int size, - bool isSigned); -extern void cheatSearchValue(const CheatSearchData *cs, int compare, int size, - bool isSigned, u32 value); -extern int cheatSearchGetCount(const CheatSearchData *cs, int size); -extern void cheatSearchUpdateValues(const CheatSearchData *cs); -extern s32 cheatSearchSignedRead(u8 *data, int off, int size); -extern u32 cheatSearchRead(u8 *data, int off, int size); -#endif +// -*- 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_CHEATSEARCH_H +#define VBA_CHEATSEARCH_H + +#include "System.h" + +struct CheatSearchBlock { + int size; + u32 offset; + u8 *bits; + u8 *data; + u8 *saved; +}; + +struct CheatSearchData { + int count; + CheatSearchBlock *blocks; +}; + +enum { + SEARCH_EQ, + SEARCH_NE, + SEARCH_LT, + SEARCH_LE, + SEARCH_GT, + SEARCH_GE +}; + +enum { + BITS_8, + BITS_16, + BITS_32 +}; + +#define SET_BIT(bits,off) \ + (bits)[(off) >> 3] |= (1 << ((off) & 7)) + +#define CLEAR_BIT(bits, off) \ + (bits)[(off) >> 3] &= ~(1 << ((off) & 7)) + +#define IS_BIT_SET(bits, off) \ + (bits)[(off) >> 3] & (1 << ((off) & 7)) + +extern CheatSearchData cheatSearchData; +extern void cheatSearchCleanup(CheatSearchData *cs); +extern void cheatSearchStart(const CheatSearchData *cs); +extern void cheatSearch(const CheatSearchData *cs, int compare, int size, + bool isSigned); +extern void cheatSearchValue(const CheatSearchData *cs, int compare, int size, + bool isSigned, u32 value); +extern int cheatSearchGetCount(const CheatSearchData *cs, int size); +extern void cheatSearchUpdateValues(const CheatSearchData *cs); +extern s32 cheatSearchSignedRead(u8 *data, int off, int size); +extern u32 cheatSearchRead(u8 *data, int off, int size); +#endif diff --git a/source/vba/Cheats.cpp b/source/vba/Cheats.cpp index 54df425..6947f59 100644 --- a/source/vba/Cheats.cpp +++ b/source/vba/Cheats.cpp @@ -1,1836 +1,2896 @@ -// 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. - -#include "sdfileio.h" -#include -#include -#include -#include - -#include "GBA.h" -#include "GBAinline.h" -#include "Cheats.h" -#include "Globals.h" -#include "NLS.h" -#include "Util.h" - -/** - * Gameshark code types: - * - * NNNNNNNN 001DC0DE - ID code for the game (game 4 character name) from ROM - * DEADFACE XXXXXXXX - changes decryption seeds - * 0AAAAAAA 000000YY - 8-bit constant write - * 1AAAAAAA 0000YYYY - 16-bit constant write - * 2AAAAAAA YYYYYYYY - 32-bit constant write - * 3AAAAAAA YYYYYYYY - ?? - * 6AAAAAAA 0000YYYY - 16-bit ROM Patch (address >> 1) - * 6AAAAAAA 1000YYYY - 16-bit ROM Patch ? (address >> 1) - * 6AAAAAAA 2000YYYY - 16-bit ROM Patch ? (address >> 1) - * 8A1AAAAA 000000YY - 8-bit button write - * 8A2AAAAA 0000YYYY - 16-bit button write - * 8A3AAAAA YYYYYYYY - 32-bit button write - * 80F00000 0000YYYY - button slow motion - * DAAAAAAA 0000YYYY - if address contains 16-bit value enable next code - * FAAAAAAA 0000YYYY - Master code function - * - * CodeBreaker codes types: - * - * 0000AAAA 000Y - Game CRC (Y are flags: 8 - CRC, 2 - DI) - * 1AAAAAAA YYYY - Master Code function (store address at ((YYYY << 0x16) - * + 0x08000100)) - * 2AAAAAAA YYYY - 16-bit or - * 3AAAAAAA YYYY - 8-bit constant write - * 4AAAAAAA YYYY - Slide code - * XXXXCCCC IIII (C is count and I is address increment, X is value incr.) - * 5AAAAAAA CCCC - Super code (Write bytes to address, CCCC is count) - * BBBBBBBB BBBB - * 6AAAAAAA YYYY - 16-bit and - * 7AAAAAAA YYYY - if address contains 16-bit value enable next code - * 8AAAAAAA YYYY - 16-bit constant write - * 9AAAAAAA YYYY - change decryption (when first code only?) - * AAAAAAAA YYYY - if address does not contain 16-bit value enable next code - * BAAAAAAA YYYY - if 16-bit < YYYY - * CAAAAAAA YYYY - if 16-bit > YYYY - * D0000020 YYYY - if button keys equal value enable next code - * EAAAAAAA YYYY - increase value stored in address - */ -#define UNKNOWN_CODE -1 -#define INT_8_BIT_WRITE 0 -#define INT_16_BIT_WRITE 1 -#define INT_32_BIT_WRITE 2 -#define GSA_16_BIT_ROM_PATCH 3 -#define GSA_8_BIT_GS_WRITE 4 -#define GSA_16_BIT_GS_WRITE 5 -#define GSA_32_BIT_GS_WRITE 6 -#define CBA_IF_KEYS_PRESSED 7 -#define CBA_IF_TRUE 8 -#define CBA_SLIDE_CODE 9 -#define CBA_IF_FALSE 10 -#define CBA_AND 11 -#define GSA_8_BIT_GS_WRITE2 12 -#define GSA_16_BIT_GS_WRITE2 13 -#define GSA_32_BIT_GS_WRITE2 14 -#define GSA_16_BIT_ROM_PATCH2 15 -#define GSA_8_BIT_SLIDE 16 -#define GSA_16_BIT_SLIDE 17 -#define GSA_32_BIT_SLIDE 18 -#define GSA_8_BIT_IF_TRUE 19 -#define GSA_32_BIT_IF_TRUE 20 -#define GSA_8_BIT_IF_FALSE 21 -#define GSA_32_BIT_IF_FALSE 22 -#define GSA_8_BIT_FILL 23 -#define GSA_16_BIT_FILL 24 -#define GSA_8_BIT_IF_TRUE2 25 -#define GSA_16_BIT_IF_TRUE2 26 -#define GSA_32_BIT_IF_TRUE2 27 -#define GSA_8_BIT_IF_FALSE2 28 -#define GSA_16_BIT_IF_FALSE2 29 -#define GSA_32_BIT_IF_FALSE2 30 -#define GSA_SLOWDOWN 31 -#define CBA_ADD 32 -#define CBA_OR 33 -#define CBA_LT 34 -#define CBA_GT 35 -#define CBA_SUPER 36 - -CheatsData cheatsList[100]; -int cheatsNumber = 0; - -u8 cheatsCBASeedBuffer[0x30]; -u32 cheatsCBASeed[4]; -u32 cheatsCBATemporaryValue = 0; -u16 cheatsCBATable[256]; -bool cheatsCBATableGenerated = false; - -u8 cheatsCBACurrentSeed[12] = { - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - -#define CHEAT_IS_HEX(a) ( ((a)>='A' && (a) <='F') || ((a) >='0' && (a) <= '9')) - -#define CHEAT_PATCH_ROM_16BIT(a,v) \ - WRITE16LE(((u16 *)&rom[(a) & 0x1ffffff]), v); - -static bool isMultilineWithData(int i) -{ - // we consider it a multiline code if it has more than one line of data - // otherwise, it can still be considered a single code - if(i < cheatsNumber && i >= 0) - switch(cheatsList[i].size) - { - case INT_8_BIT_WRITE: - case INT_16_BIT_WRITE: - case INT_32_BIT_WRITE: - case GSA_16_BIT_ROM_PATCH: - case GSA_8_BIT_GS_WRITE: - case GSA_16_BIT_GS_WRITE: - case GSA_32_BIT_GS_WRITE: - case CBA_AND: - case CBA_IF_KEYS_PRESSED: - case CBA_IF_TRUE: - case CBA_IF_FALSE: - case GSA_8_BIT_IF_TRUE: - case GSA_32_BIT_IF_TRUE: - case GSA_8_BIT_IF_FALSE: - case GSA_32_BIT_IF_FALSE: - case GSA_8_BIT_FILL: - case GSA_16_BIT_FILL: - case GSA_8_BIT_IF_TRUE2: - case GSA_16_BIT_IF_TRUE2: - case GSA_32_BIT_IF_TRUE2: - case GSA_8_BIT_IF_FALSE2: - case GSA_16_BIT_IF_FALSE2: - case GSA_32_BIT_IF_FALSE2: - case GSA_SLOWDOWN: - case CBA_ADD: - case CBA_OR: - return false; - // the codes below have two lines of data - case CBA_SLIDE_CODE: - case GSA_8_BIT_GS_WRITE2: - case GSA_16_BIT_GS_WRITE2: - case GSA_32_BIT_GS_WRITE2: - case GSA_16_BIT_ROM_PATCH2: - case GSA_8_BIT_SLIDE: - case GSA_16_BIT_SLIDE: - case GSA_32_BIT_SLIDE: - case CBA_LT: - case CBA_GT: - case CBA_SUPER: - return true; - } - return false; -} - -static int getCodeLength(int num) -{ - if(num >= cheatsNumber || num < 0) - return 1; - - // this is for all the codes that are true multiline - switch(cheatsList[num].size) - { - case INT_8_BIT_WRITE: - case INT_16_BIT_WRITE: - case INT_32_BIT_WRITE: - case GSA_16_BIT_ROM_PATCH: - case GSA_8_BIT_GS_WRITE: - case GSA_16_BIT_GS_WRITE: - case GSA_32_BIT_GS_WRITE: - case CBA_AND: - case GSA_8_BIT_FILL: - case GSA_16_BIT_FILL: - case GSA_SLOWDOWN: - case CBA_ADD: - case CBA_OR: - return 1; - case CBA_IF_KEYS_PRESSED: - case CBA_IF_TRUE: - case CBA_IF_FALSE: - case CBA_SLIDE_CODE: - case GSA_8_BIT_GS_WRITE2: - case GSA_16_BIT_GS_WRITE2: - case GSA_32_BIT_GS_WRITE2: - case GSA_16_BIT_ROM_PATCH2: - case GSA_8_BIT_SLIDE: - case GSA_16_BIT_SLIDE: - case GSA_32_BIT_SLIDE: - case GSA_8_BIT_IF_TRUE: - case GSA_32_BIT_IF_TRUE: - case GSA_8_BIT_IF_FALSE: - case GSA_32_BIT_IF_FALSE: - case CBA_LT: - case CBA_GT: - return 2; - case GSA_8_BIT_IF_TRUE2: - case GSA_16_BIT_IF_TRUE2: - case GSA_32_BIT_IF_TRUE2: - case GSA_8_BIT_IF_FALSE2: - case GSA_16_BIT_IF_FALSE2: - case GSA_32_BIT_IF_FALSE2: - return 3; - case CBA_SUPER: - return (cheatsList[num].value+5)/6; - } - return 1; -} - -int cheatsCheckKeys(u32 keys, u32 extended) -{ - int ticks = 0; - for(int i = 0; i < cheatsNumber; i++) - { - if(!cheatsList[i].enabled) - { - // make sure we skip other lines in this code - i += getCodeLength(i)-1; - continue; - } - switch(cheatsList[i].size) - { - case INT_8_BIT_WRITE: - CPUWriteByte(cheatsList[i].address, cheatsList[i].value); - break; - case INT_16_BIT_WRITE: - CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value); - break; - case INT_32_BIT_WRITE: - CPUWriteMemory(cheatsList[i].address, cheatsList[i].value); - break; - case GSA_16_BIT_ROM_PATCH: - if((cheatsList[i].status & 1) == 0) - { - if(CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) - { - cheatsList[i].oldValue = CPUReadHalfWord(cheatsList[i].address); - cheatsList[i].status |= 1; - CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, cheatsList[i].value); - } - } - break; - case GSA_8_BIT_GS_WRITE: - if(extended & 4) - { - CPUWriteByte(cheatsList[i].address, cheatsList[i].value); - } - break; - case GSA_16_BIT_GS_WRITE: - if(extended & 4) - { - CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value); - } - break; - case GSA_32_BIT_GS_WRITE: - if(extended & 4) - { - CPUWriteMemory(cheatsList[i].address, cheatsList[i].value); - } - break; - case CBA_IF_KEYS_PRESSED: - { - u16 value = cheatsList[i].value; - u32 addr = cheatsList[i].address; - if((addr & 0x30) == 0x20) - { - if((keys & value) != value) - { - i++; - } - } - else if((addr & 0x30) == 0x10) - { - if((keys & value) == value) - { - i++; - } - } - } - break; - case CBA_IF_TRUE: - if(CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) - { - i++; - } - break; - case CBA_SLIDE_CODE: - { - u32 address = cheatsList[i].address; - u16 value = cheatsList[i].value; - i++; - if(i < cheatsNumber) - { - int count = (cheatsList[i].address & 0xFFFF); - u16 vinc = (cheatsList[i].address >> 16) & 0xFFFF; - int inc = cheatsList[i].value; - - for(int x = 0; x < count; x++) - { - CPUWriteHalfWord(address, value); - address += inc; - value += vinc; - } - } - } - break; - case CBA_IF_FALSE: - if(CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value) - { - i++; - } - break; - case CBA_AND: - CPUWriteHalfWord(cheatsList[i].address, - CPUReadHalfWord(cheatsList[i].address) & - cheatsList[i].value); - break; - case GSA_8_BIT_GS_WRITE2: - i++; - if(i < cheatsNumber) - { - if(extended & 4) - { - CPUWriteByte(cheatsList[i-1].value, cheatsList[i].address); - } - } - break; - case GSA_16_BIT_GS_WRITE2: - i++; - if(i < cheatsNumber) - { - if(extended & 4) - { - CPUWriteHalfWord(cheatsList[i-1].value, cheatsList[i].address); - } - } - break; - case GSA_32_BIT_GS_WRITE2: - i++; - if(i < cheatsNumber) - { - if(extended & 4) - { - CPUWriteMemory(cheatsList[i-1].value, cheatsList[i].address); - } - } - break; - case GSA_16_BIT_ROM_PATCH2: - i++; - if(i < cheatsNumber) - { - if((cheatsList[i-1].status & 1) == 0) - { - u32 addr = ((cheatsList[i-1].value & 0x00FFFFFF) << 1) + 0x8000000; - if(CPUReadHalfWord(addr) != (cheatsList[i].address & 0xFFFF)) - { - cheatsList[i-1].oldValue = CPUReadHalfWord(addr); - cheatsList[i-1].status |= 1; - CHEAT_PATCH_ROM_16BIT(addr,cheatsList[i].address & 0xFFFF); - } - } - } - break; - case GSA_8_BIT_SLIDE: - i++; - if(i < cheatsNumber) - { - u32 addr = cheatsList[i-1].value; - u8 value = cheatsList[i].address; - int vinc = (cheatsList[i].value >> 24) & 255; - int count = (cheatsList[i].value >> 16) & 255; - int ainc = (cheatsList[i].value & 0xffff); - while(count > 0) - { - CPUWriteByte(addr, value); - value += vinc; - addr += ainc; - count--; - } - } - break; - case GSA_16_BIT_SLIDE: - i++; - if(i < cheatsNumber) - { - u32 addr = cheatsList[i-1].value; - u16 value = cheatsList[i].address; - int vinc = (cheatsList[i].value >> 24) & 255; - int count = (cheatsList[i].value >> 16) & 255; - int ainc = (cheatsList[i].value & 0xffff)*2; - while(count > 0) - { - CPUWriteHalfWord(addr, value); - value += vinc; - addr += ainc; - count--; - } - } - break; - case GSA_32_BIT_SLIDE: - i++; - if(i < cheatsNumber) - { - u32 addr = cheatsList[i-1].value; - u32 value = cheatsList[i].address; - int vinc = (cheatsList[i].value >> 24) & 255; - int count = (cheatsList[i].value >> 16) & 255; - int ainc = (cheatsList[i].value & 0xffff)*4; - while(count > 0) - { - CPUWriteMemory(addr, value); - value += vinc; - addr += ainc; - count--; - } - } - break; - case GSA_8_BIT_IF_TRUE: - if(CPUReadByte(cheatsList[i].address) != cheatsList[i].value) - { - i++; - } - break; - case GSA_32_BIT_IF_TRUE: - if(CPUReadMemory(cheatsList[i].address) != cheatsList[i].value) - { - i++; - } - break; - case GSA_8_BIT_IF_FALSE: - if(CPUReadByte(cheatsList[i].address) == cheatsList[i].value) - { - i++; - } - break; - case GSA_32_BIT_IF_FALSE: - if(CPUReadMemory(cheatsList[i].address) == cheatsList[i].value) - { - i++; - } - break; - case GSA_8_BIT_FILL: - { - u32 addr = cheatsList[i].address; - u8 v = cheatsList[i].value & 0xff; - u32 end = addr + (cheatsList[i].value >> 8); - do - { - CPUWriteByte(addr, v); - addr++; - } - while (addr <= end); - } - break; - case GSA_16_BIT_FILL: - { - u32 addr = cheatsList[i].address; - u16 v = cheatsList[i].value & 0xffff; - u32 end = addr + ((cheatsList[i].value >> 16) << 1); - do - { - CPUWriteHalfWord(addr, v); - addr+=2; - } - while (addr <= end); - } - break; - case GSA_8_BIT_IF_TRUE2: - if(CPUReadByte(cheatsList[i].address) != cheatsList[i].value) - { - i+=2; - } - break; - case GSA_16_BIT_IF_TRUE2: - if(CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) - { - i+=2; - } - break; - case GSA_32_BIT_IF_TRUE2: - if(CPUReadMemory(cheatsList[i].address) != cheatsList[i].value) - { - i+=2; - } - break; - case GSA_8_BIT_IF_FALSE2: - if(CPUReadByte(cheatsList[i].address) == cheatsList[i].value) - { - i+=2; - } - break; - case GSA_16_BIT_IF_FALSE2: - if(CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value) - { - i+=2; - } - break; - case GSA_32_BIT_IF_FALSE2: - if(CPUReadMemory(cheatsList[i].address) == cheatsList[i].value) - { - i+=2; - } - break; - case GSA_SLOWDOWN: - // check if button was pressed and released, if so toggle our state - if((cheatsList[i].status & 4) && !(extended & 4)) - cheatsList[i].status ^= 1; - if(extended & 4) - cheatsList[i].status |= 4; - else - cheatsList[i].status &= ~4; - - if(cheatsList[i].status & 1) - ticks += 2*256*((cheatsList[i].value >> 8) & 255); - break; - case CBA_ADD: - CPUWriteHalfWord(cheatsList[i].address, - CPUReadHalfWord(cheatsList[i].address) + - (u16)cheatsList[i].value); - break; - case CBA_OR: - CPUWriteHalfWord(cheatsList[i].address, - CPUReadHalfWord(cheatsList[i].address) | - cheatsList[i].value); - break; - case CBA_LT: - if(CPUReadHalfWord(cheatsList[i].address) >= cheatsList[i].value) - i++; - break; - case CBA_GT: - if(CPUReadHalfWord(cheatsList[i].address) <= cheatsList[i].value) - i++; - break; - case CBA_SUPER: - { - int count = 2*cheatsList[i].value; - u32 address = cheatsList[i].address; - for(int x = 0; x < count; x++) - { - u8 b; - int res = x % 6; - if(res < 4) - b = (cheatsList[i].address >> (24-8*res)) & 0xFF; - else - b = (cheatsList[i].value >> (8 - 8*(res-4))) & 0x0FF; - CPUWriteByte(address, b); - address++; - if(x && !res) - i++; - } - if(count % 6) - i++; - } - break; - } - } - return ticks; -} - -void cheatsAdd(const char *codeStr, - const char *desc, - u32 address, - u32 value, - int code, - int size) -{ - if(cheatsNumber < 100) - { - int x = cheatsNumber; - cheatsList[x].code = code; - cheatsList[x].size = size; - cheatsList[x].address = address; - cheatsList[x].value = value; - strcpy(cheatsList[x].codestring, codeStr); - strcpy(cheatsList[x].desc, desc); - cheatsList[x].enabled = true; - cheatsList[x].status = 0; - - // we only store the old value for this simple codes. ROM patching - // is taken care when it actually patches the ROM - switch(cheatsList[x].size) - { - case INT_8_BIT_WRITE: - cheatsList[x].oldValue = CPUReadByte(address); - break; - case INT_16_BIT_WRITE: - cheatsList[x].oldValue = CPUReadHalfWord(address); - break; - case INT_32_BIT_WRITE: - cheatsList[x].oldValue = CPUReadMemory(address); - break; - } - cheatsNumber++; - } -} - -void cheatsDelete(int number, bool restore) -{ - if(number < cheatsNumber && number >= 0) - { - int x = number; - - if(restore) - { - switch(cheatsList[x].size) - { - case INT_8_BIT_WRITE: - CPUWriteByte(cheatsList[x].address, (u8)cheatsList[x].oldValue); - break; - case INT_16_BIT_WRITE: - CPUWriteHalfWord(cheatsList[x].address, (u16)cheatsList[x].oldValue); - break; - case INT_32_BIT_WRITE: - CPUWriteMemory(cheatsList[x].address, cheatsList[x].oldValue); - break; - case GSA_16_BIT_ROM_PATCH: - if(cheatsList[x].status & 1) - { - cheatsList[x].status &= ~1; - CHEAT_PATCH_ROM_16BIT(cheatsList[x].address, - cheatsList[x].oldValue); - } - break; - case GSA_16_BIT_ROM_PATCH2: - if(cheatsList[x].status & 1) - { - cheatsList[x].status &= ~1; - CHEAT_PATCH_ROM_16BIT(((cheatsList[x].value & 0x00FFFFFF) << 1)+ - 0x8000000, - cheatsList[x].oldValue); - } - break; - } - } - if((x+1) < cheatsNumber) - { - memcpy(&cheatsList[x], &cheatsList[x+1], sizeof(CheatsData)* - (cheatsNumber-x-1)); - } - cheatsNumber--; - } -} - -void cheatsDeleteAll(bool restore) -{ - for(int i = cheatsNumber-1; i >= 0; i--) - { - cheatsDelete(i, restore); - } -} - -void cheatsEnable(int i) -{ - if(i >= 0 && i < cheatsNumber) - { - cheatsList[i].enabled = true; - } -} - -void cheatsDisable(int i) -{ - if(i >= 0 && i < cheatsNumber) - { - switch(cheatsList[i].size) - { - case GSA_16_BIT_ROM_PATCH: - if(cheatsList[i].status & 1) - { - cheatsList[i].status &= ~1; - CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, - cheatsList[i].oldValue); - } - break; - case GSA_16_BIT_ROM_PATCH2: - if(cheatsList[i].status & 1) - { - cheatsList[i].status &= ~1; - CHEAT_PATCH_ROM_16BIT(((cheatsList[i].value & 0x00FFFFFF) << 1)+ - 0x8000000, - cheatsList[i].oldValue); - } - break; - } - cheatsList[i].enabled = false; - } -} - -bool cheatsVerifyCheatCode(const char *code, const char *desc) -{ - int len = strlen(code); - if(len != 11 && len != 13 && len != 17) - { - systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s'"), code); - return false; - } - - if(code[8] != ':') - { - systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s'"), code); - return false; - } - - int i; - for(i = 0; i < 8; i++) - { - if(!CHEAT_IS_HEX(code[i])) - { - // wrong cheat - systemMessage(MSG_INVALID_CHEAT_CODE, - N_("Invalid cheat code '%s'"), code); - return false; - } - } - for(i = 9; i < len; i++) - { - if(!CHEAT_IS_HEX(code[i])) - { - // wrong cheat - systemMessage(MSG_INVALID_CHEAT_CODE, - N_("Invalid cheat code '%s'"), code); - return false; - } - } - - u32 address = 0; - u32 value = 0; - - char buffer[10]; - strncpy(buffer, code, 8); - buffer[8] = 0; - sscanf(buffer, "%x", &address); - - switch(address >> 24) - { - case 2: - case 3: - break; - default: - systemMessage(MSG_INVALID_CHEAT_CODE_ADDRESS, - N_("Invalid cheat code address: %08x"), - address); - return false; - } - - strncpy(buffer, &code[9], 8); - sscanf(buffer, "%x", &value); - int type = 0; - if(len == 13) - type = 1; - if(len == 17) - type = 2; - cheatsAdd(code, desc, address, value, type, type); - return true; -} - -void cheatsAddCheatCode(const char *code, const char *desc) -{ - cheatsVerifyCheatCode(code, desc); -} - -void cheatsDecryptGSACode(u32& address, u32& value, bool v3) -{ - u32 rollingseed = 0xC6EF3720; - u32 seeds_v1[] = { 0x09F4FBBD, 0x9681884A, 0x352027E9, 0xF3DEE5A7 }; - u32 seeds_v3[] = { 0x7AA9648F, 0x7FAE6994, 0xC0EFAAD5, 0x42712C57 }; - u32 *seeds = v3 ? seeds_v3 : seeds_v1; - - int bitsleft = 32; - while (bitsleft > 0) - { - value -= ((((address << 4) + seeds[2]) ^ (address + rollingseed)) ^ - ((address >> 5) + seeds[3])); - address -= ((((value << 4) + seeds[0]) ^ (value + rollingseed)) ^ - ((value >> 5) + seeds[1])); - rollingseed -= 0x9E3779B9; - bitsleft--; - } -} - -void cheatsAddGSACode(const char *code, const char *desc, bool v3) -{ - if(strlen(code) != 16) - { - // wrong cheat - systemMessage(MSG_INVALID_GSA_CODE, - N_("Invalid GSA code. Format is XXXXXXXXYYYYYYYY")); - return; - } - - int i; - for(i = 0; i < 16; i++) - { - if(!CHEAT_IS_HEX(code[i])) - { - // wrong cheat - systemMessage(MSG_INVALID_GSA_CODE, - N_("Invalid GSA code. Format is XXXXXXXXYYYYYYYY")); - return; - } - } - - char buffer[10]; - strncpy(buffer, code, 8); - buffer[8] = 0; - u32 address; - sscanf(buffer, "%x", &address); - strncpy(buffer, &code[8], 8); - buffer[8] = 0; - u32 value; - sscanf(buffer, "%x", &value); - - cheatsDecryptGSACode(address, value, v3); - - if(value == 0x1DC0DE) - { - u32 gamecode = READ32LE(((u32 *)&rom[0xac])); - if(gamecode != address) - { - char buffer[5]; - *((u32 *)buffer) = address; - buffer[4] = 0; - char buffer2[5]; - *((u32 *)buffer2) = READ32LE(((u32 *)&rom[0xac])); - buffer2[4] = 0; - systemMessage(MSG_GBA_CODE_WARNING, N_("Warning: cheats are for game %s. Current game is %s.\nCodes may not work correctly."), - buffer, buffer2); - } - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, v3 ? 257 : 256, - UNKNOWN_CODE); - return; - } - if(isMultilineWithData(cheatsNumber-1)) - { - cheatsAdd(code, desc, address, value, v3 ? 257 : 256, UNKNOWN_CODE); - return; - } - if(v3) - { - int type = (address >> 25) & 127; - u32 addr = (address & 0x00F00000) << 4 | (address & 0x0003FFFF); - switch(type) - { - case 0x00: - if(address == 0) - { - type = (value >> 25) & 127; - addr = (value & 0x00F00000) << 4 | (value & 0x0003FFFF); - switch(type) - { - case 0x04: - cheatsAdd(code, desc, 0, value & 0x00FFFFFF, 257, GSA_SLOWDOWN); - break; - case 0x08: - cheatsAdd(code, desc, 0, addr, 257, GSA_8_BIT_GS_WRITE2); - break; - case 0x09: - cheatsAdd(code, desc, 0, addr, 257, GSA_16_BIT_GS_WRITE2); - break; - case 0x0a: - cheatsAdd(code, desc, 0, addr, 257, GSA_32_BIT_GS_WRITE2); - break; - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - cheatsAdd(code, desc, 0, value & 0x00FFFFFF, 257, GSA_16_BIT_ROM_PATCH2); - break; - case 0x40: - cheatsAdd(code, desc, 0, addr, 257, GSA_8_BIT_SLIDE); - break; - case 0x41: - cheatsAdd(code, desc, 0, addr, 257, GSA_16_BIT_SLIDE); - break; - case 0x42: - cheatsAdd(code, desc, 0, addr, 257, GSA_32_BIT_SLIDE); - break; - default: - cheatsAdd(code, desc, address, value, 257, UNKNOWN_CODE); - break; - } - } - else - cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_FILL); - break; - case 0x01: - cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_FILL); - break; - case 0x02: - cheatsAdd(code, desc, addr, value, 257, INT_32_BIT_WRITE); - break; - case 0x04: - cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_TRUE); - break; - case 0x05: - cheatsAdd(code, desc, addr, value, 257, CBA_IF_TRUE); - break; - case 0x06: - cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_TRUE); - break; - case 0x08: - cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_FALSE); - break; - case 0x09: - cheatsAdd(code, desc, addr, value, 257, CBA_IF_FALSE); - break; - case 0x0a: - cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_FALSE); - break; - case 0x24: - cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_TRUE2); - break; - case 0x25: - cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_IF_TRUE2); - break; - case 0x26: - cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_TRUE2); - break; - case 0x28: - cheatsAdd(code, desc, addr, value, 257, GSA_8_BIT_IF_FALSE2); - break; - case 0x29: - cheatsAdd(code, desc, addr, value, 257, GSA_16_BIT_IF_FALSE2); - break; - case 0x2a: - cheatsAdd(code, desc, addr, value, 257, GSA_32_BIT_IF_FALSE2); - break; - default: - cheatsAdd(code, desc, address, value, 257, UNKNOWN_CODE); - break; - } - } - else - { - int type = (address >> 28) & 15; - switch(type) - { - case 0: - case 1: - case 2: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256, type); - break; - case 6: - address <<= 1; - type = (address >> 28) & 15; - if(type == 0x0c) - { - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256, - GSA_16_BIT_ROM_PATCH); - break; - } - // unsupported code - cheatsAdd(code, desc, address, value, 256, - UNKNOWN_CODE); - break; - case 8: - switch((address >> 20) & 15) - { - case 1: - cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256, - GSA_8_BIT_GS_WRITE); - break; - case 2: - cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256, - GSA_16_BIT_GS_WRITE); - break; - case 3: - cheatsAdd(code, desc, address & 0x0F0FFFFF, value, 256, - GSA_32_BIT_GS_WRITE); - case 15: - cheatsAdd(code, desc, 0, value & 0xFF00, 256, GSA_SLOWDOWN); - break; - default: - // unsupported code - cheatsAdd(code, desc, address, value, 256, - UNKNOWN_CODE); - break; - } - break; - case 0x0d: - if(address != 0xDEADFACE) - { - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 256, - CBA_IF_TRUE); - } - else - cheatsAdd(code, desc, address, value, 256, - UNKNOWN_CODE); - break; - default: - // unsupported code - cheatsAdd(code, desc, address, value, 256, - UNKNOWN_CODE); - break; - } - } -} - -bool cheatsImportGSACodeFile(const char *name, int game, bool v3) -{ - FILE* f = gen_fopen(name, "rb"); - if(!f) - return false; - - int games = 0; - int len = 0; - gen_fseek(f, 0x1e, SEEK_CUR); - gen_fread(&games, 1, 4, f); - bool found = false; - int g = 0; - while(games > 0) - { - if(g == game) - { - found = true; - break; - } - gen_fread(&len, 1, 4, f); - gen_fseek(f,len,SEEK_CUR); - int codes = 0; - gen_fread(&codes, 1, 4, f); - while(codes > 0) - { - gen_fread(&len, 1, 4, f); - gen_fseek(f, len, SEEK_CUR); - gen_fseek(f, 8, SEEK_CUR); - gen_fread(&len, 1, 4, f); - gen_fseek(f, len*12, SEEK_CUR); - codes--; - } - games--; - g++; - } - if(found) - { - char desc[256]; - char code[17]; - gen_fread(&len, 1, 4, f); - gen_fseek(f, len, SEEK_CUR); - int codes = 0; - gen_fread(&codes, 1, 4, f); - while(codes > 0) - { - gen_fread(&len, 1, 4, f); - gen_fread(desc, 1, len, f); - desc[len] =0; - desc[31] = 0; - gen_fread(&len, 1, 4, f); - gen_fseek(f, len, SEEK_CUR); - gen_fseek(f, 4, SEEK_CUR); - gen_fread(&len, 1, 4, f); - while(len) - { - gen_fseek(f, 4, SEEK_CUR); - gen_fread(code, 1, 8, f); - gen_fseek(f, 4, SEEK_CUR); - gen_fread(&code[8], 1, 8, f); - code[16] = 0; - cheatsAddGSACode(code, desc, v3); - len -= 2; - } - codes--; - } - } - gen_fclose(f); - return false; -} - -void cheatsCBAReverseArray(u8 *array, u8 *dest) -{ - dest[0] = array[3]; - dest[1] = array[2]; - dest[2] = array[1]; - dest[3] = array[0]; - dest[4] = array[5]; - dest[5] = array[4]; -} - -void chatsCBAScramble(u8 *array, int count, u8 b) -{ - u8 *x = array + (count >> 3); - u8 *y = array + (b >> 3); - u32 z = *x & (1 << (count & 7)); - u32 x0 = (*x & (~(1 << (count & 7)))); - if (z != 0) - z = 1; - if ((*y & (1 << (b & 7))) != 0) - x0 |= (1 << (count & 7)); - *x = x0; - u32 temp = *y & (~(1 << (b & 7))); - if (z != 0) - temp |= (1 << (b & 7)); - *y = temp; -} - -u32 cheatsCBAGetValue(u8 *array) -{ - return array[0] | array[1]<<8 | array[2] << 16 | array[3]<<24; -} - -u16 cheatsCBAGetData(u8 *array) -{ - return array[4] | array[5]<<8; -} - -void cheatsCBAArrayToValue(u8 *array, u8 *dest) -{ - dest[0] = array[3]; - dest[1] = array[2]; - dest[2] = array[1]; - dest[3] = array[0]; - dest[4] = array[5]; - dest[5] = array[4]; -} - -void cheatsCBAParseSeedCode(u32 address, u32 value, u32 *array) -{ - array[0] = 1; - array[1] = value & 0xFF; - array[2] = (address >> 0x10) & 0xFF; - array[3] = (value >> 8) & 0xFF; - array[4] = (address >> 0x18) & 0x0F; - array[5] = address & 0xFFFF; - array[6] = address; - array[7] = value; -} - -u32 cheatsCBAEncWorker() -{ - u32 x = (cheatsCBATemporaryValue * 0x41c64e6d) + 0x3039; - u32 y = (x * 0x41c64e6d) + 0x3039; - u32 z = x >> 0x10; - x = ((y >> 0x10) & 0x7fff) << 0x0f; - z = (z << 0x1e) | x; - x = (y * 0x41c64e6d) + 0x3039; - cheatsCBATemporaryValue = x; - return z | ((x >> 0x10) & 0x7fff); -} - -#define ROR(v, s) \ - (((v) >> (s)) | (((v) & ((1 << (s))-1)) << (32 - (s)))) - -u32 cheatsCBACalcIndex(u32 x, u32 y) -{ - if(y != 0) - { - if(y == 1) - x = 0; - else if(x == y) - x = 0; - if(y < 1) - return x; - else if(x < y) - return x; - u32 x0 = 1; - - while(y < 0x10000000) - { - if(y < x) - { - y = y << 4; - x0 = x0 << 4; - } - else break; - } - - while(y < 0x80000000) - { - if(y < x) - { - y = y << 1; - x0 = x0 << 1; - } - else break; - } - -loop: - u32 z = 0; - if(x >= y) - x -= y; - if(x >= (y >> 1)) - { - x -= (y >> 1); - z |= ROR(x0, 1); - } - if(x >= (y >> 2)) - { - x -= (y >> 2); - z |= ROR(x0, 2); - } - if(x >= (y >> 3)) - { - x -= (y >> 3); - z |= ROR(x0, 3); - } - - u32 temp = x0; - - if(x != 0) - { - x0 = x0 >> 4; - if(x0 != 0) - { - y = y >> 4; - goto loop; - } - } - - z = z & 0xe0000000; - - if(z != 0) - { - if((temp & 7) == 0) - return x; - } - else - return x; - - if((z & ROR(temp, 3)) != 0) - x += y >> 3; - if((z & ROR(temp, 2)) != 0) - x += y >> 2; - if((z & ROR(temp, 1)) != 0) - x += y >> 1; - return x; - } - else - {} - // should not happen in the current code - return 0; -} - -void cheatsCBAUpdateSeedBuffer(u32 a, u8 *buffer, int count) -{ - int i; - for(i = 0; i < count; i++) - buffer[i] = i; - for(i = 0; (u32)i < a; i++) - { - u32 a = cheatsCBACalcIndex(cheatsCBAEncWorker(), count); - u32 b = cheatsCBACalcIndex(cheatsCBAEncWorker(), count); - u32 t = buffer[a]; - buffer[a] = buffer[b]; - buffer[b] = t; - } -} - -void cheatsCBAChangeEncryption(u32 *seed) -{ - int i; - - cheatsCBATemporaryValue = (seed[1] ^ 0x1111); - cheatsCBAUpdateSeedBuffer(0x50, cheatsCBASeedBuffer, 0x30); - cheatsCBATemporaryValue = 0x4efad1c3; - - for(i = 0; (u32)i < seed[4]; i++) - { - cheatsCBATemporaryValue = cheatsCBAEncWorker(); - } - cheatsCBASeed[2] = cheatsCBAEncWorker(); - cheatsCBASeed[3] = cheatsCBAEncWorker(); - - cheatsCBATemporaryValue = seed[3] ^ 0xf254; - - for(i = 0; (u32)i < seed[3]; i++) - { - cheatsCBATemporaryValue = cheatsCBAEncWorker(); - } - - cheatsCBASeed[0] = cheatsCBAEncWorker(); - cheatsCBASeed[1] = cheatsCBAEncWorker(); - - *((u32 *)&cheatsCBACurrentSeed[0]) = seed[6]; - *((u32 *)&cheatsCBACurrentSeed[4]) = seed[7]; - *((u32 *)&cheatsCBACurrentSeed[8]) = 0; -} - -u16 cheatsCBAGenValue(u32 x, u32 y, u32 z) -{ - y <<= 0x10; - z <<= 0x10; - x <<= 0x18; - u32 x0 = (int)y >> 0x10; - z = (int)z >> 0x10; - x = (int)x >> 0x10; - for(int i = 0; i < 8; i++) - { - u32 temp = z ^ x; - if ((int)temp >= 0) - { - temp = z << 0x11; - } - else - { - temp = z << 0x01; - temp ^= x0; - temp = temp << 0x10; - } - z = (int)temp >> 0x10; - temp = x << 0x11; - x = (int)temp >> 0x10; - } - return z & 0xffff; -} - -void cheatsCBAGenTable() -{ - for (int i = 0; i < 0x100; i++) - { - cheatsCBATable[i] = cheatsCBAGenValue(i, 0x1021, 0); - } - cheatsCBATableGenerated = true; -} - -u16 cheatsCBACalcCRC(u8 *rom, int count) -{ - u32 crc = 0xffffffff; - - if (count & 3) - { - // 0x08000EAE - } - else - { - count = (count >> 2) - 1; - if(count != -1) - { - while(count != -1) - { - crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18) - ^ *rom++]) << 0x10) >> 0x10; - crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18) - ^ *rom++]) << 0x10) >> 0x10; - crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18) - ^ *rom++]) << 0x10) >> 0x10; - crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18) - ^ *rom++]) << 0x10) >> 0x10; - count--; - } - } - } - return crc & 0xffff; -} - -void cheatsCBADecrypt(u8 *decrypt) -{ - u8 buffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - u8 *array = &buffer[1]; - - cheatsCBAReverseArray(decrypt, array); - - for(int count = 0x2f; count >= 0; count--) - { - chatsCBAScramble(array, count, cheatsCBASeedBuffer[count]); - } - cheatsCBAArrayToValue(array, decrypt); - *((u32 *)decrypt) = cheatsCBAGetValue(decrypt) ^ - cheatsCBASeed[0]; - *((u16 *)(decrypt+4)) = (cheatsCBAGetData(decrypt) ^ - cheatsCBASeed[1]) & 0xffff; - - cheatsCBAReverseArray(decrypt, array); - - u32 cs = cheatsCBAGetValue(cheatsCBACurrentSeed); - for(int i = 0; i <= 4; i++) - { - array[i] = ((cs >> 8) ^ array[i+1]) ^ array[i] ; - } - - array[5] = (cs >> 8) ^ array[5]; - - for(int j = 5; j >=0; j--) - { - array[j] = (cs ^ array[j-1]) ^ array[j]; - } - - cheatsCBAArrayToValue(array, decrypt); - - *((u32 *)decrypt) = cheatsCBAGetValue(decrypt) - ^ cheatsCBASeed[2]; - *((u16 *)(decrypt+4)) = (cheatsCBAGetData(decrypt) - ^ cheatsCBASeed[3]) & 0xffff; -} - -int cheatsCBAGetCount() -{ - int count = 0; - for(int i = 0; i < cheatsNumber; i++) - { - if(cheatsList[i].code == 512) - count++; - } - return count; -} - -bool cheatsCBAShouldDecrypt() -{ - for(int i = 0; i < cheatsNumber; i++) - { - if(cheatsList[i].code == 512) - { - return (cheatsList[i].codestring[0] == '9'); - } - } - return false; -} - -void cheatsAddCBACode(const char *code, const char *desc) -{ - if(strlen(code) != 13) - { - // wrong cheat - systemMessage(MSG_INVALID_CBA_CODE, - N_("Invalid CBA code. Format is XXXXXXXX YYYY.")); - return; - } - - int i; - for(i = 0; i < 8; i++) - { - if(!CHEAT_IS_HEX(code[i])) - { - // wrong cheat - systemMessage(MSG_INVALID_CBA_CODE, - N_("Invalid CBA code. Format is XXXXXXXX YYYY.")); - return; - } - } - - if(code[8] != ' ') - { - systemMessage(MSG_INVALID_CBA_CODE, - N_("Invalid CBA code. Format is XXXXXXXX YYYY.")); - return; - } - - for(i = 9; i < 13; i++) - { - if(!CHEAT_IS_HEX(code[i])) - { - // wrong cheat - systemMessage(MSG_INVALID_CBA_CODE, - N_("Invalid CBA code. Format is XXXXXXXX YYYY.")); - return; - } - } - - char buffer[10]; - strncpy(buffer, code, 8); - buffer[8] = 0; - u32 address; - sscanf(buffer, "%x", &address); - strncpy(buffer, &code[9], 4); - buffer[4] = 0; - u32 value; - sscanf(buffer, "%x", &value); - - u8 array[8] = { - address & 255, - (address >> 8) & 255, - (address >> 16) & 255, - (address >> 24) & 255, - (value & 255), - (value >> 8) & 255, - 0, - 0 - }; - - if(cheatsCBAGetCount() == 0 && - (address >> 28) == 9) - { - u32 seed[8]; - cheatsCBAParseSeedCode(address, value, seed); - cheatsCBAChangeEncryption(seed); - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, UNKNOWN_CODE); - } - else - { - if(cheatsCBAShouldDecrypt()) - cheatsCBADecrypt(array); - - address = READ32LE(((u32 *)array)); - value = READ16LE(((u16 *)&array[4])); - - int type = (address >> 28) & 15; - - if(isMultilineWithData(cheatsNumber-1)) - { - cheatsAdd(code, desc, address, value, 512, UNKNOWN_CODE); - return; - } - - switch(type) - { - case 0x00: - { - if(!cheatsCBATableGenerated) - cheatsCBAGenTable(); - u32 crc = cheatsCBACalcCRC(rom, 0x10000); - if(crc != address) - { - systemMessage(MSG_CBA_CODE_WARNING, - N_("Warning: Codes seem to be for a different game.\nCodes may not work correctly.")); - } - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - UNKNOWN_CODE); - } - break; - case 0x02: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - CBA_OR); - break; - case 0x03: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - INT_8_BIT_WRITE); - break; - case 0x04: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - CBA_SLIDE_CODE); - break; - case 0x05: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - CBA_SUPER); - break; - case 0x06: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - CBA_AND); - break; - case 0x07: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - CBA_IF_TRUE); - break; - case 0x08: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - INT_16_BIT_WRITE); - break; - case 0x0a: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - CBA_IF_FALSE); - break; - case 0x0b: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - CBA_LT); - break; - case 0x0c: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - CBA_GT); - break; - case 0x0d: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - CBA_IF_KEYS_PRESSED); - break; - case 0x0e: - cheatsAdd(code, desc, address & 0x0FFFFFFF, value, 512, - CBA_ADD); - break; - default: - // unsupported code - cheatsAdd(code, desc, address & 0xFFFFFFFF, value, 512, - UNKNOWN_CODE); - break; - } - } -} - -void cheatsSaveGame(gzFile file) -{ - utilWriteInt(file, cheatsNumber); - - utilGzWrite(file, cheatsList, sizeof(cheatsList)); -} - -void cheatsReadGame(gzFile file) -{ - cheatsNumber = 0; - - cheatsNumber = utilReadInt(file); - - utilGzRead(file, cheatsList, sizeof(cheatsList)); - - bool firstCodeBreaker = true; - - for(int i = 0; i < cheatsNumber; i++) - { - cheatsList[i].status = 0; - if(!cheatsList[i].codestring[0]) - { - switch(cheatsList[i].size) - { - case 0: - sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address, - cheatsList[i].value); - break; - case 1: - sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address, - cheatsList[i].value); - break; - case 2: - sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address, - cheatsList[i].value); - break; - } - } - - if(cheatsList[i].enabled) - { - cheatsEnable(i); - } - - if(cheatsList[i].code == 512 && firstCodeBreaker) - { - firstCodeBreaker = false; - char buffer[10]; - strncpy(buffer, cheatsList[i].codestring, 8); - buffer[8] = 0; - u32 address; - sscanf(buffer, "%x", &address); - if((address >> 28) == 9) - { - strncpy(buffer, &cheatsList[i].codestring[9], 4); - buffer[4] = 0; - u32 value; - sscanf(buffer, "%x", &value); - - u32 seed[8]; - cheatsCBAParseSeedCode(address, value, seed); - cheatsCBAChangeEncryption(seed); - } - } - } -} - -void cheatsSaveCheatList(const char *file) -{ - if(cheatsNumber == 0) - return; - FILE* f = gen_fopen(file, "wb"); - if(f == NULL) - return; - int version = 1; - gen_fwrite(&version, 1, sizeof(version), f); - int type = 0; - gen_fwrite(&type, 1, sizeof(type), f); - gen_fwrite(&cheatsNumber, 1, sizeof(cheatsNumber), f); - gen_fwrite(cheatsList, 1, sizeof(cheatsList), f); - gen_fclose(f); -} - -bool cheatsLoadCheatList(const char *file) -{ - cheatsNumber = 0; - - int count = 0; - - FILE* f = gen_fopen(file, "rb"); - - if(f == NULL) - return false; - - int version = 0; - - if(gen_fread(&version, 1, sizeof(version), f) != sizeof(version)) - { - gen_fclose(f); - return false; - } - - if(version != 1) - { - systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION, - N_("Unsupported cheat list version %d"), version); - gen_fclose(f); - return false; - } - - int type = 0; - if(gen_fread(&type, 1, sizeof(type), f) != sizeof(type)) - { - gen_fclose(f); - return false; - } - - if(type != 0) - { - systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE, - N_("Unsupported cheat list type %d"), type); - gen_fclose(f); - return false; - } - - if(gen_fread(&count, 1, sizeof(count), f) != sizeof(count)) - { - gen_fclose(f); - return false; - } - - if(gen_fread(cheatsList, 1, sizeof(cheatsList), f) != sizeof(cheatsList)) - { - gen_fclose(f); - return false; - } - - bool firstCodeBreaker = true; - - for(int i = 0; i < count; i++) - { - cheatsList[i].status = 0; // remove old status as it is not used - if(!cheatsList[i].codestring[0]) - { - switch(cheatsList[i].size) - { - case 0: - sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address, - cheatsList[i].value); - break; - case 1: - sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address, - cheatsList[i].value); - break; - case 2: - sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address, - cheatsList[i].value); - break; - } - } - - if(cheatsList[i].code == 512 && firstCodeBreaker) - { - firstCodeBreaker = false; - char buffer[10]; - strncpy(buffer, cheatsList[i].codestring, 8); - buffer[8] = 0; - u32 address; - sscanf(buffer, "%x", &address); - if((address >> 28) == 9) - { - strncpy(buffer, &cheatsList[i].codestring[9], 4); - buffer[4] = 0; - u32 value; - sscanf(buffer, "%x", &value); - - u32 seed[8]; - cheatsCBAParseSeedCode(address, value, seed); - cheatsCBAChangeEncryption(seed); - } - } - } - cheatsNumber = count; - gen_fclose(f); - return true; -} - -extern int *extCpuLoopTicks; -extern int *extClockTicks; -extern int *extTicks; -extern int cpuSavedTicks; - -extern void debuggerBreakOnWrite(u32 *, u32, u32, int); - -#define CPU_BREAK_LOOP \ - cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks;\ - *extCpuLoopTicks = *extClockTicks;\ - *extTicks = *extClockTicks; - -void cheatsWriteMemory(u32 *address, u32 value, u32 mask) -{ -#ifdef BKPT_SUPPORT -#ifdef SDL - if(cheatsNumber == 0) - { - debuggerBreakOnWrite(address, *address, value, 2); - CPU_BREAK_LOOP; - *address = value; - return; - } -#endif -#endif -} - -void cheatsWriteHalfWord(u16 *address, u16 value, u16 mask) -{ -#ifdef BKPT_SUPPORT -#ifdef SDL - if(cheatsNumber == 0) - { - debuggerBreakOnWrite((u32 *)address, *address, value, 1); - CPU_BREAK_LOOP; - *address = value; - return; - } -#endif -#endif -} - -#if defined BKPT_SUPPORT && defined SDL -void cheatsWriteByte(u8 *address, u8 value) -#else -void cheatsWriteByte(u8 *, u8) -#endif -{ -#ifdef BKPT_SUPPORT -#ifdef SDL - if(cheatsNumber == 0) - { - debuggerBreakOnWrite((u32 *)address, *address, value, 0); - CPU_BREAK_LOOP; - *address = value; - return; - } -#endif -#endif -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 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. + +#include +#include +#include + +#include "agb/GBA.h" +#include "agb/GBAinline.h" +#include "Cheats.h" +#include "Globals.h" +#include "NLS.h" +#include "Util.h" + +/** + * Gameshark code types: (based on AR v1.0) + * + * NNNNNNNN 001DC0DE - ID code for the game (game 4 character name) from ROM + * DEADFACE XXXXXXXX - changes decryption seeds // Not supported by VBA. + * 0AAAAAAA 000000YY - 8-bit constant write + * 1AAAAAAA 0000YYYY - 16-bit constant write + * 2AAAAAAA YYYYYYYY - 32-bit constant write + * 30XXAAAA YYYYYYYY - 32bit Group Write, 8/16/32bit Sub/Add (depending on the XX value). + * 6AAAAAAA Z000YYYY - 16-bit ROM Patch (address >> 1). Z selects the Rom Patching register. + * - AR v1/2 hardware only supports Z=0. + * - AR v3 hardware should support Z=0,1,2 or 3. + * 8A1AAAAA 000000YY - 8-bit button write + * 8A2AAAAA 0000YYYY - 16-bit button write + * 8A4AAAAA YYYYYYYY - 32-bit button write // BUGGY ! Only writes 00000000 on the AR v1.0. + * 80F00000 0000YYYY - button slow motion + * DAAAAAAA 00Z0YYYY - Z = 0 : if 16-bit value at address != YYYY skip next line + * - Z = 1 : if 16-bit value at address == YYYY skip next line + * - Z = 2 : if 16-bit value at address > YYYY (Unsigned) skip next line + * - Z = 3 : if 16-bit value at address < YYYY (Unsigned) skip next line + * E0CCYYYY ZAAAAAAA - Z = 0 : if 16-bit value at address != YYYY skip CC lines + * - Z = 1 : if 16-bit value at address == YYYY skip CC lines + * - Z = 2 : if 16-bit value at address > YYYY (Unsigned) skip CC lines + * - Z = 3 : if 16-bit value at address < YYYY (Unsigned) skip CC lines + * FAAAAAAA 0000YYYY - Master code function + * + * + * + * CodeBreaker codes types: (based on the CBA clone "Cheatcode S" v1.1) + * + * 0000AAAA 000Y - Game CRC (Y are flags: 8 - CRC, 2 - DI) + * 1AAAAAAA YYYY - Master Code function (store address at ((YYYY << 0x16) + * + 0x08000100)) + * 2AAAAAAA YYYY - 16-bit or + * 3AAAAAAA YYYY - 8-bit constant write + * 4AAAAAAA YYYY - Slide code + * XXXXCCCC IIII (C is count and I is address increment, X is value incr.) + * 5AAAAAAA CCCC - Super code (Write bytes to address, 2*CCCC is count) + * BBBBBBBB BBBB + * 6AAAAAAA YYYY - 16-bit and + * 7AAAAAAA YYYY - if address contains 16-bit value enable next code + * 8AAAAAAA YYYY - 16-bit constant write + * 9AAAAAAA YYYY - change decryption (when first code only?) + * AAAAAAAA YYYY - if address does not contain 16-bit value enable next code + * BAAAAAAA YYYY - if 16-bit value at address <= YYYY skip next code + * CAAAAAAA YYYY - if 16-bit value at address >= YYYY skip next code + * D00000X0 YYYY - if button keys ... enable next code (else skip next code) + * EAAAAAAA YYYY - increase 16/32bit value stored in address + * FAAAAAAA YYYY - if 16-bit value at address AND YYYY = 0 then skip next code + **/ + +#define UNKNOWN_CODE -1 +#define INT_8_BIT_WRITE 0 +#define INT_16_BIT_WRITE 1 +#define INT_32_BIT_WRITE 2 +#define GSA_16_BIT_ROM_PATCH 3 +#define GSA_8_BIT_GS_WRITE 4 +#define GSA_16_BIT_GS_WRITE 5 +#define GSA_32_BIT_GS_WRITE 6 +#define CBA_IF_KEYS_PRESSED 7 +#define CBA_IF_TRUE 8 +#define CBA_SLIDE_CODE 9 +#define CBA_IF_FALSE 10 +#define CBA_AND 11 +#define GSA_8_BIT_GS_WRITE2 12 +#define GSA_16_BIT_GS_WRITE2 13 +#define GSA_32_BIT_GS_WRITE2 14 +#define GSA_16_BIT_ROM_PATCH2C 15 +#define GSA_8_BIT_SLIDE 16 +#define GSA_16_BIT_SLIDE 17 +#define GSA_32_BIT_SLIDE 18 +#define GSA_8_BIT_IF_TRUE 19 +#define GSA_32_BIT_IF_TRUE 20 +#define GSA_8_BIT_IF_FALSE 21 +#define GSA_32_BIT_IF_FALSE 22 +#define GSA_8_BIT_FILL 23 +#define GSA_16_BIT_FILL 24 +#define GSA_8_BIT_IF_TRUE2 25 +#define GSA_16_BIT_IF_TRUE2 26 +#define GSA_32_BIT_IF_TRUE2 27 +#define GSA_8_BIT_IF_FALSE2 28 +#define GSA_16_BIT_IF_FALSE2 29 +#define GSA_32_BIT_IF_FALSE2 30 +#define GSA_SLOWDOWN 31 +#define CBA_ADD 32 +#define CBA_OR 33 +#define CBA_LT 34 +#define CBA_GT 35 +#define CBA_SUPER 36 +#define GSA_8_BIT_POINTER 37 +#define GSA_16_BIT_POINTER 38 +#define GSA_32_BIT_POINTER 39 +#define GSA_8_BIT_ADD 40 +#define GSA_16_BIT_ADD 41 +#define GSA_32_BIT_ADD 42 +#define GSA_8_BIT_IF_LOWER_U 43 +#define GSA_16_BIT_IF_LOWER_U 44 +#define GSA_32_BIT_IF_LOWER_U 45 +#define GSA_8_BIT_IF_HIGHER_U 46 +#define GSA_16_BIT_IF_HIGHER_U 47 +#define GSA_32_BIT_IF_HIGHER_U 48 +#define GSA_8_BIT_IF_AND 49 +#define GSA_16_BIT_IF_AND 50 +#define GSA_32_BIT_IF_AND 51 +#define GSA_8_BIT_IF_LOWER_U2 52 +#define GSA_16_BIT_IF_LOWER_U2 53 +#define GSA_32_BIT_IF_LOWER_U2 54 +#define GSA_8_BIT_IF_HIGHER_U2 55 +#define GSA_16_BIT_IF_HIGHER_U2 56 +#define GSA_32_BIT_IF_HIGHER_U2 57 +#define GSA_8_BIT_IF_AND2 58 +#define GSA_16_BIT_IF_AND2 59 +#define GSA_32_BIT_IF_AND2 60 +#define GSA_ALWAYS 61 +#define GSA_ALWAYS2 62 +#define GSA_8_BIT_IF_LOWER_S 63 +#define GSA_16_BIT_IF_LOWER_S 64 +#define GSA_32_BIT_IF_LOWER_S 65 +#define GSA_8_BIT_IF_HIGHER_S 66 +#define GSA_16_BIT_IF_HIGHER_S 67 +#define GSA_32_BIT_IF_HIGHER_S 68 +#define GSA_8_BIT_IF_LOWER_S2 69 +#define GSA_16_BIT_IF_LOWER_S2 70 +#define GSA_32_BIT_IF_LOWER_S2 71 +#define GSA_8_BIT_IF_HIGHER_S2 72 +#define GSA_16_BIT_IF_HIGHER_S2 73 +#define GSA_32_BIT_IF_HIGHER_S2 74 +#define GSA_16_BIT_WRITE_IOREGS 75 +#define GSA_32_BIT_WRITE_IOREGS 76 +#define GSA_CODES_ON 77 +#define GSA_8_BIT_IF_TRUE3 78 +#define GSA_16_BIT_IF_TRUE3 79 +#define GSA_32_BIT_IF_TRUE3 80 +#define GSA_8_BIT_IF_FALSE3 81 +#define GSA_16_BIT_IF_FALSE3 82 +#define GSA_32_BIT_IF_FALSE3 83 +#define GSA_8_BIT_IF_LOWER_S3 84 +#define GSA_16_BIT_IF_LOWER_S3 85 +#define GSA_32_BIT_IF_LOWER_S3 86 +#define GSA_8_BIT_IF_HIGHER_S3 87 +#define GSA_16_BIT_IF_HIGHER_S3 88 +#define GSA_32_BIT_IF_HIGHER_S3 89 +#define GSA_8_BIT_IF_LOWER_U3 90 +#define GSA_16_BIT_IF_LOWER_U3 91 +#define GSA_32_BIT_IF_LOWER_U3 92 +#define GSA_8_BIT_IF_HIGHER_U3 93 +#define GSA_16_BIT_IF_HIGHER_U3 94 +#define GSA_32_BIT_IF_HIGHER_U3 95 +#define GSA_8_BIT_IF_AND3 96 +#define GSA_16_BIT_IF_AND3 97 +#define GSA_32_BIT_IF_AND3 98 +#define GSA_ALWAYS3 99 +#define GSA_16_BIT_ROM_PATCH2D 100 +#define GSA_16_BIT_ROM_PATCH2E 101 +#define GSA_16_BIT_ROM_PATCH2F 102 +#define GSA_GROUP_WRITE 103 +#define GSA_32_BIT_ADD2 104 +#define GSA_32_BIT_SUB2 105 +#define GSA_16_BIT_IF_LOWER_OR_EQ_U 106 +#define GSA_16_BIT_IF_HIGHER_OR_EQ_U 107 +#define GSA_16_BIT_MIF_TRUE 108 +#define GSA_16_BIT_MIF_FALSE 109 +#define GSA_16_BIT_MIF_LOWER_OR_EQ_U 110 +#define GSA_16_BIT_MIF_HIGHER_OR_EQ_U 111 +#define MASTER_CODE 112 +#define CHEATS_16_BIT_WRITE 114 +#define CHEATS_32_BIT_WRITE 115 + +CheatsData cheatsList[100]; +int cheatsNumber = 0; +u32 rompatch2addr [4]; +u16 rompatch2val [4]; +u16 rompatch2oldval [4]; + +u8 cheatsCBASeedBuffer[0x30]; +u32 cheatsCBASeed[4]; +u32 cheatsCBATemporaryValue = 0; +u16 cheatsCBATable[256]; +bool cheatsCBATableGenerated = false; +u16 super = 0; +extern u32 mastercode; + +u8 cheatsCBACurrentSeed[12] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +u32 seeds_v1[4]; +u32 seeds_v3[4]; + +u32 seed_gen(u8 upper, u8 seed, u8 *deadtable1, u8 *deadtable2); + +//seed tables for AR v1 +u8 v1_deadtable1[256] = { + 0x31, 0x1C, 0x23, 0xE5, 0x89, 0x8E, 0xA1, 0x37, 0x74, 0x6D, 0x67, 0xFC, 0x1F, 0xC0, 0xB1, 0x94, + 0x3B, 0x05, 0x56, 0x86, 0x00, 0x24, 0xF0, 0x17, 0x72, 0xA2, 0x3D, 0x1B, 0xE3, 0x17, 0xC5, 0x0B, + 0xB9, 0xE2, 0xBD, 0x58, 0x71, 0x1B, 0x2C, 0xFF, 0xE4, 0xC9, 0x4C, 0x5E, 0xC9, 0x55, 0x33, 0x45, + 0x7C, 0x3F, 0xB2, 0x51, 0xFE, 0x10, 0x7E, 0x75, 0x3C, 0x90, 0x8D, 0xDA, 0x94, 0x38, 0xC3, 0xE9, + 0x95, 0xEA, 0xCE, 0xA6, 0x06, 0xE0, 0x4F, 0x3F, 0x2A, 0xE3, 0x3A, 0xE4, 0x43, 0xBD, 0x7F, 0xDA, + 0x55, 0xF0, 0xEA, 0xCB, 0x2C, 0xA8, 0x47, 0x61, 0xA0, 0xEF, 0xCB, 0x13, 0x18, 0x20, 0xAF, 0x3E, + 0x4D, 0x9E, 0x1E, 0x77, 0x51, 0xC5, 0x51, 0x20, 0xCF, 0x21, 0xF9, 0x39, 0x94, 0xDE, 0xDD, 0x79, + 0x4E, 0x80, 0xC4, 0x9D, 0x94, 0xD5, 0x95, 0x01, 0x27, 0x27, 0xBD, 0x6D, 0x78, 0xB5, 0xD1, 0x31, + 0x6A, 0x65, 0x74, 0x74, 0x58, 0xB3, 0x7C, 0xC9, 0x5A, 0xED, 0x50, 0x03, 0xC4, 0xA2, 0x94, 0x4B, + 0xF0, 0x58, 0x09, 0x6F, 0x3E, 0x7D, 0xAE, 0x7D, 0x58, 0xA0, 0x2C, 0x91, 0xBB, 0xE1, 0x70, 0xEB, + 0x73, 0xA6, 0x9A, 0x44, 0x25, 0x90, 0x16, 0x62, 0x53, 0xAE, 0x08, 0xEB, 0xDC, 0xF0, 0xEE, 0x77, + 0xC2, 0xDE, 0x81, 0xE8, 0x30, 0x89, 0xDB, 0xFE, 0xBC, 0xC2, 0xDF, 0x26, 0xE9, 0x8B, 0xD6, 0x93, + 0xF0, 0xCB, 0x56, 0x90, 0xC0, 0x46, 0x68, 0x15, 0x43, 0xCB, 0xE9, 0x98, 0xE3, 0xAF, 0x31, 0x25, + 0x4D, 0x7B, 0xF3, 0xB1, 0x74, 0xE2, 0x64, 0xAC, 0xD9, 0xF6, 0xA0, 0xD5, 0x0B, 0x9B, 0x49, 0x52, + 0x69, 0x3B, 0x71, 0x00, 0x2F, 0xBB, 0xBA, 0x08, 0xB1, 0xAE, 0xBB, 0xB3, 0xE1, 0xC9, 0xA6, 0x7F, + 0x17, 0x97, 0x28, 0x72, 0x12, 0x6E, 0x91, 0xAE, 0x3A, 0xA2, 0x35, 0x46, 0x27, 0xF8, 0x12, 0x50 +}; +u8 v1_deadtable2[256] = { + 0xD8, 0x65, 0x04, 0xC2, 0x65, 0xD5, 0xB0, 0x0C, 0xDF, 0x9D, 0xF0, 0xC3, 0x9A, 0x17, 0xC9, 0xA6, + 0xE1, 0xAC, 0x0D, 0x14, 0x2F, 0x3C, 0x2C, 0x87, 0xA2, 0xBF, 0x4D, 0x5F, 0xAC, 0x2D, 0x9D, 0xE1, + 0x0C, 0x9C, 0xE7, 0x7F, 0xFC, 0xA8, 0x66, 0x59, 0xAC, 0x18, 0xD7, 0x05, 0xF0, 0xBF, 0xD1, 0x8B, + 0x35, 0x9F, 0x59, 0xB4, 0xBA, 0x55, 0xB2, 0x85, 0xFD, 0xB1, 0x72, 0x06, 0x73, 0xA4, 0xDB, 0x48, + 0x7B, 0x5F, 0x67, 0xA5, 0x95, 0xB9, 0xA5, 0x4A, 0xCF, 0xD1, 0x44, 0xF3, 0x81, 0xF5, 0x6D, 0xF6, + 0x3A, 0xC3, 0x57, 0x83, 0xFA, 0x8E, 0x15, 0x2A, 0xA2, 0x04, 0xB2, 0x9D, 0xA8, 0x0D, 0x7F, 0xB8, + 0x0F, 0xF6, 0xAC, 0xBE, 0x97, 0xCE, 0x16, 0xE6, 0x31, 0x10, 0x60, 0x16, 0xB5, 0x83, 0x45, 0xEE, + 0xD7, 0x5F, 0x2C, 0x08, 0x58, 0xB1, 0xFD, 0x7E, 0x79, 0x00, 0x34, 0xAD, 0xB5, 0x31, 0x34, 0x39, + 0xAF, 0xA8, 0xDD, 0x52, 0x6A, 0xB0, 0x60, 0x35, 0xB8, 0x1D, 0x52, 0xF5, 0xF5, 0x30, 0x00, 0x7B, + 0xF4, 0xBA, 0x03, 0xCB, 0x3A, 0x84, 0x14, 0x8A, 0x6A, 0xEF, 0x21, 0xBD, 0x01, 0xD8, 0xA0, 0xD4, + 0x43, 0xBE, 0x23, 0xE7, 0x76, 0x27, 0x2C, 0x3F, 0x4D, 0x3F, 0x43, 0x18, 0xA7, 0xC3, 0x47, 0xA5, + 0x7A, 0x1D, 0x02, 0x55, 0x09, 0xD1, 0xFF, 0x55, 0x5E, 0x17, 0xA0, 0x56, 0xF4, 0xC9, 0x6B, 0x90, + 0xB4, 0x80, 0xA5, 0x07, 0x22, 0xFB, 0x22, 0x0D, 0xD9, 0xC0, 0x5B, 0x08, 0x35, 0x05, 0xC1, 0x75, + 0x4F, 0xD0, 0x51, 0x2D, 0x2E, 0x5E, 0x69, 0xE7, 0x3B, 0xC2, 0xDA, 0xFF, 0xF6, 0xCE, 0x3E, 0x76, + 0xE8, 0x36, 0x8C, 0x39, 0xD8, 0xF3, 0xE9, 0xA6, 0x42, 0xE6, 0xC1, 0x4C, 0x05, 0xBE, 0x17, 0xF2, + 0x5C, 0x1B, 0x19, 0xDB, 0x0F, 0xF3, 0xF8, 0x49, 0xEB, 0x36, 0xF6, 0x40, 0x6F, 0xAD, 0xC1, 0x8C +}; + +//seed tables for AR v3 +u8 v3_deadtable1[256] = { + 0xD0, 0xFF, 0xBA, 0xE5, 0xC1, 0xC7, 0xDB, 0x5B, 0x16, 0xE3, 0x6E, 0x26, 0x62, 0x31, 0x2E, 0x2A, + 0xD1, 0xBB, 0x4A, 0xE6, 0xAE, 0x2F, 0x0A, 0x90, 0x29, 0x90, 0xB6, 0x67, 0x58, 0x2A, 0xB4, 0x45, + 0x7B, 0xCB, 0xF0, 0x73, 0x84, 0x30, 0x81, 0xC2, 0xD7, 0xBE, 0x89, 0xD7, 0x4E, 0x73, 0x5C, 0xC7, + 0x80, 0x1B, 0xE5, 0xE4, 0x43, 0xC7, 0x46, 0xD6, 0x6F, 0x7B, 0xBF, 0xED, 0xE5, 0x27, 0xD1, 0xB5, + 0xD0, 0xD8, 0xA3, 0xCB, 0x2B, 0x30, 0xA4, 0xF0, 0x84, 0x14, 0x72, 0x5C, 0xFF, 0xA4, 0xFB, 0x54, + 0x9D, 0x70, 0xE2, 0xFF, 0xBE, 0xE8, 0x24, 0x76, 0xE5, 0x15, 0xFB, 0x1A, 0xBC, 0x87, 0x02, 0x2A, + 0x58, 0x8F, 0x9A, 0x95, 0xBD, 0xAE, 0x8D, 0x0C, 0xA5, 0x4C, 0xF2, 0x5C, 0x7D, 0xAD, 0x51, 0xFB, + 0xB1, 0x22, 0x07, 0xE0, 0x29, 0x7C, 0xEB, 0x98, 0x14, 0xC6, 0x31, 0x97, 0xE4, 0x34, 0x8F, 0xCC, + 0x99, 0x56, 0x9F, 0x78, 0x43, 0x91, 0x85, 0x3F, 0xC2, 0xD0, 0xD1, 0x80, 0xD1, 0x77, 0xA7, 0xE2, + 0x43, 0x99, 0x1D, 0x2F, 0x8B, 0x6A, 0xE4, 0x66, 0x82, 0xF7, 0x2B, 0x0B, 0x65, 0x14, 0xC0, 0xC2, + 0x1D, 0x96, 0x78, 0x1C, 0xC4, 0xC3, 0xD2, 0xB1, 0x64, 0x07, 0xD7, 0x6F, 0x02, 0xE9, 0x44, 0x31, + 0xDB, 0x3C, 0xEB, 0x93, 0xED, 0x9A, 0x57, 0x05, 0xB9, 0x0E, 0xAF, 0x1F, 0x48, 0x11, 0xDC, 0x35, + 0x6C, 0xB8, 0xEE, 0x2A, 0x48, 0x2B, 0xBC, 0x89, 0x12, 0x59, 0xCB, 0xD1, 0x18, 0xEA, 0x72, 0x11, + 0x01, 0x75, 0x3B, 0xB5, 0x56, 0xF4, 0x8B, 0xA0, 0x41, 0x75, 0x86, 0x7B, 0x94, 0x12, 0x2D, 0x4C, + 0x0C, 0x22, 0xC9, 0x4A, 0xD8, 0xB1, 0x8D, 0xF0, 0x55, 0x2E, 0x77, 0x50, 0x1C, 0x64, 0x77, 0xAA, + 0x3E, 0xAC, 0xD3, 0x3D, 0xCE, 0x60, 0xCA, 0x5D, 0xA0, 0x92, 0x78, 0xC6, 0x51, 0xFE, 0xF9, 0x30 +}; +u8 v3_deadtable2[256] = { + 0xAA, 0xAF, 0xF0, 0x72, 0x90, 0xF7, 0x71, 0x27, 0x06, 0x11, 0xEB, 0x9C, 0x37, 0x12, 0x72, 0xAA, + 0x65, 0xBC, 0x0D, 0x4A, 0x76, 0xF6, 0x5C, 0xAA, 0xB0, 0x7A, 0x7D, 0x81, 0xC1, 0xCE, 0x2F, 0x9F, + 0x02, 0x75, 0x38, 0xC8, 0xFC, 0x66, 0x05, 0xC2, 0x2C, 0xBD, 0x91, 0xAD, 0x03, 0xB1, 0x88, 0x93, + 0x31, 0xC6, 0xAB, 0x40, 0x23, 0x43, 0x76, 0x54, 0xCA, 0xE7, 0x00, 0x96, 0x9F, 0xD8, 0x24, 0x8B, + 0xE4, 0xDC, 0xDE, 0x48, 0x2C, 0xCB, 0xF7, 0x84, 0x1D, 0x45, 0xE5, 0xF1, 0x75, 0xA0, 0xED, 0xCD, + 0x4B, 0x24, 0x8A, 0xB3, 0x98, 0x7B, 0x12, 0xB8, 0xF5, 0x63, 0x97, 0xB3, 0xA6, 0xA6, 0x0B, 0xDC, + 0xD8, 0x4C, 0xA8, 0x99, 0x27, 0x0F, 0x8F, 0x94, 0x63, 0x0F, 0xB0, 0x11, 0x94, 0xC7, 0xE9, 0x7F, + 0x3B, 0x40, 0x72, 0x4C, 0xDB, 0x84, 0x78, 0xFE, 0xB8, 0x56, 0x08, 0x80, 0xDF, 0x20, 0x2F, 0xB9, + 0x66, 0x2D, 0x60, 0x63, 0xF5, 0x18, 0x15, 0x1B, 0x86, 0x85, 0xB9, 0xB4, 0x68, 0x0E, 0xC6, 0xD1, + 0x8A, 0x81, 0x2B, 0xB3, 0xF6, 0x48, 0xF0, 0x4F, 0x9C, 0x28, 0x1C, 0xA4, 0x51, 0x2F, 0xD7, 0x4B, + 0x17, 0xE7, 0xCC, 0x50, 0x9F, 0xD0, 0xD1, 0x40, 0x0C, 0x0D, 0xCA, 0x83, 0xFA, 0x5E, 0xCA, 0xEC, + 0xBF, 0x4E, 0x7C, 0x8F, 0xF0, 0xAE, 0xC2, 0xD3, 0x28, 0x41, 0x9B, 0xC8, 0x04, 0xB9, 0x4A, 0xBA, + 0x72, 0xE2, 0xB5, 0x06, 0x2C, 0x1E, 0x0B, 0x2C, 0x7F, 0x11, 0xA9, 0x26, 0x51, 0x9D, 0x3F, 0xF8, + 0x62, 0x11, 0x2E, 0x89, 0xD2, 0x9D, 0x35, 0xB1, 0xE4, 0x0A, 0x4D, 0x93, 0x01, 0xA7, 0xD1, 0x2D, + 0x00, 0x87, 0xE2, 0x2D, 0xA4, 0xE9, 0x0A, 0x06, 0x66, 0xF8, 0x1F, 0x44, 0x75, 0xB5, 0x6B, 0x1C, + 0xFC, 0x31, 0x09, 0x48, 0xA3, 0xFF, 0x92, 0x12, 0x58, 0xE9, 0xFA, 0xAE, 0x4F, 0xE2, 0xB4, 0xCC +}; + +#define debuggerReadMemory(addr) \ + READ32LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) + +#define debuggerReadHalfWord(addr) \ + READ16LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) + +#define debuggerReadByte(addr) \ + map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] + +#define debuggerWriteMemory(addr, value) \ + WRITE32LE(&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask], value) + +#define debuggerWriteHalfWord(addr, value) \ + WRITE16LE(&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask], value) + +#define debuggerWriteByte(addr, value) \ + map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] = (value) + + +#define CHEAT_IS_HEX(a) ( ((a)>='A' && (a) <='F') || ((a) >='0' && (a) <= '9')) + +#define CHEAT_PATCH_ROM_16BIT(a,v) \ + WRITE16LE(((u16 *)&rom[(a) & 0x1ffffff]), v); + +#define CHEAT_PATCH_ROM_32BIT(a,v) \ + WRITE32LE(((u32 *)&rom[(a) & 0x1ffffff]), v); + +static bool isMultilineWithData(int i) +{ + // we consider it a multiline code if it has more than one line of data + // otherwise, it can still be considered a single code + // (Only CBA codes can be true multilines !!!) + if(i < cheatsNumber && i >= 0) + switch(cheatsList[i].size) { + case INT_8_BIT_WRITE: + case INT_16_BIT_WRITE: + case INT_32_BIT_WRITE: + case GSA_16_BIT_ROM_PATCH: + case GSA_8_BIT_GS_WRITE: + case GSA_16_BIT_GS_WRITE: + case GSA_32_BIT_GS_WRITE: + case CBA_AND: + case CBA_IF_KEYS_PRESSED: + case CBA_IF_TRUE: + case CBA_IF_FALSE: + case GSA_8_BIT_IF_TRUE: + case GSA_32_BIT_IF_TRUE: + case GSA_8_BIT_IF_FALSE: + case GSA_32_BIT_IF_FALSE: + case GSA_8_BIT_FILL: + case GSA_16_BIT_FILL: + case GSA_8_BIT_IF_TRUE2: + case GSA_16_BIT_IF_TRUE2: + case GSA_32_BIT_IF_TRUE2: + case GSA_8_BIT_IF_FALSE2: + case GSA_16_BIT_IF_FALSE2: + case GSA_32_BIT_IF_FALSE2: + case GSA_SLOWDOWN: + case CBA_ADD: + case CBA_OR: + case CBA_LT: + case CBA_GT: + case GSA_8_BIT_POINTER: + case GSA_16_BIT_POINTER: + case GSA_32_BIT_POINTER: + case GSA_8_BIT_ADD: + case GSA_16_BIT_ADD: + case GSA_32_BIT_ADD: + case GSA_8_BIT_IF_LOWER_U: + case GSA_16_BIT_IF_LOWER_U: + case GSA_32_BIT_IF_LOWER_U: + case GSA_8_BIT_IF_HIGHER_U: + case GSA_16_BIT_IF_HIGHER_U: + case GSA_32_BIT_IF_HIGHER_U: + case GSA_8_BIT_IF_AND: + case GSA_16_BIT_IF_AND: + case GSA_32_BIT_IF_AND: + case GSA_8_BIT_IF_LOWER_U2: + case GSA_16_BIT_IF_LOWER_U2: + case GSA_32_BIT_IF_LOWER_U2: + case GSA_8_BIT_IF_HIGHER_U2: + case GSA_16_BIT_IF_HIGHER_U2: + case GSA_32_BIT_IF_HIGHER_U2: + case GSA_8_BIT_IF_AND2: + case GSA_16_BIT_IF_AND2: + case GSA_32_BIT_IF_AND2: + case GSA_ALWAYS: + case GSA_ALWAYS2: + case GSA_8_BIT_IF_LOWER_S: + case GSA_16_BIT_IF_LOWER_S: + case GSA_32_BIT_IF_LOWER_S: + case GSA_8_BIT_IF_HIGHER_S: + case GSA_16_BIT_IF_HIGHER_S: + case GSA_32_BIT_IF_HIGHER_S: + case GSA_8_BIT_IF_LOWER_S2: + case GSA_16_BIT_IF_LOWER_S2: + case GSA_32_BIT_IF_LOWER_S2: + case GSA_8_BIT_IF_HIGHER_S2: + case GSA_16_BIT_IF_HIGHER_S2: + case GSA_32_BIT_IF_HIGHER_S2: + case GSA_16_BIT_WRITE_IOREGS: + case GSA_32_BIT_WRITE_IOREGS: + case GSA_CODES_ON: + case GSA_8_BIT_IF_TRUE3: + case GSA_16_BIT_IF_TRUE3: + case GSA_32_BIT_IF_TRUE3: + case GSA_8_BIT_IF_FALSE3: + case GSA_16_BIT_IF_FALSE3: + case GSA_32_BIT_IF_FALSE3: + case GSA_8_BIT_IF_LOWER_S3: + case GSA_16_BIT_IF_LOWER_S3: + case GSA_32_BIT_IF_LOWER_S3: + case GSA_8_BIT_IF_HIGHER_S3: + case GSA_16_BIT_IF_HIGHER_S3: + case GSA_32_BIT_IF_HIGHER_S3: + case GSA_8_BIT_IF_LOWER_U3: + case GSA_16_BIT_IF_LOWER_U3: + case GSA_32_BIT_IF_LOWER_U3: + case GSA_8_BIT_IF_HIGHER_U3: + case GSA_16_BIT_IF_HIGHER_U3: + case GSA_32_BIT_IF_HIGHER_U3: + case GSA_8_BIT_IF_AND3: + case GSA_16_BIT_IF_AND3: + case GSA_32_BIT_IF_AND3: + case GSA_ALWAYS3: + case GSA_8_BIT_GS_WRITE2: + case GSA_16_BIT_GS_WRITE2: + case GSA_32_BIT_GS_WRITE2: + case GSA_16_BIT_ROM_PATCH2C: + case GSA_16_BIT_ROM_PATCH2D: + case GSA_16_BIT_ROM_PATCH2E: + case GSA_16_BIT_ROM_PATCH2F: + case GSA_8_BIT_SLIDE: + case GSA_16_BIT_SLIDE: + case GSA_32_BIT_SLIDE: + case GSA_GROUP_WRITE: + case GSA_32_BIT_ADD2: + case GSA_32_BIT_SUB2: + case GSA_16_BIT_IF_LOWER_OR_EQ_U: + case GSA_16_BIT_IF_HIGHER_OR_EQ_U: + case GSA_16_BIT_MIF_TRUE: + case GSA_16_BIT_MIF_FALSE: + case GSA_16_BIT_MIF_LOWER_OR_EQ_U: + case GSA_16_BIT_MIF_HIGHER_OR_EQ_U: + case MASTER_CODE: + case CHEATS_16_BIT_WRITE: + case CHEATS_32_BIT_WRITE: + return false; + // the codes below have two lines of data + case CBA_SLIDE_CODE: + case CBA_SUPER: + return true; + } + return false; +} + +static int getCodeLength(int num) +{ + if(num >= cheatsNumber || num < 0) + return 1; + + // this is for all the codes that are true multiline + switch(cheatsList[num].size) { + case INT_8_BIT_WRITE: + case INT_16_BIT_WRITE: + case INT_32_BIT_WRITE: + case GSA_16_BIT_ROM_PATCH: + case GSA_8_BIT_GS_WRITE: + case GSA_16_BIT_GS_WRITE: + case GSA_32_BIT_GS_WRITE: + case CBA_AND: + case GSA_8_BIT_FILL: + case GSA_16_BIT_FILL: + case GSA_SLOWDOWN: + case CBA_ADD: + case CBA_OR: + case GSA_8_BIT_POINTER: + case GSA_16_BIT_POINTER: + case GSA_32_BIT_POINTER: + case GSA_8_BIT_ADD: + case GSA_16_BIT_ADD: + case GSA_32_BIT_ADD: + case GSA_CODES_ON: + case GSA_8_BIT_IF_TRUE3: + case GSA_16_BIT_IF_TRUE3: + case GSA_32_BIT_IF_TRUE3: + case GSA_8_BIT_IF_FALSE3: + case GSA_16_BIT_IF_FALSE3: + case GSA_32_BIT_IF_FALSE3: + case GSA_8_BIT_IF_LOWER_S3: + case GSA_16_BIT_IF_LOWER_S3: + case GSA_32_BIT_IF_LOWER_S3: + case GSA_8_BIT_IF_HIGHER_S3: + case GSA_16_BIT_IF_HIGHER_S3: + case GSA_32_BIT_IF_HIGHER_S3: + case GSA_8_BIT_IF_LOWER_U3: + case GSA_16_BIT_IF_LOWER_U3: + case GSA_32_BIT_IF_LOWER_U3: + case GSA_8_BIT_IF_HIGHER_U3: + case GSA_16_BIT_IF_HIGHER_U3: + case GSA_32_BIT_IF_HIGHER_U3: + case GSA_8_BIT_IF_AND3: + case GSA_16_BIT_IF_AND3: + case GSA_32_BIT_IF_AND3: + case GSA_8_BIT_IF_LOWER_U: + case GSA_16_BIT_IF_LOWER_U: + case GSA_32_BIT_IF_LOWER_U: + case GSA_8_BIT_IF_HIGHER_U: + case GSA_16_BIT_IF_HIGHER_U: + case GSA_32_BIT_IF_HIGHER_U: + case GSA_8_BIT_IF_AND: + case GSA_16_BIT_IF_AND: + case GSA_32_BIT_IF_AND: + case GSA_ALWAYS: + case GSA_8_BIT_IF_LOWER_S: + case GSA_16_BIT_IF_LOWER_S: + case GSA_32_BIT_IF_LOWER_S: + case GSA_8_BIT_IF_HIGHER_S: + case GSA_16_BIT_IF_HIGHER_S: + case GSA_32_BIT_IF_HIGHER_S: + case GSA_16_BIT_WRITE_IOREGS: + case GSA_32_BIT_WRITE_IOREGS: + case GSA_8_BIT_GS_WRITE2: + case GSA_16_BIT_GS_WRITE2: + case GSA_32_BIT_GS_WRITE2: + case GSA_16_BIT_ROM_PATCH2C: + case GSA_16_BIT_ROM_PATCH2D: + case GSA_16_BIT_ROM_PATCH2E: + case GSA_16_BIT_ROM_PATCH2F: + case GSA_8_BIT_SLIDE: + case GSA_16_BIT_SLIDE: + case GSA_32_BIT_SLIDE: + case GSA_8_BIT_IF_TRUE: + case GSA_32_BIT_IF_TRUE: + case GSA_8_BIT_IF_FALSE: + case GSA_32_BIT_IF_FALSE: + case CBA_LT: + case CBA_GT: + case CBA_IF_TRUE: + case CBA_IF_FALSE: + case GSA_8_BIT_IF_TRUE2: + case GSA_16_BIT_IF_TRUE2: + case GSA_32_BIT_IF_TRUE2: + case GSA_8_BIT_IF_FALSE2: + case GSA_16_BIT_IF_FALSE2: + case GSA_32_BIT_IF_FALSE2: + case GSA_8_BIT_IF_LOWER_U2: + case GSA_16_BIT_IF_LOWER_U2: + case GSA_32_BIT_IF_LOWER_U2: + case GSA_8_BIT_IF_HIGHER_U2: + case GSA_16_BIT_IF_HIGHER_U2: + case GSA_32_BIT_IF_HIGHER_U2: + case GSA_8_BIT_IF_AND2: + case GSA_16_BIT_IF_AND2: + case GSA_32_BIT_IF_AND2: + case GSA_ALWAYS2: + case GSA_8_BIT_IF_LOWER_S2: + case GSA_16_BIT_IF_LOWER_S2: + case GSA_32_BIT_IF_LOWER_S2: + case GSA_8_BIT_IF_HIGHER_S2: + case GSA_16_BIT_IF_HIGHER_S2: + case GSA_32_BIT_IF_HIGHER_S2: + case GSA_GROUP_WRITE: + case GSA_32_BIT_ADD2: + case GSA_32_BIT_SUB2: + case GSA_16_BIT_IF_LOWER_OR_EQ_U: + case GSA_16_BIT_IF_HIGHER_OR_EQ_U: + case GSA_16_BIT_MIF_TRUE: + case GSA_16_BIT_MIF_FALSE: + case GSA_16_BIT_MIF_LOWER_OR_EQ_U: + case GSA_16_BIT_MIF_HIGHER_OR_EQ_U: + case MASTER_CODE: + case CHEATS_16_BIT_WRITE: + case CHEATS_32_BIT_WRITE: + case UNKNOWN_CODE: + return 1; + case CBA_IF_KEYS_PRESSED: + case CBA_SLIDE_CODE: + return 2; + case CBA_SUPER: + return ((((cheatsList[num].value-1) & 0xFFFF)/3) + 1); + } + return 1; +} + +int cheatsCheckKeys(u32 keys, u32 extended) +{ + bool onoff = true; + int ticks = 0; + int i; + mastercode = 0; + + for (i = 0; i<4; i++) + if (rompatch2addr [i] != 0) { + CHEAT_PATCH_ROM_16BIT(rompatch2addr [i],rompatch2oldval [i]); + rompatch2addr [i] = 0; + } + + for (i = 0; i < cheatsNumber; i++) { + if(!cheatsList[i].enabled) { + // make sure we skip other lines in this code + i += getCodeLength(i)-1; + continue; + } + switch(cheatsList[i].size) { + case GSA_CODES_ON: + onoff = true; + break; + case GSA_SLOWDOWN: + // check if button was pressed and released, if so toggle our state + if((cheatsList[i].status & 4) && !(extended & 4)) + cheatsList[i].status ^= 1; + if(extended & 4) + cheatsList[i].status |= 4; + else + cheatsList[i].status &= ~4; + + if(cheatsList[i].status & 1) + ticks += ((cheatsList[i].value & 0xFFFF) * 7); + break; + case GSA_8_BIT_SLIDE: + i++; + if(i < cheatsNumber) { + u32 addr = cheatsList[i-1].value; + u8 value = cheatsList[i].rawaddress; + int vinc = (cheatsList[i].value >> 24) & 255; + int count = (cheatsList[i].value >> 16) & 255; + int ainc = (cheatsList[i].value & 0xffff); + while(count > 0) { + CPUWriteByte(addr, value); + value += vinc; + addr += ainc; + count--; + } + } + break; + case GSA_16_BIT_SLIDE: + i++; + if(i < cheatsNumber) { + u32 addr = cheatsList[i-1].value; + u16 value = cheatsList[i].rawaddress; + int vinc = (cheatsList[i].value >> 24) & 255; + int count = (cheatsList[i].value >> 16) & 255; + int ainc = (cheatsList[i].value & 0xffff)*2; + while(count > 0) { + CPUWriteHalfWord(addr, value); + value += vinc; + addr += ainc; + count--; + } + } + break; + case GSA_32_BIT_SLIDE: + i++; + if(i < cheatsNumber) { + u32 addr = cheatsList[i-1].value; + u32 value = cheatsList[i].rawaddress; + int vinc = (cheatsList[i].value >> 24) & 255; + int count = (cheatsList[i].value >> 16) & 255; + int ainc = (cheatsList[i].value & 0xffff)*4; + while(count > 0) { + CPUWriteMemory(addr, value); + value += vinc; + addr += ainc; + count--; + } + } + break; + case GSA_8_BIT_GS_WRITE2: + i++; + if(i < cheatsNumber) { + if(extended & 4) { + CPUWriteByte(cheatsList[i-1].value, cheatsList[i].address); + } + } + break; + case GSA_16_BIT_GS_WRITE2: + i++; + if(i < cheatsNumber) { + if(extended & 4) { + CPUWriteHalfWord(cheatsList[i-1].value, cheatsList[i].address); + } + } + break; + case GSA_32_BIT_GS_WRITE2: + i++; + if(i < cheatsNumber) { + if(extended & 4) { + CPUWriteMemory(cheatsList[i-1].value, cheatsList[i].address); + } + } + break; + case GSA_16_BIT_ROM_PATCH: + if((cheatsList[i].status & 1) == 0) { + if(CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) { + cheatsList[i].oldValue = CPUReadHalfWord(cheatsList[i].address); + cheatsList[i].status |= 1; + CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, cheatsList[i].value); + } + } + break; + case GSA_16_BIT_ROM_PATCH2C: + i++; + if(i < cheatsNumber) { + rompatch2addr [0] = ((cheatsList[i-1].value & 0x00FFFFFF) << 1) + 0x8000000; + rompatch2oldval [0] = CPUReadHalfWord(rompatch2addr [0]); + rompatch2val [0] = cheatsList[i].rawaddress & 0xFFFF; + } + break; + case GSA_16_BIT_ROM_PATCH2D: + i++; + if(i < cheatsNumber) { + rompatch2addr [1] = ((cheatsList[i-1].value & 0x00FFFFFF) << 1) + 0x8000000; + rompatch2oldval [1] = CPUReadHalfWord(rompatch2addr [1]); + rompatch2val [1] = cheatsList[i].rawaddress & 0xFFFF; + } + break; + case GSA_16_BIT_ROM_PATCH2E: + i++; + if(i < cheatsNumber) { + rompatch2addr [2] = ((cheatsList[i-1].value & 0x00FFFFFF) << 1) + 0x8000000; + rompatch2oldval [2] = CPUReadHalfWord(rompatch2addr [2]); + rompatch2val [2] = cheatsList[i].rawaddress & 0xFFFF; + } + break; + case GSA_16_BIT_ROM_PATCH2F: + i++; + if(i < cheatsNumber) { + rompatch2addr [3] = ((cheatsList[i-1].value & 0x00FFFFFF) << 1) + 0x8000000; + rompatch2oldval [3] = CPUReadHalfWord(rompatch2addr [3]); + rompatch2val [3] = cheatsList[i].rawaddress & 0xFFFF; + } + break; + case MASTER_CODE: + mastercode = cheatsList[i].address; + break; + } + if (onoff) { + switch(cheatsList[i].size) { + case INT_8_BIT_WRITE: + CPUWriteByte(cheatsList[i].address, cheatsList[i].value); + break; + case INT_16_BIT_WRITE: + CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value); + break; + case INT_32_BIT_WRITE: + CPUWriteMemory(cheatsList[i].address, cheatsList[i].value); + break; + case GSA_8_BIT_GS_WRITE: + if(extended & 4) { + CPUWriteByte(cheatsList[i].address, cheatsList[i].value); + } + break; + case GSA_16_BIT_GS_WRITE: + if(extended & 4) { + CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value); + } + break; + case GSA_32_BIT_GS_WRITE: + if(extended & 4) { + CPUWriteMemory(cheatsList[i].address, cheatsList[i].value); + } + break; + case CBA_IF_KEYS_PRESSED: + { + u16 value = cheatsList[i].value; + u32 addr = cheatsList[i].address; + if((addr & 0xF0) == 0x20) { + if((keys & value) == 0) { + i++; + } + } else if((addr & 0xF0) == 0x10) { + if((keys & value) == value) { + i++; + } + } else if((addr & 0xF0) == 0x00) { + if(((~keys) & 0x3FF) == value) { + i++; + } + } + } + break; + case CBA_IF_TRUE: + if(CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) { + i++; + } + break; + case CBA_SLIDE_CODE: + { + u32 address = cheatsList[i].address; + u16 value = cheatsList[i].value; + i++; + if(i < cheatsNumber) { + int count = ((cheatsList[i].address - 1) & 0xFFFF); + u16 vinc = (cheatsList[i].address >> 16) & 0xFFFF; + int inc = cheatsList[i].value; + for(int x = 0; x <= count ; x++) { + CPUWriteHalfWord(address, value); + address += inc; + value += vinc; + } + } + } + break; + case CBA_IF_FALSE: + if(CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value){ + i++; + } + break; + case CBA_AND: + CPUWriteHalfWord(cheatsList[i].address, + CPUReadHalfWord(cheatsList[i].address) & + cheatsList[i].value); + break; + case GSA_8_BIT_IF_TRUE: + if(CPUReadByte(cheatsList[i].address) != cheatsList[i].value) { + i++; + } + break; + case GSA_32_BIT_IF_TRUE: + if(CPUReadMemory(cheatsList[i].address) != cheatsList[i].value) { + i++; + } + break; + case GSA_8_BIT_IF_FALSE: + if(CPUReadByte(cheatsList[i].address) == cheatsList[i].value) { + i++; + } + break; + case GSA_32_BIT_IF_FALSE: + if(CPUReadMemory(cheatsList[i].address) == cheatsList[i].value) { + i++; + } + break; + case GSA_8_BIT_FILL: + { + u32 addr = cheatsList[i].address; + u8 v = cheatsList[i].value & 0xff; + u32 end = addr + (cheatsList[i].value >> 8); + do { + CPUWriteByte(addr, v); + addr++; + } while (addr <= end); + } + break; + case GSA_16_BIT_FILL: + { + u32 addr = cheatsList[i].address; + u16 v = cheatsList[i].value & 0xffff; + u32 end = addr + ((cheatsList[i].value >> 16) << 1); + do { + CPUWriteHalfWord(addr, v); + addr+=2; + } while (addr <= end); + } + break; + case GSA_8_BIT_IF_TRUE2: + if(CPUReadByte(cheatsList[i].address) != cheatsList[i].value) { + i+=2; + } + break; + case GSA_16_BIT_IF_TRUE2: + if(CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) { + i+=2; + } + break; + case GSA_32_BIT_IF_TRUE2: + if(CPUReadMemory(cheatsList[i].address) != cheatsList[i].value) { + i+=2; + } + break; + case GSA_8_BIT_IF_FALSE2: + if(CPUReadByte(cheatsList[i].address) == cheatsList[i].value) { + i+=2; + } + break; + case GSA_16_BIT_IF_FALSE2: + if(CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value) { + i+=2; + } + break; + case GSA_32_BIT_IF_FALSE2: + if(CPUReadMemory(cheatsList[i].address) == cheatsList[i].value) { + i+=2; + } + break; + case CBA_ADD: + if ((cheatsList[i].address & 1) == 0) { + CPUWriteHalfWord(cheatsList[i].address, + CPUReadHalfWord(cheatsList[i].address) + + cheatsList[i].value); + } else { + CPUWriteMemory(cheatsList[i].address & 0x0FFFFFFE, + CPUReadMemory(cheatsList[i].address & 0x0FFFFFFE) + + cheatsList[i].value); + } + break; + case CBA_OR: + CPUWriteHalfWord(cheatsList[i].address, + CPUReadHalfWord(cheatsList[i].address) | + cheatsList[i].value); + break; + case CBA_GT: + if (!(CPUReadHalfWord(cheatsList[i].address) > cheatsList[i].value)){ + i++; + } + break; + case CBA_LT: + if (!(CPUReadHalfWord(cheatsList[i].address) < cheatsList[i].value)){ + i++; + } + break; + case CBA_SUPER: + { + int count = 2*((cheatsList[i].value -1) & 0xFFFF)+1; + u32 address = cheatsList[i].address; + for(int x = 0; x <= count; x++) { + u8 b; + int res = x % 6; + if (res==0) + i++; + if(res < 4) + b = (cheatsList[i].address >> (24-8*res)) & 0xFF; + else + b = (cheatsList[i].value >> (8 - 8*(res-4))) & 0xFF; + CPUWriteByte(address, b); + address++; + } + } + break; + case GSA_8_BIT_POINTER : + if ((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000) || + (CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000)) + { + CPUWriteByte(CPUReadMemory(cheatsList[i].address)+((cheatsList[i].value & 0xFFFFFF00) >> 8), + cheatsList[i].value & 0xFF); + } + break; + case GSA_16_BIT_POINTER : + if ((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000) || + (CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000)) + { + CPUWriteHalfWord(CPUReadMemory(cheatsList[i].address)+((cheatsList[i].value & 0xFFFF0000) >> 15), + cheatsList[i].value & 0xFFFF); + } + break; + case GSA_32_BIT_POINTER : + if ((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000) || + (CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000)) + { + CPUWriteMemory(CPUReadMemory(cheatsList[i].address), + cheatsList[i].value); + } + break; + case GSA_8_BIT_ADD : + CPUWriteByte(cheatsList[i].address, + (cheatsList[i].value & 0xFF) + CPUReadMemory(cheatsList[i].address) & 0xFF); + break; + case GSA_16_BIT_ADD : + CPUWriteHalfWord(cheatsList[i].address, + (cheatsList[i].value & 0xFFFF) + CPUReadMemory(cheatsList[i].address) & 0xFFFF); + break; + case GSA_32_BIT_ADD : + CPUWriteMemory(cheatsList[i].address , + cheatsList[i].value + CPUReadMemory(cheatsList[i].address) & 0xFFFFFFFF); + break; + case GSA_8_BIT_IF_LOWER_U: + if (!(CPUReadByte(cheatsList[i].address) < (cheatsList[i].value & 0xFF))) { + i++; + } + break; + case GSA_16_BIT_IF_LOWER_U: + if (!(CPUReadHalfWord(cheatsList[i].address) < (cheatsList[i].value & 0xFFFF))) { + i++; + } + break; + case GSA_32_BIT_IF_LOWER_U: + if (!(CPUReadMemory(cheatsList[i].address) < cheatsList[i].value)) { + i++; + } + break; + case GSA_8_BIT_IF_HIGHER_U: + if (!(CPUReadByte(cheatsList[i].address) > (cheatsList[i].value & 0xFF))) { + i++; + } + break; + case GSA_16_BIT_IF_HIGHER_U: + if (!(CPUReadHalfWord(cheatsList[i].address) > (cheatsList[i].value & 0xFFFF))) { + i++; + } + break; + case GSA_32_BIT_IF_HIGHER_U: + if (!(CPUReadMemory(cheatsList[i].address) > cheatsList[i].value)) { + i++; + } + break; + case GSA_8_BIT_IF_AND: + if (!(CPUReadByte(cheatsList[i].address) & (cheatsList[i].value & 0xFF))) { + i++; + } + break; + case GSA_16_BIT_IF_AND: + if (!(CPUReadHalfWord(cheatsList[i].address) & (cheatsList[i].value & 0xFFFF))) { + i++; + } + break; + case GSA_32_BIT_IF_AND: + if (!(CPUReadMemory(cheatsList[i].address) & cheatsList[i].value)) { + i++; + } + break; + case GSA_8_BIT_IF_LOWER_U2: + if (!(CPUReadByte(cheatsList[i].address) < (cheatsList[i].value & 0xFF))) { + i+=2; + } + break; + case GSA_16_BIT_IF_LOWER_U2: + if (!(CPUReadHalfWord(cheatsList[i].address) < (cheatsList[i].value & 0xFFFF))) { + i+=2; + } + break; + case GSA_32_BIT_IF_LOWER_U2: + if (!(CPUReadMemory(cheatsList[i].address) < cheatsList[i].value)) { + i+=2; + } + break; + case GSA_8_BIT_IF_HIGHER_U2: + if (!(CPUReadByte(cheatsList[i].address) > (cheatsList[i].value & 0xFF))) { + i+=2; + } + break; + case GSA_16_BIT_IF_HIGHER_U2: + if (!(CPUReadHalfWord(cheatsList[i].address) > (cheatsList[i].value & 0xFFFF))) { + i+=2; + } + break; + case GSA_32_BIT_IF_HIGHER_U2: + if (!(CPUReadMemory(cheatsList[i].address) > cheatsList[i].value)) { + i+=2; + } + break; + case GSA_8_BIT_IF_AND2: + if (!(CPUReadByte(cheatsList[i].address) & (cheatsList[i].value & 0xFF))) { + i+=2; + } + break; + case GSA_16_BIT_IF_AND2: + if (!(CPUReadHalfWord(cheatsList[i].address) & (cheatsList[i].value & 0xFFFF))) { + i+=2; + } + break; + case GSA_32_BIT_IF_AND2: + if (!(CPUReadMemory(cheatsList[i].address) & cheatsList[i].value)) { + i+=2; + } + break; + case GSA_ALWAYS: + i++; + break; + case GSA_ALWAYS2: + i+=2; + break; + case GSA_8_BIT_IF_LOWER_S: + if (!((s8)CPUReadByte(cheatsList[i].address) < ((s8)cheatsList[i].value & 0xFF))) { + i++; + } + break; + case GSA_16_BIT_IF_LOWER_S: + if (!((s16)CPUReadHalfWord(cheatsList[i].address) < ((s16)cheatsList[i].value & 0xFFFF))) { + i++; + } + break; + case GSA_32_BIT_IF_LOWER_S: + if (!((s32)CPUReadMemory(cheatsList[i].address) < (s32)cheatsList[i].value)) { + i++; + } + break; + case GSA_8_BIT_IF_HIGHER_S: + if (!((s8)CPUReadByte(cheatsList[i].address) > ((s8)cheatsList[i].value & 0xFF))) { + i++; + } + break; + case GSA_16_BIT_IF_HIGHER_S: + if (!((s16)CPUReadHalfWord(cheatsList[i].address) > ((s16)cheatsList[i].value & 0xFFFF))) { + i++; + } + break; + case GSA_32_BIT_IF_HIGHER_S: + if (!((s32)CPUReadMemory(cheatsList[i].address) > (s32)cheatsList[i].value)) { + i++; + } + break; + case GSA_8_BIT_IF_LOWER_S2: + if (!((s8)CPUReadByte(cheatsList[i].address) < ((s8)cheatsList[i].value & 0xFF))) { + i+=2; + } + break; + case GSA_16_BIT_IF_LOWER_S2: + if (!((s16)CPUReadHalfWord(cheatsList[i].address) < ((s16)cheatsList[i].value & 0xFFFF))) { + i+=2; + } + break; + case GSA_32_BIT_IF_LOWER_S2: + if (!((s32)CPUReadMemory(cheatsList[i].address) < (s32)cheatsList[i].value)) { + i+=2; + } + break; + case GSA_8_BIT_IF_HIGHER_S2: + if (!((s8)CPUReadByte(cheatsList[i].address) > ((s8)cheatsList[i].value & 0xFF))) { + i+=2; + } + break; + case GSA_16_BIT_IF_HIGHER_S2: + if (!((s16)CPUReadHalfWord(cheatsList[i].address) > ((s16)cheatsList[i].value & 0xFFFF))) { + i+=2; + } + break; + case GSA_32_BIT_IF_HIGHER_S2: + if (!((s32)CPUReadMemory(cheatsList[i].address) > (s32)cheatsList[i].value)) { + i+=2; + } + break; + case GSA_16_BIT_WRITE_IOREGS: + if ((cheatsList[i].address <= 0x3FF) && (cheatsList[i].address != 0x6) && + (cheatsList[i].address != 0x130)) + ioMem[cheatsList[i].address & 0x3FE]=cheatsList[i].value & 0xFFFF; + break; + case GSA_32_BIT_WRITE_IOREGS: + if (cheatsList[i].address<=0x3FF) + { + if (((cheatsList[i].address & 0x3FC) != 0x6) && ((cheatsList[i].address & 0x3FC) != 0x130)) + ioMem[cheatsList[i].address & 0x3FC]= (cheatsList[i].value & 0xFFFF); + if ((((cheatsList[i].address & 0x3FC)+2) != 0x6) && ((cheatsList[i].address & 0x3FC) +2) != 0x130) + ioMem[(cheatsList[i].address & 0x3FC) + 2 ]= ((cheatsList[i].value>>16 ) & 0xFFFF); + } + break; + case GSA_8_BIT_IF_TRUE3: + if(CPUReadByte(cheatsList[i].address) != cheatsList[i].value) { + onoff=false; + } + break; + case GSA_16_BIT_IF_TRUE3: + if(CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) { + onoff=false; + } + break; + case GSA_32_BIT_IF_TRUE3: + if(CPUReadMemory(cheatsList[i].address) != cheatsList[i].value) { + onoff=false; + } + break; + case GSA_8_BIT_IF_FALSE3: + if(CPUReadByte(cheatsList[i].address) == cheatsList[i].value) { + onoff=false; + } + break; + case GSA_16_BIT_IF_FALSE3: + if(CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value) { + onoff=false; + } + break; + case GSA_32_BIT_IF_FALSE3: + if(CPUReadMemory(cheatsList[i].address) == cheatsList[i].value) { + onoff=false; + } + break; + case GSA_8_BIT_IF_LOWER_S3: + if (!((s8)CPUReadByte(cheatsList[i].address) < ((s8)cheatsList[i].value & 0xFF))) { + onoff=false; + } + break; + case GSA_16_BIT_IF_LOWER_S3: + if (!((s16)CPUReadHalfWord(cheatsList[i].address) < ((s16)cheatsList[i].value & 0xFFFF))) { + onoff=false; + } + break; + case GSA_32_BIT_IF_LOWER_S3: + if (!((s32)CPUReadMemory(cheatsList[i].address) < (s32)cheatsList[i].value)) { + onoff=false; + } + break; + case GSA_8_BIT_IF_HIGHER_S3: + if (!((s8)CPUReadByte(cheatsList[i].address) > ((s8)cheatsList[i].value & 0xFF))) { + onoff=false; + } + break; + case GSA_16_BIT_IF_HIGHER_S3: + if (!((s16)CPUReadHalfWord(cheatsList[i].address) > ((s16)cheatsList[i].value & 0xFFFF))) { + onoff=false; + } + break; + case GSA_32_BIT_IF_HIGHER_S3: + if (!((s32)CPUReadMemory(cheatsList[i].address) > (s32)cheatsList[i].value)) { + onoff=false; + } + break; + case GSA_8_BIT_IF_LOWER_U3: + if (!(CPUReadByte(cheatsList[i].address) < (cheatsList[i].value & 0xFF))) { + onoff=false; + } + break; + case GSA_16_BIT_IF_LOWER_U3: + if (!(CPUReadHalfWord(cheatsList[i].address) < (cheatsList[i].value & 0xFFFF))) { + onoff=false; + } + break; + case GSA_32_BIT_IF_LOWER_U3: + if (!(CPUReadMemory(cheatsList[i].address) < cheatsList[i].value)) { + onoff=false; + } + break; + case GSA_8_BIT_IF_HIGHER_U3: + if (!(CPUReadByte(cheatsList[i].address) > (cheatsList[i].value & 0xFF))) { + onoff=false; + } + break; + case GSA_16_BIT_IF_HIGHER_U3: + if (!(CPUReadHalfWord(cheatsList[i].address) > (cheatsList[i].value & 0xFFFF))) { + onoff=false; + } + break; + case GSA_32_BIT_IF_HIGHER_U3: + if (!(CPUReadMemory(cheatsList[i].address) > cheatsList[i].value)) { + onoff=false; + } + break; + case GSA_8_BIT_IF_AND3: + if (!(CPUReadByte(cheatsList[i].address) & (cheatsList[i].value & 0xFF))) { + onoff=false; + } + break; + case GSA_16_BIT_IF_AND3: + if (!(CPUReadHalfWord(cheatsList[i].address) & (cheatsList[i].value & 0xFFFF))) { + onoff=false; + } + break; + case GSA_32_BIT_IF_AND3: + if (!(CPUReadMemory(cheatsList[i].address) & cheatsList[i].value)) { + onoff=false; + } + break; + case GSA_ALWAYS3: + if (!(CPUReadMemory(cheatsList[i].address) & cheatsList[i].value)) { + onoff=false; + } + break; + case GSA_GROUP_WRITE: + { + int count = ((cheatsList[i].address) & 0xFFFE) +1; + u32 value = cheatsList[i].value; + if (count==0) + i++; + else + for (int x = 1; x <= count; x++) { + if ((x % 2) ==0){ + if (x cheatsList[i].value) { + i++; + } + break; + case GSA_16_BIT_IF_HIGHER_OR_EQ_U: + if(CPUReadHalfWord(cheatsList[i].address) < cheatsList[i].value) { + i++; + } + break; + case GSA_16_BIT_MIF_TRUE: + if(CPUReadHalfWord(cheatsList[i].address) != cheatsList[i].value) { + i+=((cheatsList[i].rawaddress >> 0x10) & 0xFF); + } + break; + case GSA_16_BIT_MIF_FALSE: + if(CPUReadHalfWord(cheatsList[i].address) == cheatsList[i].value) { + i+=(cheatsList[i].rawaddress >> 0x10) & 0xFF; + } + break; + case GSA_16_BIT_MIF_LOWER_OR_EQ_U: + if(CPUReadHalfWord(cheatsList[i].address) > cheatsList[i].value) { + i+=(cheatsList[i].rawaddress >> 0x10) & 0xFF; + } + break; + case GSA_16_BIT_MIF_HIGHER_OR_EQ_U: + if(CPUReadHalfWord(cheatsList[i].address) < cheatsList[i].value) { + i+=(cheatsList[i].rawaddress >> 0x10) & 0xFF; + } + break; + case CHEATS_16_BIT_WRITE: + if ((cheatsList[i].address>>24)>=0x08) { + CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, cheatsList[i].value); + } else { + CPUWriteHalfWord(cheatsList[i].address, cheatsList[i].value); + } + break; + case CHEATS_32_BIT_WRITE: + if ((cheatsList[i].address>>24)>=0x08) { + CHEAT_PATCH_ROM_32BIT(cheatsList[i].address, cheatsList[i].value); + } else { + CPUWriteMemory(cheatsList[i].address, cheatsList[i].value); + } + break; + } + } + } + for (i = 0; i<4; i++) + if (rompatch2addr [i] != 0) + CHEAT_PATCH_ROM_16BIT(rompatch2addr [i],rompatch2val [i]); + return ticks; +} + +void cheatsAdd(const char *codeStr, + const char *desc, + u32 rawaddress, + u32 address, + u32 value, + int code, + int size) +{ + if(cheatsNumber < 100) { + int x = cheatsNumber; + cheatsList[x].code = code; + cheatsList[x].size = size; + cheatsList[x].rawaddress = rawaddress; + cheatsList[x].address = address; + cheatsList[x].value = value; + strcpy(cheatsList[x].codestring, codeStr); + strcpy(cheatsList[x].desc, desc); + cheatsList[x].enabled = true; + cheatsList[x].status = 0; + + // we only store the old value for this simple codes. ROM patching + // is taken care when it actually patches the ROM + switch(cheatsList[x].size) { + case INT_8_BIT_WRITE: + cheatsList[x].oldValue = CPUReadByte(address); + break; + case INT_16_BIT_WRITE: + cheatsList[x].oldValue = CPUReadHalfWord(address); + break; + case INT_32_BIT_WRITE: + cheatsList[x].oldValue = CPUReadMemory(address); + break; + case CHEATS_16_BIT_WRITE: + cheatsList[x].oldValue = CPUReadHalfWord(address); + break; + case CHEATS_32_BIT_WRITE: + cheatsList[x].oldValue = CPUReadMemory(address); + break; + } + cheatsNumber++; + } +} + +void cheatsDelete(int number, bool restore) +{ + if(number < cheatsNumber && number >= 0) { + int x = number; + + if(restore) { + switch(cheatsList[x].size) { + case INT_8_BIT_WRITE: + CPUWriteByte(cheatsList[x].address, (u8)cheatsList[x].oldValue); + break; + case INT_16_BIT_WRITE: + CPUWriteHalfWord(cheatsList[x].address, (u16)cheatsList[x].oldValue); + break; + case INT_32_BIT_WRITE: + CPUWriteMemory(cheatsList[x].address, cheatsList[x].oldValue); + break; + case CHEATS_16_BIT_WRITE: + if ((cheatsList[x].address>>24)>=0x08) { + CHEAT_PATCH_ROM_16BIT(cheatsList[x].address, cheatsList[x].oldValue); + } else { + CPUWriteHalfWord(cheatsList[x].address, cheatsList[x].oldValue); + } + break; + case CHEATS_32_BIT_WRITE: + if ((cheatsList[x].address>>24)>=0x08) { + CHEAT_PATCH_ROM_32BIT(cheatsList[x].address, cheatsList[x].oldValue); + } else { + CPUWriteMemory(cheatsList[x].address, cheatsList[x].oldValue); + } + case GSA_16_BIT_ROM_PATCH: + if(cheatsList[x].status & 1) { + cheatsList[x].status &= ~1; + CHEAT_PATCH_ROM_16BIT(cheatsList[x].address, + cheatsList[x].oldValue); + } + break; + case GSA_16_BIT_ROM_PATCH2C: + case GSA_16_BIT_ROM_PATCH2D: + case GSA_16_BIT_ROM_PATCH2E: + case GSA_16_BIT_ROM_PATCH2F: + if(cheatsList[x].status & 1) { + cheatsList[x].status &= ~1; + } + break; + case MASTER_CODE: + mastercode=0; + break; + } + } + if((x+1) < cheatsNumber) { + memcpy(&cheatsList[x], &cheatsList[x+1], sizeof(CheatsData)* + (cheatsNumber-x-1)); + } + cheatsNumber--; + } +} + +void cheatsDeleteAll(bool restore) +{ + for(int i = cheatsNumber-1; i >= 0; i--) { + cheatsDelete(i, restore); + } +} + +void cheatsEnable(int i) +{ + if(i >= 0 && i < cheatsNumber) { + cheatsList[i].enabled = true; + mastercode = 0; + } +} + +void cheatsDisable(int i) +{ + if(i >= 0 && i < cheatsNumber) { + switch(cheatsList[i].size) { + case GSA_16_BIT_ROM_PATCH: + if(cheatsList[i].status & 1) { + cheatsList[i].status &= ~1; + CHEAT_PATCH_ROM_16BIT(cheatsList[i].address, + cheatsList[i].oldValue); + } + break; + case GSA_16_BIT_ROM_PATCH2C: + case GSA_16_BIT_ROM_PATCH2D: + case GSA_16_BIT_ROM_PATCH2E: + case GSA_16_BIT_ROM_PATCH2F: + if(cheatsList[i].status & 1) { + cheatsList[i].status &= ~1; + } + break; + case MASTER_CODE: + mastercode=0; + break; + } + cheatsList[i].enabled = false; + } +} + +bool cheatsVerifyCheatCode(const char *code, const char *desc) +{ + size_t len = strlen(code); + if(len != 11 && len != 13 && len != 17) { + systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s': wrong length"), code); + return false; + } + + if(code[8] != ':') { + systemMessage(MSG_INVALID_CHEAT_CODE, N_("Invalid cheat code '%s': no colon"), code); + return false; + } + + size_t i; + for(i = 0; i < 8; i++) { + if(!CHEAT_IS_HEX(code[i])) { + // wrong cheat + systemMessage(MSG_INVALID_CHEAT_CODE, + N_("Invalid cheat code '%s': first part is not hex"), code); + return false; + } + } + for(i = 9; i < len; i++) { + if(!CHEAT_IS_HEX(code[i])) { + // wrong cheat + systemMessage(MSG_INVALID_CHEAT_CODE, + N_("Invalid cheat code '%s' second part is not hex"), code); + return false; + } + } + + u32 address = 0; + u32 value = 0; + + char buffer[10]; + strncpy(buffer, code, 8); + buffer[8] = 0; + sscanf(buffer, "%x", &address); + + switch(address >> 24) { + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + break; + default: + systemMessage(MSG_INVALID_CHEAT_CODE_ADDRESS, + N_("Invalid cheat code address: %08x"), + address); + return false; + } + + strncpy(buffer, &code[9], 8); + sscanf(buffer, "%x", &value); + int type = 0; + if(len == 13) + type = 114; + if(len == 17) + type = 115; + cheatsAdd(code, desc, address, address, value, type, type); + return true; +} + +void cheatsAddCheatCode(const char *code, const char *desc) +{ + cheatsVerifyCheatCode(code, desc); +} + +u16 cheatsGSAGetDeadface(bool v3) +{ + for(int i = cheatsNumber-1; i >= 0; i--) + if ((cheatsList[i].address == 0xDEADFACE) && (cheatsList[i].code == (v3 ? 257 : 256))) + return cheatsList[i].value & 0xFFFF; + return 0; +} + +void cheatsGSAChangeEncryption(u16 value, bool v3) { + int i; + u8 *deadtable1, *deadtable2; + + if (v3) { + deadtable1 = (u8*)(&v3_deadtable1); + deadtable2 = (u8*)(&v3_deadtable2); + for (i = 0; i < 4; i++) + seeds_v3[i] = seed_gen(((value & 0xFF00) >> 8), (value & 0xFF) + i, deadtable1, deadtable2); + } + else { + deadtable1 = (u8*)(&v1_deadtable1); + deadtable2 = (u8*)(&v1_deadtable2); + for (i = 0; i < 4; i++){ + seeds_v1[i] = seed_gen(((value & 0xFF00) >> 8), (value & 0xFF) + i, deadtable1, deadtable2); + } + } +} + +u32 seed_gen(u8 upper, u8 seed, u8 *deadtable1, u8 *deadtable2) { + int i; + u32 newseed = 0; + + for (i = 0; i < 4; i++) + newseed = ((newseed << 8) | ((deadtable1[(i + upper) & 0xFF] + deadtable2[seed]) & 0xFF)); + + return newseed; +} + +void cheatsDecryptGSACode(u32& address, u32& value, bool v3) +{ + u32 rollingseed = 0xC6EF3720; + u32 *seeds = v3 ? seeds_v3 : seeds_v1; + + int bitsleft = 32; + while (bitsleft > 0) { + value -= ((((address << 4) + seeds[2]) ^ (address + rollingseed)) ^ + ((address >> 5) + seeds[3])); + address -= ((((value << 4) + seeds[0]) ^ (value + rollingseed)) ^ + ((value >> 5) + seeds[1])); + rollingseed -= 0x9E3779B9; + bitsleft--; + } +} + +void cheatsAddGSACode(const char *code, const char *desc, bool v3) +{ + if(strlen(code) != 16) { + // wrong cheat + systemMessage(MSG_INVALID_GSA_CODE, + N_("Invalid GSA code. Format is XXXXXXXXYYYYYYYY")); + return; + } + + int i; + for(i = 0; i < 16; i++) { + if(!CHEAT_IS_HEX(code[i])) { + // wrong cheat + systemMessage(MSG_INVALID_GSA_CODE, + N_("Invalid GSA code. Format is XXXXXXXXYYYYYYYY")); + return; + } + } + + char buffer[10]; + strncpy(buffer, code, 8); + buffer[8] = 0; + u32 address; + sscanf(buffer, "%x", &address); + strncpy(buffer, &code[8], 8); + buffer[8] = 0; + u32 value; + sscanf(buffer, "%x", &value); + cheatsGSAChangeEncryption(cheatsGSAGetDeadface (v3), v3); + cheatsDecryptGSACode(address, value, v3); + + if(value == 0x1DC0DE) { + u32 gamecode = READ32LE(((u32 *)&rom[0xac])); + if(gamecode != address) { + char buffer[5]; + *((u32 *)buffer) = address; + buffer[4] = 0; + char buffer2[5]; + *((u32 *)buffer2) = READ32LE(((u32 *)&rom[0xac])); + buffer2[4] = 0; + systemMessage(MSG_GBA_CODE_WARNING, N_("Warning: cheats are for game %s. Current game is %s.\nCodes may not work correctly."), + buffer, buffer2); + } + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value, v3 ? 257 : 256, + UNKNOWN_CODE); + return; + } + if(isMultilineWithData(cheatsNumber-1)) { + cheatsAdd(code, desc, address, address, value, v3 ? 257 : 256, UNKNOWN_CODE); + return; + } + if(v3) { + int type = ((address >> 25) & 127) | ((address >> 17) & 0x80); + u32 addr = (address & 0x00F00000) << 4 | (address & 0x0003FFFF); + u16 mcode = (address>>24 & 0xFF); + + if ((mcode & 0xFE) == 0xC4) + { + cheatsAdd(code, desc, address, (address & 0x1FFFFFF) | (0x08000000), + value, 257, MASTER_CODE); + mastercode = (address & 0x1FFFFFF) | (0x08000000); + } + else + switch(type) { + case 0x00: + if(address == 0) { + type = (value >> 25) & 127; + addr = (value & 0x00F00000) << 4 | (value & 0x0003FFFF); + switch(type) { + case 0x04: + cheatsAdd(code, desc, address, 0, value & 0x00FFFFFF, 257, GSA_SLOWDOWN); + break; + case 0x08: + cheatsAdd(code, desc, address, 0, addr, 257, GSA_8_BIT_GS_WRITE2); + break; + case 0x09: + cheatsAdd(code, desc, address, 0, addr, 257, GSA_16_BIT_GS_WRITE2); + break; + case 0x0a: + cheatsAdd(code, desc, address, 0, addr, 257, GSA_32_BIT_GS_WRITE2); + break; + case 0x0c: + cheatsAdd(code, desc, address, 0, value & 0x00FFFFFF, 257, GSA_16_BIT_ROM_PATCH2C); + break; + case 0x0d: + cheatsAdd(code, desc, address, 0, value & 0x00FFFFFF, 257, GSA_16_BIT_ROM_PATCH2D); + break; + case 0x0e: + cheatsAdd(code, desc, address, 0, value & 0x00FFFFFF, 257, GSA_16_BIT_ROM_PATCH2E); + break; + case 0x0f: + cheatsAdd(code, desc, address, 0, value & 0x00FFFFFF, 257, GSA_16_BIT_ROM_PATCH2F); + break; + case 0x20: + cheatsAdd(code, desc, address, 0, addr, 257, GSA_CODES_ON); + break; + case 0x40: + cheatsAdd(code, desc, address, 0, addr, 257, GSA_8_BIT_SLIDE); + break; + case 0x41: + cheatsAdd(code, desc, address, 0, addr, 257, GSA_16_BIT_SLIDE); + break; + case 0x42: + cheatsAdd(code, desc, address, 0, addr, 257, GSA_32_BIT_SLIDE); + break; + default: + cheatsAdd(code, desc, address, address, value, 257, UNKNOWN_CODE); + break; + } + } else + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_FILL); + break; + case 0x01: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_FILL); + break; + case 0x02: + cheatsAdd(code, desc, address, addr, value, 257, INT_32_BIT_WRITE); + break; + case 0x04: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_TRUE); + break; + case 0x05: + cheatsAdd(code, desc, address, addr, value, 257, CBA_IF_TRUE); + break; + case 0x06: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_TRUE); + break; + case 0x07: + cheatsAdd(code, desc, address, addr, value, 257, GSA_ALWAYS); + break; + case 0x08: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_FALSE); + break; + case 0x09: + cheatsAdd(code, desc, address, addr, value, 257, CBA_IF_FALSE); + break; + case 0x0a: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_FALSE); + break; + case 0xc: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_LOWER_S); + break; + case 0xd: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_LOWER_S); + break; + case 0xe: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_LOWER_S); + break; + case 0x10: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_HIGHER_S); + break; + case 0x11: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_HIGHER_S); + break; + case 0x12: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_HIGHER_S); + break; + case 0x14: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_LOWER_U); + break; + case 0x15: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_LOWER_U); + break; + case 0x16: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_LOWER_U); + break; + case 0x18: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_HIGHER_U); + break; + case 0x19: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_HIGHER_U); + break; + case 0x1A: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_HIGHER_U); + break; + case 0x1C: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_AND); + break; + case 0x1D: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_AND); + break; + case 0x1E: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_AND); + break; + case 0x20: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_POINTER); + break; + case 0x21: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_POINTER); + break; + case 0x22: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_POINTER); + break; + case 0x24: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_TRUE2); + break; + case 0x25: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_TRUE2); + break; + case 0x26: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_TRUE2); + break; + case 0x27: + cheatsAdd(code, desc, address, addr, value, 257, GSA_ALWAYS2); + break; + case 0x28: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_FALSE2); + break; + case 0x29: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_FALSE2); + break; + case 0x2a: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_FALSE2); + break; + case 0x2c: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_LOWER_S2); + break; + case 0x2d: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_LOWER_S2); + break; + case 0x2e: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_LOWER_S2); + break; + case 0x30: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_HIGHER_S2); + break; + case 0x31: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_HIGHER_S2); + break; + case 0x32: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_HIGHER_S2); + break; + case 0x34: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_LOWER_U2); + break; + case 0x35: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_LOWER_U2); + break; + case 0x36: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_LOWER_U2); + break; + case 0x38: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_HIGHER_U2); + break; + case 0x39: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_HIGHER_U2); + break; + case 0x3A: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_HIGHER_U2); + break; + case 0x3C: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_AND2); + break; + case 0x3D: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_AND2); + break; + case 0x3E: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_AND2); + break; + case 0x40: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_ADD); + break; + case 0x41: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_ADD); + break; + case 0x42: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_ADD); + break; + case 0x44: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_TRUE3); + break; + case 0x45: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_TRUE3); + break; + case 0x46: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_TRUE3); + break; + case 0x47: + cheatsAdd(code, desc, address, addr, value, 257, GSA_ALWAYS3); + break; + case 0x48: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_FALSE3); + break; + case 0x49: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_FALSE3); + break; + case 0x4a: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_FALSE3); + break; + case 0x4c: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_LOWER_S3); + break; + case 0x4d: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_LOWER_S3); + break; + case 0x4e: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_LOWER_S3); + break; + case 0x50: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_HIGHER_S3); + break; + case 0x51: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_HIGHER_S3); + break; + case 0x52: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_HIGHER_S3); + break; + case 0x54: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_LOWER_U3); + break; + case 0x55: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_LOWER_U3); + break; + case 0x56: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_LOWER_U3); + break; + case 0x58: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_HIGHER_U3); + break; + case 0x59: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_HIGHER_U3); + break; + case 0x5a: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_HIGHER_U3); + break; + case 0x5c: + cheatsAdd(code, desc, address, addr, value, 257, GSA_8_BIT_IF_AND3); + break; + case 0x5d: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_IF_AND3); + break; + case 0x5e: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_IF_AND3); + break; + case 0x63: + cheatsAdd(code, desc, address, addr, value, 257, GSA_16_BIT_WRITE_IOREGS); + break; + case 0xE3: + cheatsAdd(code, desc, address, addr, value, 257, GSA_32_BIT_WRITE_IOREGS); + break; + default: + cheatsAdd(code, desc, address, address, value, 257, UNKNOWN_CODE); + break; + } + } else { + int type = (address >> 28) & 15; + switch(type) { + case 0: + case 1: + case 2: + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value, 256, type); + break; + case 3: + switch ((address >> 0x10) & 0xFF){ + case 0x00: + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value, 256, GSA_GROUP_WRITE); + break; + case 0x10: + cheatsAdd(code, desc, address, value & 0x0FFFFFFF, address & 0xFF, 256, GSA_32_BIT_ADD ); + break; + case 0x20: + cheatsAdd(code, desc, address, value & 0x0FFFFFFF, (~(address & 0xFF)+1), 256, GSA_32_BIT_ADD ); + break; + case 0x30: + cheatsAdd(code, desc, address, value & 0x0FFFFFFF, address & 0xFFFF, 256, GSA_32_BIT_ADD ); + break; + case 0x40: + cheatsAdd(code, desc, address, value & 0x0FFFFFFF, (~(address & 0xFFFF)+1), 256, GSA_32_BIT_ADD ); + break; + case 0x50: + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value, 256, GSA_32_BIT_ADD2); + break; + case 0x60: + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value, 256, GSA_32_BIT_SUB2); + break; + default: + // unsupported code + cheatsAdd(code, desc, address, address, value, 256, + UNKNOWN_CODE); + break; + } + break; + case 6: + address <<= 1; + type = (value >> 24) & 0xFF; + if(type == 0x00) { + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value & 0xFFFF, 256, + GSA_16_BIT_ROM_PATCH); + break; + } + // unsupported code + cheatsAdd(code, desc, address, address, value, 256, + UNKNOWN_CODE); + break; + case 8: + switch((address >> 20) & 15) { + case 1: + cheatsAdd(code, desc, address, address & 0x0F0FFFFF, value, 256, + GSA_8_BIT_GS_WRITE); + break; + case 2: + cheatsAdd(code, desc, address, address & 0x0F0FFFFF, value, 256, + GSA_16_BIT_GS_WRITE); + break; + case 4: + // This code is buggy : the value is always set to 0 ! + cheatsAdd(code, desc, address, address & 0x0F0FFFFF, 0, 256, + GSA_32_BIT_GS_WRITE); + break; + case 15: + cheatsAdd(code, desc, address, 0, value & 0xFFFF, 256, GSA_SLOWDOWN); + break; + default: + // unsupported code + cheatsAdd(code, desc, address, address, value, 256, + UNKNOWN_CODE); + break; + } + break; + case 0x0d: + if(address != 0xDEADFACE) { + switch((value >> 20) & 0xF) { + case 0: + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value & 0xFFFF, 256, + CBA_IF_TRUE); + break; + case 1: + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value & 0xFFFF, 256, + CBA_IF_FALSE); + break; + case 2: + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value & 0xFFFF, 256, + GSA_16_BIT_IF_LOWER_OR_EQ_U); + break; + case 3: + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value & 0xFFFF, 256, + GSA_16_BIT_IF_HIGHER_OR_EQ_U); + break; + default: + // unsupported code + cheatsAdd(code, desc, address, address, value, 256, + UNKNOWN_CODE); + break; + } + } else + cheatsAdd(code, desc, address, address, value, 256, + UNKNOWN_CODE); + break; + case 0x0e: + switch((value >> 28) & 0xF) { + case 0: + cheatsAdd(code, desc, address, value & 0x0FFFFFFF, address & 0xFFFF, 256, + GSA_16_BIT_MIF_TRUE); + break; + case 1: + cheatsAdd(code, desc, address, value & 0x0FFFFFFF, address & 0xFFFF, 256, + GSA_16_BIT_MIF_FALSE); + break; + case 2: + cheatsAdd(code, desc, address, value & 0x0FFFFFFF, address & 0xFFFF, 256, + GSA_16_BIT_MIF_LOWER_OR_EQ_U); + break; + case 3: + cheatsAdd(code, desc, address, value & 0x0FFFFFFF, address & 0xFFFF, 256, + GSA_16_BIT_MIF_HIGHER_OR_EQ_U); + break; + default: + // unsupported code + cheatsAdd(code, desc, address, address, value, 256, + UNKNOWN_CODE); + break; + } + break; + case 0x0f: + cheatsAdd(code, desc, address, (address & 0xFFFFFFF), value, 256, MASTER_CODE); + mastercode = (address & 0xFFFFFFF); + break; + default: + // unsupported code + cheatsAdd(code, desc, address, address, value, 256, + UNKNOWN_CODE); + break; + } + } +} + +bool cheatsImportGSACodeFile(const char *name, int game, bool v3) +{ + FILE *f = fopen(name, "rb"); + if(!f) + return false; + + int games = 0; + int len = 0; + fseek(f, 0x1e, SEEK_CUR); + fread(&games, 1, 4, f); + bool found = false; + int g = 0; + while(games > 0) { + if(g == game) { + found = true; + break; + } + fread(&len, 1, 4, f); + fseek(f,len,SEEK_CUR); + int codes = 0; + fread(&codes, 1, 4, f); + while(codes > 0) { + fread(&len, 1, 4, f); + fseek(f, len, SEEK_CUR); + fseek(f, 8, SEEK_CUR); + fread(&len, 1, 4, f); + fseek(f, len*12, SEEK_CUR); + codes--; + } + games--; + g++; + } + if(found) { + char desc[256]; + char code[17]; + fread(&len, 1, 4, f); + fseek(f, len, SEEK_CUR); + int codes = 0; + fread(&codes, 1, 4, f); + while(codes > 0) { + fread(&len, 1, 4, f); + fread(desc, 1, len, f); + desc[len] =0; + desc[31] = 0; + fread(&len, 1, 4, f); + fseek(f, len, SEEK_CUR); + fseek(f, 4, SEEK_CUR); + fread(&len, 1, 4, f); + while(len) { + fseek(f, 4, SEEK_CUR); + fread(code, 1, 8, f); + fseek(f, 4, SEEK_CUR); + fread(&code[8], 1, 8, f); + code[16] = 0; + cheatsAddGSACode(code, desc, v3); + len -= 2; + } + codes--; + } + } + fclose(f); + return false; +} + +void cheatsCBAReverseArray(u8 *array, u8 *dest) +{ + dest[0] = array[3]; + dest[1] = array[2]; + dest[2] = array[1]; + dest[3] = array[0]; + dest[4] = array[5]; + dest[5] = array[4]; +} + +void chatsCBAScramble(u8 *array, int count, u8 b) +{ + u8 *x = array + (count >> 3); + u8 *y = array + (b >> 3); + u32 z = *x & (1 << (count & 7)); + u32 x0 = (*x & (~(1 << (count & 7)))); + if (z != 0) + z = 1; + if ((*y & (1 << (b & 7))) != 0) + x0 |= (1 << (count & 7)); + *x = x0; + u32 temp = *y & (~(1 << (b & 7))); + if (z != 0) + temp |= (1 << (b & 7)); + *y = temp; +} + +u32 cheatsCBAGetValue(u8 *array) +{ + return array[0] | array[1]<<8 | array[2] << 16 | array[3]<<24; +} + +u16 cheatsCBAGetData(u8 *array) +{ + return array[4] | array[5]<<8; +} + +void cheatsCBAArrayToValue(u8 *array, u8 *dest) +{ + dest[0] = array[3]; + dest[1] = array[2]; + dest[2] = array[1]; + dest[3] = array[0]; + dest[4] = array[5]; + dest[5] = array[4]; +} + +void cheatsCBAParseSeedCode(u32 address, u32 value, u32 *array) +{ + array[0] = 1; + array[1] = value & 0xFF; + array[2] = (address >> 0x10) & 0xFF; + array[3] = (value >> 8) & 0xFF; + array[4] = (address >> 0x18) & 0x0F; + array[5] = address & 0xFFFF; + array[6] = address; + array[7] = value; +} + +u32 cheatsCBAEncWorker() +{ + u32 x = (cheatsCBATemporaryValue * 0x41c64e6d) + 0x3039; + u32 y = (x * 0x41c64e6d) + 0x3039; + u32 z = x >> 0x10; + x = ((y >> 0x10) & 0x7fff) << 0x0f; + z = (z << 0x1e) | x; + x = (y * 0x41c64e6d) + 0x3039; + cheatsCBATemporaryValue = x; + return z | ((x >> 0x10) & 0x7fff); +} + +#define ROR(v, s) \ + (((v) >> (s)) | (((v) & ((1 << (s))-1)) << (32 - (s)))) + +u32 cheatsCBACalcIndex(u32 x, u32 y) +{ + if(y != 0) { + if(y == 1) + x = 0; + else if(x == y) + x = 0; + if(y < 1) + return x; + else if(x < y) + return x; + u32 x0 = 1; + + while(y < 0x10000000) { + if(y < x) { + y = y << 4; + x0 = x0 << 4; + } else break; + } + + while(y < 0x80000000) { + if(y < x) { + y = y << 1; + x0 = x0 << 1; + } else break; + } + + loop: + u32 z = 0; + if(x >= y) + x -= y; + if(x >= (y >> 1)) { + x -= (y >> 1); + z |= ROR(x0, 1); + } + if(x >= (y >> 2)) { + x -= (y >> 2); + z |= ROR(x0, 2); + } + if(x >= (y >> 3)) { + x -= (y >> 3); + z |= ROR(x0, 3); + } + + u32 temp = x0; + + if(x != 0) { + x0 = x0 >> 4; + if(x0 != 0) { + y = y >> 4; + goto loop; + } + } + + z = z & 0xe0000000; + + if(z != 0) { + if((temp & 7) == 0) + return x; + } else + return x; + + if((z & ROR(temp, 3)) != 0) + x += y >> 3; + if((z & ROR(temp, 2)) != 0) + x += y >> 2; + if((z & ROR(temp, 1)) != 0) + x += y >> 1; + return x; + } else { + } + // should not happen in the current code + return 0; +} + +void cheatsCBAUpdateSeedBuffer(u32 a, u8 *buffer, int count) +{ + int i; + for(i = 0; i < count; i++) + buffer[i] = i; + for(i = 0; (u32)i < a; i++) { + u32 a = cheatsCBACalcIndex(cheatsCBAEncWorker(), count); + u32 b = cheatsCBACalcIndex(cheatsCBAEncWorker(), count); + u32 t = buffer[a]; + buffer[a] = buffer[b]; + buffer[b] = t; + } +} + +void cheatsCBAChangeEncryption(u32 *seed) +{ + int i; + + cheatsCBATemporaryValue = (seed[1] ^ 0x1111); + cheatsCBAUpdateSeedBuffer(0x50, cheatsCBASeedBuffer, 0x30); + cheatsCBATemporaryValue = 0x4efad1c3; + + for(i = 0; (u32)i < seed[4]; i++) { + cheatsCBATemporaryValue = cheatsCBAEncWorker(); + } + cheatsCBASeed[2] = cheatsCBAEncWorker(); + cheatsCBASeed[3] = cheatsCBAEncWorker(); + + cheatsCBATemporaryValue = seed[3] ^ 0xf254; + + for(i = 0; (u32)i < seed[3]; i++) { + cheatsCBATemporaryValue = cheatsCBAEncWorker(); + } + + cheatsCBASeed[0] = cheatsCBAEncWorker(); + cheatsCBASeed[1] = cheatsCBAEncWorker(); + + *((u32 *)&cheatsCBACurrentSeed[0]) = seed[6]; + *((u32 *)&cheatsCBACurrentSeed[4]) = seed[7]; + *((u32 *)&cheatsCBACurrentSeed[8]) = 0; +} + +u16 cheatsCBAGenValue(u32 x, u32 y, u32 z) +{ + y <<= 0x10; + z <<= 0x10; + x <<= 0x18; + u32 x0 = (int)y >> 0x10; + z = (int)z >> 0x10; + x = (int)x >> 0x10; + for(int i = 0; i < 8; i++) { + u32 temp = z ^ x; + if ((int)temp >= 0) { + temp = z << 0x11; + } + else { + temp = z << 0x01; + temp ^= x0; + temp = temp << 0x10; + } + z = (int)temp >> 0x10; + temp = x << 0x11; + x = (int)temp >> 0x10; + } + return z & 0xffff; +} + +void cheatsCBAGenTable() { + for (int i = 0; i < 0x100; i++) { + cheatsCBATable[i] = cheatsCBAGenValue(i, 0x1021, 0); + } + cheatsCBATableGenerated = true; +} + +u16 cheatsCBACalcCRC(u8 *rom, int count) +{ + u32 crc = 0xffffffff; + + if (count & 3) { + // 0x08000EAE + } else { + count = (count >> 2) - 1; + if(count != -1) { + while(count != -1) { + crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18) + ^ *rom++]) << 0x10) >> 0x10; + crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18) + ^ *rom++]) << 0x10) >> 0x10; + crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18) + ^ *rom++]) << 0x10) >> 0x10; + crc = (((crc << 0x08) ^ cheatsCBATable[(((u32)crc << 0x10) >> 0x18) + ^ *rom++]) << 0x10) >> 0x10; + count--; + } + } + } + return crc & 0xffff; +} + +void cheatsCBADecrypt(u8 *decrypt) +{ + u8 buffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + u8 *array = &buffer[1]; + + cheatsCBAReverseArray(decrypt, array); + + for(int count = 0x2f; count >= 0; count--) { + chatsCBAScramble(array, count, cheatsCBASeedBuffer[count]); + } + cheatsCBAArrayToValue(array, decrypt); + *((u32 *)decrypt) = cheatsCBAGetValue(decrypt) ^ + cheatsCBASeed[0]; + *((u16 *)(decrypt+4)) = (cheatsCBAGetData(decrypt) ^ + cheatsCBASeed[1]) & 0xffff; + + cheatsCBAReverseArray(decrypt, array); + + u32 cs = cheatsCBAGetValue(cheatsCBACurrentSeed); + for(int i = 0; i <= 4; i++) { + array[i] = ((cs >> 8) ^ array[i+1]) ^ array[i] ; + } + + array[5] = (cs >> 8) ^ array[5]; + + for(int j = 5; j >=0; j--) { + array[j] = (cs ^ array[j-1]) ^ array[j]; + } + + cheatsCBAArrayToValue(array, decrypt); + + *((u32 *)decrypt) = cheatsCBAGetValue(decrypt) + ^ cheatsCBASeed[2]; + *((u16 *)(decrypt+4)) = (cheatsCBAGetData(decrypt) + ^ cheatsCBASeed[3]) & 0xffff; +} + +int cheatsCBAGetCount() +{ + int count = 0; + for(int i = 0; i < cheatsNumber; i++) { + if(cheatsList[i].code == 512) + count++; + } + return count; +} + +bool cheatsCBAShouldDecrypt() +{ + for(int i = 0; i < cheatsNumber; i++) { + if(cheatsList[i].code == 512) { + return (cheatsList[i].codestring[0] == '9'); + } + } + return false; +} + +void cheatsAddCBACode(const char *code, const char *desc) +{ + if(strlen(code) != 13) { + // wrong cheat + systemMessage(MSG_INVALID_CBA_CODE, + N_("Invalid CBA code. Format is XXXXXXXX YYYY.")); + return; + } + + int i; + for(i = 0; i < 8; i++) { + if(!CHEAT_IS_HEX(code[i])) { + // wrong cheat + systemMessage(MSG_INVALID_CBA_CODE, + N_("Invalid CBA code. Format is XXXXXXXX YYYY.")); + return; + } + } + + if(code[8] != ' ') { + systemMessage(MSG_INVALID_CBA_CODE, + N_("Invalid CBA code. Format is XXXXXXXX YYYY.")); + return; + } + + for(i = 9; i < 13; i++) { + if(!CHEAT_IS_HEX(code[i])) { + // wrong cheat + systemMessage(MSG_INVALID_CBA_CODE, + N_("Invalid CBA code. Format is XXXXXXXX YYYY.")); + return; + } + } + + char buffer[10]; + strncpy(buffer, code, 8); + buffer[8] = 0; + u32 address; + sscanf(buffer, "%x", &address); + strncpy(buffer, &code[9], 4); + buffer[4] = 0; + u32 value; + sscanf(buffer, "%x", &value); + + u8 array[8] = { + address & 255, + (address >> 8) & 255, + (address >> 16) & 255, + (address >> 24) & 255, + (value & 255), + (value >> 8) & 255, + 0, + 0 + }; + + if(cheatsCBAGetCount() == 0 && + (address >> 28) == 9) { + u32 seed[8]; + cheatsCBAParseSeedCode(address, value, seed); + cheatsCBAChangeEncryption(seed); + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value, 512, UNKNOWN_CODE); + } else { + if(cheatsCBAShouldDecrypt()) + cheatsCBADecrypt(array); + + address = READ32LE(((u32 *)array)); + value = READ16LE(((u16 *)&array[4])); + + int type = (address >> 28) & 15; + + if(isMultilineWithData(cheatsNumber-1) || (super>0)) { + cheatsAdd(code, desc, address, address, value, 512, UNKNOWN_CODE); + if (super>0) + super-= 1; + return; + } + + switch(type) { + case 0x00: + { + if(!cheatsCBATableGenerated) + cheatsCBAGenTable(); + u32 crc = cheatsCBACalcCRC(rom, 0x10000); + if(crc != address) { + systemMessage(MSG_CBA_CODE_WARNING, + N_("Warning: Codes seem to be for a different game.\nCodes may not work correctly.")); + } + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value, 512, + UNKNOWN_CODE); + } + break; + case 0x01: + cheatsAdd(code, desc, address, (address & 0x1FFFFFF) | 0x08000000, value, 512, MASTER_CODE); + mastercode = (address & 0x1FFFFFF) | 0x08000000; + break; + case 0x02: + cheatsAdd(code, desc, address, address & 0x0FFFFFFE, value, 512, + CBA_OR); + break; + case 0x03: + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value, 512, + INT_8_BIT_WRITE); + break; + case 0x04: + cheatsAdd(code, desc, address, address & 0x0FFFFFFE, value, 512, + CBA_SLIDE_CODE); + break; + case 0x05: + cheatsAdd(code, desc, address, address & 0x0FFFFFFE, value, 512, + CBA_SUPER); + super = getCodeLength(cheatsNumber-1); + break; + case 0x06: + cheatsAdd(code, desc, address, address & 0x0FFFFFFE, value, 512, + CBA_AND); + break; + case 0x07: + cheatsAdd(code, desc, address, address & 0x0FFFFFFE, value, 512, + CBA_IF_TRUE); + break; + case 0x08: + cheatsAdd(code, desc, address, address & 0x0FFFFFFE, value, 512, + INT_16_BIT_WRITE); + break; + case 0x0a: + cheatsAdd(code, desc, address, address & 0x0FFFFFFE, value, 512, + CBA_IF_FALSE); + break; + case 0x0b: + cheatsAdd(code, desc, address, address & 0x0FFFFFFE, value, 512, + CBA_GT); + break; + case 0x0c: + cheatsAdd(code, desc, address, address & 0x0FFFFFFE, value, 512, + CBA_LT); + break; + case 0x0d: + if ((address & 0xF0)<0x30) + cheatsAdd(code, desc, address, address & 0xF0, value, 512, + CBA_IF_KEYS_PRESSED); + break; + case 0x0e: + cheatsAdd(code, desc, address, address & 0x0FFFFFFF, value & 0x8000 ? value | 0xFFFF0000 : value, 512, + CBA_ADD); + break; + case 0x0f: + cheatsAdd(code, desc, address, address & 0x0FFFFFFE, value, 512, + GSA_16_BIT_IF_AND); + break; + default: + // unsupported code + cheatsAdd(code, desc, address, address & 0xFFFFFFFF, value, 512, + UNKNOWN_CODE); + break; + } + } +} + +void cheatsSaveGame(gzFile file) +{ + utilWriteInt(file, cheatsNumber); + + utilGzWrite(file, cheatsList, sizeof(cheatsList)); +} + +void cheatsReadGame(gzFile file, int version) +{ + cheatsNumber = 0; + + cheatsNumber = utilReadInt(file); + + if (version > 8) + utilGzRead(file, cheatsList, sizeof(cheatsList)); + + + bool firstCodeBreaker = true; + + for(int i = 0; i < cheatsNumber; i++) { + if (version <9) + { + cheatsList[i].code = utilReadInt(file); + cheatsList[i].size = utilReadInt(file); + cheatsList[i].status = utilReadInt(file); + cheatsList[i].enabled = utilReadInt(file) ? true : false; + utilGzRead(file, &cheatsList[i].address, sizeof(u32)); + cheatsList[i].rawaddress = cheatsList[i].address; + utilGzRead(file, &cheatsList[i].value, sizeof(u32)); + utilGzRead(file, &cheatsList[i].oldValue, sizeof(u32)); + utilGzRead(file, &cheatsList[i].codestring, 20*sizeof(char)); + utilGzRead(file, &cheatsList[i].desc, 32*sizeof(char)); + } + + cheatsList[i].status = 0; + if(!cheatsList[i].codestring[0]) { + switch(cheatsList[i].size) { + case 0: + sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address, + cheatsList[i].value); + break; + case 1: + sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address, + cheatsList[i].value); + break; + case 2: + sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address, + cheatsList[i].value); + break; + } + } + + if(cheatsList[i].enabled) { + cheatsEnable(i); + } + + if(cheatsList[i].code == 512 && firstCodeBreaker) { + firstCodeBreaker = false; + char buffer[10]; + strncpy(buffer, cheatsList[i].codestring, 8); + buffer[8] = 0; + u32 address; + sscanf(buffer, "%x", &address); + if((address >> 28) == 9) { + strncpy(buffer, &cheatsList[i].codestring[9], 4); + buffer[4] = 0; + u32 value; + sscanf(buffer, "%x", &value); + + u32 seed[8]; + cheatsCBAParseSeedCode(address, value, seed); + cheatsCBAChangeEncryption(seed); + } + } + } +} + +void cheatsSaveCheatList(const char *file) +{ + if(cheatsNumber == 0) + return; + FILE *f = fopen(file, "wb"); + if(f == NULL) + return; + int version = 1; + fwrite(&version, 1, sizeof(version), f); + int type = 1; + fwrite(&type, 1, sizeof(type), f); + fwrite(&cheatsNumber, 1, sizeof(cheatsNumber), f); + fwrite(cheatsList, 1, sizeof(cheatsList), f); + fclose(f); +} + +bool cheatsLoadCheatList(const char *file) +{ + + int count = 0; + + FILE *f = fopen(file, "rb"); + + if(f == NULL) + return false; + + int version = 0; + + if(fread(&version, 1, sizeof(version), f) != sizeof(version)) { + fclose(f); + return false; + } + + if(version != 1) { + systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_VERSION, + N_("Unsupported cheat list version %d"), version); + fclose(f); + return false; + } + + int type = 0; + if(fread(&type, 1, sizeof(type), f) != sizeof(type)) { + fclose(f); + return false; + } + + + if((type != 0) && (type != 1)) { + systemMessage(MSG_UNSUPPORTED_CHEAT_LIST_TYPE, + N_("Unsupported cheat list type %d"), type); + fclose(f); + return false; + } + + if(fread(&count, 1, sizeof(count), f) != sizeof(count)) { + fclose(f); + return false; + } + if (type == 1) + { + if(fread(cheatsList, 1, sizeof(cheatsList), f) != sizeof(cheatsList)) { + fclose(f); + return false; + } + } + else if (type == 0) + { + for(int i = 0; i < count; i++) { + fread(&cheatsList[i].code, 1, sizeof(int),f); + fread(&cheatsList[i].size, 1, sizeof(int),f); + fread(&cheatsList[i].status, 1, sizeof(int),f); + fread(&cheatsList[i].enabled, 1, sizeof(int),f); + cheatsList[i].enabled = cheatsList[i].enabled ? true : false; + fread(&cheatsList[i].address, 1, sizeof(u32),f); + cheatsList[i].rawaddress = cheatsList[i].address; + fread(&cheatsList[i].value, 1, sizeof(u32),f); + fread(&cheatsList[i].oldValue, 1, sizeof(u32),f); + fread(&cheatsList[i].codestring, 1, 20*sizeof(char),f); + if(fread(&cheatsList[i].desc, 1, 32*sizeof(char),f) != 32*sizeof(char)) { + fclose(f); + return false; + } + } + } + + bool firstCodeBreaker = true; + + for(int i = 0; i < count; i++) { + cheatsList[i].status = 0; // remove old status as it is not used + if(!cheatsList[i].codestring[0]) { + switch(cheatsList[i].size) { + case 0: + sprintf(cheatsList[i].codestring, "%08x:%02x", cheatsList[i].address, + cheatsList[i].value); + break; + case 1: + sprintf(cheatsList[i].codestring, "%08x:%04x", cheatsList[i].address, + cheatsList[i].value); + break; + case 2: + sprintf(cheatsList[i].codestring, "%08x:%08x", cheatsList[i].address, + cheatsList[i].value); + break; + } + } + + if(cheatsList[i].code == 512 && firstCodeBreaker) { + firstCodeBreaker = false; + char buffer[10]; + strncpy(buffer, cheatsList[i].codestring, 8); + buffer[8] = 0; + u32 address; + sscanf(buffer, "%x", &address); + if((address >> 28) == 9) { + strncpy(buffer, &cheatsList[i].codestring[9], 4); + buffer[4] = 0; + u32 value; + sscanf(buffer, "%x", &value); + + u32 seed[8]; + cheatsCBAParseSeedCode(address, value, seed); + cheatsCBAChangeEncryption(seed); + } + } + } + cheatsNumber = count; + fclose(f); + return true; +} + +extern int cpuNextEvent; + +extern void debuggerBreakOnWrite(u32 , u32, u32, int, int); + +#ifdef BKPT_SUPPORT +static u8 cheatsGetType(u32 address) +{ + switch(address >> 24) { + case 2: + return freezeWorkRAM[address & 0x3FFFF]; + case 3: + return freezeInternalRAM[address & 0x7FFF]; + case 5: + return freezePRAM[address & 0x3FC]; + case 6: + if (address > 0x06010000) + return freezeVRAM[address & 0x17FFF]; + else + return freezeVRAM[address & 0x1FFFF]; + case 7: + return freezeOAM[address & 0x3FC]; + } + return 0; +} +#endif + +void cheatsWriteMemory(u32 address, u32 value) +{ +#ifdef BKPT_SUPPORT +#ifdef SDL + if(cheatsNumber == 0) { + int type = cheatsGetType(address); + u32 oldValue = debuggerReadMemory(address); + if(type == 1 || (type == 2 && oldValue != value)) { + debuggerBreakOnWrite(address, oldValue, value, 2, type); + cpuNextEvent = 0; + } + debuggerWriteMemory(address, value); + } +#endif +#endif +} + +void cheatsWriteHalfWord(u32 address, u16 value) +{ +#ifdef BKPT_SUPPORT +#ifdef SDL + if(cheatsNumber == 0) { + int type = cheatsGetType(address); + u16 oldValue = debuggerReadHalfWord(address); + if(type == 1 || (type == 2 && oldValue != value)) { + debuggerBreakOnWrite(address, oldValue, value, 1, type); + cpuNextEvent = 0; + } + debuggerWriteHalfWord(address, value); + } +#endif +#endif +} + +#if defined BKPT_SUPPORT && defined SDL +void cheatsWriteByte(u32 address, u8 value) +#else +void cheatsWriteByte(u32, u8) +#endif +{ +#ifdef BKPT_SUPPORT +#ifdef SDL + if(cheatsNumber == 0) { + int type = cheatsGetType(address); + u8 oldValue = debuggerReadByte(address); + if(type == 1 || (type == 2 && oldValue != value)) { + debuggerBreakOnWrite(address, oldValue, value, 0, type); + cpuNextEvent = 0; + } + debuggerWriteByte(address, value); + } +#endif +#endif +} diff --git a/source/vba/Cheats.h b/source/vba/Cheats.h index 61d8e90..2966595 100644 --- a/source/vba/Cheats.h +++ b/source/vba/Cheats.h @@ -1,55 +1,55 @@ -// -*- 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 GBA_CHEATS_H -#define GBA_CHEATS_H - -struct CheatsData - { - int code; - int size; - int status; - bool enabled; - u32 address; - u32 value; - u32 oldValue; - char codestring[20]; - char desc[32]; - }; - -extern void cheatsAdd(const char *,const char *,u32,u32,int,int); -extern void cheatsAddCheatCode(const char *code, const char *desc); -extern void cheatsAddGSACode(const char *code, const char *desc, bool v3); -extern void cheatsAddCBACode(const char *code, const char *desc); -extern bool cheatsImportGSACodeFile(const char *name, int game, bool v3); -extern void cheatsDelete(int number, bool restore); -extern void cheatsDeleteAll(bool restore); -extern void cheatsEnable(int number); -extern void cheatsDisable(int number); -extern void cheatsSaveGame(gzFile file); -extern void cheatsReadGame(gzFile file); -extern void cheatsSaveCheatList(const char *file); -extern bool cheatsLoadCheatList(const char *file); -extern void cheatsWriteMemory(u32 *, u32, u32); -extern void cheatsWriteHalfWord(u16 *, u16, u16); -extern void cheatsWriteByte(u8 *, u8); -extern int cheatsCheckKeys(u32,u32); -extern int cheatsNumber; -extern CheatsData cheatsList[100]; -#endif // GBA_CHEATS_H +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004-2006 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 GBA_CHEATS_H +#define GBA_CHEATS_H + +struct CheatsData { + int code; + int size; + int status; + bool enabled; + u32 rawaddress; + u32 address; + u32 value; + u32 oldValue; + char codestring[20]; + char desc[32]; +}; + +extern void cheatsAdd(const char *,const char *,u32, u32,u32,int,int); +extern void cheatsAddCheatCode(const char *code, const char *desc); +extern void cheatsAddGSACode(const char *code, const char *desc, bool v3); +extern void cheatsAddCBACode(const char *code, const char *desc); +extern bool cheatsImportGSACodeFile(const char *name, int game, bool v3); +extern void cheatsDelete(int number, bool restore); +extern void cheatsDeleteAll(bool restore); +extern void cheatsEnable(int number); +extern void cheatsDisable(int number); +extern void cheatsSaveGame(gzFile file); +extern void cheatsReadGame(gzFile file, int version); +extern void cheatsSaveCheatList(const char *file); +extern bool cheatsLoadCheatList(const char *file); +extern void cheatsWriteMemory(u32, u32); +extern void cheatsWriteHalfWord(u32, u16); +extern void cheatsWriteByte(u32, u8); +extern int cheatsCheckKeys(u32,u32); +extern int cheatsNumber; +extern CheatsData cheatsList[100]; +#endif // GBA_CHEATS_H diff --git a/source/vba/EEprom.cpp b/source/vba/EEprom.cpp index 86ec201..fd9b006 100644 --- a/source/vba/EEprom.cpp +++ b/source/vba/EEprom.cpp @@ -1,214 +1,206 @@ -// 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. - -#include "GBA.h" -#include "EEprom.h" -#include "Util.h" - -extern int cpuDmaCount; - -int eepromMode = EEPROM_IDLE; -int eepromByte = 0; -int eepromBits = 0; -int eepromAddress = 0; -u8 eepromData[0x2000]; -u8 eepromBuffer[16]; -bool eepromInUse = false; -int eepromSize = 512; - -variable_desc eepromSaveData[] = { - { &eepromMode, sizeof(int) }, - { &eepromByte, sizeof(int) }, - { &eepromBits , sizeof(int) }, - { &eepromAddress , sizeof(int) }, - { &eepromInUse, sizeof(bool) }, - { &eepromData[0], 512 }, - { &eepromBuffer[0], 16 }, - { NULL, 0 } - }; - -void eepromReset() -{ - eepromMode = EEPROM_IDLE; - eepromByte = 0; - eepromBits = 0; - eepromAddress = 0; - eepromInUse = false; - eepromSize = 512; -} - -void eepromSaveGame(gzFile gzFile) -{ - utilWriteData(gzFile, eepromSaveData); - utilWriteInt(gzFile, eepromSize); - utilGzWrite(gzFile, eepromData, 0x2000); -} - -void eepromReadGame(gzFile gzFile, int version) -{ - utilReadData(gzFile, eepromSaveData); - if(version >= SAVE_GAME_VERSION_3) - { - eepromSize = utilReadInt(gzFile); - utilGzRead(gzFile, eepromData, 0x2000); - } - else - { - // prior to 0.7.1, only 4K EEPROM was supported - eepromSize = 512; - } -} - - -int eepromRead(u32 /* address */) -{ - switch(eepromMode) - { - case EEPROM_IDLE: - case EEPROM_READADDRESS: - case EEPROM_WRITEDATA: - return 1; - case EEPROM_READDATA: - { - eepromBits++; - if(eepromBits == 4) - { - eepromMode = EEPROM_READDATA2; - eepromBits = 0; - eepromByte = 0; - } - return 0; - } - case EEPROM_READDATA2: - { - int data = 0; - int address = eepromAddress << 3; - int mask = 1 << (7 - (eepromBits & 7)); - data = (eepromData[address+eepromByte] & mask) ? 1 : 0; - eepromBits++; - if((eepromBits & 7) == 0) - eepromByte++; - if(eepromBits == 0x40) - eepromMode = EEPROM_IDLE; - return data; - } - default: - return 0; - } - return 1; -} - -void eepromWrite(u32 /* address */, u8 value) -{ - if(cpuDmaCount == 0) - return; - int bit = value & 1; - switch(eepromMode) - { - case EEPROM_IDLE: - eepromByte = 0; - eepromBits = 1; - eepromBuffer[eepromByte] = bit; - eepromMode = EEPROM_READADDRESS; - break; - case EEPROM_READADDRESS: - eepromBuffer[eepromByte] <<= 1; - eepromBuffer[eepromByte] |= bit; - eepromBits++; - if((eepromBits & 7) == 0) - { - eepromByte++; - } - if(cpuDmaCount == 0x11 || cpuDmaCount == 0x51) - { - if(eepromBits == 0x11) - { - eepromInUse = true; - eepromSize = 0x2000; - eepromAddress = ((eepromBuffer[0] & 0x3F) << 8) | - ((eepromBuffer[1] & 0xFF)); - if(!(eepromBuffer[0] & 0x40)) - { - eepromBuffer[0] = bit; - eepromBits = 1; - eepromByte = 0; - eepromMode = EEPROM_WRITEDATA; - } - else - { - eepromMode = EEPROM_READDATA; - eepromByte = 0; - eepromBits = 0; - } - } - } - else - { - if(eepromBits == 9) - { - eepromInUse = true; - eepromAddress = (eepromBuffer[0] & 0x3F); - if(!(eepromBuffer[0] & 0x40)) - { - eepromBuffer[0] = bit; - eepromBits = 1; - eepromByte = 0; - eepromMode = EEPROM_WRITEDATA; - } - else - { - eepromMode = EEPROM_READDATA; - eepromByte = 0; - eepromBits = 0; - } - } - } - break; - case EEPROM_READDATA: - case EEPROM_READDATA2: - // should we reset here? - eepromMode = EEPROM_IDLE; - break; - case EEPROM_WRITEDATA: - eepromBuffer[eepromByte] <<= 1; - eepromBuffer[eepromByte] |= bit; - eepromBits++; - if((eepromBits & 7) == 0) - { - eepromByte++; - } - if(eepromBits == 0x40) - { - eepromInUse = true; - // write data; - for(int i = 0; i < 8; i++) - { - eepromData[(eepromAddress << 3) + i] = eepromBuffer[i]; - } - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - } - else if(eepromBits == 0x41) - { - eepromMode = EEPROM_IDLE; - eepromByte = 0; - eepromBits = 0; - } - break; - } -} - +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 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. + +#include +#include "agb/GBA.h" +#include "EEprom.h" +#include "Util.h" + +extern int cpuDmaCount; + +int eepromMode = EEPROM_IDLE; +int eepromByte = 0; +int eepromBits = 0; +int eepromAddress = 0; +u8 eepromData[0x2000]; +u8 eepromBuffer[16]; +bool eepromInUse = false; +int eepromSize = 512; + +variable_desc eepromSaveData[] = { + { &eepromMode, sizeof(int) }, + { &eepromByte, sizeof(int) }, + { &eepromBits , sizeof(int) }, + { &eepromAddress , sizeof(int) }, + { &eepromInUse, sizeof(bool) }, + { &eepromData[0], 512 }, + { &eepromBuffer[0], 16 }, + { NULL, 0 } +}; + +void eepromInit() +{ + memset(eepromData, 255, sizeof(eepromData)); +} + +void eepromReset() +{ + eepromMode = EEPROM_IDLE; + eepromByte = 0; + eepromBits = 0; + eepromAddress = 0; + eepromInUse = false; + eepromSize = 512; +} + +void eepromSaveGame(gzFile gzFile) +{ + utilWriteData(gzFile, eepromSaveData); + utilWriteInt(gzFile, eepromSize); + utilGzWrite(gzFile, eepromData, 0x2000); +} + +void eepromReadGame(gzFile gzFile, int version) +{ + utilReadData(gzFile, eepromSaveData); + if(version >= SAVE_GAME_VERSION_3) { + eepromSize = utilReadInt(gzFile); + utilGzRead(gzFile, eepromData, 0x2000); + } else { + // prior to 0.7.1, only 4K EEPROM was supported + eepromSize = 512; + } +} + +void eepromReadGameSkip(gzFile gzFile, int version) +{ + // skip the eeprom data in a save game + utilReadDataSkip(gzFile, eepromSaveData); + if(version >= SAVE_GAME_VERSION_3) { + utilGzSeek(gzFile, sizeof(int), SEEK_CUR); + utilGzSeek(gzFile, 0x2000, SEEK_CUR); + } +} + +int eepromRead(u32 /* address */) +{ + switch(eepromMode) { + case EEPROM_IDLE: + case EEPROM_READADDRESS: + case EEPROM_WRITEDATA: + return 1; + case EEPROM_READDATA: + { + eepromBits++; + if(eepromBits == 4) { + eepromMode = EEPROM_READDATA2; + eepromBits = 0; + eepromByte = 0; + } + return 0; + } + case EEPROM_READDATA2: + { + int data = 0; + int address = eepromAddress << 3; + int mask = 1 << (7 - (eepromBits & 7)); + data = (eepromData[address+eepromByte] & mask) ? 1 : 0; + eepromBits++; + if((eepromBits & 7) == 0) + eepromByte++; + if(eepromBits == 0x40) + eepromMode = EEPROM_IDLE; + return data; + } + default: + return 0; + } + return 1; +} + +void eepromWrite(u32 /* address */, u8 value) +{ + if(cpuDmaCount == 0) + return; + int bit = value & 1; + switch(eepromMode) { + case EEPROM_IDLE: + eepromByte = 0; + eepromBits = 1; + eepromBuffer[eepromByte] = bit; + eepromMode = EEPROM_READADDRESS; + break; + case EEPROM_READADDRESS: + eepromBuffer[eepromByte] <<= 1; + eepromBuffer[eepromByte] |= bit; + eepromBits++; + if((eepromBits & 7) == 0) { + eepromByte++; + } + if(cpuDmaCount == 0x11 || cpuDmaCount == 0x51) { + if(eepromBits == 0x11) { + eepromInUse = true; + eepromSize = 0x2000; + eepromAddress = ((eepromBuffer[0] & 0x3F) << 8) | + ((eepromBuffer[1] & 0xFF)); + if(!(eepromBuffer[0] & 0x40)) { + eepromBuffer[0] = bit; + eepromBits = 1; + eepromByte = 0; + eepromMode = EEPROM_WRITEDATA; + } else { + eepromMode = EEPROM_READDATA; + eepromByte = 0; + eepromBits = 0; + } + } + } else { + if(eepromBits == 9) { + eepromInUse = true; + eepromAddress = (eepromBuffer[0] & 0x3F); + if(!(eepromBuffer[0] & 0x40)) { + eepromBuffer[0] = bit; + eepromBits = 1; + eepromByte = 0; + eepromMode = EEPROM_WRITEDATA; + } else { + eepromMode = EEPROM_READDATA; + eepromByte = 0; + eepromBits = 0; + } + } + } + break; + case EEPROM_READDATA: + case EEPROM_READDATA2: + // should we reset here? + eepromMode = EEPROM_IDLE; + break; + case EEPROM_WRITEDATA: + eepromBuffer[eepromByte] <<= 1; + eepromBuffer[eepromByte] |= bit; + eepromBits++; + if((eepromBits & 7) == 0) { + eepromByte++; + } + if(eepromBits == 0x40) { + eepromInUse = true; + // write data; + for(int i = 0; i < 8; i++) { + eepromData[(eepromAddress << 3) + i] = eepromBuffer[i]; + } + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + } else if(eepromBits == 0x41) { + eepromMode = EEPROM_IDLE; + eepromByte = 0; + eepromBits = 0; + } + break; + } +} + diff --git a/source/vba/EEprom.h b/source/vba/EEprom.h index 4bf23af..cb25056 100644 --- a/source/vba/EEprom.h +++ b/source/vba/EEprom.h @@ -1,38 +1,40 @@ -// -*- 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_EEPROM_H -#define VBA_EEPROM_H - -extern void eepromSaveGame(gzFile gzFile); -extern void eepromReadGame(gzFile gzFile, int version); -extern int eepromRead(u32 address); -extern void eepromWrite(u32 address, u8 value); -extern void eepromReset(); -extern u8 eepromData[0x2000]; -extern bool eepromInUse; -extern int eepromSize; - -#define EEPROM_IDLE 0 -#define EEPROM_READADDRESS 1 -#define EEPROM_READDATA 2 -#define EEPROM_READDATA2 3 -#define EEPROM_WRITEDATA 4 - -#endif // VBA_EEPROM_H +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 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_EEPROM_H +#define VBA_EEPROM_H + +extern void eepromSaveGame(gzFile _gzFile); +extern void eepromReadGame(gzFile _gzFile, int version); +extern void eepromReadGameSkip(gzFile _gzFile, int version); +extern int eepromRead(u32 address); +extern void eepromWrite(u32 address, u8 value); +extern void eepromInit(); +extern void eepromReset(); +extern u8 eepromData[0x2000]; +extern bool eepromInUse; +extern int eepromSize; + +#define EEPROM_IDLE 0 +#define EEPROM_READADDRESS 1 +#define EEPROM_READDATA 2 +#define EEPROM_READDATA2 3 +#define EEPROM_WRITEDATA 4 + +#endif // VBA_EEPROM_H diff --git a/source/vba/Flash.cpp b/source/vba/Flash.cpp index 41c189a..61416d5 100644 --- a/source/vba/Flash.cpp +++ b/source/vba/Flash.cpp @@ -1,288 +1,275 @@ -// 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. - -#include -#include -#include "GBA.h" -#include "Globals.h" -#include "Flash.h" -#include "Sram.h" -#include "Util.h" - -#define FLASH_READ_ARRAY 0 -#define FLASH_CMD_1 1 -#define FLASH_CMD_2 2 -#define FLASH_AUTOSELECT 3 -#define FLASH_CMD_3 4 -#define FLASH_CMD_4 5 -#define FLASH_CMD_5 6 -#define FLASH_ERASE_COMPLETE 7 -#define FLASH_PROGRAM 8 -#define FLASH_SETBANK 9 - -u8 flashSaveMemory[0x20000]; -int flashState = FLASH_READ_ARRAY; -int flashReadState = FLASH_READ_ARRAY; -int flashSize = 0x10000; -int flashDeviceID = 0x1b; -int flashManufacturerID = 0x32; -int flashBank = 0; - -static variable_desc flashSaveData[] = { - { &flashState, sizeof(int) }, - { &flashReadState, sizeof(int) }, - { &flashSaveMemory[0], 0x10000 }, - { NULL, 0 } - }; - -static variable_desc flashSaveData2[] = { - { &flashState, sizeof(int) }, - { &flashReadState, sizeof(int) }, - { &flashSize, sizeof(int) }, - { &flashSaveMemory[0], 0x20000 }, - { NULL, 0 } - }; - -static variable_desc flashSaveData3[] = { - { &flashState, sizeof(int) }, - { &flashReadState, sizeof(int) }, - { &flashSize, sizeof(int) }, - { &flashBank, sizeof(int) }, - { &flashSaveMemory[0], 0x20000 }, - { NULL, 0 } - }; - -void flashReset() -{ - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - flashBank = 0; -} - -void flashSaveGame(gzFile gzFile) -{ - utilWriteData(gzFile, flashSaveData3); -} - -void flashReadGame(gzFile gzFile, int version) -{ - if(version < SAVE_GAME_VERSION_5) - utilReadData(gzFile, flashSaveData); - else if(version < SAVE_GAME_VERSION_7) - { - utilReadData(gzFile, flashSaveData2); - flashBank = 0; - flashSetSize(flashSize); - } - else - { - utilReadData(gzFile, flashSaveData3); - } -} - -void flashSetSize(int size) -{ - // log("Setting flash size to %d\n", size); - flashSize = size; - if(size == 0x10000) - { - flashDeviceID = 0x1b; - flashManufacturerID = 0x32; - } - else - { - flashDeviceID = 0x13; //0x09; - flashManufacturerID = 0x62; //0xc2; - } -} - -u8 flashRead(u32 address) -{ - // log("Reading %08x from %08x\n", address, reg[15].I); - // log("Current read state is %d\n", flashReadState); - address &= 0xFFFF; - - switch(flashReadState) - { - case FLASH_READ_ARRAY: - return flashSaveMemory[(flashBank << 16) + address]; - case FLASH_AUTOSELECT: - switch(address & 0xFF) - { - case 0: - // manufacturer ID - return flashManufacturerID; - case 1: - // device ID - return flashDeviceID; - } - break; - case FLASH_ERASE_COMPLETE: - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - return 0xFF; - }; - return 0; -} - -void flashSaveDecide(u32 address, u8 byte) -{ - // log("Deciding save type %08x\n", address); - if(address == 0x0e005555) - { - saveType = 2; - cpuSaveGameFunc = flashWrite; - } - else - { - saveType = 1; - cpuSaveGameFunc = sramWrite; - } - - (*cpuSaveGameFunc)(address, byte); -} - -void flashWrite(u32 address, u8 byte) -{ - // log("Writing %02x at %08x\n", byte, address); - // log("Current state is %d\n", flashState); - address &= 0xFFFF; - switch(flashState) - { - case FLASH_READ_ARRAY: - if(address == 0x5555 && byte == 0xAA) - flashState = FLASH_CMD_1; - break; - case FLASH_CMD_1: - if(address == 0x2AAA && byte == 0x55) - flashState = FLASH_CMD_2; - else - flashState = FLASH_READ_ARRAY; - break; - case FLASH_CMD_2: - if(address == 0x5555) - { - if(byte == 0x90) - { - flashState = FLASH_AUTOSELECT; - flashReadState = FLASH_AUTOSELECT; - } - else if(byte == 0x80) - { - flashState = FLASH_CMD_3; - } - else if(byte == 0xF0) - { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - else if(byte == 0xA0) - { - flashState = FLASH_PROGRAM; - } - else if(byte == 0xB0 && flashSize == 0x20000) - { - flashState = FLASH_SETBANK; - } - else - { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - } - else - { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - break; - case FLASH_CMD_3: - if(address == 0x5555 && byte == 0xAA) - { - flashState = FLASH_CMD_4; - } - else - { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - break; - case FLASH_CMD_4: - if(address == 0x2AAA && byte == 0x55) - { - flashState = FLASH_CMD_5; - } - else - { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - break; - case FLASH_CMD_5: - if(byte == 0x30) - { - // SECTOR ERASE - memset(&flashSaveMemory[(flashBank << 16) + (address & 0xF000)], - 0, - 0x1000); - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - flashReadState = FLASH_ERASE_COMPLETE; - } - else if(byte == 0x10) - { - // CHIP ERASE - memset(flashSaveMemory, 0, flashSize); - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - flashReadState = FLASH_ERASE_COMPLETE; - } - else - { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - break; - case FLASH_AUTOSELECT: - if(byte == 0xF0) - { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - else if(address == 0x5555 && byte == 0xAA) - flashState = FLASH_CMD_1; - else - { - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - } - break; - case FLASH_PROGRAM: - flashSaveMemory[(flashBank<<16)+address] = byte; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - break; - case FLASH_SETBANK: - if(address == 0) - { - flashBank = (byte & 1); - } - flashState = FLASH_READ_ARRAY; - flashReadState = FLASH_READ_ARRAY; - break; - } -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004-2006 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. + +#include +#include +#include "agb/GBA.h" +#include "Globals.h" +#include "Flash.h" +#include "Sram.h" +#include "Util.h" + +#define FLASH_READ_ARRAY 0 +#define FLASH_CMD_1 1 +#define FLASH_CMD_2 2 +#define FLASH_AUTOSELECT 3 +#define FLASH_CMD_3 4 +#define FLASH_CMD_4 5 +#define FLASH_CMD_5 6 +#define FLASH_ERASE_COMPLETE 7 +#define FLASH_PROGRAM 8 +#define FLASH_SETBANK 9 + +u8 flashSaveMemory[0x20000]; +int flashState = FLASH_READ_ARRAY; +int flashReadState = FLASH_READ_ARRAY; +int flashSize = 0x10000; +int flashDeviceID = 0x1b; +int flashManufacturerID = 0x32; +int flashBank = 0; + +static variable_desc flashSaveData[] = { + { &flashState, sizeof(int) }, + { &flashReadState, sizeof(int) }, + { &flashSaveMemory[0], 0x10000 }, + { NULL, 0 } +}; + +static variable_desc flashSaveData2[] = { + { &flashState, sizeof(int) }, + { &flashReadState, sizeof(int) }, + { &flashSize, sizeof(int) }, + { &flashSaveMemory[0], 0x20000 }, + { NULL, 0 } +}; + +static variable_desc flashSaveData3[] = { + { &flashState, sizeof(int) }, + { &flashReadState, sizeof(int) }, + { &flashSize, sizeof(int) }, + { &flashBank, sizeof(int) }, + { &flashSaveMemory[0], 0x20000 }, + { NULL, 0 } +}; + +void flashInit() +{ + memset(flashSaveMemory, 0xff, sizeof(flashSaveMemory)); +} + +void flashReset() +{ + flashState = FLASH_READ_ARRAY; + flashReadState = FLASH_READ_ARRAY; + flashBank = 0; +} + +void flashSaveGame(gzFile gzFile) +{ + utilWriteData(gzFile, flashSaveData3); +} + +void flashReadGame(gzFile gzFile, int version) +{ + if(version < SAVE_GAME_VERSION_5) + utilReadData(gzFile, flashSaveData); + else if(version < SAVE_GAME_VERSION_7) { + utilReadData(gzFile, flashSaveData2); + flashBank = 0; + flashSetSize(flashSize); + } else { + utilReadData(gzFile, flashSaveData3); + } +} + +void flashReadGameSkip(gzFile gzFile, int version) +{ + // skip the flash data in a save game + if(version < SAVE_GAME_VERSION_5) + utilReadDataSkip(gzFile, flashSaveData); + else if(version < SAVE_GAME_VERSION_7) { + utilReadDataSkip(gzFile, flashSaveData2); + } else { + utilReadDataSkip(gzFile, flashSaveData3); + } +} + +void flashSetSize(int size) +{ + // log("Setting flash size to %d\n", size); + if(size == 0x10000) { + flashDeviceID = 0x1b; + flashManufacturerID = 0x32; + } else { + flashDeviceID = 0x13; //0x09; + flashManufacturerID = 0x62; //0xc2; + } + // Added to make 64k saves compatible with 128k ones + // (allow wrongfuly set 64k saves to work for Pokemon games) + if ((size == 0x20000) && (flashSize == 0x10000)) + memcpy((u8 *)(flashSaveMemory+0x10000), (u8 *)(flashSaveMemory), 0x10000); + flashSize = size; +} + +u8 flashRead(u32 address) +{ + // log("Reading %08x from %08x\n", address, reg[15].I); + // log("Current read state is %d\n", flashReadState); + address &= 0xFFFF; + + switch(flashReadState) { + case FLASH_READ_ARRAY: + return flashSaveMemory[(flashBank << 16) + address]; + case FLASH_AUTOSELECT: + switch(address & 0xFF) { + case 0: + // manufacturer ID + return flashManufacturerID; + case 1: + // device ID + return flashDeviceID; + } + break; + case FLASH_ERASE_COMPLETE: + flashState = FLASH_READ_ARRAY; + flashReadState = FLASH_READ_ARRAY; + return 0xFF; + }; + return 0; +} + +void flashSaveDecide(u32 address, u8 byte) +{ + // log("Deciding save type %08x\n", address); + if(address == 0x0e005555) { + saveType = 2; + cpuSaveGameFunc = flashWrite; + } else { + saveType = 1; + cpuSaveGameFunc = sramWrite; + } + + (*cpuSaveGameFunc)(address, byte); +} + +void flashDelayedWrite(u32 address, u8 byte) +{ + saveType = 2; + cpuSaveGameFunc = flashWrite; + flashWrite(address, byte); +} + +void flashWrite(u32 address, u8 byte) +{ + // log("Writing %02x at %08x\n", byte, address); + // log("Current state is %d\n", flashState); + address &= 0xFFFF; + switch(flashState) { + case FLASH_READ_ARRAY: + if(address == 0x5555 && byte == 0xAA) + flashState = FLASH_CMD_1; + break; + case FLASH_CMD_1: + if(address == 0x2AAA && byte == 0x55) + flashState = FLASH_CMD_2; + else + flashState = FLASH_READ_ARRAY; + break; + case FLASH_CMD_2: + if(address == 0x5555) { + if(byte == 0x90) { + flashState = FLASH_AUTOSELECT; + flashReadState = FLASH_AUTOSELECT; + } else if(byte == 0x80) { + flashState = FLASH_CMD_3; + } else if(byte == 0xF0) { + flashState = FLASH_READ_ARRAY; + flashReadState = FLASH_READ_ARRAY; + } else if(byte == 0xA0) { + flashState = FLASH_PROGRAM; + } else if(byte == 0xB0 && flashSize == 0x20000) { + flashState = FLASH_SETBANK; + } else { + flashState = FLASH_READ_ARRAY; + flashReadState = FLASH_READ_ARRAY; + } + } else { + flashState = FLASH_READ_ARRAY; + flashReadState = FLASH_READ_ARRAY; + } + break; + case FLASH_CMD_3: + if(address == 0x5555 && byte == 0xAA) { + flashState = FLASH_CMD_4; + } else { + flashState = FLASH_READ_ARRAY; + flashReadState = FLASH_READ_ARRAY; + } + break; + case FLASH_CMD_4: + if(address == 0x2AAA && byte == 0x55) { + flashState = FLASH_CMD_5; + } else { + flashState = FLASH_READ_ARRAY; + flashReadState = FLASH_READ_ARRAY; + } + break; + case FLASH_CMD_5: + if(byte == 0x30) { + // SECTOR ERASE + memset(&flashSaveMemory[(flashBank << 16) + (address & 0xF000)], + 0, + 0x1000); + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + flashReadState = FLASH_ERASE_COMPLETE; + } else if(byte == 0x10) { + // CHIP ERASE + memset(flashSaveMemory, 0, flashSize); + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + flashReadState = FLASH_ERASE_COMPLETE; + } else { + flashState = FLASH_READ_ARRAY; + flashReadState = FLASH_READ_ARRAY; + } + break; + case FLASH_AUTOSELECT: + if(byte == 0xF0) { + flashState = FLASH_READ_ARRAY; + flashReadState = FLASH_READ_ARRAY; + } else if(address == 0x5555 && byte == 0xAA) + flashState = FLASH_CMD_1; + else { + flashState = FLASH_READ_ARRAY; + flashReadState = FLASH_READ_ARRAY; + } + break; + case FLASH_PROGRAM: + flashSaveMemory[(flashBank<<16)+address] = byte; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; + flashState = FLASH_READ_ARRAY; + flashReadState = FLASH_READ_ARRAY; + break; + case FLASH_SETBANK: + if(address == 0) { + flashBank = (byte & 1); + } + flashState = FLASH_READ_ARRAY; + flashReadState = FLASH_READ_ARRAY; + break; + } +} diff --git a/source/vba/Flash.h b/source/vba/Flash.h index b00a35e..d8f765e 100644 --- a/source/vba/Flash.h +++ b/source/vba/Flash.h @@ -1,33 +1,36 @@ -// -*- 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_FLASH_H -#define VBA_FLASH_H - -extern void flashSaveGame(gzFile gzFile); -extern void flashReadGame(gzFile gzFile, int version); -extern u8 flashRead(u32 address); -extern void flashWrite(u32 address, u8 byte); -extern u8 flashSaveMemory[0x20000]; -extern void flashSaveDecide(u32 address, u8 byte); -extern void flashReset(); -extern void flashSetSize(int size); - -extern int flashSize; -#endif // VBA_FLASH_H +// -*- 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_FLASH_H +#define VBA_FLASH_H + +extern void flashSaveGame(gzFile _gzFile); +extern void flashReadGame(gzFile _gzFile, int version); +extern void flashReadGameSkip(gzFile _gzFile, int version); +extern u8 flashRead(u32 address); +extern void flashWrite(u32 address, u8 byte); +extern void flashDelayedWrite(u32 address, u8 byte); +extern u8 flashSaveMemory[0x20000]; +extern void flashSaveDecide(u32 address, u8 byte); +extern void flashReset(); +extern void flashSetSize(int size); +extern void flashInit(); + +extern int flashSize; +#endif // VBA_FLASH_H diff --git a/source/vba/GBA.cpp b/source/vba/GBA.cpp deleted file mode 100644 index ee458fc..0000000 --- a/source/vba/GBA.cpp +++ /dev/null @@ -1,4361 +0,0 @@ -// 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. - -#include "sdfileio.h" -#include -#include -#include -#include -#include - -#include "GBA.h" -#include "GBAinline.h" -#include "Globals.h" -#include "Gfx.h" -#include "EEprom.h" -#include "Flash.h" -#include "Sound.h" -#include "Sram.h" -#include "bios.h" -#include "unzip.h" -#include "Cheats.h" -#include "NLS.h" -#include "elf.h" -#include "Util.h" -#include "Port.h" -#include "agbprint.h" -#ifdef PROFILING -#include "prof/prof.h" -#endif - -#define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]),value) - -#ifdef __GNUC__ -#define _stricmp strcasecmp -#endif - -#define CPU_BREAK_LOOP \ - cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks;\ - *extCpuLoopTicks = *extClockTicks; - -#define CPU_BREAK_LOOP_2 \ - cpuSavedTicks = cpuSavedTicks - *extCpuLoopTicks;\ - *extCpuLoopTicks = *extClockTicks;\ - *extTicks = *extClockTicks; - -extern int emulating; - -int cpuDmaTicksToUpdate = 0; -int cpuDmaCount = 0; -bool cpuDmaHack = 0; -u32 cpuDmaLast = 0; -int dummyAddress = 0; - -int *extCpuLoopTicks = NULL; -int *extClockTicks = NULL; -int *extTicks = NULL; - -int gbaSaveType = 0; // used to remember the save type on reset -bool intState = false; -bool stopState = false; -bool holdState = false; -int holdType = 0; -bool cpuSramEnabled = true; -bool cpuFlashEnabled = true; -bool cpuEEPROMEnabled = true; -bool cpuEEPROMSensorEnabled = false; - -#ifdef PROFILING -int profilingTicks = 0; -int profilingTicksReload = 0; -static char *profilBuffer = NULL; -static int profilSize = 0; -static u32 profilLowPC = 0; -static int profilScale = 0; -#endif -bool freezeWorkRAM[0x40000]; -bool freezeInternalRAM[0x8000]; -int lcdTicks = 960; -bool timer0On = false; -int timer0Ticks = 0; -int timer0Reload = 0; -int timer0ClockReload = 0; -bool timer1On = false; -int timer1Ticks = 0; -int timer1Reload = 0; -int timer1ClockReload = 0; -bool timer2On = false; -int timer2Ticks = 0; -int timer2Reload = 0; -int timer2ClockReload = 0; -bool timer3On = false; -int timer3Ticks = 0; -int timer3Reload = 0; -int timer3ClockReload = 0; -u32 dma0Source = 0; -u32 dma0Dest = 0; -u32 dma1Source = 0; -u32 dma1Dest = 0; -u32 dma2Source = 0; -u32 dma2Dest = 0; -u32 dma3Source = 0; -u32 dma3Dest = 0; -void (*cpuSaveGameFunc)(u32,u8) = flashSaveDecide; -void (*renderLine)() = mode0RenderLine; -bool fxOn = false; -bool windowOn = false; -int frameCount = 0; -char buffer[1024]; -FILE* out = NULL; -u32 lastTime = 0; -int count = 0; - -int capture = 0; -int capturePrevious = 0; -int captureNumber = 0; - -const int TIMER_TICKS[4] = - { - 1, - 64, - 256, - 1024 - }; - -const int thumbCycles[] = - { - // 0 1 2 3 4 5 6 7 8 9 a b c d e f - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 - 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 4 - 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 5 - 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 6 - 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 7 - 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 8 - 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 9 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // a - 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, // b - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, // d - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // e - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // f - }; - -const int gamepakRamWaitState[4] = - { - 4, 3, 2, 8 - }; -const int gamepakWaitState[8] = - { - 4, 3, 2, 8, 4, 3, 2, 8 - }; -const int gamepakWaitState0[8] = - { - 2, 2, 2, 2, 1, 1, 1, 1 - }; -const int gamepakWaitState1[8] = - { - 4, 4, 4, 4, 1, 1, 1, 1 - }; -const int gamepakWaitState2[8] = - { - 8, 8, 8, 8, 1, 1, 1, 1 - }; - -int memoryWait[16] = - { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 }; -int memoryWait32[16] = - { 0, 0, 9, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 0 }; -int memoryWaitSeq[16] = - { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 }; -int memoryWaitSeq32[16] = - { 2, 0, 3, 0, 0, 2, 2, 0, 4, 4, 8, 8, 16, 16, 8, 0 }; -int memoryWaitFetch[16] = - { 3, 0, 3, 0, 0, 1, 1, 0, 4, 4, 4, 4, 4, 4, 4, 0 }; -int memoryWaitFetch32[16] = - { 6, 0, 6, 0, 0, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 0 }; - -const int cpuMemoryWait[16] = - { - 0, 0, 2, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 2, 0, 0 - }; -const int cpuMemoryWait32[16] = - { - 0, 0, 3, 0, 0, 0, 0, 0, - 3, 3, 3, 3, 3, 3, 0, 0 - }; - -const bool memory32[16] = - { - true, false, false, true, true, false, false, true, false, false, false, false, false, false, true, false - }; - -u8 biosProtected[4]; - -#ifdef WORDS_BIGENDIAN -bool cpuBiosSwapped = false; -#endif - -u32 myROM[] = { - 0xEA000006, - 0xEA000093, - 0xEA000006, - 0x00000000, - 0x00000000, - 0x00000000, - 0xEA000088, - 0x00000000, - 0xE3A00302, - 0xE1A0F000, - 0xE92D5800, - 0xE55EC002, - 0xE28FB03C, - 0xE79BC10C, - 0xE14FB000, - 0xE92D0800, - 0xE20BB080, - 0xE38BB01F, - 0xE129F00B, - 0xE92D4004, - 0xE1A0E00F, - 0xE12FFF1C, - 0xE8BD4004, - 0xE3A0C0D3, - 0xE129F00C, - 0xE8BD0800, - 0xE169F00B, - 0xE8BD5800, - 0xE1B0F00E, - 0x0000009C, - 0x0000009C, - 0x0000009C, - 0x0000009C, - 0x000001F8, - 0x000001F0, - 0x000000AC, - 0x000000A0, - 0x000000FC, - 0x00000168, - 0xE12FFF1E, - 0xE1A03000, - 0xE1A00001, - 0xE1A01003, - 0xE2113102, - 0x42611000, - 0xE033C040, - 0x22600000, - 0xE1B02001, - 0xE15200A0, - 0x91A02082, - 0x3AFFFFFC, - 0xE1500002, - 0xE0A33003, - 0x20400002, - 0xE1320001, - 0x11A020A2, - 0x1AFFFFF9, - 0xE1A01000, - 0xE1A00003, - 0xE1B0C08C, - 0x22600000, - 0x42611000, - 0xE12FFF1E, - 0xE92D0010, - 0xE1A0C000, - 0xE3A01001, - 0xE1500001, - 0x81A000A0, - 0x81A01081, - 0x8AFFFFFB, - 0xE1A0000C, - 0xE1A04001, - 0xE3A03000, - 0xE1A02001, - 0xE15200A0, - 0x91A02082, - 0x3AFFFFFC, - 0xE1500002, - 0xE0A33003, - 0x20400002, - 0xE1320001, - 0x11A020A2, - 0x1AFFFFF9, - 0xE0811003, - 0xE1B010A1, - 0xE1510004, - 0x3AFFFFEE, - 0xE1A00004, - 0xE8BD0010, - 0xE12FFF1E, - 0xE0010090, - 0xE1A01741, - 0xE2611000, - 0xE3A030A9, - 0xE0030391, - 0xE1A03743, - 0xE2833E39, - 0xE0030391, - 0xE1A03743, - 0xE2833C09, - 0xE283301C, - 0xE0030391, - 0xE1A03743, - 0xE2833C0F, - 0xE28330B6, - 0xE0030391, - 0xE1A03743, - 0xE2833C16, - 0xE28330AA, - 0xE0030391, - 0xE1A03743, - 0xE2833A02, - 0xE2833081, - 0xE0030391, - 0xE1A03743, - 0xE2833C36, - 0xE2833051, - 0xE0030391, - 0xE1A03743, - 0xE2833CA2, - 0xE28330F9, - 0xE0000093, - 0xE1A00840, - 0xE12FFF1E, - 0xE3A00001, - 0xE3A01001, - 0xE92D4010, - 0xE3A0C301, - 0xE3A03000, - 0xE3A04001, - 0xE3500000, - 0x1B000004, - 0xE5CC3301, - 0xEB000002, - 0x0AFFFFFC, - 0xE8BD4010, - 0xE12FFF1E, - 0xE5CC3208, - 0xE15C20B8, - 0xE0110002, - 0x10200002, - 0x114C00B8, - 0xE5CC4208, - 0xE12FFF1E, - 0xE92D500F, - 0xE3A00301, - 0xE1A0E00F, - 0xE510F004, - 0xE8BD500F, - 0xE25EF004, - 0xE59FD044, - 0xE92D5000, - 0xE14FC000, - 0xE10FE000, - 0xE92D5000, - 0xE3A0C302, - 0xE5DCE09C, - 0xE35E00A5, - 0x1A000004, - 0x05DCE0B4, - 0x021EE080, - 0xE28FE004, - 0x159FF018, - 0x059FF018, - 0xE59FD018, - 0xE8BD5000, - 0xE169F00C, - 0xE8BD5000, - 0xE25EF004, - 0x03007FF0, - 0x09FE2000, - 0x09FFC000, - 0x03007FE0 - }; - -variable_desc saveGameStruct[] = { - { &DISPCNT , sizeof(u16) }, - { &DISPSTAT , sizeof(u16) }, - { &VCOUNT , sizeof(u16) }, - { &BG0CNT , sizeof(u16) }, - { &BG1CNT , sizeof(u16) }, - { &BG2CNT , sizeof(u16) }, - { &BG3CNT , sizeof(u16) }, - { &BG0HOFS , sizeof(u16) }, - { &BG0VOFS , sizeof(u16) }, - { &BG1HOFS , sizeof(u16) }, - { &BG1VOFS , sizeof(u16) }, - { &BG2HOFS , sizeof(u16) }, - { &BG2VOFS , sizeof(u16) }, - { &BG3HOFS , sizeof(u16) }, - { &BG3VOFS , sizeof(u16) }, - { &BG2PA , sizeof(u16) }, - { &BG2PB , sizeof(u16) }, - { &BG2PC , sizeof(u16) }, - { &BG2PD , sizeof(u16) }, - { &BG2X_L , sizeof(u16) }, - { &BG2X_H , sizeof(u16) }, - { &BG2Y_L , sizeof(u16) }, - { &BG2Y_H , sizeof(u16) }, - { &BG3PA , sizeof(u16) }, - { &BG3PB , sizeof(u16) }, - { &BG3PC , sizeof(u16) }, - { &BG3PD , sizeof(u16) }, - { &BG3X_L , sizeof(u16) }, - { &BG3X_H , sizeof(u16) }, - { &BG3Y_L , sizeof(u16) }, - { &BG3Y_H , sizeof(u16) }, - { &WIN0H , sizeof(u16) }, - { &WIN1H , sizeof(u16) }, - { &WIN0V , sizeof(u16) }, - { &WIN1V , sizeof(u16) }, - { &WININ , sizeof(u16) }, - { &WINOUT , sizeof(u16) }, - { &MOSAIC , sizeof(u16) }, - { &BLDMOD , sizeof(u16) }, - { &COLEV , sizeof(u16) }, - { &COLY , sizeof(u16) }, - { &DM0SAD_L , sizeof(u16) }, - { &DM0SAD_H , sizeof(u16) }, - { &DM0DAD_L , sizeof(u16) }, - { &DM0DAD_H , sizeof(u16) }, - { &DM0CNT_L , sizeof(u16) }, - { &DM0CNT_H , sizeof(u16) }, - { &DM1SAD_L , sizeof(u16) }, - { &DM1SAD_H , sizeof(u16) }, - { &DM1DAD_L , sizeof(u16) }, - { &DM1DAD_H , sizeof(u16) }, - { &DM1CNT_L , sizeof(u16) }, - { &DM1CNT_H , sizeof(u16) }, - { &DM2SAD_L , sizeof(u16) }, - { &DM2SAD_H , sizeof(u16) }, - { &DM2DAD_L , sizeof(u16) }, - { &DM2DAD_H , sizeof(u16) }, - { &DM2CNT_L , sizeof(u16) }, - { &DM2CNT_H , sizeof(u16) }, - { &DM3SAD_L , sizeof(u16) }, - { &DM3SAD_H , sizeof(u16) }, - { &DM3DAD_L , sizeof(u16) }, - { &DM3DAD_H , sizeof(u16) }, - { &DM3CNT_L , sizeof(u16) }, - { &DM3CNT_H , sizeof(u16) }, - { &TM0D , sizeof(u16) }, - { &TM0CNT , sizeof(u16) }, - { &TM1D , sizeof(u16) }, - { &TM1CNT , sizeof(u16) }, - { &TM2D , sizeof(u16) }, - { &TM2CNT , sizeof(u16) }, - { &TM3D , sizeof(u16) }, - { &TM3CNT , sizeof(u16) }, - { &P1 , sizeof(u16) }, - { &IE , sizeof(u16) }, - { &IF , sizeof(u16) }, - { &IME , sizeof(u16) }, - { &holdState, sizeof(bool) }, - { &holdType, sizeof(int) }, - { &lcdTicks, sizeof(int) }, - { &timer0On , sizeof(bool) }, - { &timer0Ticks , sizeof(int) }, - { &timer0Reload , sizeof(int) }, - { &timer0ClockReload , sizeof(int) }, - { &timer1On , sizeof(bool) }, - { &timer1Ticks , sizeof(int) }, - { &timer1Reload , sizeof(int) }, - { &timer1ClockReload , sizeof(int) }, - { &timer2On , sizeof(bool) }, - { &timer2Ticks , sizeof(int) }, - { &timer2Reload , sizeof(int) }, - { &timer2ClockReload , sizeof(int) }, - { &timer3On , sizeof(bool) }, - { &timer3Ticks , sizeof(int) }, - { &timer3Reload , sizeof(int) }, - { &timer3ClockReload , sizeof(int) }, - { &dma0Source , sizeof(u32) }, - { &dma0Dest , sizeof(u32) }, - { &dma1Source , sizeof(u32) }, - { &dma1Dest , sizeof(u32) }, - { &dma2Source , sizeof(u32) }, - { &dma2Dest , sizeof(u32) }, - { &dma3Source , sizeof(u32) }, - { &dma3Dest , sizeof(u32) }, - { &fxOn, sizeof(bool) }, - { &windowOn, sizeof(bool) }, - { &N_FLAG , sizeof(bool) }, - { &C_FLAG , sizeof(bool) }, - { &Z_FLAG , sizeof(bool) }, - { &V_FLAG , sizeof(bool) }, - { &armState , sizeof(bool) }, - { &armIrqEnable , sizeof(bool) }, - { &armNextPC , sizeof(u32) }, - { &armMode , sizeof(int) }, - { &saveType , sizeof(int) }, - { NULL, 0 } - }; - -//int cpuLoopTicks = 0; -int cpuSavedTicks = 0; - -#ifdef PROFILING -void cpuProfil(char *buf, int size, u32 lowPC, int scale) -{ - profilBuffer = buf; - profilSize = size; - profilLowPC = lowPC; - profilScale = scale; -} - -void cpuEnableProfiling(int hz) -{ - if(hz == 0) - hz = 100; - profilingTicks = profilingTicksReload = 16777216 / hz; - profSetHertz(hz); -} -#endif - -inline int CPUUpdateTicksAccess32(u32 address) -{ - return memoryWait32[(address>>24)&15]; -} - -inline int CPUUpdateTicksAccess16(u32 address) -{ - return memoryWait[(address>>24)&15]; -} - -inline int CPUUpdateTicksAccessSeq32(u32 address) -{ - return memoryWaitSeq32[(address>>24)&15]; -} - -inline int CPUUpdateTicksAccessSeq16(u32 address) -{ - return memoryWaitSeq[(address>>24)&15]; -} - -inline int CPUUpdateTicks() -{ - int cpuLoopTicks = lcdTicks; - - if(soundTicks < cpuLoopTicks) - cpuLoopTicks = soundTicks; - - if(timer0On && !(TM0CNT & 4) && (timer0Ticks < cpuLoopTicks)) - { - cpuLoopTicks = timer0Ticks; - } - if(timer1On && !(TM1CNT & 4) && (timer1Ticks < cpuLoopTicks)) - { - cpuLoopTicks = timer1Ticks; - } - if(timer2On && !(TM2CNT & 4) && (timer2Ticks < cpuLoopTicks)) - { - cpuLoopTicks = timer2Ticks; - } - if(timer3On && !(TM3CNT & 4) && (timer3Ticks < cpuLoopTicks)) - { - cpuLoopTicks = timer3Ticks; - } -#ifdef PROFILING - if(profilingTicksReload != 0) - { - if(profilingTicks < cpuLoopTicks) - { - cpuLoopTicks = profilingTicks; - } - } -#endif - cpuSavedTicks = cpuLoopTicks; - return cpuLoopTicks; -} - -void CPUUpdateWindow0() -{ - int x00 = WIN0H>>8; - int x01 = WIN0H & 255; - - if(x00 <= x01) - { - for(int i = 0; i < 240; i++) - { - gfxInWin0[i] = (i >= x00 && i < x01); - } - } - else - { - for(int i = 0; i < 240; i++) - { - gfxInWin0[i] = (i >= x00 || i < x01); - } - } -} - -void CPUUpdateWindow1() -{ - int x00 = WIN1H>>8; - int x01 = WIN1H & 255; - - if(x00 <= x01) - { - for(int i = 0; i < 240; i++) - { - gfxInWin1[i] = (i >= x00 && i < x01); - } - } - else - { - for(int i = 0; i < 240; i++) - { - gfxInWin1[i] = (i >= x00 || i < x01); - } - } -} - -extern u32 line0[240]; -extern u32 line1[240]; -extern u32 line2[240]; -extern u32 line3[240]; - -#define CLEAR_ARRAY(a) \ - {\ - u32 *array = (a);\ - for(int i = 0; i < 240; i++) {\ - *array++ = 0x80000000;\ - }\ - }\ - -void CPUUpdateRenderBuffers(bool force) -{ - if(!(layerEnable & 0x0100) || force) - { - CLEAR_ARRAY(line0); - } - if(!(layerEnable & 0x0200) || force) - { - CLEAR_ARRAY(line1); - } - if(!(layerEnable & 0x0400) || force) - { - CLEAR_ARRAY(line2); - } - if(!(layerEnable & 0x0800) || force) - { - CLEAR_ARRAY(line3); - } -} - -static bool CPUWriteState(gzFile gzFile) -{ - utilWriteInt(gzFile, SAVE_GAME_VERSION); - - utilGzWrite(gzFile, &rom[0xa0], 16); - - utilWriteInt(gzFile, useBios); - - utilGzWrite(gzFile, ®[0], sizeof(reg)); - - utilWriteData(gzFile, saveGameStruct); - - // new to version 0.7.1 - utilWriteInt(gzFile, stopState); - // new to version 0.8 - utilWriteInt(gzFile, intState); - - utilGzWrite(gzFile, internalRAM, 0x8000); - utilGzWrite(gzFile, paletteRAM, 0x400); - utilGzWrite(gzFile, workRAM, 0x40000); - utilGzWrite(gzFile, vram, 0x20000); - utilGzWrite(gzFile, oam, 0x400); - utilGzWrite(gzFile, pix, 4*241*162); - utilGzWrite(gzFile, ioMem, 0x400); - - eepromSaveGame(gzFile); - flashSaveGame(gzFile); - soundSaveGame(gzFile); - - cheatsSaveGame(gzFile); - - // version 1.5 - rtcSaveGame(gzFile); - - return true; -} - -bool CPUWriteState(const char *file) -{ - gzFile gzFile = utilGzOpen(file, "wb"); - - if(gzFile == NULL) - { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), file); - return false; - } - - bool res = CPUWriteState(gzFile); - - utilGzClose(gzFile); - - return res; -} - -bool CPUWriteMemState(char *memory, int available) -{ - gzFile gzFile = utilMemGzOpen(memory, available, "w"); - - if(gzFile == NULL) - { - return false; - } - - bool res = CPUWriteState(gzFile); - - long pos = utilGzMemTell(gzFile)+8; - - if(pos >= (available)) - res = false; - - utilGzClose(gzFile); - - return res; -} - -static bool CPUReadState(gzFile gzFile) -{ - int version = utilReadInt(gzFile); - - if(version > SAVE_GAME_VERSION || version < SAVE_GAME_VERSION_1) - { - systemMessage(MSG_UNSUPPORTED_VBA_SGM, - N_("Unsupported VisualBoyAdvance save game version %d"), - version); - return false; - } - - u8 romname[17]; - - utilGzRead(gzFile, romname, 16); - - if(memcmp(&rom[0xa0], romname, 16) != 0) - { - romname[16]=0; - for(int i = 0; i < 16; i++) - if(romname[i] < 32) - romname[i] = 32; - systemMessage(MSG_CANNOT_LOAD_SGM, N_("Cannot load save game for %s"), romname); - return false; - } - - bool ub = utilReadInt(gzFile) ? true : false; - - if(ub != useBios) - { - if(useBios) - systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS, - N_("Save game is not using the BIOS files")); - else - systemMessage(MSG_SAVE_GAME_USING_BIOS, - N_("Save game is using the BIOS file")); - return false; - } - - utilGzRead(gzFile, ®[0], sizeof(reg)); - - utilReadData(gzFile, saveGameStruct); - - if(version < SAVE_GAME_VERSION_3) - stopState = false; - else - stopState = utilReadInt(gzFile) ? true : false; - - if(version < SAVE_GAME_VERSION_4) - intState = false; - else - intState = utilReadInt(gzFile) ? true : false; - - utilGzRead(gzFile, internalRAM, 0x8000); - utilGzRead(gzFile, paletteRAM, 0x400); - utilGzRead(gzFile, workRAM, 0x40000); - utilGzRead(gzFile, vram, 0x20000); - utilGzRead(gzFile, oam, 0x400); - if(version < SAVE_GAME_VERSION_6) - utilGzRead(gzFile, pix, 4*240*160); - else - utilGzRead(gzFile, pix, 4*241*162); - utilGzRead(gzFile, ioMem, 0x400); - - eepromReadGame(gzFile, version); - flashReadGame(gzFile, version); - soundReadGame(gzFile, version); - - if(version > SAVE_GAME_VERSION_1) - { - cheatsReadGame(gzFile); - } - if(version > SAVE_GAME_VERSION_6) - { - rtcReadGame(gzFile); - } - - if(version <= SAVE_GAME_VERSION_7) - { - u32 temp; -#define SWAP(a,b,c) \ - temp = (a);\ - (a) = (b)<<16|(c);\ - (b) = (temp) >> 16;\ - (c) = (temp) & 0xFFFF; - - SWAP(dma0Source, DM0SAD_H, DM0SAD_L); - SWAP(dma0Dest, DM0DAD_H, DM0DAD_L); - SWAP(dma1Source, DM1SAD_H, DM1SAD_L); - SWAP(dma1Dest, DM1DAD_H, DM1DAD_L); - SWAP(dma2Source, DM2SAD_H, DM2SAD_L); - SWAP(dma2Dest, DM2DAD_H, DM2DAD_L); - SWAP(dma3Source, DM3SAD_H, DM3SAD_L); - SWAP(dma3Dest, DM3DAD_H, DM3DAD_L); - } - - // set pointers! - layerEnable = layerSettings & DISPCNT; - - CPUUpdateRender(); - CPUUpdateRenderBuffers(true); - CPUUpdateWindow0(); - CPUUpdateWindow1(); - gbaSaveType = 0; - switch(saveType) - { - case 0: - cpuSaveGameFunc = flashSaveDecide; - break; - case 1: - cpuSaveGameFunc = sramWrite; - gbaSaveType = 1; - break; - case 2: - cpuSaveGameFunc = flashWrite; - gbaSaveType = 2; - break; - default: - systemMessage(MSG_UNSUPPORTED_SAVE_TYPE, - N_("Unsupported save type %d"), saveType); - break; - } - if(eepromInUse) - gbaSaveType = 3; - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - return true; -} - -bool CPUReadMemState(char *memory, int available) -{ - gzFile gzFile = utilMemGzOpen(memory, available, "r"); - - bool res = CPUReadState(gzFile); - - utilGzClose(gzFile); - - return res; -} - -bool CPUReadState(const char * file) -{ - gzFile gzFile = utilGzOpen(file, "rb"); - - if(gzFile == NULL) - return false; - - bool res = CPUReadState(gzFile); - - utilGzClose(gzFile); - - return res; -} - -bool CPUExportEepromFile(const char *fileName) -{ - if(eepromInUse) - { - FILE* file = gen_fopen(fileName, "wb"); - - if(!file) - { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), - fileName); - return false; - } - - for(int i = 0; i < eepromSize;) - { - for(int j = 0; j < 8; j++) - { - if(gen_fwrite(&eepromData[i+7-j], 1, 1, file) != 1) - { - gen_fclose(file); - return false; - } - } - i += 8; - } - gen_fclose(file); - } - return true; -} - -bool CPUWriteBatteryFile(const char *fileName) -{ - if(gbaSaveType == 0) - { - if(eepromInUse) - gbaSaveType = 3; - else switch(saveType) - { - case 1: - gbaSaveType = 1; - break; - case 2: - gbaSaveType = 2; - break; - } - } - - if(gbaSaveType) - { - FILE* file = gen_fopen(fileName, "wb"); - - if(!file) - { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), - fileName); - return false; - } - - // only save if Flash/Sram in use or EEprom in use - if(gbaSaveType != 3) - { - if(gbaSaveType == 2) - { - if(gen_fwrite(flashSaveMemory, 1, flashSize, file) != (int)flashSize) - { - gen_fclose(file); - return false; - } - } - else - { - if(gen_fwrite(flashSaveMemory, 1, 0x10000, file) != 0x10000) - { - gen_fclose(file); - return false; - } - } - } - else - { - if(gen_fwrite(eepromData, 1, eepromSize, file) != (int)eepromSize) - { - gen_fclose(file); - return false; - } - } - gen_fclose(file); - } - return true; -} - -bool CPUReadGSASnapshot(const char *fileName) -{ - int i; - FILE* file = gen_fopen(fileName, "rb"); - - if(!file) - { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); - return false; - } - - // check file size to know what we should read - // gen_fseek(file, 0, SEEK_END); - - // long size = ftell(file); - gen_fseek(file, 0x0, SEEK_SET); - gen_fread(&i, 1, 4, file); - gen_fseek(file, i, SEEK_CUR); // Skip SharkPortSave - gen_fseek(file, 4, SEEK_CUR); // skip some sort of flag - gen_fread(&i, 1, 4, file); // name length - gen_fseek(file, i, SEEK_CUR); // skip name - gen_fread(&i, 1, 4, file); // desc length - gen_fseek(file, i, SEEK_CUR); // skip desc - gen_fread(&i, 1, 4, file); // notes length - gen_fseek(file, i, SEEK_CUR); // skip notes - int saveSize; - gen_fread(&saveSize, 1, 4, file); // read length - saveSize -= 0x1c; // remove header size - char buffer[17]; - char buffer2[17]; - gen_fread(buffer, 1, 16, file); - buffer[16] = 0; - for(i = 0; i < 16; i++) - if(buffer[i] < 32) - buffer[i] = 32; - memcpy(buffer2, &rom[0xa0], 16); - buffer2[16] = 0; - for(i = 0; i < 16; i++) - if(buffer2[i] < 32) - buffer2[i] = 32; - if(memcmp(buffer, buffer2, 16)) - { - systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, - N_("Cannot import snapshot for %s. Current game is %s"), - buffer, - buffer2); - gen_fclose(file); - return false; - } - gen_fseek(file, 12, SEEK_CUR); // skip some flags - if(saveSize >= 65536) - { - if(gen_fread(flashSaveMemory, 1, saveSize, file) != (int)saveSize) - { - gen_fclose(file); - return false; - } - } - else - { - systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, - N_("Unsupported snapshot file %s"), - fileName); - gen_fclose(file); - return false; - } - gen_fclose(file); - CPUReset(); - return true; -} - -bool CPUWriteGSASnapshot(const char *fileName, - const char *title, - const char *desc, - const char *notes) -{ - FILE* file = gen_fopen(fileName, "wb"); - - if(!file) - { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); - return false; - } - - u8 buffer[17]; - - utilPutDword(buffer, 0x0d); // SharkPortSave length - gen_fwrite(buffer, 1, 4, file); - gen_fwrite("SharkPortSave", 1, 0x0d, file); - utilPutDword(buffer, 0x000f0000); - gen_fwrite(buffer, 1, 4, file); // save type 0x000f0000 = GBA save - utilPutDword(buffer, strlen(title)); - gen_fwrite(buffer, 1, 4, file); // title length - gen_fwrite(title, 1, strlen(title), file); - utilPutDword(buffer, strlen(desc)); - gen_fwrite(buffer, 1, 4, file); // desc length - gen_fwrite(desc, 1, strlen(desc), file); - utilPutDword(buffer, strlen(notes)); - gen_fwrite(buffer, 1, 4, file); // notes length - gen_fwrite(notes, 1, strlen(notes), file); - int saveSize = 0x10000; - if(gbaSaveType == 2) - saveSize = flashSize; - int totalSize = saveSize + 0x1c; - - utilPutDword(buffer, totalSize); // length of remainder of save - CRC - gen_fwrite(buffer, 1, 4, file); - - char temp[0x2001c]; - memset(temp, 0, 28); - memcpy(temp, &rom[0xa0], 16); // copy internal name - temp[0x10] = rom[0xbe]; // reserved area (old checksum) - temp[0x11] = rom[0xbf]; // reserved area (old checksum) - temp[0x12] = rom[0xbd]; // complement check - temp[0x13] = rom[0xb0]; // maker - temp[0x14] = 1; // 1 save ? - memcpy(&temp[0x1c], flashSaveMemory, saveSize); // copy save - gen_fwrite(temp, 1, totalSize, file); // write save + header - u32 crc = 0; - - for(int i = 0; i < totalSize; i++) - { - crc += ((u32)temp[i] << (crc % 0x18)); - } - - utilPutDword(buffer, crc); - gen_fwrite(buffer, 1, 4, file); // CRC? - - gen_fclose(file); - return true; -} - -bool CPUImportEepromFile(const char *fileName) -{ - FILE* file = gen_fopen(fileName, "rb"); - - if(!file) - return false; - - - // check file size to know what we should read - gen_fseek(file, 0, SEEK_END); - - long size = ftell(file); - - gen_fseek(file, 0, SEEK_SET); - if(size == 512 || size == 0x2000) - { - if(gen_fread(eepromData, 1, size, file) != (int)size) - { - gen_fclose(file); - return false; - } - for(int i = 0; i < size;) - { - u8 tmp = eepromData[i]; - eepromData[i] = eepromData[7-i]; - eepromData[7-i] = tmp; - i++; - tmp = eepromData[i]; - eepromData[i] = eepromData[7-i]; - eepromData[7-i] = tmp; - i++; - tmp = eepromData[i]; - eepromData[i] = eepromData[7-i]; - eepromData[7-i] = tmp; - i++; - tmp = eepromData[i]; - eepromData[i] = eepromData[7-i]; - eepromData[7-i] = tmp; - i++; - i += 4; - } - } - else - return false; - gen_fclose(file); - return true; -} - -bool CPUReadBatteryFile(const char *fileName) -{ - FILE* file = gen_fopen(fileName, "rb"); - - if(!file) - return false; - - // check file size to know what we should read - gen_fseek(file, 0, SEEK_END); - - long size = ftell(file); - - - gen_fseek(file, 0, SEEK_SET); - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - if(size == 512 || size == 0x2000) - { - if(gen_fread(eepromData, 1, size, file) != (int)size) - { - gen_fclose(file); - return false; - } - } - else - { - if(size == 0x20000) - { - if(gen_fread(flashSaveMemory, 1, 0x20000, file) != 0x20000) - { - gen_fclose(file); - return false; - } - flashSetSize(0x20000); - } - else - { - if(gen_fread(flashSaveMemory, 1, 0x10000, file) != 0x10000) - { - gen_fclose(file); - return false; - } - flashSetSize(0x10000); - } - } - gen_fclose(file); - return true; -} - -bool CPUWritePNGFile(const char *fileName) -{ - return utilWritePNGFile(fileName, 240, 160, pix); -} - -bool CPUWriteBMPFile(const char *fileName) -{ - return utilWriteBMPFile(fileName, 240, 160, pix); -} - -bool CPUIsZipFile(const char * file) -{ - if(strlen(file) > 4) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".zip") == 0) - return true; - } - } - - return false; -} - -bool CPUIsGBAImage(const char * file) -{ - cpuIsMultiBoot = false; - if(strlen(file) > 4) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".gba") == 0) - return true; - if(_stricmp(p, ".agb") == 0) - return true; - if(_stricmp(p, ".bin") == 0) - return true; - if(_stricmp(p, ".elf") == 0) - return true; - if(_stricmp(p, ".mb") == 0) - { - cpuIsMultiBoot = true; - return true; - } - } - } - - return false; -} - -bool CPUIsGBABios(const char * file) -{ - if(strlen(file) > 4) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".gba") == 0) - return true; - if(_stricmp(p, ".agb") == 0) - return true; - if(_stricmp(p, ".bin") == 0) - return true; - if(_stricmp(p, ".bios") == 0) - return true; - } - } - - return false; -} - -bool CPUIsELF(const char *file) -{ - if(strlen(file) > 4) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".elf") == 0) - return true; - } - } - return false; -} - -void CPUCleanUp() -{ -#ifdef PROFILING - if(profilingTicksReload) - { - profCleanup(); - } -#endif - - if(rom != NULL) - { - free(rom); - rom = NULL; - } - - if(vram != NULL) - { - free(vram); - vram = NULL; - } - - if(paletteRAM != NULL) - { - free(paletteRAM); - paletteRAM = NULL; - } - - if(internalRAM != NULL) - { - free(internalRAM); - internalRAM = NULL; - } - - if(workRAM != NULL) - { - free(workRAM); - workRAM = NULL; - } - - if(bios != NULL) - { - free(bios); - bios = NULL; - } - - if(pix != NULL) - { - // this causes system to CRASH when switching from GBA to GB and then back to GBA - //free(pix); - pix = NULL; - } - - if(oam != NULL) - { - free(oam); - oam = NULL; - } - - if(ioMem != NULL) - { - free(ioMem); - ioMem = NULL; - } - - elfCleanUp(); - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - emulating = 0; -} - -int CPULoadRom(const char *szFile) -{ - int size = 0x2000000; - - if(rom != NULL) - { - CPUCleanUp(); - } - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - rom = (u8 *)malloc(0x2000000); - if(rom == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "ROM"); - return 0; - } - workRAM = (u8 *)calloc(1, 0x40000); - if(workRAM == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "WRAM"); - return 0; - } - - u8 *whereToLoad = rom; - if(cpuIsMultiBoot) - whereToLoad = workRAM; - - if(CPUIsELF(szFile)) - { - FILE* f = gen_fopen(szFile, "rb"); - if(!f) - { - systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), - szFile); - free(rom); - rom = NULL; - free(workRAM); - workRAM = NULL; - return 0; - } - bool res = elfRead(szFile, size, f); - if(!res || size == 0) - { - free(rom); - rom = NULL; - free(workRAM); - workRAM = NULL; - elfCleanUp(); - return 0; - } - } - else if(!utilLoad(szFile, - utilIsGBAImage, - whereToLoad, - size)) - { - free(rom); - rom = NULL; - free(workRAM); - workRAM = NULL; - return 0; - } - - u16 *temp = (u16 *)(rom+((size+1)&~1)); - int i; - for(i = (size+1)&~1; i < 0x2000000; i+=2) - { - WRITE16LE(temp, (i >> 1) & 0xFFFF); - temp++; - } - - bios = (u8 *)calloc(1,0x4000); - if(bios == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "BIOS"); - CPUCleanUp(); - return 0; - } - internalRAM = (u8 *)calloc(1,0x8000); - if(internalRAM == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "IRAM"); - CPUCleanUp(); - return 0; - } - paletteRAM = (u8 *)calloc(1,0x400); - if(paletteRAM == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "PRAM"); - CPUCleanUp(); - return 0; - } - vram = (u8 *)calloc(1, 0x20000); - if(vram == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "VRAM"); - CPUCleanUp(); - return 0; - } - oam = (u8 *)calloc(1, 0x400); - if(oam == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "OAM"); - CPUCleanUp(); - return 0; - } - pix = (u8 *)calloc(1, 4 * 241 * 162); - if(pix == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "PIX"); - CPUCleanUp(); - return 0; - } - ioMem = (u8 *)calloc(1, 0x400); - if(ioMem == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "IO"); - CPUCleanUp(); - return 0; - } - - CPUUpdateRenderBuffers(true); - - return size; -} - -void CPUUpdateRender() -{ - switch(DISPCNT & 7) - { - case 0: - if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || - cpuDisableSfx) - renderLine = mode0RenderLine; - else if(fxOn && !windowOn && !(layerEnable & 0x8000)) - renderLine = mode0RenderLineNoWindow; - else - renderLine = mode0RenderLineAll; - break; - case 1: - if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || - cpuDisableSfx) - renderLine = mode1RenderLine; - else if(fxOn && !windowOn && !(layerEnable & 0x8000)) - renderLine = mode1RenderLineNoWindow; - else - renderLine = mode1RenderLineAll; - break; - case 2: - if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || - cpuDisableSfx) - renderLine = mode2RenderLine; - else if(fxOn && !windowOn && !(layerEnable & 0x8000)) - renderLine = mode2RenderLineNoWindow; - else - renderLine = mode2RenderLineAll; - break; - case 3: - if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || - cpuDisableSfx) - renderLine = mode3RenderLine; - else if(fxOn && !windowOn && !(layerEnable & 0x8000)) - renderLine = mode3RenderLineNoWindow; - else - renderLine = mode3RenderLineAll; - break; - case 4: - if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || - cpuDisableSfx) - renderLine = mode4RenderLine; - else if(fxOn && !windowOn && !(layerEnable & 0x8000)) - renderLine = mode4RenderLineNoWindow; - else - renderLine = mode4RenderLineAll; - break; - case 5: - if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || - cpuDisableSfx) - renderLine = mode5RenderLine; - else if(fxOn && !windowOn && !(layerEnable & 0x8000)) - renderLine = mode5RenderLineNoWindow; - else - renderLine = mode5RenderLineAll; - default: - break; - } -} - -void CPUUpdateCPSR() -{ - u32 CPSR = reg[16].I & 0x40; - if(N_FLAG) - CPSR |= 0x80000000; - if(Z_FLAG) - CPSR |= 0x40000000; - if(C_FLAG) - CPSR |= 0x20000000; - if(V_FLAG) - CPSR |= 0x10000000; - if(!armState) - CPSR |= 0x00000020; - if(!armIrqEnable) - CPSR |= 0x80; - CPSR |= (armMode & 0x1F); - reg[16].I = CPSR; -} - -void CPUUpdateFlags(bool breakLoop) -{ - u32 CPSR = reg[16].I; - - N_FLAG = (CPSR & 0x80000000) ? true: false; - Z_FLAG = (CPSR & 0x40000000) ? true: false; - C_FLAG = (CPSR & 0x20000000) ? true: false; - V_FLAG = (CPSR & 0x10000000) ? true: false; - armState = (CPSR & 0x20) ? false : true; - armIrqEnable = (CPSR & 0x80) ? false : true; - if(breakLoop) - { - if(armIrqEnable && (IF & IE) && (IME & 1)) - { - CPU_BREAK_LOOP_2; - } - } -} - -void CPUUpdateFlags() -{ - CPUUpdateFlags(true); -} - -#ifdef WORDS_BIGENDIAN -static void CPUSwap(volatile u32 *a, volatile u32 *b) -{ - volatile u32 c = *b; - *b = *a; - *a = c; -} -#else -static void CPUSwap(u32 *a, u32 *b) -{ - u32 c = *b; - *b = *a; - *a = c; -} -#endif - -void CPUSwitchMode(int mode, bool saveState, bool breakLoop) -{ - // if(armMode == mode) - // return; - - CPUUpdateCPSR(); - - switch(armMode) - { - case 0x10: - case 0x1F: - reg[R13_USR].I = reg[13].I; - reg[R14_USR].I = reg[14].I; - reg[17].I = reg[16].I; - break; - case 0x11: - CPUSwap(®[R8_FIQ].I, ®[8].I); - CPUSwap(®[R9_FIQ].I, ®[9].I); - CPUSwap(®[R10_FIQ].I, ®[10].I); - CPUSwap(®[R11_FIQ].I, ®[11].I); - CPUSwap(®[R12_FIQ].I, ®[12].I); - reg[R13_FIQ].I = reg[13].I; - reg[R14_FIQ].I = reg[14].I; - reg[SPSR_FIQ].I = reg[17].I; - break; - case 0x12: - reg[R13_IRQ].I = reg[13].I; - reg[R14_IRQ].I = reg[14].I; - reg[SPSR_IRQ].I = reg[17].I; - break; - case 0x13: - reg[R13_SVC].I = reg[13].I; - reg[R14_SVC].I = reg[14].I; - reg[SPSR_SVC].I = reg[17].I; - break; - case 0x17: - reg[R13_ABT].I = reg[13].I; - reg[R14_ABT].I = reg[14].I; - reg[SPSR_ABT].I = reg[17].I; - break; - case 0x1b: - reg[R13_UND].I = reg[13].I; - reg[R14_UND].I = reg[14].I; - reg[SPSR_UND].I = reg[17].I; - break; - } - - u32 CPSR = reg[16].I; - u32 SPSR = reg[17].I; - - switch(mode) - { - case 0x10: - case 0x1F: - reg[13].I = reg[R13_USR].I; - reg[14].I = reg[R14_USR].I; - reg[16].I = SPSR; - break; - case 0x11: - CPUSwap(®[8].I, ®[R8_FIQ].I); - CPUSwap(®[9].I, ®[R9_FIQ].I); - CPUSwap(®[10].I, ®[R10_FIQ].I); - CPUSwap(®[11].I, ®[R11_FIQ].I); - CPUSwap(®[12].I, ®[R12_FIQ].I); - reg[13].I = reg[R13_FIQ].I; - reg[14].I = reg[R14_FIQ].I; - if(saveState) - reg[17].I = CPSR; - else - reg[17].I = reg[SPSR_FIQ].I; - break; - case 0x12: - reg[13].I = reg[R13_IRQ].I; - reg[14].I = reg[R14_IRQ].I; - reg[16].I = SPSR; - if(saveState) - reg[17].I = CPSR; - else - reg[17].I = reg[SPSR_IRQ].I; - break; - case 0x13: - reg[13].I = reg[R13_SVC].I; - reg[14].I = reg[R14_SVC].I; - reg[16].I = SPSR; - if(saveState) - reg[17].I = CPSR; - else - reg[17].I = reg[SPSR_SVC].I; - break; - case 0x17: - reg[13].I = reg[R13_ABT].I; - reg[14].I = reg[R14_ABT].I; - reg[16].I = SPSR; - if(saveState) - reg[17].I = CPSR; - else - reg[17].I = reg[SPSR_ABT].I; - break; - case 0x1b: - reg[13].I = reg[R13_UND].I; - reg[14].I = reg[R14_UND].I; - reg[16].I = SPSR; - if(saveState) - reg[17].I = CPSR; - else - reg[17].I = reg[SPSR_UND].I; - break; - default: - systemMessage(MSG_UNSUPPORTED_ARM_MODE, N_("Unsupported ARM mode %02x"), mode); - break; - } - armMode = mode; - CPUUpdateFlags(breakLoop); - CPUUpdateCPSR(); -} - -void CPUSwitchMode(int mode, bool saveState) -{ - CPUSwitchMode(mode, saveState, true); -} - -void CPUUndefinedException() -{ - u32 PC = reg[15].I; - bool savedArmState = armState; - CPUSwitchMode(0x1b, true, false); - reg[14].I = PC - (savedArmState ? 4 : 2); - reg[15].I = 0x04; - armState = true; - armIrqEnable = false; - armNextPC = 0x04; - reg[15].I += 4; -} - -void CPUSoftwareInterrupt() -{ - u32 PC = reg[15].I; - bool savedArmState = armState; - CPUSwitchMode(0x13, true, false); - reg[14].I = PC - (savedArmState ? 4 : 2); - reg[15].I = 0x08; - armState = true; - armIrqEnable = false; - armNextPC = 0x08; - reg[15].I += 4; -} - -void CPUSoftwareInterrupt(int comment) -{ - static bool disableMessage = false; - if(armState) comment >>= 16; -#ifdef BKPT_SUPPORT - if(comment == 0xff) - { - extern void (*dbgOutput)(char *, u32); - dbgOutput(NULL, reg[0].I); - return; - } -#endif -#ifdef PROFILING - if(comment == 0xfe) - { - profStartup(reg[0].I, reg[1].I); - return; - } - if(comment == 0xfd) - { - profControl(reg[0].I); - return; - } - if(comment == 0xfc) - { - profCleanup(); - return; - } - if(comment == 0xfb) - { - profCount(); - return; - } -#endif - if(comment == 0xfa) - { - agbPrintFlush(); - return; - } -#ifdef SDL - if(comment == 0xf9) - { - emulating = 0; - CPU_BREAK_LOOP_2; - return; - } -#endif - if(useBios) - { -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, - armState ? armNextPC - 4: armNextPC -2, - reg[0].I, - reg[1].I, - reg[2].I, - VCOUNT); - } -#endif - CPUSoftwareInterrupt(); - return; - } - // This would be correct, but it causes problems if uncommented - // else { - // biosProtected = 0xe3a02004; - // } - - switch(comment) - { - case 0x00: - BIOS_SoftReset(); - break; - case 0x01: - BIOS_RegisterRamReset(); - break; - case 0x02: -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("Halt: (VCOUNT = %2d)\n", - VCOUNT); - } -#endif - holdState = true; - holdType = -1; - break; - case 0x03: -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("Stop: (VCOUNT = %2d)\n", - VCOUNT); - } -#endif - holdState = true; - holdType = -1; - stopState = true; - break; - case 0x04: -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n", - reg[0].I, - reg[1].I, - VCOUNT); - } -#endif - CPUSoftwareInterrupt(); - break; - case 0x05: -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("VBlankIntrWait: (VCOUNT = %2d)\n", - VCOUNT); - } -#endif - CPUSoftwareInterrupt(); - break; - case 0x06: - CPUSoftwareInterrupt(); - break; - case 0x07: - CPUSoftwareInterrupt(); - break; - case 0x08: - BIOS_Sqrt(); - break; - case 0x09: - BIOS_ArcTan(); - break; - case 0x0A: - BIOS_ArcTan2(); - break; - case 0x0B: - BIOS_CpuSet(); - break; - case 0x0C: - BIOS_CpuFastSet(); - break; - case 0x0E: - BIOS_BgAffineSet(); - break; - case 0x0F: - BIOS_ObjAffineSet(); - break; - case 0x10: - BIOS_BitUnPack(); - break; - case 0x11: - BIOS_LZ77UnCompWram(); - break; - case 0x12: - BIOS_LZ77UnCompVram(); - break; - case 0x13: - BIOS_HuffUnComp(); - break; - case 0x14: - BIOS_RLUnCompWram(); - break; - case 0x15: - BIOS_RLUnCompVram(); - break; - case 0x16: - BIOS_Diff8bitUnFilterWram(); - break; - case 0x17: - BIOS_Diff8bitUnFilterVram(); - break; - case 0x18: - BIOS_Diff16bitUnFilter(); - break; - case 0x19: -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n", - reg[0].I, - VCOUNT); - } -#endif - if(reg[0].I) - systemSoundPause(); - else - systemSoundResume(); - break; - case 0x1F: - BIOS_MidiKey2Freq(); - break; - case 0x2A: - BIOS_SndDriverJmpTableCopy(); - // let it go, because we don't really emulate this function - default: -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, - armState ? armNextPC - 4: armNextPC -2, - reg[0].I, - reg[1].I, - reg[2].I, - VCOUNT); - } -#endif - - if(!disableMessage) - { - systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION, - N_("Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."), - comment, - armMode ? armNextPC - 4: armNextPC - 2); - disableMessage = true; - } - break; - } -} - -void CPUCompareVCOUNT() -{ - if(VCOUNT == (DISPSTAT >> 8)) - { - DISPSTAT |= 4; - UPDATE_REG(0x04, DISPSTAT); - - if(DISPSTAT & 0x20) - { - IF |= 4; - UPDATE_REG(0x202, IF); - } - } - else - { - DISPSTAT &= 0xFFFB; - UPDATE_REG(0x4, DISPSTAT); - } -} - -void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32) -{ - int sm = s >> 24; - int dm = d >> 24; - - int sc = c; - - cpuDmaCount = c; - - if(transfer32) - { - s &= 0xFFFFFFFC; - if(s < 0x02000000 && (reg[15].I >> 24)) - { - while(c != 0) - { - CPUWriteMemory(d, 0); - d += di; - c--; - } - } - else - { - while(c != 0) - { - CPUWriteMemory(d, CPUReadMemory(s)); - d += di; - s += si; - c--; - } - } - } - else - { - s &= 0xFFFFFFFE; - si = (int)si >> 1; - di = (int)di >> 1; - if(s < 0x02000000 && (reg[15].I >> 24)) - { - while(c != 0) - { - CPUWriteHalfWord(d, 0); - d += di; - c--; - } - } - else - { - while(c != 0) - { - cpuDmaLast = CPUReadHalfWord(s); - CPUWriteHalfWord(d, cpuDmaLast); - d += di; - s += si; - c--; - } - } - } - - cpuDmaCount = 0; - - int sw = 1+memoryWaitSeq[sm & 15]; - int dw = 1+memoryWaitSeq[dm & 15]; - - int totalTicks = 0; - - if(transfer32) - { - if(!memory32[sm & 15]) - sw <<= 1; - if(!memory32[dm & 15]) - dw <<= 1; - } - - totalTicks = (sw+dw)*sc; - - cpuDmaTicksToUpdate += totalTicks; - - if(*extCpuLoopTicks >= 0) - { - CPU_BREAK_LOOP; - } -} - -void CPUCheckDMA(int reason, int dmamask) -{ - cpuDmaHack = 0; - // DMA 0 - if((DM0CNT_H & 0x8000) && (dmamask & 1)) - { - if(((DM0CNT_H >> 12) & 3) == reason) - { - u32 sourceIncrement = 4; - u32 destIncrement = 4; - switch((DM0CNT_H >> 7) & 3) - { - case 0: - break; - case 1: - sourceIncrement = (u32)-4; - break; - case 2: - sourceIncrement = 0; - break; - } - switch((DM0CNT_H >> 5) & 3) - { - case 0: - break; - case 1: - destIncrement = (u32)-4; - break; - case 2: - destIncrement = 0; - break; - } -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_DMA0) - { - int count = (DM0CNT_L ? DM0CNT_L : 0x4000) << 1; - if(DM0CNT_H & 0x0400) - count <<= 1; - log("DMA0: s=%08x d=%08x c=%04x count=%08x\n", dma0Source, dma0Dest, - DM0CNT_H, - count); - } -#endif - doDMA(dma0Source, dma0Dest, sourceIncrement, destIncrement, - DM0CNT_L ? DM0CNT_L : 0x4000, - DM0CNT_H & 0x0400); - cpuDmaHack = 1; - if(DM0CNT_H & 0x4000) - { - IF |= 0x0100; - UPDATE_REG(0x202, IF); - } - - if(((DM0CNT_H >> 5) & 3) == 3) - { - dma0Dest = DM0DAD_L | (DM0DAD_H << 16); - } - - if(!(DM0CNT_H & 0x0200) || (reason == 0)) - { - DM0CNT_H &= 0x7FFF; - UPDATE_REG(0xBA, DM0CNT_H); - } - } - } - - // DMA 1 - if((DM1CNT_H & 0x8000) && (dmamask & 2)) - { - if(((DM1CNT_H >> 12) & 3) == reason) - { - u32 sourceIncrement = 4; - u32 destIncrement = 4; - switch((DM1CNT_H >> 7) & 3) - { - case 0: - break; - case 1: - sourceIncrement = (u32)-4; - break; - case 2: - sourceIncrement = 0; - break; - } - switch((DM1CNT_H >> 5) & 3) - { - case 0: - break; - case 1: - destIncrement = (u32)-4; - break; - case 2: - destIncrement = 0; - break; - } - if(reason == 3) - { -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_DMA1) - { - log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest, - DM1CNT_H, - 16); - } -#endif - doDMA(dma1Source, dma1Dest, sourceIncrement, 0, 4, - 0x0400); - } - else - { -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_DMA1) - { - int count = (DM1CNT_L ? DM1CNT_L : 0x4000) << 1; - if(DM1CNT_H & 0x0400) - count <<= 1; - log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest, - DM1CNT_H, - count); - } -#endif - doDMA(dma1Source, dma1Dest, sourceIncrement, destIncrement, - DM1CNT_L ? DM1CNT_L : 0x4000, - DM1CNT_H & 0x0400); - } - cpuDmaHack = 1; - - if(DM1CNT_H & 0x4000) - { - IF |= 0x0200; - UPDATE_REG(0x202, IF); - } - - if(((DM1CNT_H >> 5) & 3) == 3) - { - dma1Dest = DM1DAD_L | (DM1DAD_H << 16); - } - - if(!(DM1CNT_H & 0x0200) || (reason == 0)) - { - DM1CNT_H &= 0x7FFF; - UPDATE_REG(0xC6, DM1CNT_H); - } - } - } - - // DMA 2 - if((DM2CNT_H & 0x8000) && (dmamask & 4)) - { - if(((DM2CNT_H >> 12) & 3) == reason) - { - u32 sourceIncrement = 4; - u32 destIncrement = 4; - switch((DM2CNT_H >> 7) & 3) - { - case 0: - break; - case 1: - sourceIncrement = (u32)-4; - break; - case 2: - sourceIncrement = 0; - break; - } - switch((DM2CNT_H >> 5) & 3) - { - case 0: - break; - case 1: - destIncrement = (u32)-4; - break; - case 2: - destIncrement = 0; - break; - } - if(reason == 3) - { -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_DMA2) - { - int count = (4) << 2; - log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest, - DM2CNT_H, - count); - } -#endif - doDMA(dma2Source, dma2Dest, sourceIncrement, 0, 4, - 0x0400); - } - else - { -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_DMA2) - { - int count = (DM2CNT_L ? DM2CNT_L : 0x4000) << 1; - if(DM2CNT_H & 0x0400) - count <<= 1; - log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest, - DM2CNT_H, - count); - } -#endif - doDMA(dma2Source, dma2Dest, sourceIncrement, destIncrement, - DM2CNT_L ? DM2CNT_L : 0x4000, - DM2CNT_H & 0x0400); - } - cpuDmaHack = 1; - if(DM2CNT_H & 0x4000) - { - IF |= 0x0400; - UPDATE_REG(0x202, IF); - } - - if(((DM2CNT_H >> 5) & 3) == 3) - { - dma2Dest = DM2DAD_L | (DM2DAD_H << 16); - } - - if(!(DM2CNT_H & 0x0200) || (reason == 0)) - { - DM2CNT_H &= 0x7FFF; - UPDATE_REG(0xD2, DM2CNT_H); - } - } - } - - // DMA 3 - if((DM3CNT_H & 0x8000) && (dmamask & 8)) - { - if(((DM3CNT_H >> 12) & 3) == reason) - { - u32 sourceIncrement = 4; - u32 destIncrement = 4; - switch((DM3CNT_H >> 7) & 3) - { - case 0: - break; - case 1: - sourceIncrement = (u32)-4; - break; - case 2: - sourceIncrement = 0; - break; - } - switch((DM3CNT_H >> 5) & 3) - { - case 0: - break; - case 1: - destIncrement = (u32)-4; - break; - case 2: - destIncrement = 0; - break; - } -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_DMA3) - { - int count = (DM3CNT_L ? DM3CNT_L : 0x10000) << 1; - if(DM3CNT_H & 0x0400) - count <<= 1; - log("DMA3: s=%08x d=%08x c=%04x count=%08x\n", dma3Source, dma3Dest, - DM3CNT_H, - count); - } -#endif - doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement, - DM3CNT_L ? DM3CNT_L : 0x10000, - DM3CNT_H & 0x0400); - if(DM3CNT_H & 0x4000) - { - IF |= 0x0800; - UPDATE_REG(0x202, IF); - } - - if(((DM3CNT_H >> 5) & 3) == 3) - { - dma3Dest = DM3DAD_L | (DM3DAD_H << 16); - } - - if(!(DM3CNT_H & 0x0200) || (reason == 0)) - { - DM3CNT_H &= 0x7FFF; - UPDATE_REG(0xDE, DM3CNT_H); - } - } - } - cpuDmaHack = 0; -} - -void CPUUpdateRegister(u32 address, u16 value) -{ - switch(address) - { - case 0x00: - { - bool change = ((DISPCNT ^ value) & 0x80) ? true : false; - bool changeBG = ((DISPCNT ^ value) & 0x0F00) ? true : false; - DISPCNT = (value & 0xFFF7); - UPDATE_REG(0x00, DISPCNT); - layerEnable = layerSettings & value; - windowOn = (layerEnable & 0x6000) ? true : false; - if(change && !((value & 0x80))) - { - if(!(DISPSTAT & 1)) - { - lcdTicks = 960; - // VCOUNT = 0; - // UPDATE_REG(0x06, VCOUNT); - DISPSTAT &= 0xFFFC; - UPDATE_REG(0x04, DISPSTAT); - CPUCompareVCOUNT(); - } - // (*renderLine)(); - } - CPUUpdateRender(); - // we only care about changes in BG0-BG3 - if(changeBG) - CPUUpdateRenderBuffers(false); - // CPUUpdateTicks(); - } - break; - case 0x04: - DISPSTAT = (value & 0xFF38) | (DISPSTAT & 7); - UPDATE_REG(0x04, DISPSTAT); - break; - case 0x06: - // not writable - break; - case 0x08: - BG0CNT = (value & 0xDFCF); - UPDATE_REG(0x08, BG0CNT); - break; - case 0x0A: - BG1CNT = (value & 0xDFCF); - UPDATE_REG(0x0A, BG1CNT); - break; - case 0x0C: - BG2CNT = (value & 0xFFCF); - UPDATE_REG(0x0C, BG2CNT); - break; - case 0x0E: - BG3CNT = (value & 0xFFCF); - UPDATE_REG(0x0E, BG3CNT); - break; - case 0x10: - BG0HOFS = value & 511; - UPDATE_REG(0x10, BG0HOFS); - break; - case 0x12: - BG0VOFS = value & 511; - UPDATE_REG(0x12, BG0VOFS); - break; - case 0x14: - BG1HOFS = value & 511; - UPDATE_REG(0x14, BG1HOFS); - break; - case 0x16: - BG1VOFS = value & 511; - UPDATE_REG(0x16, BG1VOFS); - break; - case 0x18: - BG2HOFS = value & 511; - UPDATE_REG(0x18, BG2HOFS); - break; - case 0x1A: - BG2VOFS = value & 511; - UPDATE_REG(0x1A, BG2VOFS); - break; - case 0x1C: - BG3HOFS = value & 511; - UPDATE_REG(0x1C, BG3HOFS); - break; - case 0x1E: - BG3VOFS = value & 511; - UPDATE_REG(0x1E, BG3VOFS); - break; - case 0x20: - BG2PA = value; - UPDATE_REG(0x20, BG2PA); - break; - case 0x22: - BG2PB = value; - UPDATE_REG(0x22, BG2PB); - break; - case 0x24: - BG2PC = value; - UPDATE_REG(0x24, BG2PC); - break; - case 0x26: - BG2PD = value; - UPDATE_REG(0x26, BG2PD); - break; - case 0x28: - BG2X_L = value; - UPDATE_REG(0x28, BG2X_L); - gfxBG2Changed |= 1; - break; - case 0x2A: - BG2X_H = (value & 0xFFF); - UPDATE_REG(0x2A, BG2X_H); - gfxBG2Changed |= 1; - break; - case 0x2C: - BG2Y_L = value; - UPDATE_REG(0x2C, BG2Y_L); - gfxBG2Changed |= 2; - break; - case 0x2E: - BG2Y_H = value & 0xFFF; - UPDATE_REG(0x2E, BG2Y_H); - gfxBG2Changed |= 2; - break; - case 0x30: - BG3PA = value; - UPDATE_REG(0x30, BG3PA); - break; - case 0x32: - BG3PB = value; - UPDATE_REG(0x32, BG3PB); - break; - case 0x34: - BG3PC = value; - UPDATE_REG(0x34, BG3PC); - break; - case 0x36: - BG3PD = value; - UPDATE_REG(0x36, BG3PD); - break; - case 0x38: - BG3X_L = value; - UPDATE_REG(0x38, BG3X_L); - gfxBG3Changed |= 1; - break; - case 0x3A: - BG3X_H = value & 0xFFF; - UPDATE_REG(0x3A, BG3X_H); - gfxBG3Changed |= 1; - break; - case 0x3C: - BG3Y_L = value; - UPDATE_REG(0x3C, BG3Y_L); - gfxBG3Changed |= 2; - break; - case 0x3E: - BG3Y_H = value & 0xFFF; - UPDATE_REG(0x3E, BG3Y_H); - gfxBG3Changed |= 2; - break; - case 0x40: - WIN0H = value; - UPDATE_REG(0x40, WIN0H); - CPUUpdateWindow0(); - break; - case 0x42: - WIN1H = value; - UPDATE_REG(0x42, WIN1H); - CPUUpdateWindow1(); - break; - case 0x44: - WIN0V = value; - UPDATE_REG(0x44, WIN0V); - break; - case 0x46: - WIN1V = value; - UPDATE_REG(0x46, WIN1V); - break; - case 0x48: - WININ = value & 0x3F3F; - UPDATE_REG(0x48, WININ); - break; - case 0x4A: - WINOUT = value & 0x3F3F; - UPDATE_REG(0x4A, WINOUT); - break; - case 0x4C: - MOSAIC = value; - UPDATE_REG(0x4C, MOSAIC); - break; - case 0x50: - BLDMOD = value & 0x3FFF; - UPDATE_REG(0x50, BLDMOD); - fxOn = ((BLDMOD>>6)&3) != 0; - CPUUpdateRender(); - break; - case 0x52: - COLEV = value & 0x1F1F; - UPDATE_REG(0x52, COLEV); - break; - case 0x54: - COLY = value & 0x1F; - UPDATE_REG(0x54, COLY); - break; - case 0x60: - case 0x62: - case 0x64: - case 0x68: - case 0x6c: - case 0x70: - case 0x72: - case 0x74: - case 0x78: - case 0x7c: - case 0x80: - case 0x84: - soundEvent(address&0xFF, (u8)(value & 0xFF)); - soundEvent((address&0xFF)+1, (u8)(value>>8)); - break; - case 0x82: - case 0x88: - case 0xa0: - case 0xa2: - case 0xa4: - case 0xa6: - case 0x90: - case 0x92: - case 0x94: - case 0x96: - case 0x98: - case 0x9a: - case 0x9c: - case 0x9e: - soundEvent(address&0xFF, value); - break; - case 0xB0: - DM0SAD_L = value; - UPDATE_REG(0xB0, DM0SAD_L); - break; - case 0xB2: - DM0SAD_H = value & 0x07FF; - UPDATE_REG(0xB2, DM0SAD_H); - break; - case 0xB4: - DM0DAD_L = value; - UPDATE_REG(0xB4, DM0DAD_L); - break; - case 0xB6: - DM0DAD_H = value & 0x07FF; - UPDATE_REG(0xB6, DM0DAD_H); - break; - case 0xB8: - DM0CNT_L = value & 0x3FFF; - UPDATE_REG(0xB8, 0); - break; - case 0xBA: - { - bool start = ((DM0CNT_H ^ value) & 0x8000) ? true : false; - value &= 0xF7E0; - - DM0CNT_H = value; - UPDATE_REG(0xBA, DM0CNT_H); - - if(start && (value & 0x8000)) - { - dma0Source = DM0SAD_L | (DM0SAD_H << 16); - dma0Dest = DM0DAD_L | (DM0DAD_H << 16); - CPUCheckDMA(0, 1); - } - } - break; - case 0xBC: - DM1SAD_L = value; - UPDATE_REG(0xBC, DM1SAD_L); - break; - case 0xBE: - DM1SAD_H = value & 0x0FFF; - UPDATE_REG(0xBE, DM1SAD_H); - break; - case 0xC0: - DM1DAD_L = value; - UPDATE_REG(0xC0, DM1DAD_L); - break; - case 0xC2: - DM1DAD_H = value & 0x07FF; - UPDATE_REG(0xC2, DM1DAD_H); - break; - case 0xC4: - DM1CNT_L = value & 0x3FFF; - UPDATE_REG(0xC4, 0); - break; - case 0xC6: - { - bool start = ((DM1CNT_H ^ value) & 0x8000) ? true : false; - value &= 0xF7E0; - - DM1CNT_H = value; - UPDATE_REG(0xC6, DM1CNT_H); - - if(start && (value & 0x8000)) - { - dma1Source = DM1SAD_L | (DM1SAD_H << 16); - dma1Dest = DM1DAD_L | (DM1DAD_H << 16); - CPUCheckDMA(0, 2); - } - } - break; - case 0xC8: - DM2SAD_L = value; - UPDATE_REG(0xC8, DM2SAD_L); - break; - case 0xCA: - DM2SAD_H = value & 0x0FFF; - UPDATE_REG(0xCA, DM2SAD_H); - break; - case 0xCC: - DM2DAD_L = value; - UPDATE_REG(0xCC, DM2DAD_L); - break; - case 0xCE: - DM2DAD_H = value & 0x07FF; - UPDATE_REG(0xCE, DM2DAD_H); - break; - case 0xD0: - DM2CNT_L = value & 0x3FFF; - UPDATE_REG(0xD0, 0); - break; - case 0xD2: - { - bool start = ((DM2CNT_H ^ value) & 0x8000) ? true : false; - - value &= 0xF7E0; - - DM2CNT_H = value; - UPDATE_REG(0xD2, DM2CNT_H); - - if(start && (value & 0x8000)) - { - dma2Source = DM2SAD_L | (DM2SAD_H << 16); - dma2Dest = DM2DAD_L | (DM2DAD_H << 16); - - CPUCheckDMA(0, 4); - } - } - break; - case 0xD4: - DM3SAD_L = value; - UPDATE_REG(0xD4, DM3SAD_L); - break; - case 0xD6: - DM3SAD_H = value & 0x0FFF; - UPDATE_REG(0xD6, DM3SAD_H); - break; - case 0xD8: - DM3DAD_L = value; - UPDATE_REG(0xD8, DM3DAD_L); - break; - case 0xDA: - DM3DAD_H = value & 0x0FFF; - UPDATE_REG(0xDA, DM3DAD_H); - break; - case 0xDC: - DM3CNT_L = value; - UPDATE_REG(0xDC, 0); - break; - case 0xDE: - { - bool start = ((DM3CNT_H ^ value) & 0x8000) ? true : false; - - value &= 0xFFE0; - - DM3CNT_H = value; - UPDATE_REG(0xDE, DM3CNT_H); - - if(start && (value & 0x8000)) - { - dma3Source = DM3SAD_L | (DM3SAD_H << 16); - dma3Dest = DM3DAD_L | (DM3DAD_H << 16); - CPUCheckDMA(0,8); - } - } - break; - case 0x100: - timer0Reload = value; - break; - case 0x102: - timer0Ticks = timer0ClockReload = TIMER_TICKS[value & 3]; - if(!timer0On && (value & 0x80)) - { - // reload the counter - TM0D = timer0Reload; - if(timer0ClockReload == 1) - timer0Ticks = 0x10000 - TM0D; - UPDATE_REG(0x100, TM0D); - } - timer0On = value & 0x80 ? true : false; - TM0CNT = value & 0xC7; - UPDATE_REG(0x102, TM0CNT); - // CPUUpdateTicks(); - break; - case 0x104: - timer1Reload = value; - break; - case 0x106: - timer1Ticks = timer1ClockReload = TIMER_TICKS[value & 3]; - if(!timer1On && (value & 0x80)) - { - // reload the counter - TM1D = timer1Reload; - if(timer1ClockReload == 1) - timer1Ticks = 0x10000 - TM1D; - UPDATE_REG(0x104, TM1D); - } - timer1On = value & 0x80 ? true : false; - TM1CNT = value & 0xC7; - UPDATE_REG(0x106, TM1CNT); - break; - case 0x108: - timer2Reload = value; - break; - case 0x10A: - timer2Ticks = timer2ClockReload = TIMER_TICKS[value & 3]; - if(!timer2On && (value & 0x80)) - { - // reload the counter - TM2D = timer2Reload; - if(timer2ClockReload == 1) - timer2Ticks = 0x10000 - TM2D; - UPDATE_REG(0x108, TM2D); - } - timer2On = value & 0x80 ? true : false; - TM2CNT = value & 0xC7; - UPDATE_REG(0x10A, TM2CNT); - break; - case 0x10C: - timer3Reload = value; - break; - case 0x10E: - timer3Ticks = timer3ClockReload = TIMER_TICKS[value & 3]; - if(!timer3On && (value & 0x80)) - { - // reload the counter - TM3D = timer3Reload; - if(timer3ClockReload == 1) - timer3Ticks = 0x10000 - TM3D; - UPDATE_REG(0x10C, TM3D); - } - timer3On = value & 0x80 ? true : false; - TM3CNT = value & 0xC7; - UPDATE_REG(0x10E, TM3CNT); - break; - case 0x128: - if(value & 0x80) - { - value &= 0xff7f; - if(value & 1 && (value & 0x4000)) - { - UPDATE_REG(0x12a, 0xFF); - IF |= 0x80; - UPDATE_REG(0x202, IF); - value &= 0x7f7f; - } - } - UPDATE_REG(0x128, value); - break; - case 0x130: - P1 |= (value & 0x3FF); - UPDATE_REG(0x130, P1); - break; - case 0x132: - UPDATE_REG(0x132, value & 0xC3FF); - break; - case 0x200: - IE = value & 0x3FFF; - UPDATE_REG(0x200, IE); - if((IME & 1) && (IF & IE) && armIrqEnable) - { - CPU_BREAK_LOOP_2; - } - break; - case 0x202: - IF ^= (value & IF); - UPDATE_REG(0x202, IF); - break; - case 0x204: - { - int i; - memoryWait[0x0e] = memoryWaitSeq[0x0e] = gamepakRamWaitState[value & 3]; - - if(!speedHack) - { - memoryWait[0x08] = memoryWait[0x09] = gamepakWaitState[(value >> 2) & 7]; - memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = - gamepakWaitState0[(value >> 2) & 7]; - - memoryWait[0x0a] = memoryWait[0x0b] = gamepakWaitState[(value >> 5) & 7]; - memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = - gamepakWaitState1[(value >> 5) & 7]; - - memoryWait[0x0c] = memoryWait[0x0d] = gamepakWaitState[(value >> 8) & 7]; - memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = - gamepakWaitState2[(value >> 8) & 7]; - } - else - { - memoryWait[0x08] = memoryWait[0x09] = 4; - memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = 2; - - memoryWait[0x0a] = memoryWait[0x0b] = 4; - memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = 4; - - memoryWait[0x0c] = memoryWait[0x0d] = 4; - memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = 8; - } - for(i = 0; i < 16; i++) - { - memoryWaitFetch32[i] = memoryWait32[i] = memoryWait[i] * - (memory32[i] ? 1 : 2); - memoryWaitFetch[i] = memoryWait[i]; - } - memoryWaitFetch32[3] += 1; - memoryWaitFetch32[2] += 3; - - if(value & 0x4000) - { - for(i = 8; i < 16; i++) - { - memoryWaitFetch32[i] = 2*cpuMemoryWait[i]; - memoryWaitFetch[i] = cpuMemoryWait[i]; - } - } - UPDATE_REG(0x204, value); - } - break; - case 0x208: - IME = value & 1; - UPDATE_REG(0x208, IME); - if((IME & 1) && (IF & IE) && armIrqEnable) - { - CPU_BREAK_LOOP_2; - } - break; - case 0x300: - if(value != 0) - value &= 0xFFFE; - UPDATE_REG(0x300, value); - break; - default: - UPDATE_REG(address&0x3FE, value); - break; - } -} - -void CPUWriteHalfWord(u32 address, u16 value) -{ -#ifdef DEV_VERSION - 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 SDL - if(*((u16 *)&freezeWorkRAM[address & 0x3FFFE])) - cheatsWriteHalfWord((u16 *)&workRAM[address & 0x3FFFE], - value, - *((u16 *)&freezeWorkRAM[address & 0x3FFFE])); - else -#endif - WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]),value); - break; - case 3: -#ifdef SDL - if(*((u16 *)&freezeInternalRAM[address & 0x7ffe])) - cheatsWriteHalfWord((u16 *)&internalRAM[address & 0x7ffe], - value, - *((u16 *)&freezeInternalRAM[address & 0x7ffe])); - else -#endif - WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value); - break; - case 4: - CPUUpdateRegister(address & 0x3fe, value); - break; - case 5: - WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value); - break; - case 6: - if(address & 0x10000) - WRITE16LE(((u16 *)&vram[address & 0x17ffe]), value); - else - WRITE16LE(((u16 *)&vram[address & 0x1fffe]), value); - break; - case 7: - 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 DEV_VERSION - if(systemVerbose & VERBOSE_ILLEGAL_WRITE) - { - log("Illegal halfword write: %04x to %08x from %08x\n", - value, - address, - armMode ? armNextPC - 4 : armNextPC - 2); - } -#endif - break; - } -} - -void CPUWriteByte(u32 address, u8 b) -{ - switch(address >> 24) - { - case 2: -#ifdef SDL - if(freezeWorkRAM[address & 0x3FFFF]) - cheatsWriteByte(&workRAM[address & 0x3FFFF], b); - else -#endif - workRAM[address & 0x3FFFF] = b; - break; - case 3: -#ifdef SDL - if(freezeInternalRAM[address & 0x7fff]) - cheatsWriteByte(&internalRAM[address & 0x7fff], b); - else -#endif - internalRAM[address & 0x7fff] = b; - break; - case 4: - switch(address & 0x3FF) - { - case 0x301: - if(b == 0x80) - stopState = true; - holdState = 1; - holdType = -1; - break; - 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; - default: - // if(address & 1) { - // CPUWriteHalfWord(address-1, (CPUReadHalfWord(address-1)&0x00FF)|((int)b<<8)); - // } else - if(address & 1) - CPUUpdateRegister(address & 0x3fe, - ((READ16LE(((u16 *)&ioMem[address & 0x3fe]))) - & 0x00FF) | - b<<8); - else - CPUUpdateRegister(address & 0x3fe, - ((READ16LE(((u16 *)&ioMem[address & 0x3fe])) & 0xFF00) | b)); - } - break; - case 5: - // no need to switch - *((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b; - break; - case 6: - // no need to switch - if(address & 0x10000) - *((u16 *)&vram[address & 0x17FFE]) = (b << 8) | b; - else - *((u16 *)&vram[address & 0x1FFFE]) = (b << 8) | b; - break; - case 7: - // no need to switch - *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b; - break; - case 13: - if(cpuEEPROMEnabled) - { - eepromWrite(address, b); - break; - } - goto unwritable; - case 14: - if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) - { - (*cpuSaveGameFunc)(address, b); - break; - } - // default - default: -unwritable: -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_ILLEGAL_WRITE) - { - log("Illegal byte write: %02x to %08x from %08x\n", - b, - address, - armMode ? armNextPC - 4 : armNextPC -2 ); - } -#endif - break; - } -} - -u8 cpuBitsSet[256]; -u8 cpuLowestBitSet[256]; - -void CPUInit(const char *biosFileName, bool useBiosFile) -{ -#ifdef WORDS_BIGENDIAN - if(!cpuBiosSwapped) - { - for(unsigned int i = 0; i < sizeof(myROM)/4; i++) - { - WRITE32LE(&myROM[i], myROM[i]); - } - cpuBiosSwapped = true; - } -#endif - gbaSaveType = 0; - eepromInUse = 0; - saveType = 0; - useBios = false; - - if(useBiosFile) - { -#if 0 - int size = 0x4000; - if(utilLoad(biosFileName, - CPUIsGBABios, - bios, - size)) - { - if(size == 0x4000) - useBios = true; - else - systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BIOS file size")); - } -#else - FILE* bfil; - int res; - bfil = gen_fopen(biosFileName, "rb"); - if ( bfil == NULL ) - { - useBios = false; - } - else - { - res = gen_fread(bios, 1, 0x4000, bfil); - gen_fclose(bfil); - useBios = true; - } -#endif - } - - if(!useBios) - { - memcpy(bios, myROM, sizeof(myROM)); - } - - int i = 0; - - biosProtected[0] = 0x00; - biosProtected[1] = 0xf0; - biosProtected[2] = 0x29; - biosProtected[3] = 0xe1; - - for(i = 0; i < 256; i++) - { - int count = 0; - int j; - for(j = 0; j < 8; j++) - if(i & (1 << j)) - count++; - cpuBitsSet[i] = count; - - for(j = 0; j < 8; j++) - if(i & (1 << j)) - break; - cpuLowestBitSet[i] = j; - } - - for(i = 0; i < 0x400; i++) - ioReadable[i] = true; - for(i = 0x10; i < 0x48; i++) - ioReadable[i] = false; - for(i = 0x4c; i < 0x50; i++) - ioReadable[i] = false; - for(i = 0x54; i < 0x60; i++) - ioReadable[i] = false; - for(i = 0x8c; i < 0x90; i++) - ioReadable[i] = false; - for(i = 0xa0; i < 0xb8; i++) - ioReadable[i] = false; - for(i = 0xbc; i < 0xc4; i++) - ioReadable[i] = false; - for(i = 0xc8; i < 0xd0; i++) - ioReadable[i] = false; - for(i = 0xd4; i < 0xdc; i++) - ioReadable[i] = false; - for(i = 0xe0; i < 0x100; i++) - ioReadable[i] = false; - for(i = 0x110; i < 0x120; i++) - ioReadable[i] = false; - for(i = 0x12c; i < 0x130; i++) - ioReadable[i] = false; - for(i = 0x138; i < 0x140; i++) - ioReadable[i] = false; - for(i = 0x144; i < 0x150; i++) - ioReadable[i] = false; - for(i = 0x15c; i < 0x200; i++) - ioReadable[i] = false; - for(i = 0x20c; i < 0x300; i++) - ioReadable[i] = false; - for(i = 0x304; i < 0x400; i++) - ioReadable[i] = false; - -#if 0 - *((u16 *)&rom[0x1fe209c]) = 0xdffa; // SWI 0xFA - *((u16 *)&rom[0x1fe209e]) = 0x4770; // BX LR -#endif - -} - -void CPUReset() -{ - if(gbaSaveType == 0) - { - if(eepromInUse) - gbaSaveType = 3; - else - switch(saveType) - { - case 1: - gbaSaveType = 1; - break; - case 2: - gbaSaveType = 2; - break; - } - } - rtcReset(); - // clen registers - memset(®[0], 0, sizeof(reg)); - // clean OAM - memset(oam, 0, 0x400); - // clean palette - memset(paletteRAM, 0, 0x400); - // clean picture - memset(pix, 0, 4*160*240); - // clean vram - memset(vram, 0, 0x20000); - // clean io memory - memset(ioMem, 0, 0x400); - - DISPCNT = 0x0080; - DISPSTAT = 0x0000; - VCOUNT = 0x0000; - BG0CNT = 0x0000; - BG1CNT = 0x0000; - BG2CNT = 0x0000; - BG3CNT = 0x0000; - BG0HOFS = 0x0000; - BG0VOFS = 0x0000; - BG1HOFS = 0x0000; - BG1VOFS = 0x0000; - BG2HOFS = 0x0000; - BG2VOFS = 0x0000; - BG3HOFS = 0x0000; - BG3VOFS = 0x0000; - BG2PA = 0x0100; - BG2PB = 0x0000; - BG2PC = 0x0000; - BG2PD = 0x0100; - BG2X_L = 0x0000; - BG2X_H = 0x0000; - BG2Y_L = 0x0000; - BG2Y_H = 0x0000; - BG3PA = 0x0100; - BG3PB = 0x0000; - BG3PC = 0x0000; - BG3PD = 0x0100; - BG3X_L = 0x0000; - BG3X_H = 0x0000; - BG3Y_L = 0x0000; - BG3Y_H = 0x0000; - WIN0H = 0x0000; - WIN1H = 0x0000; - WIN0V = 0x0000; - WIN1V = 0x0000; - WININ = 0x0000; - WINOUT = 0x0000; - MOSAIC = 0x0000; - BLDMOD = 0x0000; - COLEV = 0x0000; - COLY = 0x0000; - DM0SAD_L = 0x0000; - DM0SAD_H = 0x0000; - DM0DAD_L = 0x0000; - DM0DAD_H = 0x0000; - DM0CNT_L = 0x0000; - DM0CNT_H = 0x0000; - DM1SAD_L = 0x0000; - DM1SAD_H = 0x0000; - DM1DAD_L = 0x0000; - DM1DAD_H = 0x0000; - DM1CNT_L = 0x0000; - DM1CNT_H = 0x0000; - DM2SAD_L = 0x0000; - DM2SAD_H = 0x0000; - DM2DAD_L = 0x0000; - DM2DAD_H = 0x0000; - DM2CNT_L = 0x0000; - DM2CNT_H = 0x0000; - DM3SAD_L = 0x0000; - DM3SAD_H = 0x0000; - DM3DAD_L = 0x0000; - DM3DAD_H = 0x0000; - DM3CNT_L = 0x0000; - DM3CNT_H = 0x0000; - TM0D = 0x0000; - TM0CNT = 0x0000; - TM1D = 0x0000; - TM1CNT = 0x0000; - TM2D = 0x0000; - TM2CNT = 0x0000; - TM3D = 0x0000; - TM3CNT = 0x0000; - P1 = 0x03FF; - IE = 0x0000; - IF = 0x0000; - IME = 0x0000; - - armMode = 0x1F; - - if(cpuIsMultiBoot) - { - reg[13].I = 0x03007F00; - reg[15].I = 0x02000000; - reg[16].I = 0x00000000; - reg[R13_IRQ].I = 0x03007FA0; - reg[R13_SVC].I = 0x03007FE0; - armIrqEnable = true; - } - else - { - if(useBios && !skipBios) - { - reg[15].I = 0x00000000; - armMode = 0x13; - armIrqEnable = false; - } - else - { - reg[13].I = 0x03007F00; - reg[15].I = 0x08000000; - reg[16].I = 0x00000000; - reg[R13_IRQ].I = 0x03007FA0; - reg[R13_SVC].I = 0x03007FE0; - armIrqEnable = true; - } - } - armState = true; - C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false; - UPDATE_REG(0x00, DISPCNT); - UPDATE_REG(0x20, BG2PA); - UPDATE_REG(0x26, BG2PD); - UPDATE_REG(0x30, BG3PA); - UPDATE_REG(0x36, BG3PD); - UPDATE_REG(0x130, P1); - UPDATE_REG(0x88, 0x200); - - // disable FIQ - reg[16].I |= 0x40; - - CPUUpdateCPSR(); - - armNextPC = reg[15].I; - reg[15].I += 4; - - // reset internal state - holdState = false; - holdType = 0; - - biosProtected[0] = 0x00; - biosProtected[1] = 0xf0; - biosProtected[2] = 0x29; - biosProtected[3] = 0xe1; - - lcdTicks = 960; - timer0On = false; - timer0Ticks = 0; - timer0Reload = 0; - timer0ClockReload = 0; - timer1On = false; - timer1Ticks = 0; - timer1Reload = 0; - timer1ClockReload = 0; - timer2On = false; - timer2Ticks = 0; - timer2Reload = 0; - timer2ClockReload = 0; - timer3On = false; - timer3Ticks = 0; - timer3Reload = 0; - timer3ClockReload = 0; - dma0Source = 0; - dma0Dest = 0; - dma1Source = 0; - dma1Dest = 0; - dma2Source = 0; - dma2Dest = 0; - dma3Source = 0; - dma3Dest = 0; - cpuSaveGameFunc = flashSaveDecide; - renderLine = mode0RenderLine; - fxOn = false; - windowOn = false; - frameCount = 0; - saveType = 0; - layerEnable = DISPCNT & layerSettings; - - CPUUpdateRenderBuffers(true); - - for(int i = 0; i < 256; i++) - { - map[i].address = (u8 *)&dummyAddress; - map[i].mask = 0; - } - - map[0].address = bios; - map[0].mask = 0x3FFF; - map[2].address = workRAM; - map[2].mask = 0x3FFFF; - map[3].address = internalRAM; - map[3].mask = 0x7FFF; - map[4].address = ioMem; - map[4].mask = 0x3FF; - map[5].address = paletteRAM; - map[5].mask = 0x3FF; - map[6].address = vram; - map[6].mask = 0x1FFFF; - map[7].address = oam; - map[7].mask = 0x3FF; - map[8].address = rom; - map[8].mask = 0x1FFFFFF; - map[9].address = rom; - map[9].mask = 0x1FFFFFF; - map[10].address = rom; - map[10].mask = 0x1FFFFFF; - map[12].address = rom; - map[12].mask = 0x1FFFFFF; - map[14].address = flashSaveMemory; - map[14].mask = 0xFFFF; - - eepromReset(); - flashReset(); - - soundReset(); - - CPUUpdateWindow0(); - CPUUpdateWindow1(); - - // make sure registers are correctly initialized if not using BIOS - if(!useBios) - { - if(cpuIsMultiBoot) - BIOS_RegisterRamReset(0xfe); - else - BIOS_RegisterRamReset(0xff); - } - else - { - if(cpuIsMultiBoot) - BIOS_RegisterRamReset(0xfe); - } - - switch(cpuSaveType) - { - case 0: // automatic - cpuSramEnabled = true; - cpuFlashEnabled = true; - cpuEEPROMEnabled = true; - cpuEEPROMSensorEnabled = false; - break; - case 1: // EEPROM - cpuSramEnabled = false; - cpuFlashEnabled = false; - cpuEEPROMEnabled = true; - cpuEEPROMSensorEnabled = false; - break; - case 2: // SRAM - cpuSramEnabled = true; - cpuFlashEnabled = false; - cpuEEPROMEnabled = false; - cpuEEPROMSensorEnabled = false; - cpuSaveGameFunc = sramWrite; - break; - case 3: // FLASH - cpuSramEnabled = false; - cpuFlashEnabled = true; - cpuEEPROMEnabled = false; - cpuEEPROMSensorEnabled = false; - cpuSaveGameFunc = flashWrite; - break; - case 4: // EEPROM+Sensor - cpuSramEnabled = false; - cpuFlashEnabled = false; - cpuEEPROMEnabled = true; - cpuEEPROMSensorEnabled = true; - break; - case 5: // NONE - cpuSramEnabled = false; - cpuFlashEnabled = false; - cpuEEPROMEnabled = false; - cpuEEPROMSensorEnabled = false; - break; - } - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - lastTime = systemGetClock(); -} - -void CPUInterrupt() -{ - u32 PC = reg[15].I; - bool savedState = armState; - CPUSwitchMode(0x12, true, false); - reg[14].I = PC; - if(!savedState) - reg[14].I += 2; - reg[15].I = 0x18; - armState = true; - armIrqEnable = false; - - armNextPC = reg[15].I; - reg[15].I += 4; - - // if(!holdState) - biosProtected[0] = 0x02; - biosProtected[1] = 0xc0; - biosProtected[2] = 0x5e; - biosProtected[3] = 0xe5; -} - -void log(const char *defaultMsg, ...) -{ -#if 0 - char buffer[2048]; - va_list valist; - - va_start(valist, defaultMsg); - vsprintf(buffer, defaultMsg, valist); - - if(out == NULL) - { - out = gen_fopen("trace.log","w"); - } - - fputs(buffer, out); - - va_end(valist); -#endif -} - -void CPULoop(int ticks) -{ - int clockTicks; - int cpuLoopTicks = 0; - int timerOverflow = 0; - // variables used by the CPU core - - extCpuLoopTicks = &cpuLoopTicks; - extClockTicks = &clockTicks; - extTicks = &ticks; - - cpuLoopTicks = CPUUpdateTicks(); - if(cpuLoopTicks > ticks) - { - cpuLoopTicks = ticks; - cpuSavedTicks = ticks; - } - - if(intState) - { - cpuLoopTicks = 5; - cpuSavedTicks = 5; - } - - for(;;) - { -#ifndef FINAL_VERSION - if(systemDebug) - { - if(systemDebug >= 10 && !holdState) - { - CPUUpdateCPSR(); - sprintf(buffer, "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n", - reg[0].I, reg[1].I, reg[2].I, reg[3].I, reg[4].I, reg[5].I, - reg[6].I, reg[7].I, reg[8].I, reg[9].I, reg[10].I, reg[11].I, - reg[12].I, reg[13].I, reg[14].I, reg[15].I, reg[16].I, - reg[17].I); -#ifdef SDL - log(buffer); -#else - winlog(buffer); -#endif - } - else if(!holdState) - { - sprintf(buffer, "PC=%08x\n", armNextPC); -#ifdef SDL - log(buffer); -#else - winlog(buffer); -#endif - } - } -#endif - - if(!holdState) - { - if(armState) - { -#include "arm-new.h" - } - else - { -#include "thumb.h" - } - } - else - { - clockTicks = lcdTicks; - - if(soundTicks < clockTicks) - clockTicks = soundTicks; - - if(timer0On && (timer0Ticks < clockTicks)) - { - clockTicks = timer0Ticks; - } - if(timer1On && (timer1Ticks < clockTicks)) - { - clockTicks = timer1Ticks; - } - if(timer2On && (timer2Ticks < clockTicks)) - { - clockTicks = timer2Ticks; - } - if(timer3On && (timer3Ticks < clockTicks)) - { - clockTicks = timer3Ticks; - } -#ifdef PROFILING - if(profilingTicksReload != 0) - { - if(profilingTicks < clockTicks) - { - clockTicks = profilingTicks; - } - } -#endif - } - - cpuLoopTicks -= clockTicks; - if((cpuLoopTicks <= 0)) - { - if(cpuSavedTicks) - { - clockTicks = cpuSavedTicks;// + cpuLoopTicks; - } - cpuDmaTicksToUpdate = -cpuLoopTicks; - -updateLoop: - lcdTicks -= clockTicks; - - if(lcdTicks <= 0) - { - if(DISPSTAT & 1) - { // V-BLANK - // if in V-Blank mode, keep computing... - if(DISPSTAT & 2) - { - lcdTicks += 960; - VCOUNT++; - UPDATE_REG(0x06, VCOUNT); - DISPSTAT &= 0xFFFD; - UPDATE_REG(0x04, DISPSTAT); - CPUCompareVCOUNT(); - } - else - { - lcdTicks += 272; - DISPSTAT |= 2; - UPDATE_REG(0x04, DISPSTAT); - if(DISPSTAT & 16) - { - IF |= 2; - UPDATE_REG(0x202, IF); - } - } - - if(VCOUNT >= 228) - { - DISPSTAT &= 0xFFFC; - UPDATE_REG(0x04, DISPSTAT); - VCOUNT = 0; - UPDATE_REG(0x06, VCOUNT); - CPUCompareVCOUNT(); - } - } - else - { - int framesToSkip = systemFrameSkip; - if(speedup) - framesToSkip = 9; // try 6 FPS during speedup - - if(DISPSTAT & 2) - { - // if in H-Blank, leave it and move to drawing mode - VCOUNT++; - UPDATE_REG(0x06, VCOUNT); - - lcdTicks += (960); - DISPSTAT &= 0xFFFD; - if(VCOUNT == 160) - { - count++; - systemFrame(); - - if((count % 10) == 0) - { - system10Frames(60); - } - if(count == 60) - { - u32 time = systemGetClock(); - if(time != lastTime) - { - u32 t = 100000/(time - lastTime); - systemShowSpeed(t); - } - else - systemShowSpeed(0); - lastTime = time; - count = 0; - } - u32 joy = 0; - // update joystick information - if(systemReadJoypads()) - // read default joystick - joy = systemReadJoypad(-1); - P1 = 0x03FF ^ (joy & 0x3FF); - if(cpuEEPROMSensorEnabled) - systemUpdateMotionSensor(); - UPDATE_REG(0x130, P1); - u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132])); - // this seems wrong, but there are cases where the game - // can enter the stop state without requesting an IRQ from - // the joypad. - if((P1CNT & 0x4000) || stopState) - { - u16 p1 = (0x3FF ^ P1) & 0x3FF; - if(P1CNT & 0x8000) - { - if(p1 == (P1CNT & 0x3FF)) - { - IF |= 0x1000; - UPDATE_REG(0x202, IF); - } - } - else - { - if(p1 & P1CNT) - { - IF |= 0x1000; - UPDATE_REG(0x202, IF); - } - } - } - - u32 ext = (joy >> 10); - int cheatTicks = 0; - if(cheatsEnabled) - cheatsCheckKeys(P1^0x3FF, ext); - cpuDmaTicksToUpdate += cheatTicks; - speedup = (ext & 1) ? true : false; - capture = (ext & 2) ? true : false; - - if(capture && !capturePrevious) - { - captureNumber++; - systemScreenCapture(captureNumber); - } - capturePrevious = capture; - - DISPSTAT |= 1; - DISPSTAT &= 0xFFFD; - UPDATE_REG(0x04, DISPSTAT); - if(DISPSTAT & 0x0008) - { - IF |= 1; - UPDATE_REG(0x202, IF); - } - CPUCheckDMA(1, 0x0f); - if(frameCount >= framesToSkip) - { - systemDrawScreen(); - frameCount = 0; - } - else - frameCount++; - if(systemPauseOnFrame()) - ticks = 0; - } - - UPDATE_REG(0x04, DISPSTAT); - - CPUCompareVCOUNT(); - } - else - { - if(frameCount >= framesToSkip) - { - (*renderLine)(); - - switch(systemColorDepth) - { - case 16: - { - u16 *dest = (u16 *)pix + 242 * (VCOUNT+1); - for(int x = 0; x < 240;) - { - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - *dest++ = systemColorMap16[lineMix[x++]&0xFFFF]; - } - // for filters that read past the screen - *dest++ = 0; - } - break; - case 24: - { - u8 *dest = (u8 *)pix + 240 * VCOUNT * 3; - for(int x = 0; x < 240;) - { - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF]; - dest += 3; - } - } - break; - case 32: - { - u32 *dest = (u32 *)pix + 241 * (VCOUNT+1); - for(int x = 0; x < 240; ) - { - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF]; - } - } - break; - } - } - // entering H-Blank - DISPSTAT |= 2; - UPDATE_REG(0x04, DISPSTAT); - lcdTicks += 272; - CPUCheckDMA(2, 0x0f); - if(DISPSTAT & 16) - { - IF |= 2; - UPDATE_REG(0x202, IF); - } - } - } - } - - if(!stopState) - { - if(timer0On) - { - if(timer0ClockReload == 1) - { - u32 tm0d = TM0D + clockTicks; - if(tm0d > 0xffff) - { - tm0d += timer0Reload; - timerOverflow |= 1; - soundTimerOverflow(0); - if(TM0CNT & 0x40) - { - IF |= 0x08; - UPDATE_REG(0x202, IF); - } - } - TM0D = tm0d; - timer0Ticks = 0x10000 - TM0D; - UPDATE_REG(0x100, TM0D); - } - else - { - timer0Ticks -= clockTicks; - if(timer0Ticks <= 0) - { - timer0Ticks += timer0ClockReload; - TM0D++; - if(TM0D == 0) - { - TM0D = timer0Reload; - timerOverflow |= 1; - soundTimerOverflow(0); - if(TM0CNT & 0x40) - { - IF |= 0x08; - UPDATE_REG(0x202, IF); - } - } - UPDATE_REG(0x100, TM0D); - } - } - } - - if(timer1On) - { - if(TM1CNT & 4) - { - if(timerOverflow & 1) - { - TM1D++; - if(TM1D == 0) - { - TM1D += timer1Reload; - timerOverflow |= 2; - soundTimerOverflow(1); - if(TM1CNT & 0x40) - { - IF |= 0x10; - UPDATE_REG(0x202, IF); - } - } - UPDATE_REG(0x104, TM1D); - } - } - else - { - if(timer1ClockReload == 1) - { - u32 tm1d = TM1D + clockTicks; - if(tm1d > 0xffff) - { - tm1d += timer1Reload; - timerOverflow |= 2; - soundTimerOverflow(1); - if(TM1CNT & 0x40) - { - IF |= 0x10; - UPDATE_REG(0x202, IF); - } - } - TM1D = tm1d; - timer1Ticks = 0x10000 - TM1D; - UPDATE_REG(0x104, TM1D); - } - else - { - timer1Ticks -= clockTicks; - if(timer1Ticks <= 0) - { - timer1Ticks += timer1ClockReload; - TM1D++; - - if(TM1D == 0) - { - TM1D = timer1Reload; - timerOverflow |= 2; - soundTimerOverflow(1); - if(TM1CNT & 0x40) - { - IF |= 0x10; - UPDATE_REG(0x202, IF); - } - } - UPDATE_REG(0x104, TM1D); - } - } - } - } - - if(timer2On) - { - if(TM2CNT & 4) - { - if(timerOverflow & 2) - { - TM2D++; - if(TM2D == 0) - { - TM2D += timer2Reload; - timerOverflow |= 4; - if(TM2CNT & 0x40) - { - IF |= 0x20; - UPDATE_REG(0x202, IF); - } - } - UPDATE_REG(0x108, TM2D); - } - } - else - { - if(timer2ClockReload == 1) - { - u32 tm2d = TM2D + clockTicks; - if(tm2d > 0xffff) - { - tm2d += timer2Reload; - timerOverflow |= 4; - if(TM2CNT & 0x40) - { - IF |= 0x20; - UPDATE_REG(0x202, IF); - } - } - TM2D = tm2d; - timer2Ticks = 0x10000 - TM2D; - UPDATE_REG(0x108, TM2D); - } - else - { - timer2Ticks -= clockTicks; - if(timer2Ticks <= 0) - { - timer2Ticks += timer2ClockReload; - TM2D++; - - if(TM2D == 0) - { - TM2D = timer2Reload; - timerOverflow |= 4; - if(TM2CNT & 0x40) - { - IF |= 0x20; - UPDATE_REG(0x202, IF); - } - } - UPDATE_REG(0x108, TM2D); - } - } - } - } - - if(timer3On) - { - if(TM3CNT & 4) - { - if(timerOverflow & 4) - { - TM3D++; - if(TM3D == 0) - { - TM3D += timer3Reload; - if(TM3CNT & 0x40) - { - IF |= 0x40; - UPDATE_REG(0x202, IF); - } - } - UPDATE_REG(0x10c, TM3D); - } - } - else - { - if(timer3ClockReload == 1) - { - u32 tm3d = TM3D + clockTicks; - if(tm3d > 0xffff) - { - tm3d += timer3Reload; - if(TM3CNT & 0x40) - { - IF |= 0x40; - UPDATE_REG(0x202, IF); - } - } - TM3D = tm3d; - timer3Ticks = 0x10000 - TM3D; - UPDATE_REG(0x10C, TM3D); - } - else - { - timer3Ticks -= clockTicks; - if(timer3Ticks <= 0) - { - timer3Ticks += timer3ClockReload; - TM3D++; - - if(TM3D == 0) - { - TM3D = timer3Reload; - if(TM3CNT & 0x40) - { - IF |= 0x40; - UPDATE_REG(0x202, IF); - } - } - UPDATE_REG(0x10C, TM3D); - } - } - } - } - } - // we shouldn't be doing sound in stop state, but we lose synchronization - // if sound is disabled, so in stop state, soundTick will just produce - // mute sound - soundTicks -= clockTicks; - if(soundTicks <= 0) - { - soundTick(); - soundTicks += SOUND_CLOCK_TICKS; - } - timerOverflow = 0; - -#ifdef PROFILING - profilingTicks -= clockTicks; - if(profilingTicks <= 0) - { - profilingTicks += profilingTicksReload; - if(profilBuffer && profilSize) - { - u16 *b = (u16 *)profilBuffer; - int pc = ((reg[15].I - profilLowPC) * profilScale)/0x10000; - if(pc >= 0 && pc < profilSize) - { - b[pc]++; - } - } - } -#endif - - ticks -= clockTicks; - - cpuLoopTicks = CPUUpdateTicks(); - - if(cpuDmaTicksToUpdate > 0) - { - clockTicks = cpuSavedTicks; - if(clockTicks > cpuDmaTicksToUpdate) - clockTicks = cpuDmaTicksToUpdate; - cpuDmaTicksToUpdate -= clockTicks; - if(cpuDmaTicksToUpdate < 0) - cpuDmaTicksToUpdate = 0; - goto updateLoop; - } - - if(IF && (IME & 1) && armIrqEnable) - { - int res = IF & IE; - if(stopState) - res &= 0x3080; - if(res) - { - if(intState) - { - CPUInterrupt(); - intState = false; - if(holdState) - { - holdState = false; - stopState = false; - } - } - else - { - if(!holdState) - { - intState = true; - cpuLoopTicks = 5; - cpuSavedTicks = 5; - } - else - { - CPUInterrupt(); - if(holdState) - { - holdState = false; - stopState = false; - } - } - } - } - } - - if(ticks <= 0) - break; - } - } -} - -struct EmulatedSystem GBASystem = - { - // emuMain - CPULoop, - // emuReset - CPUReset, - // emuCleanUp - CPUCleanUp, - // emuReadBattery - CPUReadBatteryFile, - // emuWriteBattery - CPUWriteBatteryFile, - // emuReadState - CPUReadState, - // emuWriteState - CPUWriteState, - // emuReadMemState - CPUReadMemState, - // emuWriteMemState - CPUWriteMemState, - // emuWritePNG - CPUWritePNGFile, - // emuWriteBMP - CPUWriteBMPFile, - // emuUpdateCPSR - CPUUpdateCPSR, - // emuHasDebugger - true, - // emuCount -#ifdef FINAL_VERSION - 250000 -#else - 5000 -#endif - }; diff --git a/source/vba/GBAinline.h b/source/vba/GBAinline.h deleted file mode 100644 index f4fc4c7..0000000 --- a/source/vba/GBAinline.h +++ /dev/null @@ -1,556 +0,0 @@ -// -*- 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 diff --git a/source/vba/Gfx.h b/source/vba/Gfx.h deleted file mode 100644 index 36c6592..0000000 --- a/source/vba/Gfx.h +++ /dev/null @@ -1,1809 +0,0 @@ -// -*- 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_GFX_H -#define VBA_GFX_H - -#include "GBA.h" -#include "Gfx.h" -#include "Globals.h" - -#include "Port.h" - -//#define SPRITE_DEBUG - -void gfxDrawTextScreen(u16, u16, u16, u32 *); -void gfxDrawRotScreen(u16, - u16, u16, - u16, u16, - u16, u16, - u16, u16, - int&, int&, - int, - u32*); -void gfxDrawRotScreen16Bit(u16, - u16, u16, - u16, u16, - u16, u16, - u16, u16, - int&, int&, - int, - u32*); -void gfxDrawRotScreen256(u16, - u16, u16, - u16, u16, - u16, u16, - u16, u16, - int&, int&, - int, - u32*); -void gfxDrawRotScreen16Bit160(u16, - u16, u16, - u16, u16, - u16, u16, - u16, u16, - int&, int&, - int, - u32*); -void gfxDrawSprites(u32 *); -void gfxIncreaseBrightness(u32 *line, int coeff); -void gfxDecreaseBrightness(u32 *line, int coeff); -void gfxAlphaBlend(u32 *ta, u32 *tb, int ca, int cb); - -void mode0RenderLine(); -void mode0RenderLineNoWindow(); -void mode0RenderLineAll(); - -void mode1RenderLine(); -void mode1RenderLineNoWindow(); -void mode1RenderLineAll(); - -void mode2RenderLine(); -void mode2RenderLineNoWindow(); -void mode2RenderLineAll(); - -void mode3RenderLine(); -void mode3RenderLineNoWindow(); -void mode3RenderLineAll(); - -void mode4RenderLine(); -void mode4RenderLineNoWindow(); -void mode4RenderLineAll(); - -void mode5RenderLine(); -void mode5RenderLineNoWindow(); -void mode5RenderLineAll(); - -extern int coeff[32]; -extern u32 line0[240]; -extern u32 line1[240]; -extern u32 line2[240]; -extern u32 line3[240]; -extern u32 lineOBJ[240]; -extern u32 lineOBJWin[240]; -extern u32 lineMix[240]; -extern bool gfxInWin0[240]; -extern bool gfxInWin1[240]; - -extern int gfxBG2Changed; -extern int gfxBG3Changed; - -extern int gfxBG2X; -extern int gfxBG2Y; -extern int gfxBG2LastX; -extern int gfxBG2LastY; -extern int gfxBG3X; -extern int gfxBG3Y; -extern int gfxBG3LastX; -extern int gfxBG3LastY; -extern int gfxLastVCOUNT; - -inline void gfxClearArray(u32 *array) -{ - for(int i = 0; i < 240; i++) - { - *array++ = 0x80000000; - } -} - -inline void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs, - u32 *line) -{ - u16 *palette = (u16 *)paletteRAM; - u8 *charBase = &vram[((control >> 2) & 0x03) * 0x4000]; - u16 *screenBase = (u16 *)&vram[((control >> 8) & 0x1f) * 0x800]; - u32 prio = ((control & 3)<<25) + 0x1000000; - int sizeX = 256; - int sizeY = 256; - switch((control >> 14) & 3) - { - case 0: - break; - case 1: - sizeX = 512; - break; - case 2: - sizeY = 512; - break; - case 3: - sizeX = 512; - sizeY = 512; - break; - } - - int maskX = sizeX-1; - int maskY = sizeY-1; - - bool mosaicOn = (control & 0x40) ? true : false; - - int xxx = hofs & maskX; - int yyy = (vofs + VCOUNT) & maskY; - int mosaicX = (MOSAIC & 0x000F)+1; - int mosaicY = ((MOSAIC & 0x00F0)>>4)+1; - - if(mosaicOn) - { - if((VCOUNT % mosaicY) != 0) - { - mosaicY = (VCOUNT / mosaicY) * mosaicY; - yyy = (vofs + mosaicY) & maskY; - } - } - - if(yyy > 255 && sizeY > 256) - { - yyy &= 255; - screenBase += 0x400; - if(sizeX > 256) - screenBase += 0x400; - } - - int yshift = ((yyy>>3)<<5); - if((control) & 0x80) - { - u16 *screenSource = screenBase + 0x400 * (xxx>>8) + ((xxx & 255)>>3) + yshift; - for(int x = 0; x < 240; x++) - { - u16 data = READ16LE(screenSource); - - int tile = data & 0x3FF; - int tileX = (xxx & 7); - int tileY = yyy & 7; - - if(data & 0x0400) - tileX = 7 - tileX; - if(data & 0x0800) - tileY = 7 - tileY; - - u8 color = charBase[tile * 64 + tileY * 8 + tileX]; - - line[x] = color ? (READ16LE(&palette[color]) | prio): 0x80000000; - - if(data & 0x0400) - { - if(tileX == 0) - screenSource++; - } - else if(tileX == 7) - screenSource++; - xxx++; - if(xxx == 256) - { - if(sizeX > 256) - screenSource = screenBase + 0x400 + yshift; - else - { - screenSource = screenBase + yshift; - xxx = 0; - } - } - else if(xxx >= sizeX) - { - xxx = 0; - screenSource = screenBase + yshift; - } - } - } - else - { - u16 *screenSource = screenBase + 0x400*(xxx>>8)+((xxx&255)>>3) + - yshift; - for(int x = 0; x < 240; x++) - { - u16 data = READ16LE(screenSource); - - int tile = data & 0x3FF; - int tileX = (xxx & 7); - int tileY = yyy & 7; - - if(data & 0x0400) - tileX = 7 - tileX; - if(data & 0x0800) - tileY = 7 - tileY; - - u8 color = charBase[(tile<<5) + (tileY<<2) + (tileX>>1)]; - - if(tileX & 1) - { - color = (color >> 4); - } - else - { - color &= 0x0F; - } - - int pal = (READ16LE(screenSource)>>8) & 0xF0; - line[x] = color ? (READ16LE(&palette[pal + color])|prio): 0x80000000; - - if(data & 0x0400) - { - if(tileX == 0) - screenSource++; - } - else if(tileX == 7) - screenSource++; - xxx++; - if(xxx == 256) - { - if(sizeX > 256) - screenSource = screenBase + 0x400 + yshift; - else - { - screenSource = screenBase + yshift; - xxx = 0; - } - } - else if(xxx >= sizeX) - { - xxx = 0; - screenSource = screenBase + yshift; - } - } - } - if(mosaicOn) - { - if(mosaicX > 1) - { - int m = 1; - for(int i = 0; i < 239; i++) - { - line[i+1] = line[i]; - m++; - if(m == mosaicX) - { - m = 1; - i++; - } - } - } - } -} - -inline void gfxDrawRotScreen(u16 control, - u16 x_l, u16 x_h, - u16 y_l, u16 y_h, - u16 pa, u16 pb, - u16 pc, u16 pd, - int& currentX, int& currentY, - int changed, - u32 *line) -{ - u16 *palette = (u16 *)paletteRAM; - u8 *charBase = &vram[((control >> 2) & 0x03) * 0x4000]; - u8 *screenBase = (u8 *)&vram[((control >> 8) & 0x1f) * 0x800]; - int prio = ((control & 3) << 25) + 0x1000000; - - int sizeX = 128; - int sizeY = 128; - switch((control >> 14) & 3) - { - case 0: - break; - case 1: - sizeX = sizeY = 256; - break; - case 2: - sizeX = sizeY = 512; - break; - case 3: - sizeX = sizeY = 1024; - break; - } - - int dx = pa & 0x7FFF; - if(pa & 0x8000) - dx |= 0xFFFF8000; - int dmx = pb & 0x7FFF; - if(pb & 0x8000) - dmx |= 0xFFFF8000; - int dy = pc & 0x7FFF; - if(pc & 0x8000) - dy |= 0xFFFF8000; - int dmy = pd & 0x7FFFF; - if(pd & 0x8000) - dmy |= 0xFFFF8000; - - if(VCOUNT == 0) - changed = 3; - - if(changed & 1) - { - currentX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - currentX |= 0xF8000000; - } - else - { - currentX += dmx; - } - - if(changed & 2) - { - currentY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - currentY |= 0xF8000000; - } - else - { - currentY += dmy; - } - - int realX = currentX; - int realY = currentY; - - if(control & 0x40) - { - int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; - int y = (VCOUNT % mosaicY); - realX -= y*dmx; - realY -= y*dmy; - } - - int xxx = (realX >> 8); - int yyy = (realY >> 8); - - if(control & 0x2000) - { - xxx %= sizeX; - yyy %= sizeY; - if(xxx < 0) - xxx += sizeX; - if(yyy < 0) - yyy += sizeY; - } - - if(control & 0x80) - { - for(int x = 0; x < 240; x++) - { - if(xxx < 0 || - yyy < 0 || - xxx >= sizeX || - yyy >= sizeY) - { - line[x] = 0x80000000; - } - else - { - int tile = screenBase[(xxx>>3) + (yyy>>3)*(sizeX>>3)]; - - int tileX = (xxx & 7); - int tileY = yyy & 7; - - u8 color = charBase[(tile<<6) + (tileY<<3) + tileX]; - - line[x] = color ? (READ16LE(&palette[color])|prio): 0x80000000; - } - realX += dx; - realY += dy; - - xxx = (realX >> 8); - yyy = (realY >> 8); - - if(control & 0x2000) - { - xxx %= sizeX; - yyy %= sizeY; - if(xxx < 0) - xxx += sizeX; - if(yyy < 0) - yyy += sizeY; - } - } - } - else - { - for(int x = 0; x < 240; x++) - { - if(xxx < 0 || - yyy < 0 || - xxx >= sizeX || - yyy >= sizeY) - { - line[x] = 0x80000000; - } - else - { - int tile = screenBase[(xxx>>3) + (yyy>>3)*(sizeX>>3)]; - - int tileX = (xxx & 7); - int tileY = yyy & 7; - - u8 color = charBase[(tile<<6) + (tileY<<3) + tileX]; - - line[x] = color ? (READ16LE(&palette[color])|prio): 0x80000000; - } - realX += dx; - realY += dy; - - xxx = (realX >> 8); - yyy = (realY >> 8); - - if(control & 0x2000) - { - xxx %= sizeX; - yyy %= sizeY; - if(xxx < 0) - xxx += sizeX; - if(yyy < 0) - yyy += sizeY; - } - } - } - - if(control & 0x40) - { - int mosaicX = (MOSAIC & 0xF) + 1; - if(mosaicX > 1) - { - int m = 1; - for(int i = 0; i < 239; i++) - { - line[i+1] = line[i]; - m++; - if(m == mosaicX) - { - m = 1; - i++; - } - } - } - } -} - -inline void gfxDrawRotScreen16Bit(u16 control, - u16 x_l, u16 x_h, - u16 y_l, u16 y_h, - u16 pa, u16 pb, - u16 pc, u16 pd, - int& currentX, int& currentY, - int changed, - u32 *line) -{ - u16 *screenBase = (u16 *)&vram[0]; - int prio = ((control & 3) << 25) + 0x1000000; - int sizeX = 240; - int sizeY = 160; - - int startX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - startX |= 0xF8000000; - int startY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - startY |= 0xF8000000; - - int dx = pa & 0x7FFF; - if(pa & 0x8000) - dx |= 0xFFFF8000; - int dmx = pb & 0x7FFF; - if(pb & 0x8000) - dmx |= 0xFFFF8000; - int dy = pc & 0x7FFF; - if(pc & 0x8000) - dy |= 0xFFFF8000; - int dmy = pd & 0x7FFFF; - if(pd & 0x8000) - dmy |= 0xFFFF8000; - - if(VCOUNT == 0) - changed = 3; - - if(changed & 1) - { - currentX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - currentX |= 0xF8000000; - } - else - currentX += dmx; - - if(changed & 2) - { - currentY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - currentY |= 0xF8000000; - } - else - { - currentY += dmy; - } - - int realX = currentX; - int realY = currentY; - - if(control & 0x40) - { - int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; - int y = (VCOUNT % mosaicY); - realX -= y*dmx; - realY -= y*dmy; - } - - int xxx = (realX >> 8); - int yyy = (realY >> 8); - - for(int x = 0; x < 240; x++) - { - if(xxx < 0 || - yyy < 0 || - xxx >= sizeX || - yyy >= sizeY) - { - line[x] = 0x80000000; - } - else - { - line[x] = (READ16LE(&screenBase[yyy * sizeX + xxx]) | prio); - } - realX += dx; - realY += dy; - - xxx = (realX >> 8); - yyy = (realY >> 8); - } - - if(control & 0x40) - { - int mosaicX = (MOSAIC & 0xF) + 1; - if(mosaicX > 1) - { - int m = 1; - for(int i = 0; i < 239; i++) - { - line[i+1] = line[i]; - m++; - if(m == mosaicX) - { - m = 1; - i++; - } - } - } - } -} - -inline void gfxDrawRotScreen256(u16 control, - u16 x_l, u16 x_h, - u16 y_l, u16 y_h, - u16 pa, u16 pb, - u16 pc, u16 pd, - int ¤tX, int& currentY, - int changed, - u32 *line) -{ - u16 *palette = (u16 *)paletteRAM; - u8 *screenBase = (DISPCNT & 0x0010) ? &vram[0xA000] : &vram[0x0000]; - int prio = ((control & 3) << 25) + 0x1000000; - int sizeX = 240; - int sizeY = 160; - - int startX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - startX |= 0xF8000000; - int startY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - startY |= 0xF8000000; - - int dx = pa & 0x7FFF; - if(pa & 0x8000) - dx |= 0xFFFF8000; - int dmx = pb & 0x7FFF; - if(pb & 0x8000) - dmx |= 0xFFFF8000; - int dy = pc & 0x7FFF; - if(pc & 0x8000) - dy |= 0xFFFF8000; - int dmy = pd & 0x7FFFF; - if(pd & 0x8000) - dmy |= 0xFFFF8000; - - if(VCOUNT == 0) - changed = 3; - - if(changed & 1) - { - currentX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - currentX |= 0xF8000000; - } - else - { - currentX += dmx; - } - - if(changed & 2) - { - currentY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - currentY |= 0xF8000000; - } - else - { - currentY += dmy; - } - - int realX = currentX; - int realY = currentY; - - if(control & 0x40) - { - int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; - int y = (VCOUNT / mosaicY) * mosaicY; - realX = startX + y*dmx; - realY = startY + y*dmy; - } - - int xxx = (realX >> 8); - int yyy = (realY >> 8); - - for(int x = 0; x < 240; x++) - { - if(xxx < 0 || - yyy < 0 || - xxx >= sizeX || - yyy >= sizeY) - { - line[x] = 0x80000000; - } - else - { - u8 color = screenBase[yyy * 240 + xxx]; - - line[x] = color ? (READ16LE(&palette[color])|prio): 0x80000000; - } - realX += dx; - realY += dy; - - xxx = (realX >> 8); - yyy = (realY >> 8); - } - - if(control & 0x40) - { - int mosaicX = (MOSAIC & 0xF) + 1; - if(mosaicX > 1) - { - int m = 1; - for(int i = 0; i < 239; i++) - { - line[i+1] = line[i]; - m++; - if(m == mosaicX) - { - m = 1; - i++; - } - } - } - } -} - -inline void gfxDrawRotScreen16Bit160(u16 control, - u16 x_l, u16 x_h, - u16 y_l, u16 y_h, - u16 pa, u16 pb, - u16 pc, u16 pd, - int& currentX, int& currentY, - int changed, - u32 *line) -{ - u16 *screenBase = (DISPCNT & 0x0010) ? (u16 *)&vram[0xa000] : - (u16 *)&vram[0]; - int prio = ((control & 3) << 25) + 0x1000000; - int sizeX = 160; - int sizeY = 128; - - int startX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - startX |= 0xF8000000; - int startY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - startY |= 0xF8000000; - - int dx = pa & 0x7FFF; - if(pa & 0x8000) - dx |= 0xFFFF8000; - int dmx = pb & 0x7FFF; - if(pb & 0x8000) - dmx |= 0xFFFF8000; - int dy = pc & 0x7FFF; - if(pc & 0x8000) - dy |= 0xFFFF8000; - int dmy = pd & 0x7FFFF; - if(pd & 0x8000) - dmy |= 0xFFFF8000; - - if(VCOUNT == 0) - changed = 3; - - if(changed & 1) - { - currentX = (x_l) | ((x_h & 0x07FF)<<16); - if(x_h & 0x0800) - currentX |= 0xF8000000; - } - else - { - currentX += dmx; - } - - if(changed & 2) - { - currentY = (y_l) | ((y_h & 0x07FF)<<16); - if(y_h & 0x0800) - currentY |= 0xF8000000; - } - else - { - currentY += dmy; - } - - int realX = currentX; - int realY = currentY; - - if(control & 0x40) - { - int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; - int y = (VCOUNT / mosaicY) * mosaicY; - realX = startX + y*dmx; - realY = startY + y*dmy; - } - - int xxx = (realX >> 8); - int yyy = (realY >> 8); - - for(int x = 0; x < 240; x++) - { - if(xxx < 0 || - yyy < 0 || - xxx >= sizeX || - yyy >= sizeY) - { - line[x] = 0x80000000; - } - else - { - line[x] = (READ16LE(&screenBase[yyy * sizeX + xxx]) | prio); - } - realX += dx; - realY += dy; - - xxx = (realX >> 8); - yyy = (realY >> 8); - } - - if(control & 0x40) - { - int mosaicX = (MOSAIC & 0xF) + 1; - if(mosaicX > 1) - { - int m = 1; - for(int i = 0; i < 239; i++) - { - line[i+1] = line[i]; - m++; - if(m == mosaicX) - { - m = 1; - i++; - } - } - } - } -} - -inline void gfxDrawSprites(u32 *lineOBJ) -{ - int m=0; - gfxClearArray(lineOBJ); - if(layerEnable & 0x1000) - { - u16 *sprites = (u16 *)oam; - u16 *spritePalette = &((u16 *)paletteRAM)[256]; - int mosaicY = ((MOSAIC & 0xF000)>>12) + 1; - int mosaicX = ((MOSAIC & 0xF00)>>8) + 1; - for(int x = 0; x < 128 ; x++) - { - u16 a0 = READ16LE(sprites++); - u16 a1 = READ16LE(sprites++); - u16 a2 = READ16LE(sprites++); - sprites++; - - // ignore OBJ-WIN - if((a0 & 0x0c00) == 0x0800) - continue; - - int sizeY = 8; - int sizeX = 8; - - switch(((a0 >>12) & 0x0c)|(a1>>14)) - { - case 0: - break; - case 1: - sizeX = sizeY = 16; - break; - case 2: - sizeX = sizeY = 32; - break; - case 3: - sizeX = sizeY = 64; - break; - case 4: - sizeX = 16; - break; - case 5: - sizeX = 32; - break; - case 6: - sizeX = 32; - sizeY = 16; - break; - case 7: - sizeX = 64; - sizeY = 32; - break; - case 8: - sizeY = 16; - break; - case 9: - sizeY = 32; - break; - case 10: - sizeX = 16; - sizeY = 32; - break; - case 11: - sizeX = 32; - sizeY = 64; - break; - default: - continue; - } - -#ifdef SPRITE_DEBUG - int maskX = sizeX-1; - int maskY = sizeY-1; -#endif - - int sy = (a0 & 255); - - if(sy > 160) - sy -= 256; - - if(a0 & 0x0100) - { - int fieldX = sizeX; - int fieldY = sizeY; - if(a0 & 0x0200) - { - fieldX <<= 1; - fieldY <<= 1; - } - - int t = VCOUNT - sy; - if((t >= 0) && (t < fieldY)) - { - int sx = (a1 & 0x1FF); - if((sx < 240) || (((sx + fieldX) & 511) < 240)) - { - // int t2 = t - (fieldY >> 1); - int rot = (a1 >> 9) & 0x1F; - u16 *OAM = (u16 *)oam; - int dx = READ16LE(&OAM[3 + (rot << 4)]); - if(dx & 0x8000) - dx |= 0xFFFF8000; - int dmx = READ16LE(&OAM[7 + (rot << 4)]); - if(dmx & 0x8000) - dmx |= 0xFFFF8000; - int dy = READ16LE(&OAM[11 + (rot << 4)]); - if(dy & 0x8000) - dy |= 0xFFFF8000; - int dmy = READ16LE(&OAM[15 + (rot << 4)]); - if(dmy & 0x8000) - dmy |= 0xFFFF8000; - - if(a0 & 0x1000) - { - t -= (t % mosaicY); - } - - int realX = ((sizeX) << 7) - (fieldX >> 1)*dx - (fieldY>>1)*dmx - + t * dmx; - int realY = ((sizeY) << 7) - (fieldX >> 1)*dy - (fieldY>>1)*dmy - + t * dmy; - - u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - - if(a0 & 0x2000) - { - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - int inc = 32; - if(DISPCNT & 0x40) - inc = sizeX >> 2; - else - c &= 0x3FE; - for(int x = 0; x < fieldX; x++) - { - int xxx = realX >> 8; - int yyy = realY >> 8; - - if(xxx < 0 || xxx >= sizeX || - yyy < 0 || yyy >= sizeY || - sx >= 240); - else - { - u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) - + ((yyy & 7)<<3) + ((xxx >> 3)<<6) + - (xxx & 7))&0x7FFF)]; - if ((color==0) && (((prio >> 25)&3) < - ((lineOBJ[sx]>>25)&3))) - { - lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) - { - lineOBJ[sx] = READ16LE(&spritePalette[color]) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - - if (a0 & 0x1000) - { - m++; - if (m==mosaicX) - m=0; - } -#ifdef SPRITE_DEBUG - if(t == 0 || t == maskY || x == 0 || x == maskX) - lineOBJ[sx] = 0x001F; -#endif - } - sx = (sx+1)&511; - ; - realX += dx; - realY += dy; - } - } - else - { - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - if(DISPCNT & 0x40) - inc = sizeX >> 3; - int palette = (a2 >> 8) & 0xF0; - for(int x = 0; x < fieldX; x++) - { - int xxx = realX >> 8; - int yyy = realY >> 8; - if(xxx < 0 || xxx >= sizeX || - yyy < 0 || yyy >= sizeY || - sx >= 240); - else - { - u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) - + ((yyy & 7)<<2) + ((xxx >> 3)<<5) + - ((xxx & 7)>>1))&0x7FFF)]; - if(xxx & 1) - color >>= 4; - else - color &= 0x0F; - - if ((color==0) && (((prio >> 25)&3) < - ((lineOBJ[sx]>>25)&3))) - { - lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) - { - lineOBJ[sx] = READ16LE(&spritePalette[palette+color]) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - } - if((a0 & 0x1000) && m) - { - m++; - if (m==mosaicX) - m=0; - } - -#ifdef SPRITE_DEBUG - if(t == 0 || t == maskY || x == 0 || x == maskX) - lineOBJ[sx] = 0x001F; -#endif - sx = (sx+1)&511; - ; - realX += dx; - realY += dy; - - } - } - } - } - } - else - { - int t = VCOUNT - sy; - if((t >= 0) && (t < sizeY)) - { - int sx = (a1 & 0x1FF); - if(((sx < 240)||(((sx+sizeX)&511)<240)) && !(a0 & 0x0200)) - { - if(a0 & 0x2000) - { - if(a1 & 0x2000) - t = sizeY - t - 1; - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - if(DISPCNT & 0x40) - { - inc = sizeX >> 2; - } - else - { - c &= 0x3FE; - } - int xxx = 0; - if(a1 & 0x1000) - xxx = sizeX-1; - - if(a0 & 0x1000) - { - t -= (t % mosaicY); - } - - int address = 0x10000 + ((((c+ (t>>3) * inc) << 5) - + ((t & 7) << 3) + ((xxx>>3)<<6) + (xxx & 7)) & 0x7FFF); - - if(a1 & 0x1000) - xxx = 7; - u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - - for(int xx = 0; xx < sizeX; xx++) - { - if(sx < 240) - { - u8 color = vram[address]; - if ((color==0) && (((prio >> 25)&3) < - ((lineOBJ[sx]>>25)&3))) - { - lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) - { - lineOBJ[sx] = READ16LE(&spritePalette[color]) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - - if (a0 & 0x1000) - { - m++; - if (m==mosaicX) - m=0; - } - -#ifdef SPRITE_DEBUG - if(t == 0 || t == maskY || xx == 0 || xx == maskX) - lineOBJ[sx] = 0x001F; -#endif - } - - sx = (sx+1) & 511; - if(a1 & 0x1000) - { - xxx--; - address--; - if(xxx == -1) - { - address -= 56; - xxx = 7; - } - if(address < 0x10000) - address += 0x8000; - } - else - { - xxx++; - address++; - if(xxx == 8) - { - address += 56; - xxx = 0; - } - if(address > 0x17fff) - address -= 0x8000; - } - } - } - else - { - if(a1 & 0x2000) - t = sizeY - t - 1; - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - if(DISPCNT & 0x40) - { - inc = sizeX >> 3; - } - int xxx = 0; - if(a1 & 0x1000) - xxx = sizeX - 1; - - if(a0 & 0x1000) - { - t -= (t % mosaicY); - } - - int address = 0x10000 + ((((c + (t>>3) * inc)<<5) - + ((t & 7)<<2) + ((xxx>>3)<<5) + ((xxx & 7) >> 1))&0x7FFF); - u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - int palette = (a2 >> 8) & 0xF0; - if(a1 & 0x1000) - { - xxx = 7; - for(int xx = sizeX - 1; xx >= 0; xx--) - { - if(sx < 240) - { - u8 color = vram[address]; - if(xx & 1) - { - color = (color >> 4); - } - else - color &= 0x0F; - - if ((color==0) && (((prio >> 25)&3) < - ((lineOBJ[sx]>>25)&3))) - { - lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) - { - lineOBJ[sx] = READ16LE(&spritePalette[palette + color]) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - } - if (a0 & 0x1000) - { - m++; - if (m==mosaicX) - m=0; - } -#ifdef SPRITE_DEBUG - if(t == 0 || t == maskY || xx == 0 || xx == maskX) - lineOBJ[sx] = 0x001F; -#endif - sx = (sx+1) & 511; - xxx--; - if(!(xx & 1)) - address--; - if(xxx == -1) - { - xxx = 7; - address -= 28; - } - if(address < 0x10000) - address += 0x8000; - } - } - else - { - for(int xx = 0; xx < sizeX; xx++) - { - if(sx < 240) - { - u8 color = vram[address]; - if(xx & 1) - { - color = (color >> 4); - } - else - color &= 0x0F; - - if ((color==0) && (((prio >> 25)&3) < - ((lineOBJ[sx]>>25)&3))) - { - lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - } - else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) - { - lineOBJ[sx] = READ16LE(&spritePalette[palette + color]) | prio; - if((a0 & 0x1000) && m) - lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; - - } - } - if (a0 & 0x1000) - { - m++; - if (m==mosaicX) - m=0; - } -#ifdef SPRITE_DEBUG - if(t == 0 || t == maskY || xx == 0 || xx == maskX) - lineOBJ[sx] = 0x001F; -#endif - sx = (sx+1) & 511; - xxx++; - if(xx & 1) - address++; - if(xxx == 8) - { - address += 28; - xxx = 0; - } - if(address > 0x17fff) - address -= 0x8000; - } - } - } - } - } - } - } - } -} - -inline void gfxDrawOBJWin(u32 *lineOBJWin) -{ - gfxClearArray(lineOBJWin); - if(layerEnable & 0x8000) - { - u16 *sprites = (u16 *)oam; - // u16 *spritePalette = &((u16 *)paletteRAM)[256]; - for(int x = 0; x < 128 ; x++) - { - u16 a0 = READ16LE(sprites++); - u16 a1 = READ16LE(sprites++); - u16 a2 = READ16LE(sprites++); - sprites++; - - // ignore non OBJ-WIN - if((a0 & 0x0c00) != 0x0800) - continue; - - int sizeY = 8; - int sizeX = 8; - - switch(((a0 >>12) & 0x0c)|(a1>>14)) - { - case 0: - break; - case 1: - sizeX = sizeY = 16; - break; - case 2: - sizeX = sizeY = 32; - break; - case 3: - sizeX = sizeY = 64; - break; - case 4: - sizeX = 16; - break; - case 5: - sizeX = 32; - break; - case 6: - sizeX = 32; - sizeY = 16; - break; - case 7: - sizeX = 64; - sizeY = 32; - break; - case 8: - sizeY = 16; - break; - case 9: - sizeY = 32; - break; - case 10: - sizeX = 16; - sizeY = 32; - break; - case 11: - sizeX = 32; - sizeY = 64; - break; - default: - continue; - } - - int sy = (a0 & 255); - - if(sy > 160) - sy -= 256; - - if(a0 & 0x0100) - { - int fieldX = sizeX; - int fieldY = sizeY; - if(a0 & 0x0200) - { - fieldX <<= 1; - fieldY <<= 1; - } - - int t = VCOUNT - sy; - if((t >= 0) && (t < fieldY)) - { - int sx = (a1 & 0x1FF); - if((sx < 240) || (((sx + fieldX) & 511) < 240)) - { - // int t2 = t - (fieldY >> 1); - int rot = (a1 >> 9) & 0x1F; - u16 *OAM = (u16 *)oam; - int dx = READ16LE(&OAM[3 + (rot << 4)]); - if(dx & 0x8000) - dx |= 0xFFFF8000; - int dmx = READ16LE(&OAM[7 + (rot << 4)]); - if(dmx & 0x8000) - dmx |= 0xFFFF8000; - int dy = READ16LE(&OAM[11 + (rot << 4)]); - if(dy & 0x8000) - dy |= 0xFFFF8000; - int dmy = READ16LE(&OAM[15 + (rot << 4)]); - if(dmy & 0x8000) - dmy |= 0xFFFF8000; - - int realX = ((sizeX) << 7) - (fieldX >> 1)*dx - (fieldY>>1)*dmx - + t * dmx; - int realY = ((sizeY) << 7) - (fieldX >> 1)*dy - (fieldY>>1)*dmy - + t * dmy; - - // u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - - if(a0 & 0x2000) - { - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - int inc = 32; - if(DISPCNT & 0x40) - inc = sizeX >> 2; - else - c &= 0x3FE; - for(int x = 0; x < fieldX; x++) - { - int xxx = realX >> 8; - int yyy = realY >> 8; - - if(xxx < 0 || xxx >= sizeX || - yyy < 0 || yyy >= sizeY) - {} - else - { - u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) - + ((yyy & 7)<<3) + ((xxx >> 3)<<6) + - (xxx & 7))&0x7fff)]; - if(color) - { - lineOBJWin[sx] = 1; - } - } - sx = (sx+1)&511; - ; - realX += dx; - realY += dy; - } - } - else - { - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - if(DISPCNT & 0x40) - inc = sizeX >> 3; - // int palette = (a2 >> 8) & 0xF0; - for(int x = 0; x < fieldX; x++) - { - int xxx = realX >> 8; - int yyy = realY >> 8; - - // if(x == 0 || x == (sizeX-1) || - // t == 0 || t == (sizeY-1)) { - // lineOBJ[sx] = 0x001F | prio; - // } else { - if(xxx < 0 || xxx >= sizeX || - yyy < 0 || yyy >= sizeY) - {} - else - { - u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) - + ((yyy & 7)<<2) + ((xxx >> 3)<<5) + - ((xxx & 7)>>1))&0x7fff)]; - if(xxx & 1) - color >>= 4; - else - color &= 0x0F; - - if(color) - { - lineOBJWin[sx] = 1; - } - } - // } - sx = (sx+1)&511; - ; - realX += dx; - realY += dy; - } - } - } - } - } - else - { - int t = VCOUNT - sy; - if((t >= 0) && (t < sizeY)) - { - int sx = (a1 & 0x1FF); - if(((sx < 240)||(((sx+sizeX)&511)<240)) && !(a0 & 0x0200)) - { - if(a0 & 0x2000) - { - if(a1 & 0x2000) - t = sizeY - t - 1; - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - if(DISPCNT & 0x40) - { - inc = sizeX >> 2; - } - else - { - c &= 0x3FE; - } - int xxx = 0; - if(a1 & 0x1000) - xxx = sizeX-1; - int address = 0x10000 + ((((c+ (t>>3) * inc) << 5) - + ((t & 7) << 3) + ((xxx>>3)<<6) + (xxx & 7))&0x7fff); - if(a1 & 0x1000) - xxx = 7; - // u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - for(int xx = 0; xx < sizeX; xx++) - { - if(sx < 240) - { - u8 color = vram[address]; - if(color) - { - lineOBJWin[sx] = 1; - } - } - - sx = (sx+1) & 511; - if(a1 & 0x1000) - { - xxx--; - address--; - if(xxx == -1) - { - address -= 56; - xxx = 7; - } - if(address < 0x10000) - address += 0x8000; - } - else - { - xxx++; - address++; - if(xxx == 8) - { - address += 56; - xxx = 0; - } - if(address > 0x17fff) - address -= 0x8000; - } - } - } - else - { - if(a1 & 0x2000) - t = sizeY - t - 1; - int c = (a2 & 0x3FF); - if((DISPCNT & 7) > 2 && (c < 512)) - continue; - - int inc = 32; - if(DISPCNT & 0x40) - { - inc = sizeX >> 3; - } - int xxx = 0; - if(a1 & 0x1000) - xxx = sizeX - 1; - int address = 0x10000 + ((((c + (t>>3) * inc)<<5) - + ((t & 7)<<2) + ((xxx>>3)<<5) + ((xxx & 7) >> 1))&0x7fff); - // u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); - // int palette = (a2 >> 8) & 0xF0; - if(a1 & 0x1000) - { - xxx = 7; - for(int xx = sizeX - 1; xx >= 0; xx--) - { - if(sx < 240) - { - u8 color = vram[address]; - if(xx & 1) - { - color = (color >> 4); - } - else - color &= 0x0F; - - if(color) - { - lineOBJWin[sx] = 1; - } - } - sx = (sx+1) & 511; - xxx--; - if(!(xx & 1)) - address--; - if(xxx == -1) - { - xxx = 7; - address -= 28; - } - if(address < 0x10000) - address += 0x8000; - } - } - else - { - for(int xx = 0; xx < sizeX; xx++) - { - if(sx < 240) - { - u8 color = vram[address]; - if(xx & 1) - { - color = (color >> 4); - } - else - color &= 0x0F; - - if(color) - { - lineOBJWin[sx] = 1; - } - } - sx = (sx+1) & 511; - xxx++; - if(xx & 1) - address++; - if(xxx == 8) - { - address += 28; - xxx = 0; - } - if(address > 0x17fff) - address -= 0x8000; - } - } - } - } - } - } - } - } -} - -inline u32 gfxIncreaseBrightness(u32 color, int coeff) -{ - int r = (color & 0x1F); - int g = ((color >> 5) & 0x1F); - int b = ((color >> 10) & 0x1F); - - r = r + (((31 - r) * coeff) >> 4); - g = g + (((31 - g) * coeff) >> 4); - b = b + (((31 - b) * coeff) >> 4); - if(r > 31) - r = 31; - if(g > 31) - g = 31; - if(b > 31) - b = 31; - color = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; - return color; -} - -inline void gfxIncreaseBrightness(u32 *line, int coeff) -{ - for(int x = 0; x < 240; x++) - { - u32 color = *line; - int r = (color & 0x1F); - int g = ((color >> 5) & 0x1F); - int b = ((color >> 10) & 0x1F); - - r = r + (((31 - r) * coeff) >> 4); - g = g + (((31 - g) * coeff) >> 4); - b = b + (((31 - b) * coeff) >> 4); - if(r > 31) - r = 31; - if(g > 31) - g = 31; - if(b > 31) - b = 31; - *line++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; - } -} - -inline u32 gfxDecreaseBrightness(u32 color, int coeff) -{ - int r = (color & 0x1F); - int g = ((color >> 5) & 0x1F); - int b = ((color >> 10) & 0x1F); - - r = r - ((r * coeff) >> 4); - g = g - ((g * coeff) >> 4); - b = b - ((b * coeff) >> 4); - if(r < 0) - r = 0; - if(g < 0) - g = 0; - if(b < 0) - b = 0; - color = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; - - return color; -} - -inline void gfxDecreaseBrightness(u32 *line, int coeff) -{ - for(int x = 0; x < 240; x++) - { - u32 color = *line; - int r = (color & 0x1F); - int g = ((color >> 5) & 0x1F); - int b = ((color >> 10) & 0x1F); - - r = r - ((r * coeff) >> 4); - g = g - ((g * coeff) >> 4); - b = b - ((b * coeff) >> 4); - if(r < 0) - r = 0; - if(g < 0) - g = 0; - if(b < 0) - b = 0; - *line++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; - } -} - -inline u32 gfxAlphaBlend(u32 color, u32 color2, int ca, int cb) -{ - if(color < 0x80000000) - { - int r = (color & 0x1F); - int g = ((color >> 5) & 0x1F); - int b = ((color >> 10) & 0x1F); - int r0 = (color2 & 0x1F); - int g0 = ((color2 >> 5) & 0x1F); - int b0 = ((color2 >> 10) & 0x1F); - - r = ((r * ca) >> 4) + ((r0 * cb) >> 4); - g = ((g * ca) >> 4) + ((g0 * cb) >> 4); - b = ((b * ca) >> 4) + ((b0 * cb) >> 4); - - if(r > 31) - r = 31; - if(g > 31) - g = 31; - if(b > 31) - b = 31; - - return (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; - } - return color; -} - -inline void gfxAlphaBlend(u32 *ta, u32 *tb, int ca, int cb) -{ - for(int x = 0; x < 240; x++) - { - u32 color = *ta; - if(color < 0x80000000) - { - int r = (color & 0x1F); - int g = ((color >> 5) & 0x1F); - int b = ((color >> 10) & 0x1F); - u32 color2 = (*tb++); - int r0 = (color2 & 0x1F); - int g0 = ((color2 >> 5) & 0x1F); - int b0 = ((color2 >> 10) & 0x1F); - - r = ((r * ca) >> 4) + ((r0 * cb) >> 4); - g = ((g * ca) >> 4) + ((g0 * cb) >> 4); - b = ((b * ca) >> 4) + ((b0 * cb) >> 4); - - if(r > 31) - r = 31; - if(g > 31) - g = 31; - if(b > 31) - b = 31; - - *ta++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; - } - else - { - ta++; - tb++; - } - } -} - -#endif // VBA_GFX_H diff --git a/source/vba/Globals.cpp b/source/vba/Globals.cpp index f6e7968..5d2433c 100644 --- a/source/vba/Globals.cpp +++ b/source/vba/Globals.cpp @@ -1,135 +1,141 @@ -// 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. - -#include "GBA.h" - -reg_pair reg[45]; -memoryMap map[256]; -bool ioReadable[0x400]; -bool N_FLAG = 0; -bool C_FLAG = 0; -bool Z_FLAG = 0; -bool V_FLAG = 0; -bool armState = true; -bool armIrqEnable = true; -u32 armNextPC = 0x00000000; -int armMode = 0x1f; -u32 stop = 0x08000568; -int saveType = 0; -bool useBios = false; -bool skipBios = false; -int frameSkip = 1; -bool speedup = false; -bool synchronize = true; -bool cpuDisableSfx = false; -bool cpuIsMultiBoot = false; -bool parseDebug = true; -int layerSettings = 0xff00; -int layerEnable = 0xff00; -bool speedHack = false; -int cpuSaveType = 0; -bool cpuEnhancedDetection = true; -bool cheatsEnabled = true; - -u8 *bios = NULL; -u8 *rom = NULL; -u8 *internalRAM = NULL; -u8 *workRAM = NULL; -u8 *paletteRAM = NULL; -u8 *vram = NULL; -u8 *pix = NULL; -u8 *oam = NULL; -u8 *ioMem = NULL; - -u16 DISPCNT = 0x0080; -u16 DISPSTAT = 0x0000; -u16 VCOUNT = 0x0000; -u16 BG0CNT = 0x0000; -u16 BG1CNT = 0x0000; -u16 BG2CNT = 0x0000; -u16 BG3CNT = 0x0000; -u16 BG0HOFS = 0x0000; -u16 BG0VOFS = 0x0000; -u16 BG1HOFS = 0x0000; -u16 BG1VOFS = 0x0000; -u16 BG2HOFS = 0x0000; -u16 BG2VOFS = 0x0000; -u16 BG3HOFS = 0x0000; -u16 BG3VOFS = 0x0000; -u16 BG2PA = 0x0100; -u16 BG2PB = 0x0000; -u16 BG2PC = 0x0000; -u16 BG2PD = 0x0100; -u16 BG2X_L = 0x0000; -u16 BG2X_H = 0x0000; -u16 BG2Y_L = 0x0000; -u16 BG2Y_H = 0x0000; -u16 BG3PA = 0x0100; -u16 BG3PB = 0x0000; -u16 BG3PC = 0x0000; -u16 BG3PD = 0x0100; -u16 BG3X_L = 0x0000; -u16 BG3X_H = 0x0000; -u16 BG3Y_L = 0x0000; -u16 BG3Y_H = 0x0000; -u16 WIN0H = 0x0000; -u16 WIN1H = 0x0000; -u16 WIN0V = 0x0000; -u16 WIN1V = 0x0000; -u16 WININ = 0x0000; -u16 WINOUT = 0x0000; -u16 MOSAIC = 0x0000; -u16 BLDMOD = 0x0000; -u16 COLEV = 0x0000; -u16 COLY = 0x0000; -u16 DM0SAD_L = 0x0000; -u16 DM0SAD_H = 0x0000; -u16 DM0DAD_L = 0x0000; -u16 DM0DAD_H = 0x0000; -u16 DM0CNT_L = 0x0000; -u16 DM0CNT_H = 0x0000; -u16 DM1SAD_L = 0x0000; -u16 DM1SAD_H = 0x0000; -u16 DM1DAD_L = 0x0000; -u16 DM1DAD_H = 0x0000; -u16 DM1CNT_L = 0x0000; -u16 DM1CNT_H = 0x0000; -u16 DM2SAD_L = 0x0000; -u16 DM2SAD_H = 0x0000; -u16 DM2DAD_L = 0x0000; -u16 DM2DAD_H = 0x0000; -u16 DM2CNT_L = 0x0000; -u16 DM2CNT_H = 0x0000; -u16 DM3SAD_L = 0x0000; -u16 DM3SAD_H = 0x0000; -u16 DM3DAD_L = 0x0000; -u16 DM3DAD_H = 0x0000; -u16 DM3CNT_L = 0x0000; -u16 DM3CNT_H = 0x0000; -u16 TM0D = 0x0000; -u16 TM0CNT = 0x0000; -u16 TM1D = 0x0000; -u16 TM1CNT = 0x0000; -u16 TM2D = 0x0000; -u16 TM2CNT = 0x0000; -u16 TM3D = 0x0000; -u16 TM3CNT = 0x0000; -u16 P1 = 0xFFFF; -u16 IE = 0x0000; -u16 IF = 0x0000; -u16 IME = 0x0000; +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 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. + +#include "agb/GBA.h" + +#ifdef BKPT_SUPPORT +int oldreg[17]; +char oldbuffer[10]; +#endif + +reg_pair reg[45]; +memoryMap map[256]; +bool ioReadable[0x400]; +bool N_FLAG = 0; +bool C_FLAG = 0; +bool Z_FLAG = 0; +bool V_FLAG = 0; +bool armState = true; +bool armIrqEnable = true; +u32 armNextPC = 0x00000000; +int armMode = 0x1f; +u32 stop = 0x08000568; +int saveType = 0; +bool useBios = false; +bool skipBios = false; +int frameSkip = 1; +bool speedup = false; +bool synchronize = true; +bool cpuDisableSfx = false; +bool cpuIsMultiBoot = false; +bool parseDebug = true; +int layerSettings = 0xff00; +int layerEnable = 0xff00; +bool speedHack = false; +int cpuSaveType = 0; +bool cheatsEnabled = true; +bool mirroringEnable = false; +bool skipSaveGameBattery = false; + +u8 *bios = NULL; +u8 *rom = NULL; +u8 *internalRAM = NULL; +u8 *workRAM = NULL; +u8 *paletteRAM = NULL; +u8 *vram = NULL; +u8 *pix = NULL; +u8 *oam = NULL; +u8 *ioMem = NULL; + +u16 DISPCNT = 0x0080; +u16 DISPSTAT = 0x0000; +u16 VCOUNT = 0x0000; +u16 BG0CNT = 0x0000; +u16 BG1CNT = 0x0000; +u16 BG2CNT = 0x0000; +u16 BG3CNT = 0x0000; +u16 BG0HOFS = 0x0000; +u16 BG0VOFS = 0x0000; +u16 BG1HOFS = 0x0000; +u16 BG1VOFS = 0x0000; +u16 BG2HOFS = 0x0000; +u16 BG2VOFS = 0x0000; +u16 BG3HOFS = 0x0000; +u16 BG3VOFS = 0x0000; +u16 BG2PA = 0x0100; +u16 BG2PB = 0x0000; +u16 BG2PC = 0x0000; +u16 BG2PD = 0x0100; +u16 BG2X_L = 0x0000; +u16 BG2X_H = 0x0000; +u16 BG2Y_L = 0x0000; +u16 BG2Y_H = 0x0000; +u16 BG3PA = 0x0100; +u16 BG3PB = 0x0000; +u16 BG3PC = 0x0000; +u16 BG3PD = 0x0100; +u16 BG3X_L = 0x0000; +u16 BG3X_H = 0x0000; +u16 BG3Y_L = 0x0000; +u16 BG3Y_H = 0x0000; +u16 WIN0H = 0x0000; +u16 WIN1H = 0x0000; +u16 WIN0V = 0x0000; +u16 WIN1V = 0x0000; +u16 WININ = 0x0000; +u16 WINOUT = 0x0000; +u16 MOSAIC = 0x0000; +u16 BLDMOD = 0x0000; +u16 COLEV = 0x0000; +u16 COLY = 0x0000; +u16 DM0SAD_L = 0x0000; +u16 DM0SAD_H = 0x0000; +u16 DM0DAD_L = 0x0000; +u16 DM0DAD_H = 0x0000; +u16 DM0CNT_L = 0x0000; +u16 DM0CNT_H = 0x0000; +u16 DM1SAD_L = 0x0000; +u16 DM1SAD_H = 0x0000; +u16 DM1DAD_L = 0x0000; +u16 DM1DAD_H = 0x0000; +u16 DM1CNT_L = 0x0000; +u16 DM1CNT_H = 0x0000; +u16 DM2SAD_L = 0x0000; +u16 DM2SAD_H = 0x0000; +u16 DM2DAD_L = 0x0000; +u16 DM2DAD_H = 0x0000; +u16 DM2CNT_L = 0x0000; +u16 DM2CNT_H = 0x0000; +u16 DM3SAD_L = 0x0000; +u16 DM3SAD_H = 0x0000; +u16 DM3DAD_L = 0x0000; +u16 DM3DAD_H = 0x0000; +u16 DM3CNT_L = 0x0000; +u16 DM3CNT_H = 0x0000; +u16 TM0D = 0x0000; +u16 TM0CNT = 0x0000; +u16 TM1D = 0x0000; +u16 TM1CNT = 0x0000; +u16 TM2D = 0x0000; +u16 TM2CNT = 0x0000; +u16 TM3D = 0x0000; +u16 TM3CNT = 0x0000; +u16 P1 = 0xFFFF; +u16 IE = 0x0000; +u16 IF = 0x0000; +u16 IME = 0x0000; diff --git a/source/vba/Globals.h b/source/vba/Globals.h index 86c4aee..8439848 100644 --- a/source/vba/Globals.h +++ b/source/vba/Globals.h @@ -1,149 +1,153 @@ -// -*- 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_GLOBALS_H -#define VBA_GLOBALS_H - -#define VERBOSE_SWI 1 -#define VERBOSE_UNALIGNED_MEMORY 2 -#define VERBOSE_ILLEGAL_WRITE 4 -#define VERBOSE_ILLEGAL_READ 8 -#define VERBOSE_DMA0 16 -#define VERBOSE_DMA1 32 -#define VERBOSE_DMA2 64 -#define VERBOSE_DMA3 128 -#define VERBOSE_UNDEFINED 256 -#define VERBOSE_AGBPRINT 512 - -extern reg_pair reg[45]; -extern bool ioReadable[0x400]; -extern bool N_FLAG; -extern bool C_FLAG; -extern bool Z_FLAG; -extern bool V_FLAG; -extern bool armState; -extern bool armIrqEnable; -extern u32 armNextPC; -extern int armMode; -extern u32 stop; -extern int saveType; -extern bool useBios; -extern bool skipBios; -extern int frameSkip; -extern bool speedup; -extern bool synchronize; -extern bool cpuDisableSfx; -extern bool cpuIsMultiBoot; -extern bool parseDebug; -extern int layerSettings; -extern int layerEnable; -extern bool speedHack; -extern int cpuSaveType; -extern bool cpuEnhancedDetection; -extern bool cheatsEnabled; - -extern u8 *bios; -extern u8 *rom; -extern u8 *internalRAM; -extern u8 *workRAM; -extern u8 *paletteRAM; -extern u8 *vram; -extern u8 *pix; -extern u8 *oam; -extern u8 *ioMem; - -extern u16 DISPCNT; -extern u16 DISPSTAT; -extern u16 VCOUNT; -extern u16 BG0CNT; -extern u16 BG1CNT; -extern u16 BG2CNT; -extern u16 BG3CNT; -extern u16 BG0HOFS; -extern u16 BG0VOFS; -extern u16 BG1HOFS; -extern u16 BG1VOFS; -extern u16 BG2HOFS; -extern u16 BG2VOFS; -extern u16 BG3HOFS; -extern u16 BG3VOFS; -extern u16 BG2PA; -extern u16 BG2PB; -extern u16 BG2PC; -extern u16 BG2PD; -extern u16 BG2X_L; -extern u16 BG2X_H; -extern u16 BG2Y_L; -extern u16 BG2Y_H; -extern u16 BG3PA; -extern u16 BG3PB; -extern u16 BG3PC; -extern u16 BG3PD; -extern u16 BG3X_L; -extern u16 BG3X_H; -extern u16 BG3Y_L; -extern u16 BG3Y_H; -extern u16 WIN0H; -extern u16 WIN1H; -extern u16 WIN0V; -extern u16 WIN1V; -extern u16 WININ; -extern u16 WINOUT; -extern u16 MOSAIC; -extern u16 BLDMOD; -extern u16 COLEV; -extern u16 COLY; -extern u16 DM0SAD_L; -extern u16 DM0SAD_H; -extern u16 DM0DAD_L; -extern u16 DM0DAD_H; -extern u16 DM0CNT_L; -extern u16 DM0CNT_H; -extern u16 DM1SAD_L; -extern u16 DM1SAD_H; -extern u16 DM1DAD_L; -extern u16 DM1DAD_H; -extern u16 DM1CNT_L; -extern u16 DM1CNT_H; -extern u16 DM2SAD_L; -extern u16 DM2SAD_H; -extern u16 DM2DAD_L; -extern u16 DM2DAD_H; -extern u16 DM2CNT_L; -extern u16 DM2CNT_H; -extern u16 DM3SAD_L; -extern u16 DM3SAD_H; -extern u16 DM3DAD_L; -extern u16 DM3DAD_H; -extern u16 DM3CNT_L; -extern u16 DM3CNT_H; -extern u16 TM0D; -extern u16 TM0CNT; -extern u16 TM1D; -extern u16 TM1CNT; -extern u16 TM2D; -extern u16 TM2CNT; -extern u16 TM3D; -extern u16 TM3CNT; -extern u16 P1; -extern u16 IE; -extern u16 IF; -extern u16 IME; - -#endif // VBA_GLOBALS_H +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 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_GLOBALS_H +#define VBA_GLOBALS_H + +#include "agb/GBA.h" + +#define VERBOSE_SWI 1 +#define VERBOSE_UNALIGNED_MEMORY 2 +#define VERBOSE_ILLEGAL_WRITE 4 +#define VERBOSE_ILLEGAL_READ 8 +#define VERBOSE_DMA0 16 +#define VERBOSE_DMA1 32 +#define VERBOSE_DMA2 64 +#define VERBOSE_DMA3 128 +#define VERBOSE_UNDEFINED 256 +#define VERBOSE_AGBPRINT 512 +#define VERBOSE_SOUNDOUTPUT 1024 + +extern reg_pair reg[45]; +extern bool ioReadable[0x400]; +extern bool N_FLAG; +extern bool C_FLAG; +extern bool Z_FLAG; +extern bool V_FLAG; +extern bool armState; +extern bool armIrqEnable; +extern u32 armNextPC; +extern int armMode; +extern u32 stop; +extern int saveType; +extern bool useBios; +extern bool skipBios; +extern int frameSkip; +extern bool speedup; +extern bool synchronize; +extern bool cpuDisableSfx; +extern bool cpuIsMultiBoot; +extern bool parseDebug; +extern int layerSettings; +extern int layerEnable; +extern bool speedHack; +extern int cpuSaveType; +extern bool cheatsEnabled; +extern bool mirroringEnable; +extern bool skipSaveGameBattery; + +extern u8 *bios; +extern u8 *rom; +extern u8 *internalRAM; +extern u8 *workRAM; +extern u8 *paletteRAM; +extern u8 *vram; +extern u8 *pix; +extern u8 *oam; +extern u8 *ioMem; + +extern u16 DISPCNT; +extern u16 DISPSTAT; +extern u16 VCOUNT; +extern u16 BG0CNT; +extern u16 BG1CNT; +extern u16 BG2CNT; +extern u16 BG3CNT; +extern u16 BG0HOFS; +extern u16 BG0VOFS; +extern u16 BG1HOFS; +extern u16 BG1VOFS; +extern u16 BG2HOFS; +extern u16 BG2VOFS; +extern u16 BG3HOFS; +extern u16 BG3VOFS; +extern u16 BG2PA; +extern u16 BG2PB; +extern u16 BG2PC; +extern u16 BG2PD; +extern u16 BG2X_L; +extern u16 BG2X_H; +extern u16 BG2Y_L; +extern u16 BG2Y_H; +extern u16 BG3PA; +extern u16 BG3PB; +extern u16 BG3PC; +extern u16 BG3PD; +extern u16 BG3X_L; +extern u16 BG3X_H; +extern u16 BG3Y_L; +extern u16 BG3Y_H; +extern u16 WIN0H; +extern u16 WIN1H; +extern u16 WIN0V; +extern u16 WIN1V; +extern u16 WININ; +extern u16 WINOUT; +extern u16 MOSAIC; +extern u16 BLDMOD; +extern u16 COLEV; +extern u16 COLY; +extern u16 DM0SAD_L; +extern u16 DM0SAD_H; +extern u16 DM0DAD_L; +extern u16 DM0DAD_H; +extern u16 DM0CNT_L; +extern u16 DM0CNT_H; +extern u16 DM1SAD_L; +extern u16 DM1SAD_H; +extern u16 DM1DAD_L; +extern u16 DM1DAD_H; +extern u16 DM1CNT_L; +extern u16 DM1CNT_H; +extern u16 DM2SAD_L; +extern u16 DM2SAD_H; +extern u16 DM2DAD_L; +extern u16 DM2DAD_H; +extern u16 DM2CNT_L; +extern u16 DM2CNT_H; +extern u16 DM3SAD_L; +extern u16 DM3SAD_H; +extern u16 DM3DAD_L; +extern u16 DM3DAD_H; +extern u16 DM3CNT_L; +extern u16 DM3CNT_H; +extern u16 TM0D; +extern u16 TM0CNT; +extern u16 TM1D; +extern u16 TM1CNT; +extern u16 TM2D; +extern u16 TM2CNT; +extern u16 TM3D; +extern u16 TM3CNT; +extern u16 P1; +extern u16 IE; +extern u16 IF; +extern u16 IME; + +#endif // VBA_GLOBALS_H diff --git a/source/vba/Mode0.cpp b/source/vba/Mode0.cpp index b2a0187..8e82d94 100644 --- a/source/vba/Mode0.cpp +++ b/source/vba/Mode0.cpp @@ -1,652 +1,509 @@ -// 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. - -#include "GBA.h" -#include "Globals.h" -#include "Gfx.h" - -void mode0RenderLine() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x80) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - return; - } - - if(layerEnable & 0x0100) - { - gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0); - } - - if(layerEnable & 0x0200) - { - gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1); - } - - if(layerEnable & 0x0400) - { - gfxDrawTextScreen(BG2CNT, BG2HOFS, BG2VOFS, line2); - } - - if(layerEnable & 0x0800) - { - gfxDrawTextScreen(BG3CNT, BG3HOFS, BG3VOFS, line3); - } - - gfxDrawSprites(lineOBJ); - - u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = backdrop; - u8 top = 0x20; - - if(line0[x] < color) - { - color = line0[x]; - top = 0x01; - } - - if((u8)(line1[x]>>24) < (u8)(color >> 24)) - { - color = line1[x]; - top = 0x02; - } - - if((u8)(line2[x]>>24) < (u8)(color >> 24)) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(line3[x]>>24) < (u8)(color >> 24)) - { - color = line3[x]; - top = 0x08; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if((top & 0x10) && (color & 0x00010000)) - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((u8)(line0[x]>>24) < (u8)(back >> 24)) - { - back = line0[x]; - top2 = 0x01; - } - - if((u8)(line1[x]>>24) < (u8)(back >> 24)) - { - back = line1[x]; - top2 = 0x02; - } - - if((u8)(line2[x]>>24) < (u8)(back >> 24)) - { - back = line2[x]; - top2 = 0x04; - } - - if((u8)(line3[x]>>24) < (u8)(back >> 24)) - { - back = line3[x]; - top2 = 0x08; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } -} - -void mode0RenderLineNoWindow() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x80) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - return; - } - - if(layerEnable & 0x0100) - { - gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0); - } - - if(layerEnable & 0x0200) - { - gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1); - } - - if(layerEnable & 0x0400) - { - gfxDrawTextScreen(BG2CNT, BG2HOFS, BG2VOFS, line2); - } - - if(layerEnable & 0x0800) - { - gfxDrawTextScreen(BG3CNT, BG3HOFS, BG3VOFS, line3); - } - - gfxDrawSprites(lineOBJ); - - u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); - - int effect = (BLDMOD >> 6) & 3; - - for(int x = 0; x < 240; x++) - { - u32 color = backdrop; - u8 top = 0x20; - - if(line0[x] < color) - { - color = line0[x]; - top = 0x01; - } - - if(line1[x] < (color & 0xFF000000)) - { - color = line1[x]; - top = 0x02; - } - - if(line2[x] < (color & 0xFF000000)) - { - color = line2[x]; - top = 0x04; - } - - if(line3[x] < (color & 0xFF000000)) - { - color = line3[x]; - top = 0x08; - } - - if(lineOBJ[x] < (color & 0xFF000000)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if(!(color & 0x00010000)) - { - switch(effect) - { - case 0: - break; - case 1: - { - if(top & BLDMOD) - { - u32 back = backdrop; - u8 top2 = 0x20; - if(line0[x] < back) - { - if(top != 0x01) - { - back = line0[x]; - top2 = 0x01; - } - } - - if(line1[x] < (back & 0xFF000000)) - { - if(top != 0x02) - { - back = line1[x]; - top2 = 0x02; - } - } - - if(line2[x] < (back & 0xFF000000)) - { - if(top != 0x04) - { - back = line2[x]; - top2 = 0x04; - } - } - - if(line3[x] < (back & 0xFF000000)) - { - if(top != 0x08) - { - back = line3[x]; - top2 = 0x08; - } - } - - if(lineOBJ[x] < (back & 0xFF000000)) - { - if(top != 0x10) - { - back = lineOBJ[x]; - top2 = 0x10; - } - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - else - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if(line0[x] < back) - { - back = line0[x]; - top2 = 0x01; - } - - if(line1[x] < (back & 0xFF000000)) - { - back = line1[x]; - top2 = 0x02; - } - - if(line2[x] < (back & 0xFF000000)) - { - back = line2[x]; - top2 = 0x04; - } - - if(line3[x] < (back & 0xFF000000)) - { - back = line3[x]; - top2 = 0x08; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } -} - -void mode0RenderLineAll() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x80) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - return; - } - - bool inWindow0 = false; - bool inWindow1 = false; - - if(layerEnable & 0x2000) - { - u8 v0 = WIN0V >> 8; - u8 v1 = WIN0V & 255; - inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1); - else - inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1); - } - if(layerEnable & 0x4000) - { - u8 v0 = WIN1V >> 8; - u8 v1 = WIN1V & 255; - inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1); - else - inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1); - } - - if((layerEnable & 0x0100)) - { - gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0); - } - - if((layerEnable & 0x0200)) - { - gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1); - } - - if((layerEnable & 0x0400)) - { - gfxDrawTextScreen(BG2CNT, BG2HOFS, BG2VOFS, line2); - } - - if((layerEnable & 0x0800)) - { - gfxDrawTextScreen(BG3CNT, BG3HOFS, BG3VOFS, line3); - } - - gfxDrawSprites(lineOBJ); - gfxDrawOBJWin(lineOBJWin); - - u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); - - u8 inWin0Mask = WININ & 0xFF; - u8 inWin1Mask = WININ >> 8; - u8 outMask = WINOUT & 0xFF; - - for(int x = 0; x < 240; x++) - { - u32 color = backdrop; - u8 top = 0x20; - u8 mask = outMask; - - if(!(lineOBJWin[x] & 0x80000000)) - { - mask = WINOUT >> 8; - } - - if(inWindow1) - { - if(gfxInWin1[x]) - mask = inWin1Mask; - } - - if(inWindow0) - { - if(gfxInWin0[x]) - { - mask = inWin0Mask; - } - } - - if((mask & 1) && (line0[x] < color)) - { - color = line0[x]; - top = 0x01; - } - - if((mask & 2) && ((u8)(line1[x]>>24) < (u8)(color >> 24))) - { - color = line1[x]; - top = 0x02; - } - - if((mask & 4) && ((u8)(line2[x]>>24) < (u8)(color >> 24))) - { - color = line2[x]; - top = 0x04; - } - - if((mask & 8) && ((u8)(line3[x]>>24) < (u8)(color >> 24))) - { - color = line3[x]; - top = 0x08; - } - - if((mask & 16) && ((u8)(lineOBJ[x]>>24) < (u8)(color >> 24))) - { - color = lineOBJ[x]; - top = 0x10; - } - - // special FX on in the window - if(mask & 32) - { - if(!(color & 0x00010000)) - { - switch((BLDMOD >> 6) & 3) - { - case 0: - break; - case 1: - { - if(top & BLDMOD) - { - u32 back = backdrop; - u8 top2 = 0x20; - if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x01) - { - back = line0[x]; - top2 = 0x01; - } - } - - if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x02) - { - back = line1[x]; - top2 = 0x02; - } - } - - if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x04) - { - back = line2[x]; - top2 = 0x04; - } - } - - if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x08) - { - back = line3[x]; - top2 = 0x08; - } - } - - if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x10) - { - back = lineOBJ[x]; - top2 = 0x10; - } - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - else - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((mask & 1) && ((u8)(line0[x]>>24) < (u8)(back >> 24))) - { - back = line0[x]; - top2 = 0x01; - } - - if((mask & 2) && ((u8)(line1[x]>>24) < (u8)(back >> 24))) - { - back = line1[x]; - top2 = 0x02; - } - - if((mask & 4) && ((u8)(line2[x]>>24) < (u8)(back >> 24))) - { - back = line2[x]; - top2 = 0x04; - } - - if((mask & 8) && ((u8)(line3[x]>>24) < (u8)(back >> 24))) - { - back = line3[x]; - top2 = 0x08; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - } - else if(color & 0x00010000) - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((mask & 1) && ((u8)(line0[x]>>24) < (u8)(back >> 24))) - { - back = line0[x]; - top2 = 0x01; - } - - if((mask & 2) && ((u8)(line1[x]>>24) < (u8)(back >> 24))) - { - back = line1[x]; - top2 = 0x02; - } - - if((mask & 4) && ((u8)(line2[x]>>24) < (u8)(back >> 24))) - { - back = line2[x]; - top2 = 0x04; - } - - if((mask & 8) && ((u8)(line3[x]>>24) < (u8)(back >> 24))) - { - back = line3[x]; - top2 = 0x08; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } -} +// 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. + +#include "agb/GBA.h" +#include "Globals.h" +#include "agb/GBAGfx.h" + +void mode0RenderLine() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x80) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + return; + } + + if(layerEnable & 0x0100) { + gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0); + } + + if(layerEnable & 0x0200) { + gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1); + } + + if(layerEnable & 0x0400) { + gfxDrawTextScreen(BG2CNT, BG2HOFS, BG2VOFS, line2); + } + + if(layerEnable & 0x0800) { + gfxDrawTextScreen(BG3CNT, BG3HOFS, BG3VOFS, line3); + } + + gfxDrawSprites(lineOBJ); + + u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = backdrop; + u8 top = 0x20; + + if(line0[x] < color) { + color = line0[x]; + top = 0x01; + } + + if((u8)(line1[x]>>24) < (u8)(color >> 24)) { + color = line1[x]; + top = 0x02; + } + + if((u8)(line2[x]>>24) < (u8)(color >> 24)) { + color = line2[x]; + top = 0x04; + } + + if((u8)(line3[x]>>24) < (u8)(color >> 24)) { + color = line3[x]; + top = 0x08; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) { + color = lineOBJ[x]; + top = 0x10; + } + + if((top & 0x10) && (color & 0x00010000)) { + // semi-transparent OBJ + u32 back = backdrop; + u8 top2 = 0x20; + + if((u8)(line0[x]>>24) < (u8)(back >> 24)) { + back = line0[x]; + top2 = 0x01; + } + + if((u8)(line1[x]>>24) < (u8)(back >> 24)) { + back = line1[x]; + top2 = 0x02; + } + + if((u8)(line2[x]>>24) < (u8)(back >> 24)) { + back = line2[x]; + top2 = 0x04; + } + + if((u8)(line3[x]>>24) < (u8)(back >> 24)) { + back = line3[x]; + top2 = 0x08; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } + + lineMix[x] = color; + } +} + +void mode0RenderLineNoWindow() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x80) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + return; + } + + if(layerEnable & 0x0100) { + gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0); + } + + if(layerEnable & 0x0200) { + gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1); + } + + if(layerEnable & 0x0400) { + gfxDrawTextScreen(BG2CNT, BG2HOFS, BG2VOFS, line2); + } + + if(layerEnable & 0x0800) { + gfxDrawTextScreen(BG3CNT, BG3HOFS, BG3VOFS, line3); + } + + gfxDrawSprites(lineOBJ); + + u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); + + int effect = (BLDMOD >> 6) & 3; + + for(int x = 0; x < 240; x++) { + u32 color = backdrop; + u8 top = 0x20; + + if(line0[x] < color) { + color = line0[x]; + top = 0x01; + } + + if(line1[x] < (color & 0xFF000000)) { + color = line1[x]; + top = 0x02; + } + + if(line2[x] < (color & 0xFF000000)) { + color = line2[x]; + top = 0x04; + } + + if(line3[x] < (color & 0xFF000000)) { + color = line3[x]; + top = 0x08; + } + + if(lineOBJ[x] < (color & 0xFF000000)) { + color = lineOBJ[x]; + top = 0x10; + } + + if(!(color & 0x00010000)) { + switch(effect) { + case 0: + break; + case 1: + { + if(top & BLDMOD) { + u32 back = backdrop; + u8 top2 = 0x20; + if(line0[x] < back) { + if(top != 0x01) { + back = line0[x]; + top2 = 0x01; + } + } + + if(line1[x] < (back & 0xFF000000)) { + if(top != 0x02) { + back = line1[x]; + top2 = 0x02; + } + } + + if(line2[x] < (back & 0xFF000000)) { + if(top != 0x04) { + back = line2[x]; + top2 = 0x04; + } + } + + if(line3[x] < (back & 0xFF000000)) { + if(top != 0x08) { + back = line3[x]; + top2 = 0x08; + } + } + + if(lineOBJ[x] < (back & 0xFF000000)) { + if(top != 0x10) { + back = lineOBJ[x]; + top2 = 0x10; + } + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + + } + } + break; + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } else { + // semi-transparent OBJ + u32 back = backdrop; + u8 top2 = 0x20; + + if(line0[x] < back) { + back = line0[x]; + top2 = 0x01; + } + + if(line1[x] < (back & 0xFF000000)) { + back = line1[x]; + top2 = 0x02; + } + + if(line2[x] < (back & 0xFF000000)) { + back = line2[x]; + top2 = 0x04; + } + + if(line3[x] < (back & 0xFF000000)) { + back = line3[x]; + top2 = 0x08; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } + + lineMix[x] = color; + } +} + +void mode0RenderLineAll() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x80) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + return; + } + + bool inWindow0 = false; + bool inWindow1 = false; + + if(layerEnable & 0x2000) { + u8 v0 = WIN0V >> 8; + u8 v1 = WIN0V & 255; + inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); + if(v1 >= v0) + inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1); + else + inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1); + } + if(layerEnable & 0x4000) { + u8 v0 = WIN1V >> 8; + u8 v1 = WIN1V & 255; + inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); + if(v1 >= v0) + inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1); + else + inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1); + } + + if((layerEnable & 0x0100)) { + gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0); + } + + if((layerEnable & 0x0200)) { + gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1); + } + + if((layerEnable & 0x0400)) { + gfxDrawTextScreen(BG2CNT, BG2HOFS, BG2VOFS, line2); + } + + if((layerEnable & 0x0800)) { + gfxDrawTextScreen(BG3CNT, BG3HOFS, BG3VOFS, line3); + } + + gfxDrawSprites(lineOBJ); + gfxDrawOBJWin(lineOBJWin); + + u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); + + u8 inWin0Mask = WININ & 0xFF; + u8 inWin1Mask = WININ >> 8; + u8 outMask = WINOUT & 0xFF; + + for(int x = 0; x < 240; x++) { + u32 color = backdrop; + u8 top = 0x20; + u8 mask = outMask; + + if(!(lineOBJWin[x] & 0x80000000)) { + mask = WINOUT >> 8; + } + + if(inWindow1) { + if(gfxInWin1[x]) + mask = inWin1Mask; + } + + if(inWindow0) { + if(gfxInWin0[x]) { + mask = inWin0Mask; + } + } + + if((mask & 1) && (line0[x] < color)) { + color = line0[x]; + top = 0x01; + } + + if((mask & 2) && ((u8)(line1[x]>>24) < (u8)(color >> 24))) { + color = line1[x]; + top = 0x02; + } + + if((mask & 4) && ((u8)(line2[x]>>24) < (u8)(color >> 24))) { + color = line2[x]; + top = 0x04; + } + + if((mask & 8) && ((u8)(line3[x]>>24) < (u8)(color >> 24))) { + color = line3[x]; + top = 0x08; + } + + if((mask & 16) && ((u8)(lineOBJ[x]>>24) < (u8)(color >> 24))) { + color = lineOBJ[x]; + top = 0x10; + } + + if(color & 0x00010000) { + // semi-transparent OBJ + u32 back = backdrop; + u8 top2 = 0x20; + + if((mask & 1) && ((u8)(line0[x]>>24) < (u8)(back >> 24))) { + back = line0[x]; + top2 = 0x01; + } + + if((mask & 2) && ((u8)(line1[x]>>24) < (u8)(back >> 24))) { + back = line1[x]; + top2 = 0x02; + } + + if((mask & 4) && ((u8)(line2[x]>>24) < (u8)(back >> 24))) { + back = line2[x]; + top2 = 0x04; + } + + if((mask & 8) && ((u8)(line3[x]>>24) < (u8)(back >> 24))) { + back = line3[x]; + top2 = 0x08; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } else if(mask & 32) { + // special FX on in the window + switch((BLDMOD >> 6) & 3) { + case 0: + break; + case 1: + { + if(top & BLDMOD) { + u32 back = backdrop; + u8 top2 = 0x20; + if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) { + if(top != 0x01) { + back = line0[x]; + top2 = 0x01; + } + } + + if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) { + if(top != 0x02) { + back = line1[x]; + top2 = 0x02; + } + } + + if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) { + if(top != 0x04) { + back = line2[x]; + top2 = 0x04; + } + } + + if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) { + if(top != 0x08) { + back = line3[x]; + top2 = 0x08; + } + } + + if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { + if(top != 0x10) { + back = lineOBJ[x]; + top2 = 0x10; + } + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + } + } + break; + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + + lineMix[x] = color; + } +} diff --git a/source/vba/Mode1.cpp b/source/vba/Mode1.cpp index f1ccdbf..9da41fc 100644 --- a/source/vba/Mode1.cpp +++ b/source/vba/Mode1.cpp @@ -1,599 +1,476 @@ -// 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. - -#include "GBA.h" -#include "Globals.h" -#include "Gfx.h" - -void mode1RenderLine() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x80) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - if(layerEnable & 0x0100) - { - gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0); - } - - if(layerEnable & 0x0200) - { - gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1); - } - - if(layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - BG2PA, BG2PB, BG2PC, BG2PD, - gfxBG2X, gfxBG2Y, changed, line2); - } - - gfxDrawSprites(lineOBJ); - - u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = backdrop; - u8 top = 0x20; - - if(line0[x] < color) - { - color = line0[x]; - top = 0x01; - } - - if((u8)(line1[x]>>24) < (u8)(color >> 24)) - { - color = line1[x]; - top = 0x02; - } - - if((u8)(line2[x]>>24) < (u8)(color >> 24)) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if((top & 0x10) && (color & 0x00010000)) - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((u8)(line0[x]>>24) < (u8)(back >> 24)) - { - back = line0[x]; - top2 = 0x01; - } - - if((u8)(line1[x]>>24) < (u8)(back >> 24)) - { - back = line1[x]; - top2 = 0x02; - } - - if((u8)(line2[x]>>24) < (u8)(back >> 24)) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxLastVCOUNT = VCOUNT; -} - -void mode1RenderLineNoWindow() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x80) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - if(layerEnable & 0x0100) - { - gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0); - } - - - if(layerEnable & 0x0200) - { - gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1); - } - - if(layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - BG2PA, BG2PB, BG2PC, BG2PD, - gfxBG2X, gfxBG2Y, changed, line2); - } - - gfxDrawSprites(lineOBJ); - - u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = backdrop; - u8 top = 0x20; - - if(line0[x] < color) - { - color = line0[x]; - top = 0x01; - } - - if((u8)(line1[x]>>24) < (u8)(color >> 24)) - { - color = line1[x]; - top = 0x02; - } - - if((u8)(line2[x]>>24) < (u8)(color >> 24)) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if(!(color & 0x00010000)) - { - switch((BLDMOD >> 6) & 3) - { - case 0: - break; - case 1: - { - if(top & BLDMOD) - { - u32 back = backdrop; - u8 top2 = 0x20; - if((u8)(line0[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x01) - { - back = line0[x]; - top2 = 0x01; - } - } - - if((u8)(line1[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x02) - { - back = line1[x]; - top2 = 0x02; - } - } - - if((u8)(line2[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x04) - { - back = line2[x]; - top2 = 0x04; - } - } - - if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x10) - { - back = lineOBJ[x]; - top2 = 0x10; - } - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - else - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((u8)(line0[x]>>24) < (u8)(back >> 24)) - { - back = line0[x]; - top2 = 0x01; - } - - if((u8)(line1[x]>>24) < (u8)(back >> 24)) - { - back = line1[x]; - top2 = 0x02; - } - - if((u8)(line2[x]>>24) < (u8)(back >> 24)) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxLastVCOUNT = VCOUNT; -} - -void mode1RenderLineAll() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x80) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - bool inWindow0 = false; - bool inWindow1 = false; - - if(layerEnable & 0x2000) - { - u8 v0 = WIN0V >> 8; - u8 v1 = WIN0V & 255; - inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1); - else - inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1); - } - if(layerEnable & 0x4000) - { - u8 v0 = WIN1V >> 8; - u8 v1 = WIN1V & 255; - inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1); - else - inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1); - } - - if(layerEnable & 0x0100) - { - gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0); - } - - if(layerEnable & 0x0200) - { - gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1); - } - - if(layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - BG2PA, BG2PB, BG2PC, BG2PD, - gfxBG2X, gfxBG2Y, changed, line2); - } - - gfxDrawSprites(lineOBJ); - gfxDrawOBJWin(lineOBJWin); - - u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); - - u8 inWin0Mask = WININ & 0xFF; - u8 inWin1Mask = WININ >> 8; - u8 outMask = WINOUT & 0xFF; - - for(int x = 0; x < 240; x++) - { - u32 color = backdrop; - u8 top = 0x20; - u8 mask = outMask; - - if(!(lineOBJWin[x] & 0x80000000)) - { - mask = WINOUT >> 8; - } - - if(inWindow1) - { - if(gfxInWin1[x]) - mask = inWin1Mask; - } - - if(inWindow0) - { - if(gfxInWin0[x]) - { - mask = inWin0Mask; - } - } - - if(line0[x] < color && (mask & 1)) - { - color = line0[x]; - top = 0x01; - } - - if((u8)(line1[x]>>24) < (u8)(color >> 24) && (mask & 2)) - { - color = line1[x]; - top = 0x02; - } - - if((u8)(line2[x]>>24) < (u8)(color >> 24) && (mask & 4)) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16)) - { - color = lineOBJ[x]; - top = 0x10; - } - - // special FX on the window - if(mask & 32) - { - if(!(color & 0x00010000)) - { - switch((BLDMOD >> 6) & 3) - { - case 0: - break; - case 1: - { - if(top & BLDMOD) - { - u32 back = backdrop; - u8 top2 = 0x20; - if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x01) - { - back = line0[x]; - top2 = 0x01; - } - } - - if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x02) - { - back = line1[x]; - top2 = 0x02; - } - } - - if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x04) - { - back = line2[x]; - top2 = 0x04; - } - } - - if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x10) - { - back = lineOBJ[x]; - top2 = 0x10; - } - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - else - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) - { - back = line0[x]; - top2 = 0x01; - } - - if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) - { - back = line1[x]; - top2 = 0x02; - } - - if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - } - else if(color & 0x00010000) - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) - { - back = line0[x]; - top2 = 0x01; - } - - if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) - { - back = line1[x]; - top2 = 0x02; - } - - if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxLastVCOUNT = VCOUNT; -} +// 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. + +#include "agb/GBA.h" +#include "Globals.h" +#include "agb/GBAGfx.h" + +void mode1RenderLine() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x80) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + if(layerEnable & 0x0100) { + gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0); + } + + if(layerEnable & 0x0200) { + gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1); + } + + if(layerEnable & 0x0400) { + int changed = gfxBG2Changed; + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, + BG2PA, BG2PB, BG2PC, BG2PD, + gfxBG2X, gfxBG2Y, changed, line2); + } + + gfxDrawSprites(lineOBJ); + + u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = backdrop; + u8 top = 0x20; + + if(line0[x] < color) { + color = line0[x]; + top = 0x01; + } + + if((u8)(line1[x]>>24) < (u8)(color >> 24)) { + color = line1[x]; + top = 0x02; + } + + if((u8)(line2[x]>>24) < (u8)(color >> 24)) { + color = line2[x]; + top = 0x04; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) { + color = lineOBJ[x]; + top = 0x10; + } + + if((top & 0x10) && (color & 0x00010000)) { + // semi-transparent OBJ + u32 back = backdrop; + u8 top2 = 0x20; + + if((u8)(line0[x]>>24) < (u8)(back >> 24)) { + back = line0[x]; + top2 = 0x01; + } + + if((u8)(line1[x]>>24) < (u8)(back >> 24)) { + back = line1[x]; + top2 = 0x02; + } + + if((u8)(line2[x]>>24) < (u8)(back >> 24)) { + back = line2[x]; + top2 = 0x04; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxLastVCOUNT = VCOUNT; +} + +void mode1RenderLineNoWindow() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x80) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + if(layerEnable & 0x0100) { + gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0); + } + + + if(layerEnable & 0x0200) { + gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1); + } + + if(layerEnable & 0x0400) { + int changed = gfxBG2Changed; + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, + BG2PA, BG2PB, BG2PC, BG2PD, + gfxBG2X, gfxBG2Y, changed, line2); + } + + gfxDrawSprites(lineOBJ); + + u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = backdrop; + u8 top = 0x20; + + if(line0[x] < color) { + color = line0[x]; + top = 0x01; + } + + if((u8)(line1[x]>>24) < (u8)(color >> 24)) { + color = line1[x]; + top = 0x02; + } + + if((u8)(line2[x]>>24) < (u8)(color >> 24)) { + color = line2[x]; + top = 0x04; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) { + color = lineOBJ[x]; + top = 0x10; + } + + if(!(color & 0x00010000)) { + switch((BLDMOD >> 6) & 3) { + case 0: + break; + case 1: + { + if(top & BLDMOD) { + u32 back = backdrop; + u8 top2 = 0x20; + if((u8)(line0[x]>>24) < (u8)(back >> 24)) { + if(top != 0x01) { + back = line0[x]; + top2 = 0x01; + } + } + + if((u8)(line1[x]>>24) < (u8)(back >> 24)) { + if(top != 0x02) { + back = line1[x]; + top2 = 0x02; + } + } + + if((u8)(line2[x]>>24) < (u8)(back >> 24)) { + if(top != 0x04) { + back = line2[x]; + top2 = 0x04; + } + } + + if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { + if(top != 0x10) { + back = lineOBJ[x]; + top2 = 0x10; + } + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + } + } + break; + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } else { + // semi-transparent OBJ + u32 back = backdrop; + u8 top2 = 0x20; + + if((u8)(line0[x]>>24) < (u8)(back >> 24)) { + back = line0[x]; + top2 = 0x01; + } + + if((u8)(line1[x]>>24) < (u8)(back >> 24)) { + back = line1[x]; + top2 = 0x02; + } + + if((u8)(line2[x]>>24) < (u8)(back >> 24)) { + back = line2[x]; + top2 = 0x04; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxLastVCOUNT = VCOUNT; +} + +void mode1RenderLineAll() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x80) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + bool inWindow0 = false; + bool inWindow1 = false; + + if(layerEnable & 0x2000) { + u8 v0 = WIN0V >> 8; + u8 v1 = WIN0V & 255; + inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); + if(v1 >= v0) + inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1); + else + inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1); + } + if(layerEnable & 0x4000) { + u8 v0 = WIN1V >> 8; + u8 v1 = WIN1V & 255; + inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); + if(v1 >= v0) + inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1); + else + inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1); + } + + if(layerEnable & 0x0100) { + gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0); + } + + if(layerEnable & 0x0200) { + gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1); + } + + if(layerEnable & 0x0400) { + int changed = gfxBG2Changed; + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, + BG2PA, BG2PB, BG2PC, BG2PD, + gfxBG2X, gfxBG2Y, changed, line2); + } + + gfxDrawSprites(lineOBJ); + gfxDrawOBJWin(lineOBJWin); + + u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); + + u8 inWin0Mask = WININ & 0xFF; + u8 inWin1Mask = WININ >> 8; + u8 outMask = WINOUT & 0xFF; + + for(int x = 0; x < 240; x++) { + u32 color = backdrop; + u8 top = 0x20; + u8 mask = outMask; + + if(!(lineOBJWin[x] & 0x80000000)) { + mask = WINOUT >> 8; + } + + if(inWindow1) { + if(gfxInWin1[x]) + mask = inWin1Mask; + } + + if(inWindow0) { + if(gfxInWin0[x]) { + mask = inWin0Mask; + } + } + + if(line0[x] < color && (mask & 1)) { + color = line0[x]; + top = 0x01; + } + + if((u8)(line1[x]>>24) < (u8)(color >> 24) && (mask & 2)) { + color = line1[x]; + top = 0x02; + } + + if((u8)(line2[x]>>24) < (u8)(color >> 24) && (mask & 4)) { + color = line2[x]; + top = 0x04; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16)) { + color = lineOBJ[x]; + top = 0x10; + } + + if(color & 0x00010000) { + // semi-transparent OBJ + u32 back = backdrop; + u8 top2 = 0x20; + + if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) { + back = line0[x]; + top2 = 0x01; + } + + if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) { + back = line1[x]; + top2 = 0x02; + } + + if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) { + back = line2[x]; + top2 = 0x04; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } else if(mask & 32) { + // special FX on the window + switch((BLDMOD >> 6) & 3) { + case 0: + break; + case 1: + { + if(top & BLDMOD) { + u32 back = backdrop; + u8 top2 = 0x20; + + if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) { + if(top != 0x01) { + back = line0[x]; + top2 = 0x01; + } + } + + if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) { + if(top != 0x02) { + back = line1[x]; + top2 = 0x02; + } + } + + if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) { + if(top != 0x04) { + back = line2[x]; + top2 = 0x04; + } + } + + if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { + if(top != 0x10) { + back = lineOBJ[x]; + top2 = 0x10; + } + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + } + } + break; + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxLastVCOUNT = VCOUNT; +} diff --git a/source/vba/Mode2.cpp b/source/vba/Mode2.cpp index e2954cb..9b3bb52 100644 --- a/source/vba/Mode2.cpp +++ b/source/vba/Mode2.cpp @@ -1,550 +1,446 @@ -// 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. - -#include "GBA.h" -#include "Globals.h" -#include "Gfx.h" - -void mode2RenderLine() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x80) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - if(layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - BG2PA, BG2PB, BG2PC, BG2PD, gfxBG2X, gfxBG2Y, - changed, line2); - } - - if(layerEnable & 0x0800) - { - int changed = gfxBG3Changed; - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen(BG3CNT, BG3X_L, BG3X_H, BG3Y_L, BG3Y_H, - BG3PA, BG3PB, BG3PC, BG3PD, gfxBG3X, gfxBG3Y, - changed, line3); - } - - gfxDrawSprites(lineOBJ); - - u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = backdrop; - u8 top = 0x20; - - - if((u8)(line2[x]>>24) < (u8)(color >> 24)) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(line3[x]>>24) < (u8)(color >> 24)) - { - color = line3[x]; - top = 0x08; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if((top & 0x10) && (color & 0x00010000)) - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((u8)(line2[x]>>24) < (u8)(back >> 24)) - { - back = line2[x]; - top2 = 0x04; - } - - if((u8)(line3[x]>>24) < (u8)(back >> 24)) - { - back = line3[x]; - top2 = 0x08; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxBG3Changed = 0; - gfxLastVCOUNT = VCOUNT; -} - -void mode2RenderLineNoWindow() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x80) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - if(layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - BG2PA, BG2PB, BG2PC, BG2PD, gfxBG2X, gfxBG2Y, - changed, line2); - } - - if(layerEnable & 0x0800) - { - int changed = gfxBG3Changed; - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen(BG3CNT, BG3X_L, BG3X_H, BG3Y_L, BG3Y_H, - BG3PA, BG3PB, BG3PC, BG3PD, gfxBG3X, gfxBG3Y, - changed, line3); - } - - gfxDrawSprites(lineOBJ); - - u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = backdrop; - u8 top = 0x20; - - - if((u8)(line2[x]>>24) < (u8)(color >> 24)) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(line3[x]>>24) < (u8)(color >> 24)) - { - color = line3[x]; - top = 0x08; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if(!(color & 0x00010000)) - { - switch((BLDMOD >> 6) & 3) - { - case 0: - break; - case 1: - { - if(top & BLDMOD) - { - u32 back = backdrop; - u8 top2 = 0x20; - - if((u8)(line2[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x04) - { - back = line2[x]; - top2 = 0x04; - } - } - - if((u8)(line3[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x08) - { - back = line3[x]; - top2 = 0x08; - } - } - - if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x10) - { - back = lineOBJ[x]; - top2 = 0x10; - } - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - else - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((u8)(line2[x]>>24) < (u8)(back >> 24)) - { - back = line2[x]; - top2 = 0x04; - } - - if((u8)(line3[x]>>24) < (u8)(back >> 24)) - { - back = line3[x]; - top2 = 0x08; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxBG3Changed = 0; - gfxLastVCOUNT = VCOUNT; -} - -void mode2RenderLineAll() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x80) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - bool inWindow0 = false; - bool inWindow1 = false; - - if(layerEnable & 0x2000) - { - u8 v0 = WIN0V >> 8; - u8 v1 = WIN0V & 255; - inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1); - else - inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1); - } - if(layerEnable & 0x4000) - { - u8 v0 = WIN1V >> 8; - u8 v1 = WIN1V & 255; - inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1); - else - inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1); - } - - if(layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - BG2PA, BG2PB, BG2PC, BG2PD, gfxBG2X, gfxBG2Y, - changed, line2); - } - - if(layerEnable & 0x0800) - { - int changed = gfxBG3Changed; - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen(BG3CNT, BG3X_L, BG3X_H, BG3Y_L, BG3Y_H, - BG3PA, BG3PB, BG3PC, BG3PD, gfxBG3X, gfxBG3Y, - changed, line3); - } - - gfxDrawSprites(lineOBJ); - gfxDrawOBJWin(lineOBJWin); - - u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); - - u8 inWin0Mask = WININ & 0xFF; - u8 inWin1Mask = WININ >> 8; - u8 outMask = WINOUT & 0xFF; - - for(int x = 0; x < 240; x++) - { - u32 color = backdrop; - u8 top = 0x20; - u8 mask = outMask; - - if(!(lineOBJWin[x] & 0x80000000)) - { - mask = WINOUT >> 8; - } - - if(inWindow1) - { - if(gfxInWin1[x]) - mask = inWin1Mask; - } - - if(inWindow0) - { - if(gfxInWin0[x]) - { - mask = inWin0Mask; - } - } - - if(line2[x] < color && (mask & 4)) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(line3[x]>>24) < (u8)(color >> 24) && (mask & 8)) - { - color = line3[x]; - top = 0x08; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if(mask & 32) - { - if(!(color & 0x00010000)) - { - switch((BLDMOD >> 6) & 3) - { - case 0: - break; - case 1: - { - if(top & BLDMOD) - { - u32 back = backdrop; - u8 top2 = 0x20; - - if((mask & 4) && line2[x] < back) - { - if(top != 0x04) - { - back = line2[x]; - top2 = 0x04; - } - } - - if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x08) - { - back = line3[x]; - top2 = 0x08; - } - } - - if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x10) - { - back = lineOBJ[x]; - top2 = 0x10; - } - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - else - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((mask & 4) && line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) - { - back = line3[x]; - top2 = 0x08; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - } - else if(color & 0x00010000) - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((mask & 4) && line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) - { - back = line3[x]; - top2 = 0x08; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxBG3Changed = 0; - gfxLastVCOUNT = VCOUNT; -} +// 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. + +#include "agb/GBA.h" +#include "Globals.h" +#include "agb/GBAGfx.h" + +void mode2RenderLine() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x80) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + if(layerEnable & 0x0400) { + int changed = gfxBG2Changed; + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, + BG2PA, BG2PB, BG2PC, BG2PD, gfxBG2X, gfxBG2Y, + changed, line2); + } + + if(layerEnable & 0x0800) { + int changed = gfxBG3Changed; + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen(BG3CNT, BG3X_L, BG3X_H, BG3Y_L, BG3Y_H, + BG3PA, BG3PB, BG3PC, BG3PD, gfxBG3X, gfxBG3Y, + changed, line3); + } + + gfxDrawSprites(lineOBJ); + + u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = backdrop; + u8 top = 0x20; + + + if((u8)(line2[x]>>24) < (u8)(color >> 24)) { + color = line2[x]; + top = 0x04; + } + + if((u8)(line3[x]>>24) < (u8)(color >> 24)) { + color = line3[x]; + top = 0x08; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) { + color = lineOBJ[x]; + top = 0x10; + } + + if((top & 0x10) && (color & 0x00010000)) { + // semi-transparent OBJ + u32 back = backdrop; + u8 top2 = 0x20; + + if((u8)(line2[x]>>24) < (u8)(back >> 24)) { + back = line2[x]; + top2 = 0x04; + } + + if((u8)(line3[x]>>24) < (u8)(back >> 24)) { + back = line3[x]; + top2 = 0x08; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxBG3Changed = 0; + gfxLastVCOUNT = VCOUNT; +} + +void mode2RenderLineNoWindow() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x80) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + if(layerEnable & 0x0400) { + int changed = gfxBG2Changed; + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, + BG2PA, BG2PB, BG2PC, BG2PD, gfxBG2X, gfxBG2Y, + changed, line2); + } + + if(layerEnable & 0x0800) { + int changed = gfxBG3Changed; + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen(BG3CNT, BG3X_L, BG3X_H, BG3Y_L, BG3Y_H, + BG3PA, BG3PB, BG3PC, BG3PD, gfxBG3X, gfxBG3Y, + changed, line3); + } + + gfxDrawSprites(lineOBJ); + + u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = backdrop; + u8 top = 0x20; + + + if((u8)(line2[x]>>24) < (u8)(color >> 24)) { + color = line2[x]; + top = 0x04; + } + + if((u8)(line3[x]>>24) < (u8)(color >> 24)) { + color = line3[x]; + top = 0x08; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) { + color = lineOBJ[x]; + top = 0x10; + } + + if(!(color & 0x00010000)) { + switch((BLDMOD >> 6) & 3) { + case 0: + break; + case 1: + { + if(top & BLDMOD) { + u32 back = backdrop; + u8 top2 = 0x20; + + if((u8)(line2[x]>>24) < (u8)(back >> 24)) { + if(top != 0x04) { + back = line2[x]; + top2 = 0x04; + } + } + + if((u8)(line3[x]>>24) < (u8)(back >> 24)) { + if(top != 0x08) { + back = line3[x]; + top2 = 0x08; + } + } + + if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { + if(top != 0x10) { + back = lineOBJ[x]; + top2 = 0x10; + } + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + } + } + break; + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } else { + // semi-transparent OBJ + u32 back = backdrop; + u8 top2 = 0x20; + + if((u8)(line2[x]>>24) < (u8)(back >> 24)) { + back = line2[x]; + top2 = 0x04; + } + + if((u8)(line3[x]>>24) < (u8)(back >> 24)) { + back = line3[x]; + top2 = 0x08; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxBG3Changed = 0; + gfxLastVCOUNT = VCOUNT; +} + +void mode2RenderLineAll() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x80) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + bool inWindow0 = false; + bool inWindow1 = false; + + if(layerEnable & 0x2000) { + u8 v0 = WIN0V >> 8; + u8 v1 = WIN0V & 255; + inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); + if(v1 >= v0) + inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1); + else + inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1); + } + if(layerEnable & 0x4000) { + u8 v0 = WIN1V >> 8; + u8 v1 = WIN1V & 255; + inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); + if(v1 >= v0) + inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1); + else + inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1); + } + + if(layerEnable & 0x0400) { + int changed = gfxBG2Changed; + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, + BG2PA, BG2PB, BG2PC, BG2PD, gfxBG2X, gfxBG2Y, + changed, line2); + } + + if(layerEnable & 0x0800) { + int changed = gfxBG3Changed; + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen(BG3CNT, BG3X_L, BG3X_H, BG3Y_L, BG3Y_H, + BG3PA, BG3PB, BG3PC, BG3PD, gfxBG3X, gfxBG3Y, + changed, line3); + } + + gfxDrawSprites(lineOBJ); + gfxDrawOBJWin(lineOBJWin); + + u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); + + u8 inWin0Mask = WININ & 0xFF; + u8 inWin1Mask = WININ >> 8; + u8 outMask = WINOUT & 0xFF; + + for(int x = 0; x < 240; x++) { + u32 color = backdrop; + u8 top = 0x20; + u8 mask = outMask; + + if(!(lineOBJWin[x] & 0x80000000)) { + mask = WINOUT >> 8; + } + + if(inWindow1) { + if(gfxInWin1[x]) + mask = inWin1Mask; + } + + if(inWindow0) { + if(gfxInWin0[x]) { + mask = inWin0Mask; + } + } + + if(line2[x] < color && (mask & 4)) { + color = line2[x]; + top = 0x04; + } + + if((u8)(line3[x]>>24) < (u8)(color >> 24) && (mask & 8)) { + color = line3[x]; + top = 0x08; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16)) { + color = lineOBJ[x]; + top = 0x10; + } + + if(color & 0x00010000) { + // semi-transparent OBJ + u32 back = backdrop; + u8 top2 = 0x20; + + if((mask & 4) && line2[x] < back) { + back = line2[x]; + top2 = 0x04; + } + + if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) { + back = line3[x]; + top2 = 0x08; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } else if(mask & 32) { + // special FX on the window + switch((BLDMOD >> 6) & 3) { + case 0: + break; + case 1: + { + if(top & BLDMOD) { + u32 back = backdrop; + u8 top2 = 0x20; + + if((mask & 4) && line2[x] < back) { + if(top != 0x04) { + back = line2[x]; + top2 = 0x04; + } + } + + if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) { + if(top != 0x08) { + back = line3[x]; + top2 = 0x08; + } + } + + if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { + if(top != 0x10) { + back = lineOBJ[x]; + top2 = 0x10; + } + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + } + } + break; + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxBG3Changed = 0; + gfxLastVCOUNT = VCOUNT; +} diff --git a/source/vba/Mode3.cpp b/source/vba/Mode3.cpp index 8a61021..74766c6 100644 --- a/source/vba/Mode3.cpp +++ b/source/vba/Mode3.cpp @@ -1,463 +1,377 @@ -// 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. - -#include "GBA.h" -#include "Globals.h" -#include "Gfx.h" - -void mode3RenderLine() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x80) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - if(layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen16Bit(BG2CNT, BG2X_L, BG2X_H, - BG2Y_L, BG2Y_H, BG2PA, BG2PB, - BG2PC, BG2PD, - gfxBG2X, gfxBG2Y, changed, - line2); - } - - gfxDrawSprites(lineOBJ); - - u32 background = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = background; - u8 top = 0x20; - - if(line2[x] < color) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >>24)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if((top & 0x10) && (color & 0x00010000)) - { - // semi-transparent OBJ - u32 back = background; - u8 top2 = 0x20; - - if(line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxLastVCOUNT = VCOUNT; -} - -void mode3RenderLineNoWindow() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x80) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - if(layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen16Bit(BG2CNT, BG2X_L, BG2X_H, - BG2Y_L, BG2Y_H, BG2PA, BG2PB, - BG2PC, BG2PD, - gfxBG2X, gfxBG2Y, changed, - line2); - } - - gfxDrawSprites(lineOBJ); - - u32 background = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = background; - u8 top = 0x20; - - if(line2[x] < color) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >>24)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if(!(color & 0x00010000)) - { - switch((BLDMOD >> 6) & 3) - { - case 0: - break; - case 1: - { - if(top & BLDMOD) - { - u32 back = background; - u8 top2 = 0x20; - - if(line2[x] < back) - { - if(top != 0x04) - { - back = line2[x]; - top2 = 0x04; - } - } - - if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x10) - { - back = lineOBJ[x]; - top2 = 0x10; - } - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - else - { - // semi-transparent OBJ - u32 back = background; - u8 top2 = 0x20; - - if(line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxLastVCOUNT = VCOUNT; -} - -void mode3RenderLineAll() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x80) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - bool inWindow0 = false; - bool inWindow1 = false; - - if(layerEnable & 0x2000) - { - u8 v0 = WIN0V >> 8; - u8 v1 = WIN0V & 255; - inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1); - else - inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1); - } - if(layerEnable & 0x4000) - { - u8 v0 = WIN1V >> 8; - u8 v1 = WIN1V & 255; - inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1); - else - inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1); - } - - if(layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen16Bit(BG2CNT, BG2X_L, BG2X_H, - BG2Y_L, BG2Y_H, BG2PA, BG2PB, - BG2PC, BG2PD, - gfxBG2X, gfxBG2Y, changed, - line2); - } - - gfxDrawSprites(lineOBJ); - gfxDrawOBJWin(lineOBJWin); - - u8 inWin0Mask = WININ & 0xFF; - u8 inWin1Mask = WININ >> 8; - u8 outMask = WINOUT & 0xFF; - - u32 background = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = background; - u8 top = 0x20; - u8 mask = outMask; - - if(!(lineOBJWin[x] & 0x80000000)) - { - mask = WINOUT >> 8; - } - - if(inWindow1) - { - if(gfxInWin1[x]) - mask = inWin1Mask; - } - - if(inWindow0) - { - if(gfxInWin0[x]) - { - mask = inWin0Mask; - } - } - - if((mask & 4) && (line2[x] < color)) - { - color = line2[x]; - top = 0x04; - } - - if((mask & 16) && ((u8)(lineOBJ[x]>>24) < (u8)(color >>24))) - { - color = lineOBJ[x]; - top = 0x10; - } - - if(mask & 32) - { - if(!(color & 0x00010000)) - { - switch((BLDMOD >> 6) & 3) - { - case 0: - break; - case 1: - { - if(top & BLDMOD) - { - u32 back = background; - u8 top2 = 0x20; - - if((mask & 4) && line2[x] < back) - { - if(top != 0x04) - { - back = line2[x]; - top2 = 0x04; - } - } - - if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x10) - { - back = lineOBJ[x]; - top2 = 0x10; - } - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - else - { - // semi-transparent OBJ - u32 back = background; - u8 top2 = 0x20; - - if((mask & 4) && line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - } - else if(color & 0x00010000) - { - // semi-transparent OBJ - u32 back = background; - u8 top2 = 0x20; - - if((mask & 4) && line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxLastVCOUNT = VCOUNT; -} +// 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. + +#include "agb/GBA.h" +#include "Globals.h" +#include "agb/GBAGfx.h" + +void mode3RenderLine() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x80) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + if(layerEnable & 0x0400) { + int changed = gfxBG2Changed; + + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen16Bit(BG2CNT, BG2X_L, BG2X_H, + BG2Y_L, BG2Y_H, BG2PA, BG2PB, + BG2PC, BG2PD, + gfxBG2X, gfxBG2Y, changed, + line2); + } + + gfxDrawSprites(lineOBJ); + + u32 background = (READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = background; + u8 top = 0x20; + + if(line2[x] < color) { + color = line2[x]; + top = 0x04; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >>24)) { + color = lineOBJ[x]; + top = 0x10; + } + + if((top & 0x10) && (color & 0x00010000)) { + // semi-transparent OBJ + u32 back = background; + u8 top2 = 0x20; + + if(line2[x] < back) { + back = line2[x]; + top2 = 0x04; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxLastVCOUNT = VCOUNT; +} + +void mode3RenderLineNoWindow() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x80) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + if(layerEnable & 0x0400) { + int changed = gfxBG2Changed; + + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen16Bit(BG2CNT, BG2X_L, BG2X_H, + BG2Y_L, BG2Y_H, BG2PA, BG2PB, + BG2PC, BG2PD, + gfxBG2X, gfxBG2Y, changed, + line2); + } + + gfxDrawSprites(lineOBJ); + + u32 background = (READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = background; + u8 top = 0x20; + + if(line2[x] < color) { + color = line2[x]; + top = 0x04; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >>24)) { + color = lineOBJ[x]; + top = 0x10; + } + + if(!(color & 0x00010000)) { + switch((BLDMOD >> 6) & 3) { + case 0: + break; + case 1: + { + if(top & BLDMOD) { + u32 back = background; + u8 top2 = 0x20; + + if(line2[x] < back) { + if(top != 0x04) { + back = line2[x]; + top2 = 0x04; + } + } + + if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { + if(top != 0x10) { + back = lineOBJ[x]; + top2 = 0x10; + } + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + + } + } + break; + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } else { + // semi-transparent OBJ + u32 back = background; + u8 top2 = 0x20; + + if(line2[x] < back) { + back = line2[x]; + top2 = 0x04; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxLastVCOUNT = VCOUNT; +} + +void mode3RenderLineAll() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x80) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + bool inWindow0 = false; + bool inWindow1 = false; + + if(layerEnable & 0x2000) { + u8 v0 = WIN0V >> 8; + u8 v1 = WIN0V & 255; + inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); + if(v1 >= v0) + inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1); + else + inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1); + } + if(layerEnable & 0x4000) { + u8 v0 = WIN1V >> 8; + u8 v1 = WIN1V & 255; + inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); + if(v1 >= v0) + inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1); + else + inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1); + } + + if(layerEnable & 0x0400) { + int changed = gfxBG2Changed; + + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen16Bit(BG2CNT, BG2X_L, BG2X_H, + BG2Y_L, BG2Y_H, BG2PA, BG2PB, + BG2PC, BG2PD, + gfxBG2X, gfxBG2Y, changed, + line2); + } + + gfxDrawSprites(lineOBJ); + gfxDrawOBJWin(lineOBJWin); + + u8 inWin0Mask = WININ & 0xFF; + u8 inWin1Mask = WININ >> 8; + u8 outMask = WINOUT & 0xFF; + + u32 background = (READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = background; + u8 top = 0x20; + u8 mask = outMask; + + if(!(lineOBJWin[x] & 0x80000000)) { + mask = WINOUT >> 8; + } + + if(inWindow1) { + if(gfxInWin1[x]) + mask = inWin1Mask; + } + + if(inWindow0) { + if(gfxInWin0[x]) { + mask = inWin0Mask; + } + } + + if((mask & 4) && (line2[x] < color)) { + color = line2[x]; + top = 0x04; + } + + if((mask & 16) && ((u8)(lineOBJ[x]>>24) < (u8)(color >>24))) { + color = lineOBJ[x]; + top = 0x10; + } + + if(color & 0x00010000) { + // semi-transparent OBJ + u32 back = background; + u8 top2 = 0x20; + + if((mask & 4) && line2[x] < back) { + back = line2[x]; + top2 = 0x04; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } else if(mask & 32) { + switch((BLDMOD >> 6) & 3) { + case 0: + break; + case 1: + { + if(top & BLDMOD) { + u32 back = background; + u8 top2 = 0x20; + + if((mask & 4) && line2[x] < back) { + if(top != 0x04) { + back = line2[x]; + top2 = 0x04; + } + } + + if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { + if(top != 0x10) { + back = lineOBJ[x]; + top2 = 0x10; + } + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + + } + } + break; + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxLastVCOUNT = VCOUNT; +} diff --git a/source/vba/Mode4.cpp b/source/vba/Mode4.cpp index a451172..957592c 100644 --- a/source/vba/Mode4.cpp +++ b/source/vba/Mode4.cpp @@ -1,460 +1,374 @@ -// 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. - -#include "GBA.h" -#include "Gfx.h" -#include "Globals.h" - -void mode4RenderLine() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x0080) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - if(layerEnable & 0x400) - { - int changed = gfxBG2Changed; - - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen256(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - BG2PA, BG2PB, BG2PC, BG2PD, - gfxBG2X, gfxBG2Y, changed, - line2); - } - - gfxDrawSprites(lineOBJ); - - u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = backdrop; - u8 top = 0x20; - - if(line2[x] < color) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if((top & 0x10) && (color & 0x00010000)) - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if(line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxLastVCOUNT = VCOUNT; -} - -void mode4RenderLineNoWindow() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x0080) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - if(layerEnable & 0x400) - { - int changed = gfxBG2Changed; - - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen256(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - BG2PA, BG2PB, BG2PC, BG2PD, - gfxBG2X, gfxBG2Y, changed, - line2); - } - - gfxDrawSprites(lineOBJ); - - u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = backdrop; - u8 top = 0x20; - - if(line2[x] < color) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if(!(color & 0x00010000)) - { - switch((BLDMOD >> 6) & 3) - { - case 0: - break; - case 1: - { - if(top & BLDMOD) - { - u32 back = backdrop; - u8 top2 = 0x20; - - if(line2[x] < back) - { - if(top != 0x04) - { - back = line2[x]; - top2 = 0x04; - } - } - - if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x10) - { - back = lineOBJ[x]; - top2 = 0x10; - } - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - else - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if(line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxLastVCOUNT = VCOUNT; -} - -void mode4RenderLineAll() -{ - u16 *palette = (u16 *)paletteRAM; - - if(DISPCNT & 0x0080) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - bool inWindow0 = false; - bool inWindow1 = false; - - if(layerEnable & 0x2000) - { - u8 v0 = WIN0V >> 8; - u8 v1 = WIN0V & 255; - inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1); - else - inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1); - } - if(layerEnable & 0x4000) - { - u8 v0 = WIN1V >> 8; - u8 v1 = WIN1V & 255; - inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1); - else - inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1); - } - - if(layerEnable & 0x400) - { - int changed = gfxBG2Changed; - - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen256(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, - BG2PA, BG2PB, BG2PC, BG2PD, - gfxBG2X, gfxBG2Y, changed, - line2); - } - - gfxDrawSprites(lineOBJ); - gfxDrawOBJWin(lineOBJWin); - - u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); - - u8 inWin0Mask = WININ & 0xFF; - u8 inWin1Mask = WININ >> 8; - u8 outMask = WINOUT & 0xFF; - - for(int x = 0; x < 240; x++) - { - u32 color = backdrop; - u8 top = 0x20; - u8 mask = outMask; - - if(!(lineOBJWin[x] & 0x80000000)) - { - mask = WINOUT >> 8; - } - - if(inWindow1) - { - if(gfxInWin1[x]) - mask = inWin1Mask; - } - - if(inWindow0) - { - if(gfxInWin0[x]) - { - mask = inWin0Mask; - } - } - - if((mask & 4) && (line2[x] < color)) - { - color = line2[x]; - top = 0x04; - } - - if((mask & 16) && ((u8)(lineOBJ[x]>>24) < (u8)(color >>24))) - { - color = lineOBJ[x]; - top = 0x10; - } - - if(mask & 32) - { - if(!(color & 0x00010000)) - { - switch((BLDMOD >> 6) & 3) - { - case 0: - break; - case 1: - { - if(top & BLDMOD) - { - u32 back = backdrop; - u8 top2 = 0x20; - - if((mask & 4) && line2[x] < back) - { - if(top != 0x04) - { - back = line2[x]; - top2 = 0x04; - } - } - - if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x10) - { - back = lineOBJ[x]; - top2 = 0x10; - } - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - else - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((mask & 4) && line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - } - else if(color & 0x00010000) - { - // semi-transparent OBJ - u32 back = backdrop; - u8 top2 = 0x20; - - if((mask & 4) && line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxLastVCOUNT = VCOUNT; -} +// 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. + +#include "agb/GBA.h" +#include "agb/GBAGfx.h" +#include "Globals.h" + +void mode4RenderLine() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x0080) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + if(layerEnable & 0x400) { + int changed = gfxBG2Changed; + + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen256(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, + BG2PA, BG2PB, BG2PC, BG2PD, + gfxBG2X, gfxBG2Y, changed, + line2); + } + + gfxDrawSprites(lineOBJ); + + u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = backdrop; + u8 top = 0x20; + + if(line2[x] < color) { + color = line2[x]; + top = 0x04; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) { + color = lineOBJ[x]; + top = 0x10; + } + + if((top & 0x10) && (color & 0x00010000)) { + // semi-transparent OBJ + u32 back = backdrop; + u8 top2 = 0x20; + + if(line2[x] < back) { + back = line2[x]; + top2 = 0x04; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxLastVCOUNT = VCOUNT; +} + +void mode4RenderLineNoWindow() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x0080) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + if(layerEnable & 0x400) { + int changed = gfxBG2Changed; + + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen256(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, + BG2PA, BG2PB, BG2PC, BG2PD, + gfxBG2X, gfxBG2Y, changed, + line2); + } + + gfxDrawSprites(lineOBJ); + + u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = backdrop; + u8 top = 0x20; + + if(line2[x] < color) { + color = line2[x]; + top = 0x04; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) { + color = lineOBJ[x]; + top = 0x10; + } + + if(!(color & 0x00010000)) { + switch((BLDMOD >> 6) & 3) { + case 0: + break; + case 1: + { + if(top & BLDMOD) { + u32 back = backdrop; + u8 top2 = 0x20; + + if(line2[x] < back) { + if(top != 0x04) { + back = line2[x]; + top2 = 0x04; + } + } + + if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { + if(top != 0x10) { + back = lineOBJ[x]; + top2 = 0x10; + } + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + + } + } + break; + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } else { + // semi-transparent OBJ + u32 back = backdrop; + u8 top2 = 0x20; + + if(line2[x] < back) { + back = line2[x]; + top2 = 0x04; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxLastVCOUNT = VCOUNT; +} + +void mode4RenderLineAll() +{ + u16 *palette = (u16 *)paletteRAM; + + if(DISPCNT & 0x0080) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + bool inWindow0 = false; + bool inWindow1 = false; + + if(layerEnable & 0x2000) { + u8 v0 = WIN0V >> 8; + u8 v1 = WIN0V & 255; + inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); + if(v1 >= v0) + inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1); + else + inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1); + } + if(layerEnable & 0x4000) { + u8 v0 = WIN1V >> 8; + u8 v1 = WIN1V & 255; + inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); + if(v1 >= v0) + inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1); + else + inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1); + } + + if(layerEnable & 0x400) { + int changed = gfxBG2Changed; + + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen256(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H, + BG2PA, BG2PB, BG2PC, BG2PD, + gfxBG2X, gfxBG2Y, changed, + line2); + } + + gfxDrawSprites(lineOBJ); + gfxDrawOBJWin(lineOBJWin); + + u32 backdrop = (READ16LE(&palette[0]) | 0x30000000); + + u8 inWin0Mask = WININ & 0xFF; + u8 inWin1Mask = WININ >> 8; + u8 outMask = WINOUT & 0xFF; + + for(int x = 0; x < 240; x++) { + u32 color = backdrop; + u8 top = 0x20; + u8 mask = outMask; + + if(!(lineOBJWin[x] & 0x80000000)) { + mask = WINOUT >> 8; + } + + if(inWindow1) { + if(gfxInWin1[x]) + mask = inWin1Mask; + } + + if(inWindow0) { + if(gfxInWin0[x]) { + mask = inWin0Mask; + } + } + + if((mask & 4) && (line2[x] < color)) { + color = line2[x]; + top = 0x04; + } + + if((mask & 16) && ((u8)(lineOBJ[x]>>24) < (u8)(color >>24))) { + color = lineOBJ[x]; + top = 0x10; + } + + if(color & 0x00010000) { + // semi-transparent OBJ + u32 back = backdrop; + u8 top2 = 0x20; + + if((mask & 4) && line2[x] < back) { + back = line2[x]; + top2 = 0x04; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } else if(mask & 32) { + switch((BLDMOD >> 6) & 3) { + case 0: + break; + case 1: + { + if(top & BLDMOD) { + u32 back = backdrop; + u8 top2 = 0x20; + + if((mask & 4) && line2[x] < back) { + if(top != 0x04) { + back = line2[x]; + top2 = 0x04; + } + } + + if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { + if(top != 0x10) { + back = lineOBJ[x]; + top2 = 0x10; + } + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + + } + } + break; + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxLastVCOUNT = VCOUNT; +} diff --git a/source/vba/Mode5.cpp b/source/vba/Mode5.cpp index 83c4390..2b99661 100644 --- a/source/vba/Mode5.cpp +++ b/source/vba/Mode5.cpp @@ -1,463 +1,377 @@ -// 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. - -#include "GBA.h" -#include "Globals.h" -#include "Gfx.h" - -void mode5RenderLine() -{ - if(DISPCNT & 0x0080) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - u16 *palette = (u16 *)paletteRAM; - - if(layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen16Bit160(BG2CNT, BG2X_L, BG2X_H, - BG2Y_L, BG2Y_H, BG2PA, BG2PB, - BG2PC, BG2PD, - gfxBG2X, gfxBG2Y, changed, - line2); - } - - gfxDrawSprites(lineOBJ); - - u32 background = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = background; - u8 top = 0x20; - - if(line2[x] < color) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >>24)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if((top & 0x10) && (color & 0x00010000)) - { - // semi-transparent OBJ - u32 back = background; - u8 top2 = 0x20; - - if(line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxLastVCOUNT = VCOUNT; -} - -void mode5RenderLineNoWindow() -{ - if(DISPCNT & 0x0080) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - u16 *palette = (u16 *)paletteRAM; - - if(layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen16Bit160(BG2CNT, BG2X_L, BG2X_H, - BG2Y_L, BG2Y_H, BG2PA, BG2PB, - BG2PC, BG2PD, - gfxBG2X, gfxBG2Y, changed, - line2); - } - - gfxDrawSprites(lineOBJ); - - u32 background = ( READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = background; - u8 top = 0x20; - - if(line2[x] < color) - { - color = line2[x]; - top = 0x04; - } - - if((u8)(lineOBJ[x]>>24) < (u8)(color >>24)) - { - color = lineOBJ[x]; - top = 0x10; - } - - if(!(color & 0x00010000)) - { - switch((BLDMOD >> 6) & 3) - { - case 0: - break; - case 1: - { - if(top & BLDMOD) - { - u32 back = background; - u8 top2 = 0x20; - - if(line2[x] < back) - { - if(top != 0x04) - { - back = line2[x]; - top2 = 0x04; - } - } - - if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x10) - { - back = lineOBJ[x]; - top2 = 0x10; - } - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - else - { - // semi-transparent OBJ - u32 back = background; - u8 top2 = 0x20; - - if(line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxLastVCOUNT = VCOUNT; -} - -void mode5RenderLineAll() -{ - if(DISPCNT & 0x0080) - { - for(int x = 0; x < 240; x++) - { - lineMix[x] = 0x7fff; - } - gfxLastVCOUNT = VCOUNT; - return; - } - - u16 *palette = (u16 *)paletteRAM; - - if(layerEnable & 0x0400) - { - int changed = gfxBG2Changed; - - if(gfxLastVCOUNT > VCOUNT) - changed = 3; - - gfxDrawRotScreen16Bit160(BG2CNT, BG2X_L, BG2X_H, - BG2Y_L, BG2Y_H, BG2PA, BG2PB, - BG2PC, BG2PD, - gfxBG2X, gfxBG2Y, changed, - line2); - } - - gfxDrawSprites(lineOBJ); - gfxDrawOBJWin(lineOBJWin); - - bool inWindow0 = false; - bool inWindow1 = false; - - if(layerEnable & 0x2000) - { - u8 v0 = WIN0V >> 8; - u8 v1 = WIN0V & 255; - inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1); - else - inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1); - } - if(layerEnable & 0x4000) - { - u8 v0 = WIN1V >> 8; - u8 v1 = WIN1V & 255; - inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); - if(v1 >= v0) - inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1); - else - inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1); - } - - u8 inWin0Mask = WININ & 0xFF; - u8 inWin1Mask = WININ >> 8; - u8 outMask = WINOUT & 0xFF; - - u32 background = (READ16LE(&palette[0]) | 0x30000000); - - for(int x = 0; x < 240; x++) - { - u32 color = background; - u8 top = 0x20; - u8 mask = outMask; - - if(!(lineOBJWin[x] & 0x80000000)) - { - mask = WINOUT >> 8; - } - - if(inWindow1) - { - if(gfxInWin1[x]) - mask = inWin1Mask; - } - - if(inWindow0) - { - if(gfxInWin0[x]) - { - mask = inWin0Mask; - } - } - - if((mask & 4) && (line2[x] < color)) - { - color = line2[x]; - top = 0x04; - } - - if((mask & 16) && ((u8)(lineOBJ[x]>>24) < (u8)(color >>24))) - { - color = lineOBJ[x]; - top = 0x10; - } - - if(mask & 32) - { - if(!(color & 0x00010000)) - { - switch((BLDMOD >> 6) & 3) - { - case 0: - break; - case 1: - { - if(top & BLDMOD) - { - u32 back = background; - u8 top2 = 0x20; - - if((mask & 4) && line2[x] < back) - { - if(top != 0x04) - { - back = line2[x]; - top2 = 0x04; - } - } - - if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) - { - if(top != 0x10) - { - back = lineOBJ[x]; - top2 = 0x10; - } - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - - } - } - break; - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - else - { - // semi-transparent OBJ - u32 back = background; - u8 top2 = 0x20; - - if((mask & 4) && line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - } - else if(color & 0x00010000) - { - // semi-transparent OBJ - u32 back = background; - u8 top2 = 0x20; - - if((mask & 4) && line2[x] < back) - { - back = line2[x]; - top2 = 0x04; - } - - if(top2 & (BLDMOD>>8)) - color = gfxAlphaBlend(color, back, - coeff[COLEV & 0x1F], - coeff[(COLEV >> 8) & 0x1F]); - else - { - switch((BLDMOD >> 6) & 3) - { - case 2: - if(BLDMOD & top) - color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); - break; - case 3: - if(BLDMOD & top) - color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); - break; - } - } - } - - lineMix[x] = color; - } - gfxBG2Changed = 0; - gfxLastVCOUNT = VCOUNT; -} +// 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. + +#include "agb/GBA.h" +#include "Globals.h" +#include "agb/GBAGfx.h" + +void mode5RenderLine() +{ + if(DISPCNT & 0x0080) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + u16 *palette = (u16 *)paletteRAM; + + if(layerEnable & 0x0400) { + int changed = gfxBG2Changed; + + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen16Bit160(BG2CNT, BG2X_L, BG2X_H, + BG2Y_L, BG2Y_H, BG2PA, BG2PB, + BG2PC, BG2PD, + gfxBG2X, gfxBG2Y, changed, + line2); + } + + gfxDrawSprites(lineOBJ); + + u32 background = (READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = background; + u8 top = 0x20; + + if(line2[x] < color) { + color = line2[x]; + top = 0x04; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >>24)) { + color = lineOBJ[x]; + top = 0x10; + } + + if((top & 0x10) && (color & 0x00010000)) { + // semi-transparent OBJ + u32 back = background; + u8 top2 = 0x20; + + if(line2[x] < back) { + back = line2[x]; + top2 = 0x04; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxLastVCOUNT = VCOUNT; +} + +void mode5RenderLineNoWindow() +{ + if(DISPCNT & 0x0080) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + u16 *palette = (u16 *)paletteRAM; + + if(layerEnable & 0x0400) { + int changed = gfxBG2Changed; + + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen16Bit160(BG2CNT, BG2X_L, BG2X_H, + BG2Y_L, BG2Y_H, BG2PA, BG2PB, + BG2PC, BG2PD, + gfxBG2X, gfxBG2Y, changed, + line2); + } + + gfxDrawSprites(lineOBJ); + + u32 background = ( READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = background; + u8 top = 0x20; + + if(line2[x] < color) { + color = line2[x]; + top = 0x04; + } + + if((u8)(lineOBJ[x]>>24) < (u8)(color >>24)) { + color = lineOBJ[x]; + top = 0x10; + } + + if(!(color & 0x00010000)) { + switch((BLDMOD >> 6) & 3) { + case 0: + break; + case 1: + { + if(top & BLDMOD) { + u32 back = background; + u8 top2 = 0x20; + + if(line2[x] < back) { + if(top != 0x04) { + back = line2[x]; + top2 = 0x04; + } + } + + if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { + if(top != 0x10) { + back = lineOBJ[x]; + top2 = 0x10; + } + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + + } + } + break; + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } else { + // semi-transparent OBJ + u32 back = background; + u8 top2 = 0x20; + + if(line2[x] < back) { + back = line2[x]; + top2 = 0x04; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxLastVCOUNT = VCOUNT; +} + +void mode5RenderLineAll() +{ + if(DISPCNT & 0x0080) { + for(int x = 0; x < 240; x++) { + lineMix[x] = 0x7fff; + } + gfxLastVCOUNT = VCOUNT; + return; + } + + u16 *palette = (u16 *)paletteRAM; + + if(layerEnable & 0x0400) { + int changed = gfxBG2Changed; + + if(gfxLastVCOUNT > VCOUNT) + changed = 3; + + gfxDrawRotScreen16Bit160(BG2CNT, BG2X_L, BG2X_H, + BG2Y_L, BG2Y_H, BG2PA, BG2PB, + BG2PC, BG2PD, + gfxBG2X, gfxBG2Y, changed, + line2); + } + + gfxDrawSprites(lineOBJ); + gfxDrawOBJWin(lineOBJWin); + + bool inWindow0 = false; + bool inWindow1 = false; + + if(layerEnable & 0x2000) { + u8 v0 = WIN0V >> 8; + u8 v1 = WIN0V & 255; + inWindow0 = ((v0 == v1) && (v0 >= 0xe8)); + if(v1 >= v0) + inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1); + else + inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1); + } + if(layerEnable & 0x4000) { + u8 v0 = WIN1V >> 8; + u8 v1 = WIN1V & 255; + inWindow1 = ((v0 == v1) && (v0 >= 0xe8)); + if(v1 >= v0) + inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1); + else + inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1); + } + + u8 inWin0Mask = WININ & 0xFF; + u8 inWin1Mask = WININ >> 8; + u8 outMask = WINOUT & 0xFF; + + u32 background = (READ16LE(&palette[0]) | 0x30000000); + + for(int x = 0; x < 240; x++) { + u32 color = background; + u8 top = 0x20; + u8 mask = outMask; + + if(!(lineOBJWin[x] & 0x80000000)) { + mask = WINOUT >> 8; + } + + if(inWindow1) { + if(gfxInWin1[x]) + mask = inWin1Mask; + } + + if(inWindow0) { + if(gfxInWin0[x]) { + mask = inWin0Mask; + } + } + + if((mask & 4) && (line2[x] < color)) { + color = line2[x]; + top = 0x04; + } + + if((mask & 16) && ((u8)(lineOBJ[x]>>24) < (u8)(color >>24))) { + color = lineOBJ[x]; + top = 0x10; + } + + if(color & 0x00010000) { + // semi-transparent OBJ + u32 back = background; + u8 top2 = 0x20; + + if((mask & 4) && line2[x] < back) { + back = line2[x]; + top2 = 0x04; + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + else { + switch((BLDMOD >> 6) & 3) { + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + } else if(mask & 32) { + switch((BLDMOD >> 6) & 3) { + case 0: + break; + case 1: + { + if(top & BLDMOD) { + u32 back = background; + u8 top2 = 0x20; + + if((mask & 4) && line2[x] < back) { + if(top != 0x04) { + back = line2[x]; + top2 = 0x04; + } + } + + if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { + if(top != 0x10) { + back = lineOBJ[x]; + top2 = 0x10; + } + } + + if(top2 & (BLDMOD>>8)) + color = gfxAlphaBlend(color, back, + coeff[COLEV & 0x1F], + coeff[(COLEV >> 8) & 0x1F]); + + } + } + break; + case 2: + if(BLDMOD & top) + color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]); + break; + case 3: + if(BLDMOD & top) + color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]); + break; + } + } + + lineMix[x] = color; + } + gfxBG2Changed = 0; + gfxLastVCOUNT = VCOUNT; +} diff --git a/source/vba/NLS.h b/source/vba/NLS.h index ca024de..44b7ff0 100644 --- a/source/vba/NLS.h +++ b/source/vba/NLS.h @@ -1,62 +1,64 @@ -// -*- 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. - -#define N_(String) (String) - -#define MSG_UNSUPPORTED_VBA_SGM 1 -#define MSG_CANNOT_LOAD_SGM 2 -#define MSG_SAVE_GAME_NOT_USING_BIOS 3 -#define MSG_SAVE_GAME_USING_BIOS 4 -#define MSG_UNSUPPORTED_SAVE_TYPE 5 -#define MSG_CANNOT_OPEN_FILE 6 -#define MSG_BAD_ZIP_FILE 7 -#define MSG_NO_IMAGE_ON_ZIP 8 -#define MSG_ERROR_OPENING_IMAGE 9 -#define MSG_ERROR_READING_IMAGE 10 -#define MSG_UNSUPPORTED_BIOS_FUNCTION 11 -#define MSG_INVALID_BIOS_FILE_SIZE 12 -#define MSG_INVALID_CHEAT_CODE 13 -#define MSG_UNKNOWN_ARM_OPCODE 14 -#define MSG_UNKNOWN_THUMB_OPCODE 15 -#define MSG_ERROR_CREATING_FILE 16 -#define MSG_FAILED_TO_READ_SGM 17 -#define MSG_FAILED_TO_READ_RTC 18 -#define MSG_UNSUPPORTED_VB_SGM 19 -#define MSG_CANNOT_LOAD_SGM_FOR 20 -#define MSG_ERROR_OPENING_IMAGE_FROM 21 -#define MSG_ERROR_READING_IMAGE_FROM 22 -#define MSG_UNSUPPORTED_ROM_SIZE 23 -#define MSG_UNSUPPORTED_RAM_SIZE 24 -#define MSG_UNKNOWN_CARTRIDGE_TYPE 25 -#define MSG_MAXIMUM_NUMBER_OF_CHEATS 26 -#define MSG_INVALID_GAMESHARK_CODE 27 -#define MSG_INVALID_GAMEGENIE_CODE 28 -#define MSG_INVALID_CHEAT_TO_REMOVE 29 -#define MSG_INVALID_CHEAT_CODE_ADDRESS 30 -#define MSG_UNSUPPORTED_CHEAT_LIST_VERSION 31 -#define MSG_UNSUPPORTED_CHEAT_LIST_TYPE 32 -#define MSG_INVALID_GSA_CODE 33 -#define MSG_CANNOT_IMPORT_SNAPSHOT_FOR 34 -#define MSG_UNSUPPORTED_SNAPSHOT_FILE 35 -#define MSG_UNSUPPORTED_ARM_MODE 36 -#define MSG_UNSUPPORTED_CODE_FILE 37 -#define MSG_GBA_CODE_WARNING 38 -#define MSG_INVALID_CBA_CODE 39 -#define MSG_CBA_CODE_WARNING 40 -#define MSG_OUT_OF_MEMORY 41 +// -*- 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. + +#define N_(String) (String) + +#define MSG_UNSUPPORTED_VBA_SGM 1 +#define MSG_CANNOT_LOAD_SGM 2 +#define MSG_SAVE_GAME_NOT_USING_BIOS 3 +#define MSG_SAVE_GAME_USING_BIOS 4 +#define MSG_UNSUPPORTED_SAVE_TYPE 5 +#define MSG_CANNOT_OPEN_FILE 6 +#define MSG_BAD_ZIP_FILE 7 +#define MSG_NO_IMAGE_ON_ZIP 8 +#define MSG_ERROR_OPENING_IMAGE 9 +#define MSG_ERROR_READING_IMAGE 10 +#define MSG_UNSUPPORTED_BIOS_FUNCTION 11 +#define MSG_INVALID_BIOS_FILE_SIZE 12 +#define MSG_INVALID_CHEAT_CODE 13 +#define MSG_UNKNOWN_ARM_OPCODE 14 +#define MSG_UNKNOWN_THUMB_OPCODE 15 +#define MSG_ERROR_CREATING_FILE 16 +#define MSG_FAILED_TO_READ_SGM 17 +#define MSG_FAILED_TO_READ_RTC 18 +#define MSG_UNSUPPORTED_VB_SGM 19 +#define MSG_CANNOT_LOAD_SGM_FOR 20 +#define MSG_ERROR_OPENING_IMAGE_FROM 21 +#define MSG_ERROR_READING_IMAGE_FROM 22 +#define MSG_UNSUPPORTED_ROM_SIZE 23 +#define MSG_UNSUPPORTED_RAM_SIZE 24 +#define MSG_UNKNOWN_CARTRIDGE_TYPE 25 +#define MSG_MAXIMUM_NUMBER_OF_CHEATS 26 +#define MSG_INVALID_GAMESHARK_CODE 27 +#define MSG_INVALID_GAMEGENIE_CODE 28 +#define MSG_INVALID_CHEAT_TO_REMOVE 29 +#define MSG_INVALID_CHEAT_CODE_ADDRESS 30 +#define MSG_UNSUPPORTED_CHEAT_LIST_VERSION 31 +#define MSG_UNSUPPORTED_CHEAT_LIST_TYPE 32 +#define MSG_INVALID_GSA_CODE 33 +#define MSG_CANNOT_IMPORT_SNAPSHOT_FOR 34 +#define MSG_UNSUPPORTED_SNAPSHOT_FILE 35 +#define MSG_UNSUPPORTED_ARM_MODE 36 +#define MSG_UNSUPPORTED_CODE_FILE 37 +#define MSG_GBA_CODE_WARNING 38 +#define MSG_INVALID_CBA_CODE 39 +#define MSG_CBA_CODE_WARNING 40 +#define MSG_OUT_OF_MEMORY 41 +#define MSG_WRONG_GAMESHARK_CODE 42 +#define MSG_UNSUPPORTED_GAMESHARK_CODE 43 diff --git a/source/vba/Port.h b/source/vba/Port.h index b5c2cc4..db76d55 100644 --- a/source/vba/Port.h +++ b/source/vba/Port.h @@ -1,77 +1,75 @@ -// -*- 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_PORT_H -#define VBA_PORT_H - -// swaps a 16-bit value -static inline u16 swap16(u16 v) -{ - return (v<<8)|(v>>8); -} - -// swaps a 32-bit value -static inline u32 swap32(u32 v) -{ - return (v<<24)|((v<<8)&0xff0000)|((v>>8)&0xff00)|(v>>24); -} - -#ifdef WORDS_BIGENDIAN -#define __ppc__ - -#if defined(__GNUC__) && defined(__ppc__) - -#define READ16LE(base) \ - ({ unsigned short lhbrxResult; \ - __asm__ ("lhbrx %0, 0, %1" : "=r" (lhbrxResult) : "r" (base) : "memory"); \ - lhbrxResult; }) - -#define READ32LE(base) \ - ({ unsigned long lwbrxResult; \ - __asm__ ("lwbrx %0, 0, %1" : "=r" (lwbrxResult) : "r" (base) : "memory"); \ - lwbrxResult; }) - -#define WRITE16LE(base, value) \ - __asm__ ("sthbrx %0, 0, %1" : : "r" (value), "r" (base) : "memory") - -#define WRITE32LE(base, value) \ - __asm__ ("stwbrx %0, 0, %1" : : "r" (value), "r" (base) : "memory") - -#else -#define READ16LE(x) \ - swap16(*((u16 *)(x))) -#define READ32LE(x) \ - swap32(*((u32 *)(x))) -#define WRITE16LE(x,v) \ - *((u16 *)x) = swap16((v)) -#define WRITE32LE(x,v) \ - *((u32 *)x) = swap32((v)) -#endif -#else -#define READ16LE(x) \ - *((u16 *)x) -#define READ32LE(x) \ - *((u32 *)x) -#define WRITE16LE(x,v) \ - *((u16 *)x) = (v) -#define WRITE32LE(x,v) \ - *((u32 *)x) = (v) -#endif - -#endif +// -*- 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_PORT_H +#define VBA_PORT_H + +// swaps a 16-bit value +static inline u16 swap16(u16 v) +{ + return (v<<8)|(v>>8); +} + +// swaps a 32-bit value +static inline u32 swap32(u32 v) +{ + return (v<<24)|((v<<8)&0xff0000)|((v>>8)&0xff00)|(v>>24); +} + +#ifdef WORDS_BIGENDIAN +#if defined(__GNUC__) && defined(__ppc__) + +#define READ16LE(base) \ + ({ unsigned short lhbrxResult; \ + __asm__ ("lhbrx %0, 0, %1" : "=r" (lhbrxResult) : "r" (base) : "memory"); \ + lhbrxResult; }) + +#define READ32LE(base) \ + ({ unsigned long lwbrxResult; \ + __asm__ ("lwbrx %0, 0, %1" : "=r" (lwbrxResult) : "r" (base) : "memory"); \ + lwbrxResult; }) + +#define WRITE16LE(base, value) \ + __asm__ ("sthbrx %0, 0, %1" : : "r" (value), "r" (base) : "memory") + +#define WRITE32LE(base, value) \ + __asm__ ("stwbrx %0, 0, %1" : : "r" (value), "r" (base) : "memory") + +#else +#define READ16LE(x) \ + swap16(*((u16 *)(x))) +#define READ32LE(x) \ + swap32(*((u32 *)(x))) +#define WRITE16LE(x,v) \ + *((u16 *)x) = swap16((v)) +#define WRITE32LE(x,v) \ + *((u32 *)x) = swap32((v)) +#endif +#else +#define READ16LE(x) \ + *((u16 *)x) +#define READ32LE(x) \ + *((u32 *)x) +#define WRITE16LE(x,v) \ + *((u16 *)x) = (v) +#define WRITE32LE(x,v) \ + *((u32 *)x) = (v) +#endif + +#endif diff --git a/source/vba/RTC.cpp b/source/vba/RTC.cpp index 6b76558..344b6f0 100644 --- a/source/vba/RTC.cpp +++ b/source/vba/RTC.cpp @@ -1,245 +1,227 @@ -// 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. - -#include "System.h" -#include "GBA.h" -#include "Globals.h" -#include "Port.h" -#include "Util.h" -#include "NLS.h" -#include "vmmem.h" - -#include -#include - -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) - { - if(address == 0x80000c8) - return rtcClockData.byte2; - else if(address == 0x80000c6) - return rtcClockData.byte1; - else if(address == 0x80000c4) - { - return rtcClockData.byte0; - } - } - - //return READ16LE((&rom[address & 0x1FFFFFE])); - return VMRead16( 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 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] = 0; - 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)); -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 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. + +#include "System.h" +#include "agb/GBA.h" +#include "Globals.h" +#include "Port.h" +#include "Util.h" +#include "NLS.h" +#include "vmmem.h" + +#include +#include + +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])); + return VMRead16( 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)); +} diff --git a/source/vba/RTC.h b/source/vba/RTC.h index acbd3f6..baac958 100644 --- a/source/vba/RTC.h +++ b/source/vba/RTC.h @@ -1,31 +1,31 @@ -// -*- 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_RTC_H -#define VBA_RTC_H -extern u16 rtcRead(u32 address); -extern bool rtcWrite(u32 address, u16 value); -extern void rtcEnable(bool); -extern bool rtcIsEnabled(); -extern void rtcReset(); - -extern void rtcReadGame(gzFile gzFile); -extern void rtcSaveGame(gzFile gzFile); - -#endif +// -*- 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_RTC_H +#define VBA_RTC_H +extern u16 rtcRead(u32 address); +extern bool rtcWrite(u32 address, u16 value); +extern void rtcEnable(bool); +extern bool rtcIsEnabled(); +extern void rtcReset(); + +extern void rtcReadGame(gzFile gzFile); +extern void rtcSaveGame(gzFile gzFile); + +#endif diff --git a/source/vba/Sound.cpp b/source/vba/Sound.cpp index 3ad8906..7bb3c5e 100644 --- a/source/vba/Sound.cpp +++ b/source/vba/Sound.cpp @@ -1,6 +1,7 @@ // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. // Copyright (C) 1999-2003 Forgotten // Copyright (C) 2004 Forgotten and the VBA development team +// Copyright (C) 2004-2006 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 @@ -18,82 +19,83 @@ #include -#include "GBA.h" -#include "Globals.h" #include "Sound.h" + +#include "agb/GBA.h" +#include "Globals.h" #include "Util.h" #define USE_TICKS_AS 380 #define SOUND_MAGIC 0x60000000 #define SOUND_MAGIC_2 0x30000000 -#define NOISE_MAGIC 5 +#define NOISE_MAGIC 5 extern bool stopState; u8 soundWavePattern[4][32] = { - {0x01,0x01,0x01,0x01, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff}, - {0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff}, - {0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff}, - {0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff} - }; + {0x01,0x01,0x01,0x01, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff}, + {0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff}, + {0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff}, + {0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff} +}; int soundFreqRatio[8] = { - 1048576, // 0 - 524288, // 1 - 262144, // 2 - 174763, // 3 - 131072, // 4 - 104858, // 5 - 87381, // 6 - 74898 // 7 - }; + 1048576, // 0 + 524288, // 1 + 262144, // 2 + 174763, // 3 + 131072, // 4 + 104858, // 5 + 87381, // 6 + 74898 // 7 +}; int soundShiftClock[16]= { - 2, // 0 - 4, // 1 - 8, // 2 - 16, // 3 - 32, // 4 - 64, // 5 - 128, // 6 - 256, // 7 - 512, // 8 - 1024, // 9 - 2048, // 10 - 4096, // 11 - 8192, // 12 - 16384, // 13 - 1, // 14 - 1 // 15 - }; + 2, // 0 + 4, // 1 + 8, // 2 + 16, // 3 + 32, // 4 + 64, // 5 + 128, // 6 + 256, // 7 + 512, // 8 + 1024, // 9 + 2048, // 10 + 4096, // 11 + 8192, // 12 + 16384, // 13 + 1, // 14 + 1 // 15 +}; int soundVolume = 0; @@ -202,422 +204,398 @@ bool soundLowPass = false; bool soundReverse = false; variable_desc soundSaveStruct[] = { - { &soundPaused, sizeof(int) }, - { &soundPlay, sizeof(int) }, - { &soundTicks, sizeof(int) }, - { &SOUND_CLOCK_TICKS, sizeof(int) }, - { &soundLevel1, sizeof(int) }, - { &soundLevel2, sizeof(int) }, - { &soundBalance, sizeof(int) }, - { &soundMasterOn, sizeof(int) }, - { &soundIndex, sizeof(int) }, - { &sound1On, sizeof(int) }, - { &sound1ATL, sizeof(int) }, - { &sound1Skip, sizeof(int) }, - { &sound1Index, sizeof(int) }, - { &sound1Continue, sizeof(int) }, - { &sound1EnvelopeVolume, sizeof(int) }, - { &sound1EnvelopeATL, sizeof(int) }, - { &sound1EnvelopeATLReload, sizeof(int) }, - { &sound1EnvelopeUpDown, sizeof(int) }, - { &sound1SweepATL, sizeof(int) }, - { &sound1SweepATLReload, sizeof(int) }, - { &sound1SweepSteps, sizeof(int) }, - { &sound1SweepUpDown, sizeof(int) }, - { &sound1SweepStep, sizeof(int) }, - { &sound2On, sizeof(int) }, - { &sound2ATL, sizeof(int) }, - { &sound2Skip, sizeof(int) }, - { &sound2Index, sizeof(int) }, - { &sound2Continue, sizeof(int) }, - { &sound2EnvelopeVolume, sizeof(int) }, - { &sound2EnvelopeATL, sizeof(int) }, - { &sound2EnvelopeATLReload, sizeof(int) }, - { &sound2EnvelopeUpDown, sizeof(int) }, - { &sound3On, sizeof(int) }, - { &sound3ATL, sizeof(int) }, - { &sound3Skip, sizeof(int) }, - { &sound3Index, sizeof(int) }, - { &sound3Continue, sizeof(int) }, - { &sound3OutputLevel, sizeof(int) }, - { &sound4On, sizeof(int) }, - { &sound4ATL, sizeof(int) }, - { &sound4Skip, sizeof(int) }, - { &sound4Index, sizeof(int) }, - { &sound4Clock, sizeof(int) }, - { &sound4ShiftRight, sizeof(int) }, - { &sound4ShiftSkip, sizeof(int) }, - { &sound4ShiftIndex, sizeof(int) }, - { &sound4NSteps, sizeof(int) }, - { &sound4CountDown, sizeof(int) }, - { &sound4Continue, sizeof(int) }, - { &sound4EnvelopeVolume, sizeof(int) }, - { &sound4EnvelopeATL, sizeof(int) }, - { &sound4EnvelopeATLReload, sizeof(int) }, - { &sound4EnvelopeUpDown, sizeof(int) }, - { &soundEnableFlag, sizeof(int) }, - { &soundControl, sizeof(int) }, - { &soundDSFifoAIndex, sizeof(int) }, - { &soundDSFifoACount, sizeof(int) }, - { &soundDSFifoAWriteIndex, sizeof(int) }, - { &soundDSAEnabled, sizeof(bool) }, - { &soundDSATimer, sizeof(int) }, - { &soundDSFifoA[0], 32 }, - { &soundDSAValue, sizeof(u8) }, - { &soundDSFifoBIndex, sizeof(int) }, - { &soundDSFifoBCount, sizeof(int) }, - { &soundDSFifoBWriteIndex, sizeof(int) }, - { &soundDSBEnabled, sizeof(int) }, - { &soundDSBTimer, sizeof(int) }, - { &soundDSFifoB[0], 32 }, - { &soundDSBValue, sizeof(int) }, - { &soundBuffer[0][0], 6*735 }, - { &soundFinalWave[0], 2*735 }, - { NULL, 0 } - }; + { &soundPaused, sizeof(int) }, + { &soundPlay, sizeof(int) }, + { &soundTicks, sizeof(int) }, + { &SOUND_CLOCK_TICKS, sizeof(int) }, + { &soundLevel1, sizeof(int) }, + { &soundLevel2, sizeof(int) }, + { &soundBalance, sizeof(int) }, + { &soundMasterOn, sizeof(int) }, + { &soundIndex, sizeof(int) }, + { &sound1On, sizeof(int) }, + { &sound1ATL, sizeof(int) }, + { &sound1Skip, sizeof(int) }, + { &sound1Index, sizeof(int) }, + { &sound1Continue, sizeof(int) }, + { &sound1EnvelopeVolume, sizeof(int) }, + { &sound1EnvelopeATL, sizeof(int) }, + { &sound1EnvelopeATLReload, sizeof(int) }, + { &sound1EnvelopeUpDown, sizeof(int) }, + { &sound1SweepATL, sizeof(int) }, + { &sound1SweepATLReload, sizeof(int) }, + { &sound1SweepSteps, sizeof(int) }, + { &sound1SweepUpDown, sizeof(int) }, + { &sound1SweepStep, sizeof(int) }, + { &sound2On, sizeof(int) }, + { &sound2ATL, sizeof(int) }, + { &sound2Skip, sizeof(int) }, + { &sound2Index, sizeof(int) }, + { &sound2Continue, sizeof(int) }, + { &sound2EnvelopeVolume, sizeof(int) }, + { &sound2EnvelopeATL, sizeof(int) }, + { &sound2EnvelopeATLReload, sizeof(int) }, + { &sound2EnvelopeUpDown, sizeof(int) }, + { &sound3On, sizeof(int) }, + { &sound3ATL, sizeof(int) }, + { &sound3Skip, sizeof(int) }, + { &sound3Index, sizeof(int) }, + { &sound3Continue, sizeof(int) }, + { &sound3OutputLevel, sizeof(int) }, + { &sound4On, sizeof(int) }, + { &sound4ATL, sizeof(int) }, + { &sound4Skip, sizeof(int) }, + { &sound4Index, sizeof(int) }, + { &sound4Clock, sizeof(int) }, + { &sound4ShiftRight, sizeof(int) }, + { &sound4ShiftSkip, sizeof(int) }, + { &sound4ShiftIndex, sizeof(int) }, + { &sound4NSteps, sizeof(int) }, + { &sound4CountDown, sizeof(int) }, + { &sound4Continue, sizeof(int) }, + { &sound4EnvelopeVolume, sizeof(int) }, + { &sound4EnvelopeATL, sizeof(int) }, + { &sound4EnvelopeATLReload, sizeof(int) }, + { &sound4EnvelopeUpDown, sizeof(int) }, + { &soundEnableFlag, sizeof(int) }, + { &soundControl, sizeof(int) }, + { &soundDSFifoAIndex, sizeof(int) }, + { &soundDSFifoACount, sizeof(int) }, + { &soundDSFifoAWriteIndex, sizeof(int) }, + { &soundDSAEnabled, sizeof(bool) }, + { &soundDSATimer, sizeof(int) }, + { &soundDSFifoA[0], 32 }, + { &soundDSAValue, sizeof(u8) }, + { &soundDSFifoBIndex, sizeof(int) }, + { &soundDSFifoBCount, sizeof(int) }, + { &soundDSFifoBWriteIndex, sizeof(int) }, + { &soundDSBEnabled, sizeof(int) }, + { &soundDSBTimer, sizeof(int) }, + { &soundDSFifoB[0], 32 }, + { &soundDSBValue, sizeof(int) }, + { &soundBuffer[0][0], 6*735 }, + { &soundFinalWave[0], 2*735 }, + { NULL, 0 } +}; variable_desc soundSaveStructV2[] = { - { &sound3WaveRam[0], 0x20 }, - { &sound3Bank, sizeof(int) }, - { &sound3DataSize, sizeof(int) }, - { &sound3ForcedOutput, sizeof(int) }, - { NULL, 0 } - }; + { &sound3WaveRam[0], 0x20 }, + { &sound3Bank, sizeof(int) }, + { &sound3DataSize, sizeof(int) }, + { &sound3ForcedOutput, sizeof(int) }, + { NULL, 0 } +}; void soundEvent(u32 address, u8 data) { int freq = 0; - switch(address) - { - case NR10: - data &= 0x7f; - sound1SweepATL = sound1SweepATLReload = 344 * ((data >> 4) & 7); - sound1SweepSteps = data & 7; - sound1SweepUpDown = data & 0x08; + switch(address) { + case NR10: + data &= 0x7f; + sound1SweepATL = sound1SweepATLReload = 344 * ((data >> 4) & 7); + sound1SweepSteps = data & 7; + sound1SweepUpDown = data & 0x08; + sound1SweepStep = 0; + ioMem[address] = data; + break; + case NR11: + sound1Wave = soundWavePattern[data >> 6]; + sound1ATL = 172 * (64 - (data & 0x3f)); + ioMem[address] = data; + break; + case NR12: + sound1EnvelopeUpDown = data & 0x08; + sound1EnvelopeATLReload = 689 * (data & 7); + if((data & 0xF8) == 0) + sound1EnvelopeVolume = 0; + ioMem[address] = data; + break; + case NR13: + freq = (((int)(ioMem[NR14] & 7)) << 8) | data; + sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f)); + freq = 2048 - freq; + if(freq) { + sound1Skip = SOUND_MAGIC / freq; + } else + sound1Skip = 0; + ioMem[address] = data; + break; + case NR14: + data &= 0xC7; + freq = (((int)(data&7) << 8) | ioMem[NR13]); + freq = 2048 - freq; + sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f)); + sound1Continue = data & 0x40; + if(freq) { + sound1Skip = SOUND_MAGIC / freq; + } else + sound1Skip = 0; + if(data & 0x80) { + ioMem[NR52] |= 1; + sound1EnvelopeVolume = ioMem[NR12] >> 4; + sound1EnvelopeUpDown = ioMem[NR12] & 0x08; + sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f)); + sound1EnvelopeATLReload = sound1EnvelopeATL = 689 * (ioMem[NR12] & 7); + sound1SweepATL = sound1SweepATLReload = 344 * ((ioMem[NR10] >> 4) & 7); + sound1SweepSteps = ioMem[NR10] & 7; + sound1SweepUpDown = ioMem[NR10] & 0x08; sound1SweepStep = 0; - ioMem[address] = data; - break; - case NR11: - sound1Wave = soundWavePattern[data >> 6]; - sound1ATL = 172 * (64 - (data & 0x3f)); - ioMem[address] = data; - break; - case NR12: - sound1EnvelopeUpDown = data & 0x08; - sound1EnvelopeATLReload = 689 * (data & 7); - if((data & 0xF8) == 0) - sound1EnvelopeVolume = 0; - ioMem[address] = data; - break; - case NR13: - freq = (((int)(ioMem[NR14] & 7)) << 8) | data; - sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f)); - freq = 2048 - freq; - if(freq) - { - sound1Skip = SOUND_MAGIC / freq; - } - else - sound1Skip = 0; - ioMem[address] = data; - break; - case NR14: - data &= 0xC7; - freq = (((int)(data&7) << 8) | ioMem[NR13]); - freq = 2048 - freq; - sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f)); - sound1Continue = data & 0x40; - if(freq) - { - sound1Skip = SOUND_MAGIC / freq; - } - else - sound1Skip = 0; - if(data & 0x80) - { - ioMem[NR52] |= 1; - sound1EnvelopeVolume = ioMem[NR12] >> 4; - sound1EnvelopeUpDown = ioMem[NR12] & 0x08; - sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f)); - sound1EnvelopeATLReload = sound1EnvelopeATL = 689 * (ioMem[NR12] & 7); - sound1SweepATL = sound1SweepATLReload = 344 * ((ioMem[NR10] >> 4) & 7); - sound1SweepSteps = ioMem[NR10] & 7; - sound1SweepUpDown = ioMem[NR10] & 0x08; - sound1SweepStep = 0; - - sound1Index = 0; - sound1On = 1; - } - ioMem[address] = data; - break; - case NR21: - sound2Wave = soundWavePattern[data >> 6]; - sound2ATL = 172 * (64 - (data & 0x3f)); - ioMem[address] = data; - break; - case NR22: - sound2EnvelopeUpDown = data & 0x08; - sound2EnvelopeATLReload = 689 * (data & 7); - if((data & 0xF8) == 0) - sound2EnvelopeVolume = 0; - ioMem[address] = data; - break; - case NR23: - freq = (((int)(ioMem[NR24] & 7)) << 8) | data; + + sound1Index = 0; + sound1On = 1; + } + ioMem[address] = data; + break; + case NR21: + sound2Wave = soundWavePattern[data >> 6]; + sound2ATL = 172 * (64 - (data & 0x3f)); + ioMem[address] = data; + break; + case NR22: + sound2EnvelopeUpDown = data & 0x08; + sound2EnvelopeATLReload = 689 * (data & 7); + if((data & 0xF8) == 0) + sound2EnvelopeVolume = 0; + ioMem[address] = data; + break; + case NR23: + freq = (((int)(ioMem[NR24] & 7)) << 8) | data; + sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f)); + freq = 2048 - freq; + if(freq) { + sound2Skip = SOUND_MAGIC / freq; + } else + sound2Skip = 0; + ioMem[address] = data; + break; + case NR24: + data &= 0xC7; + freq = (((int)(data&7) << 8) | ioMem[NR23]); + freq = 2048 - freq; + sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f)); + sound2Continue = data & 0x40; + if(freq) { + sound2Skip = SOUND_MAGIC / freq; + } else + sound2Skip = 0; + if(data & 0x80) { + ioMem[NR52] |= 2; + sound2EnvelopeVolume = ioMem[NR22] >> 4; + sound2EnvelopeUpDown = ioMem[NR22] & 0x08; sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f)); - freq = 2048 - freq; - if(freq) - { - sound2Skip = SOUND_MAGIC / freq; - } - else - sound2Skip = 0; - ioMem[address] = data; - break; - case NR24: - data &= 0xC7; - freq = (((int)(data&7) << 8) | ioMem[NR23]); - freq = 2048 - freq; - sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f)); - sound2Continue = data & 0x40; - if(freq) - { - sound2Skip = SOUND_MAGIC / freq; - } - else - sound2Skip = 0; - if(data & 0x80) - { - ioMem[NR52] |= 2; - sound2EnvelopeVolume = ioMem[NR22] >> 4; - sound2EnvelopeUpDown = ioMem[NR22] & 0x08; - sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f)); - sound2EnvelopeATLReload = sound2EnvelopeATL = 689 * (ioMem[NR22] & 7); + sound2EnvelopeATLReload = sound2EnvelopeATL = 689 * (ioMem[NR22] & 7); + + sound2Index = 0; + sound2On = 1; + } + ioMem[address] = data; + break; + case NR30: + data &= 0xe0; + if(!(data & 0x80)) { + ioMem[NR52] &= 0xfb; + sound3On = 0; + } + if(((data >> 6) & 1) != sound3Bank) + memcpy(&ioMem[0x90], &sound3WaveRam[(((data >> 6) & 1) * 0x10)^0x10], + 0x10); + sound3Bank = (data >> 6) & 1; + sound3DataSize = (data >> 5) & 1; + ioMem[address] = data; + break; + case NR31: + sound3ATL = 172 * (256-data); + ioMem[address] = data; + break; + case NR32: + data &= 0xe0; + sound3OutputLevel = (data >> 5) & 3; + sound3ForcedOutput = (data >> 7) & 1; + ioMem[address] = data; + break; + case NR33: + freq = 2048 - (((int)(ioMem[NR34]&7) << 8) | data); + if(freq) { + sound3Skip = SOUND_MAGIC_2 / freq; + } else + sound3Skip = 0; + ioMem[address] = data; + break; + case NR34: + data &= 0xc7; + freq = 2048 - (((data &7) << 8) | (int)ioMem[NR33]); + if(freq) { + sound3Skip = SOUND_MAGIC_2 / freq; + } else { + sound3Skip = 0; + } + sound3Continue = data & 0x40; + if((data & 0x80) && (ioMem[NR30] & 0x80)) { + ioMem[NR52] |= 4; + sound3ATL = 172 * (256 - ioMem[NR31]); + sound3Index = 0; + sound3On = 1; + } + ioMem[address] = data; + break; + case NR41: + data &= 0x3f; + sound4ATL = 172 * (64 - (data & 0x3f)); + ioMem[address] = data; + break; + case NR42: + sound4EnvelopeUpDown = data & 0x08; + sound4EnvelopeATLReload = 689 * (data & 7); + if((data & 0xF8) == 0) + sound4EnvelopeVolume = 0; + ioMem[address] = data; + break; + case NR43: + freq = soundFreqRatio[data & 7]; + sound4NSteps = data & 0x08; - sound2Index = 0; - sound2On = 1; - } - break; - ioMem[address] = data; - case NR30: - data &= 0xe0; - if(!(data & 0x80)) - { - ioMem[NR52] &= 0xfb; - sound3On = 0; - } - if(((data >> 6) & 1) != sound3Bank) - memcpy(&ioMem[0x90], &sound3WaveRam[(((data >> 6) & 1) * 0x10)^0x10], - 0x10); - sound3Bank = (data >> 6) & 1; - sound3DataSize = (data >> 5) & 1; - ioMem[address] = data; - break; - case NR31: - sound3ATL = 172 * (256-data); - ioMem[address] = data; - break; - case NR32: - data &= 0xe0; - sound3OutputLevel = (data >> 5) & 3; - sound3ForcedOutput = (data >> 7) & 1; - ioMem[address] = data; - break; - case NR33: - freq = 2048 - (((int)(ioMem[NR34]&7) << 8) | data); - if(freq) - { - sound3Skip = SOUND_MAGIC_2 / freq; - } - else - sound3Skip = 0; - ioMem[address] = data; - break; - case NR34: - data &= 0xc7; - freq = 2048 - (((data &7) << 8) | (int)ioMem[NR33]); - if(freq) - { - sound3Skip = SOUND_MAGIC_2 / freq; - } - else - { - sound3Skip = 0; - } - sound3Continue = data & 0x40; - if((data & 0x80) && (ioMem[NR30] & 0x80)) - { - ioMem[NR52] |= 4; - sound3ATL = 172 * (256 - ioMem[NR31]); - sound3Index = 0; - sound3On = 1; - } - ioMem[address] = data; - break; - case NR41: - data &= 0x3f; - sound4ATL = 172 * (64 - (data & 0x3f)); - ioMem[address] = data; - break; - case NR42: - sound4EnvelopeUpDown = data & 0x08; - sound4EnvelopeATLReload = 689 * (data & 7); - if((data & 0xF8) == 0) - sound4EnvelopeVolume = 0; - ioMem[address] = data; - break; - case NR43: - freq = soundFreqRatio[data & 7]; - sound4NSteps = data & 0x08; + sound4Skip = (freq << 8) / NOISE_MAGIC; + + sound4Clock = data >> 4; + + freq = freq / soundShiftClock[sound4Clock]; + + sound4ShiftSkip = (freq << 8) / NOISE_MAGIC; + ioMem[address] = data; + break; + case NR44: + data &= 0xc0; + sound4Continue = data & 0x40; + if(data & 0x80) { + ioMem[NR52] |= 8; + sound4EnvelopeVolume = ioMem[NR42] >> 4; + sound4EnvelopeUpDown = ioMem[NR42] & 0x08; + sound4ATL = 172 * (64 - (ioMem[NR41] & 0x3f)); + sound4EnvelopeATLReload = sound4EnvelopeATL = 689 * (ioMem[NR42] & 7); + + sound4On = 1; + + sound4Index = 0; + sound4ShiftIndex = 0; + + freq = soundFreqRatio[ioMem[NR43] & 7]; sound4Skip = (freq << 8) / NOISE_MAGIC; - - sound4Clock = data >> 4; - - freq = freq / soundShiftClock[sound4Clock]; + + sound4NSteps = ioMem[NR43] & 0x08; + + freq = freq / soundShiftClock[ioMem[NR43] >> 4]; sound4ShiftSkip = (freq << 8) / NOISE_MAGIC; - ioMem[address] = data; - break; - case NR44: - data &= 0xc0; - sound4Continue = data & 0x40; - if(data & 0x80) - { - ioMem[NR52] |= 8; - sound4EnvelopeVolume = ioMem[NR42] >> 4; - sound4EnvelopeUpDown = ioMem[NR42] & 0x08; - sound4ATL = 172 * (64 - (ioMem[NR41] & 0x3f)); - sound4EnvelopeATLReload = sound4EnvelopeATL = 689 * (ioMem[NR42] & 7); - - sound4On = 1; - - sound4Index = 0; - sound4ShiftIndex = 0; - - freq = soundFreqRatio[ioMem[NR43] & 7]; - - sound4Skip = (freq << 8) / NOISE_MAGIC; - - sound4NSteps = ioMem[NR43] & 0x08; - - freq = freq / soundShiftClock[ioMem[NR43] >> 4]; - - sound4ShiftSkip = (freq << 8) / NOISE_MAGIC; - if(sound4NSteps) - sound4ShiftRight = 0x7fff; - else - sound4ShiftRight = 0x7f; - } - ioMem[address] = data; - break; - case NR50: - data &= 0x77; - soundLevel1 = data & 7; - soundLevel2 = (data >> 4) & 7; - ioMem[address] = data; - break; - case NR51: - soundBalance = (data & soundEnableFlag); - ioMem[address] = data; - break; - case NR52: - data &= 0x80; - data |= ioMem[NR52] & 15; - soundMasterOn = data & 0x80; - if(!(data & 0x80)) - { - sound1On = 0; - sound2On = 0; - sound3On = 0; - sound4On = 0; - } - ioMem[address] = data; - break; - 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: - sound3WaveRam[(sound3Bank*0x10)^0x10+(address&15)] = data; - break; + if(sound4NSteps) + sound4ShiftRight = 0x7fff; + else + sound4ShiftRight = 0x7f; } + ioMem[address] = data; + break; + case NR50: + data &= 0x77; + soundLevel1 = data & 7; + soundLevel2 = (data >> 4) & 7; + ioMem[address] = data; + break; + case NR51: + soundBalance = (data & soundEnableFlag); + ioMem[address] = data; + break; + case NR52: + data &= 0x80; + data |= ioMem[NR52] & 15; + soundMasterOn = data & 0x80; + if(!(data & 0x80)) { + sound1On = 0; + sound2On = 0; + sound3On = 0; + sound4On = 0; + } + ioMem[address] = data; + break; + 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: + sound3WaveRam[(sound3Bank*0x10)^0x10+(address&15)] = data; + break; + } } void soundEvent(u32 address, u16 data) { - switch(address) - { - case SGCNT0_H: - data &= 0xFF0F; - soundControl = data & 0x770F; - ; - if(data & 0x0800) - { - soundDSFifoAWriteIndex = 0; - soundDSFifoAIndex = 0; - soundDSFifoACount = 0; - soundDSAValue = 0; - memset(soundDSFifoA, 0, 32); - } - soundDSAEnabled = (data & 0x0300) ? true : false; - soundDSATimer = (data & 0x0400) ? 1 : 0; - if(data & 0x8000) - { - soundDSFifoBWriteIndex = 0; - soundDSFifoBIndex = 0; - soundDSFifoBCount = 0; - soundDSBValue = 0; - memset(soundDSFifoB, 0, 32); - } - soundDSBEnabled = (data & 0x3000) ? true : false; - soundDSBTimer = (data & 0x4000) ? 1 : 0; - *((u16 *)&ioMem[address]) = data; - break; - case FIFOA_L: - case FIFOA_H: - soundDSFifoA[soundDSFifoAWriteIndex++] = data & 0xFF; - soundDSFifoA[soundDSFifoAWriteIndex++] = data >> 8; - soundDSFifoACount += 2; - soundDSFifoAWriteIndex &= 31; - *((u16 *)&ioMem[address]) = data; - break; - case FIFOB_L: - case FIFOB_H: - soundDSFifoB[soundDSFifoBWriteIndex++] = data & 0xFF; - soundDSFifoB[soundDSFifoBWriteIndex++] = data >> 8; - soundDSFifoBCount += 2; - soundDSFifoBWriteIndex &= 31; - *((u16 *)&ioMem[address]) = data; - break; - case 0x88: - data &= 0xC3FF; - *((u16 *)&ioMem[address]) = data; - break; - case 0x90: - case 0x92: - case 0x94: - case 0x96: - case 0x98: - case 0x9a: - case 0x9c: - case 0x9e: - *((u16 *)&sound3WaveRam[(sound3Bank*0x10)^0x10+(address&14)]) = data; - *((u16 *)&ioMem[address]) = data; - break; + switch(address) { + case SGCNT0_H: + data &= 0xFF0F; + soundControl = data & 0x770F; + if(data & 0x0800) { + soundDSFifoAWriteIndex = 0; + soundDSFifoAIndex = 0; + soundDSFifoACount = 0; + soundDSAValue = 0; + memset(soundDSFifoA, 0, 32); } + soundDSAEnabled = (data & 0x0300) ? true : false; + soundDSATimer = (data & 0x0400) ? 1 : 0; + if(data & 0x8000) { + soundDSFifoBWriteIndex = 0; + soundDSFifoBIndex = 0; + soundDSFifoBCount = 0; + soundDSBValue = 0; + memset(soundDSFifoB, 0, 32); + } + soundDSBEnabled = (data & 0x3000) ? true : false; + soundDSBTimer = (data & 0x4000) ? 1 : 0; + *((u16 *)&ioMem[address]) = soundControl; + break; + case FIFOA_L: + case FIFOA_H: + soundDSFifoA[soundDSFifoAWriteIndex++] = data & 0xFF; + soundDSFifoA[soundDSFifoAWriteIndex++] = data >> 8; + soundDSFifoACount += 2; + soundDSFifoAWriteIndex &= 31; + *((u16 *)&ioMem[address]) = data; + break; + case FIFOB_L: + case FIFOB_H: + soundDSFifoB[soundDSFifoBWriteIndex++] = data & 0xFF; + soundDSFifoB[soundDSFifoBWriteIndex++] = data >> 8; + soundDSFifoBCount += 2; + soundDSFifoBWriteIndex &= 31; + *((u16 *)&ioMem[address]) = data; + break; + case 0x88: + data &= 0xC3FF; + *((u16 *)&ioMem[address]) = data; + break; + case 0x90: + case 0x92: + case 0x94: + case 0x96: + case 0x98: + case 0x9a: + case 0x9c: + case 0x9e: + *((u16 *)&sound3WaveRam[(sound3Bank*0x10)^0x10+(address&14)]) = data; + *((u16 *)&ioMem[address]) = data; + break; + } } void soundChannel1() @@ -626,96 +604,78 @@ void soundChannel1() int freq = 0; int value = 0; + + if(sound1On && (sound1ATL || !sound1Continue)) { + sound1Index += soundQuality*sound1Skip; + sound1Index &= 0x1fffffff; - if(sound1On && (sound1ATL || !sound1Continue)) - { - sound1Index += soundQuality*sound1Skip; - sound1Index &= 0x1fffffff; - - value = ((s8)sound1Wave[sound1Index>>24]) * vol; - } + value = ((s8)sound1Wave[sound1Index>>24]) * vol; + } soundBuffer[0][soundIndex] = value; - - if(sound1On) - { - if(sound1ATL) - { - sound1ATL-=soundQuality; - - if(sound1ATL <=0 && sound1Continue) - { - ioMem[NR52] &= 0xfe; - sound1On = 0; - } - } - - if(sound1EnvelopeATL) - { - sound1EnvelopeATL-=soundQuality; - - if(sound1EnvelopeATL<=0) - { - if(sound1EnvelopeUpDown) - { - if(sound1EnvelopeVolume < 15) - sound1EnvelopeVolume++; - } - else - { - if(sound1EnvelopeVolume) - sound1EnvelopeVolume--; - } - - sound1EnvelopeATL += sound1EnvelopeATLReload; - } - } - - if(sound1SweepATL) - { - sound1SweepATL-=soundQuality; - - if(sound1SweepATL<=0) - { - freq = (((int)(ioMem[NR14]&7) << 8) | ioMem[NR13]); - - int updown = 1; - - if(sound1SweepUpDown) - updown = -1; - - int newfreq = 0; - if(sound1SweepSteps) - { - newfreq = freq + updown * freq / (1 << sound1SweepSteps); - if(newfreq == freq) - newfreq = 0; - } - else - newfreq = freq; - - if(newfreq < 0) - { - sound1SweepATL += sound1SweepATLReload; - } - else if(newfreq > 2047) - { - sound1SweepATL = 0; - sound1On = 0; - ioMem[NR52] &= 0xfe; - } - else - { - sound1SweepATL += sound1SweepATLReload; - sound1Skip = SOUND_MAGIC/(2048 - newfreq); - - ioMem[NR13] = newfreq & 0xff; - ioMem[NR14] = (ioMem[NR14] & 0xf8) |((newfreq >> 8) & 7); - } - } - } + + if(sound1On) { + if(sound1ATL) { + sound1ATL-=soundQuality; + + if(sound1ATL <=0 && sound1Continue) { + ioMem[NR52] &= 0xfe; + sound1On = 0; + } } + + if(sound1EnvelopeATL) { + sound1EnvelopeATL-=soundQuality; + + if(sound1EnvelopeATL<=0) { + if(sound1EnvelopeUpDown) { + if(sound1EnvelopeVolume < 15) + sound1EnvelopeVolume++; + } else { + if(sound1EnvelopeVolume) + sound1EnvelopeVolume--; + } + + sound1EnvelopeATL += sound1EnvelopeATLReload; + } + } + + if(sound1SweepATL) { + sound1SweepATL-=soundQuality; + + if(sound1SweepATL<=0) { + freq = (((int)(ioMem[NR14]&7) << 8) | ioMem[NR13]); + + int updown = 1; + + if(sound1SweepUpDown) + updown = -1; + + int newfreq = 0; + if(sound1SweepSteps) { + newfreq = freq + updown * freq / (1 << sound1SweepSteps); + if(newfreq == freq) + newfreq = 0; + } else + newfreq = freq; + + if(newfreq < 0) { + sound1SweepATL += sound1SweepATLReload; + } else if(newfreq > 2047) { + sound1SweepATL = 0; + sound1On = 0; + ioMem[NR52] &= 0xfe; + } else { + sound1SweepATL += sound1SweepATLReload; + sound1Skip = SOUND_MAGIC/(2048 - newfreq); + + ioMem[NR13] = newfreq & 0xff; + ioMem[NR14] = (ioMem[NR14] & 0xf8) |((newfreq >> 8) & 7); + } + } + } + } } void soundChannel2() @@ -724,122 +684,98 @@ void soundChannel2() int vol = sound2EnvelopeVolume; int value = 0; + + if(sound2On && (sound2ATL || !sound2Continue)) { + sound2Index += soundQuality*sound2Skip; + sound2Index &= 0x1fffffff; - if(sound2On && (sound2ATL || !sound2Continue)) - { - sound2Index += soundQuality*sound2Skip; - sound2Index &= 0x1fffffff; - - value = ((s8)sound2Wave[sound2Index>>24]) * vol; - } - + value = ((s8)sound2Wave[sound2Index>>24]) * vol; + } + soundBuffer[1][soundIndex] = value; - - if(sound2On) - { - if(sound2ATL) - { - sound2ATL-=soundQuality; - - if(sound2ATL <= 0 && sound2Continue) - { - ioMem[NR52] &= 0xfd; - sound2On = 0; - } - } - - if(sound2EnvelopeATL) - { - sound2EnvelopeATL-=soundQuality; - - if(sound2EnvelopeATL <= 0) - { - if(sound2EnvelopeUpDown) - { - if(sound2EnvelopeVolume < 15) - sound2EnvelopeVolume++; - } - else - { - if(sound2EnvelopeVolume) - sound2EnvelopeVolume--; - } - sound2EnvelopeATL += sound2EnvelopeATLReload; - } - } + + if(sound2On) { + if(sound2ATL) { + sound2ATL-=soundQuality; + + if(sound2ATL <= 0 && sound2Continue) { + ioMem[NR52] &= 0xfd; + sound2On = 0; + } } -} + + if(sound2EnvelopeATL) { + sound2EnvelopeATL-=soundQuality; + + if(sound2EnvelopeATL <= 0) { + if(sound2EnvelopeUpDown) { + if(sound2EnvelopeVolume < 15) + sound2EnvelopeVolume++; + } else { + if(sound2EnvelopeVolume) + sound2EnvelopeVolume--; + } + sound2EnvelopeATL += sound2EnvelopeATLReload; + } + } + } +} void soundChannel3() { int value = sound3Last; - - if(sound3On && (sound3ATL || !sound3Continue)) - { - sound3Index += soundQuality*sound3Skip; - if(sound3DataSize) - { - sound3Index &= 0x3fffffff; - value = sound3WaveRam[sound3Index>>25]; - } - else - { - sound3Index &= 0x1fffffff; - value = sound3WaveRam[sound3Bank*0x10 + (sound3Index>>25)]; - } - - if( (sound3Index & 0x01000000)) - { - value &= 0x0f; - } - else - { - value >>= 4; - } - - value -= 8; - //value *= 2; - value <<= 1; - - if(sound3ForcedOutput) - { - value = ((value >> 1) + value) >> 1; - } - else - { - switch(sound3OutputLevel) - { - case 0: - value = 0; - break; - case 1: - break; - case 2: - value = (value >> 1); - break; - case 3: - value = (value >> 2); - break; - } - } - sound3Last = value; + + if(sound3On && (sound3ATL || !sound3Continue)) { + sound3Index += soundQuality*sound3Skip; + if(sound3DataSize) { + sound3Index &= 0x3fffffff; + value = sound3WaveRam[sound3Index>>25]; + } else { + sound3Index &= 0x1fffffff; + value = sound3WaveRam[sound3Bank*0x10 + (sound3Index>>25)]; + } + + if( (sound3Index & 0x01000000)) { + value &= 0x0f; + } else { + value >>= 4; } + value -= 8; + value *= 2; + + if(sound3ForcedOutput) { + value = ((value >> 1) + value) >> 1; + } else { + switch(sound3OutputLevel) { + case 0: + value = 0; + break; + case 1: + break; + case 2: + value = (value >> 1); + break; + case 3: + value = (value >> 2); + break; + } + } + sound3Last = value; + } + soundBuffer[2][soundIndex] = value; - - if(sound3On) - { - if(sound3ATL) - { - sound3ATL-=soundQuality; - - if(sound3ATL <= 0 && sound3Continue) - { - ioMem[NR52] &= 0xfb; - sound3On = 0; - } - } + + if(sound3On) { + if(sound3ATL) { + sound3ATL-=soundQuality; + + if(sound3ATL <= 0 && sound3Continue) { + ioMem[NR52] &= 0xfb; + sound3On = 0; + } } + } } void soundChannel4() @@ -848,81 +784,64 @@ void soundChannel4() int value = 0; - if(sound4Clock <= 0x0c) - { - if(sound4On && (sound4ATL || !sound4Continue)) - { - sound4Index += soundQuality*sound4Skip; - sound4ShiftIndex += soundQuality*sound4ShiftSkip; + if(sound4Clock <= 0x0c) { + if(sound4On && (sound4ATL || !sound4Continue)) { + sound4Index += soundQuality*sound4Skip; + sound4ShiftIndex += soundQuality*sound4ShiftSkip; - if(sound4NSteps) - { - while(sound4ShiftIndex > 0x1fffff) - { - sound4ShiftRight = (((sound4ShiftRight << 6) ^ - (sound4ShiftRight << 5)) & 0x40) | - (sound4ShiftRight >> 1); - sound4ShiftIndex -= 0x200000; - } - } - else - { - while(sound4ShiftIndex > 0x1fffff) - { - sound4ShiftRight = (((sound4ShiftRight << 14) ^ - (sound4ShiftRight << 13)) & 0x4000) | - (sound4ShiftRight >> 1); - - sound4ShiftIndex -= 0x200000; - } - } - - sound4Index &= 0x1fffff; - sound4ShiftIndex &= 0x1fffff; - - value = ((sound4ShiftRight & 1)*2-1) * vol; + if(sound4NSteps) { + while(sound4ShiftIndex > 0x1fffff) { + sound4ShiftRight = (((sound4ShiftRight << 6) ^ + (sound4ShiftRight << 5)) & 0x40) | + (sound4ShiftRight >> 1); + sound4ShiftIndex -= 0x200000; } - else - { - value = 0; + } else { + while(sound4ShiftIndex > 0x1fffff) { + sound4ShiftRight = (((sound4ShiftRight << 14) ^ + (sound4ShiftRight << 13)) & 0x4000) | + (sound4ShiftRight >> 1); + + sound4ShiftIndex -= 0x200000; } + } + + sound4Index &= 0x1fffff; + sound4ShiftIndex &= 0x1fffff; + + value = ((sound4ShiftRight & 1)*2-1) * vol; + } else { + value = 0; } - + } + soundBuffer[3][soundIndex] = value; - if(sound4On) - { - if(sound4ATL) - { - sound4ATL-=soundQuality; - - if(sound4ATL <= 0 && sound4Continue) - { - ioMem[NR52] &= 0xfd; - sound4On = 0; - } - } - - if(sound4EnvelopeATL) - { - sound4EnvelopeATL-=soundQuality; - - if(sound4EnvelopeATL <= 0) - { - if(sound4EnvelopeUpDown) - { - if(sound4EnvelopeVolume < 15) - sound4EnvelopeVolume++; - } - else - { - if(sound4EnvelopeVolume) - sound4EnvelopeVolume--; - } - sound4EnvelopeATL += sound4EnvelopeATLReload; - } - } + if(sound4On) { + if(sound4ATL) { + sound4ATL-=soundQuality; + + if(sound4ATL <= 0 && sound4Continue) { + ioMem[NR52] &= 0xfd; + sound4On = 0; + } } + + if(sound4EnvelopeATL) { + sound4EnvelopeATL-=soundQuality; + + if(sound4EnvelopeATL <= 0) { + if(sound4EnvelopeUpDown) { + if(sound4EnvelopeVolume < 15) + sound4EnvelopeVolume++; + } else { + if(sound4EnvelopeVolume) + sound4EnvelopeVolume--; + } + sound4EnvelopeATL += sound4EnvelopeATLReload; + } + } + } } void soundDirectSoundA() @@ -932,29 +851,25 @@ void soundDirectSoundA() void soundDirectSoundATimer() { - if(soundDSAEnabled) - { - if(soundDSFifoACount <= 16) - { - CPUCheckDMA(3, 2); - if(soundDSFifoACount <= 16) - { - soundEvent(FIFOA_L, (u16)0); - soundEvent(FIFOA_H, (u16)0); - soundEvent(FIFOA_L, (u16)0); - soundEvent(FIFOA_H, (u16)0); - soundEvent(FIFOA_L, (u16)0); - soundEvent(FIFOA_H, (u16)0); - soundEvent(FIFOA_L, (u16)0); - soundEvent(FIFOA_H, (u16)0); - } - } - - soundDSAValue = (soundDSFifoA[soundDSFifoAIndex]); - soundDSFifoAIndex = (++soundDSFifoAIndex) & 31; - soundDSFifoACount--; + if(soundDSAEnabled) { + if(soundDSFifoACount <= 16) { + CPUCheckDMA(3, 2); + if(soundDSFifoACount <= 16) { + soundEvent(FIFOA_L, (u16)0); + soundEvent(FIFOA_H, (u16)0); + soundEvent(FIFOA_L, (u16)0); + soundEvent(FIFOA_H, (u16)0); + soundEvent(FIFOA_L, (u16)0); + soundEvent(FIFOA_H, (u16)0); + soundEvent(FIFOA_L, (u16)0); + soundEvent(FIFOA_H, (u16)0); + } } - else + + soundDSAValue = (soundDSFifoA[soundDSFifoAIndex]); + soundDSFifoAIndex = (soundDSFifoAIndex + 1) & 31; + soundDSFifoACount--; + } else soundDSAValue = 0; } @@ -965,44 +880,37 @@ void soundDirectSoundB() void soundDirectSoundBTimer() { - if(soundDSBEnabled) - { - if(soundDSFifoBCount <= 16) - { - CPUCheckDMA(3, 4); - if(soundDSFifoBCount <= 16) - { - soundEvent(FIFOB_L, (u16)0); - soundEvent(FIFOB_H, (u16)0); - soundEvent(FIFOB_L, (u16)0); - soundEvent(FIFOB_H, (u16)0); - soundEvent(FIFOB_L, (u16)0); - soundEvent(FIFOB_H, (u16)0); - soundEvent(FIFOB_L, (u16)0); - soundEvent(FIFOB_H, (u16)0); - } - } - - soundDSBValue = (soundDSFifoB[soundDSFifoBIndex]); - soundDSFifoBIndex = (++soundDSFifoBIndex) & 31; - soundDSFifoBCount--; - } - else - { - soundDSBValue = 0; + if(soundDSBEnabled) { + if(soundDSFifoBCount <= 16) { + CPUCheckDMA(3, 4); + if(soundDSFifoBCount <= 16) { + soundEvent(FIFOB_L, (u16)0); + soundEvent(FIFOB_H, (u16)0); + soundEvent(FIFOB_L, (u16)0); + soundEvent(FIFOB_H, (u16)0); + soundEvent(FIFOB_L, (u16)0); + soundEvent(FIFOB_H, (u16)0); + soundEvent(FIFOB_L, (u16)0); + soundEvent(FIFOB_H, (u16)0); + } } + + soundDSBValue = (soundDSFifoB[soundDSFifoBIndex]); + soundDSFifoBIndex = (soundDSFifoBIndex + 1) & 31; + soundDSFifoBCount--; + } else { + soundDSBValue = 0; + } } void soundTimerOverflow(int timer) { - if(soundDSAEnabled && (soundDSATimer == timer)) - { - soundDirectSoundATimer(); - } - if(soundDSBEnabled && (soundDSBTimer == timer)) - { - soundDirectSoundBTimer(); - } + if(soundDSAEnabled && (soundDSATimer == timer)) { + soundDirectSoundATimer(); + } + if(soundDSBEnabled && (soundDSBTimer == timer)) { + soundDirectSoundBTimer(); + } } #ifndef max @@ -1016,93 +924,83 @@ void soundMix() int ratio = ioMem[0x82] & 3; int dsaRatio = ioMem[0x82] & 4; int dsbRatio = ioMem[0x82] & 8; + + if(soundBalance & 16) { + cgbRes = ((s8)soundBuffer[0][soundIndex]); + } + if(soundBalance & 32) { + cgbRes += ((s8)soundBuffer[1][soundIndex]); + } + if(soundBalance & 64) { + cgbRes += ((s8)soundBuffer[2][soundIndex]); + } + if(soundBalance & 128) { + cgbRes += ((s8)soundBuffer[3][soundIndex]); + } - if(soundBalance & 16) - { - cgbRes = ((s8)soundBuffer[0][soundIndex]); - } - if(soundBalance & 32) - { - cgbRes += ((s8)soundBuffer[1][soundIndex]); - } - if(soundBalance & 64) - { - cgbRes += ((s8)soundBuffer[2][soundIndex]); - } - if(soundBalance & 128) - { - cgbRes += ((s8)soundBuffer[3][soundIndex]); - } - - if((soundControl & 0x0200) && (soundEnableFlag & 0x100)) - { - if(!dsaRatio) - res = ((s8)soundBuffer[4][soundIndex])>>1; - else - res = ((s8)soundBuffer[4][soundIndex]); - } - - if((soundControl & 0x2000) && (soundEnableFlag & 0x200)) - { - if(!dsbRatio) - res += ((s8)soundBuffer[5][soundIndex])>>1; - else - res += ((s8)soundBuffer[5][soundIndex]); - } - + if((soundControl & 0x0200) && (soundEnableFlag & 0x100)){ + if(!dsaRatio) + res = ((s8)soundBuffer[4][soundIndex])>>1; + else + res = ((s8)soundBuffer[4][soundIndex]); + } + + if((soundControl & 0x2000) && (soundEnableFlag & 0x200)){ + if(!dsbRatio) + res += ((s8)soundBuffer[5][soundIndex])>>1; + else + res += ((s8)soundBuffer[5][soundIndex]); + } + res = (res * 170); cgbRes = (cgbRes * 52 * soundLevel1); - switch(ratio) - { - case 0: - case 3: // prohibited, but 25% - cgbRes >>= 2; - break; - case 1: - cgbRes >>= 1; - break; - case 2: - break; - } + switch(ratio) { + case 0: + case 3: // prohibited, but 25% + cgbRes >>= 2; + break; + case 1: + cgbRes >>= 1; + break; + case 2: + break; + } res += cgbRes; - if(soundEcho) - { - res *= 2; - res += soundFilter[soundEchoIndex]; - res /= 2; - soundFilter[soundEchoIndex++] = res; - } + if(soundEcho) { + res *= 2; + res += soundFilter[soundEchoIndex]; + res /= 2; + soundFilter[soundEchoIndex++] = res; + } - if(soundLowPass) - { - soundLeft[4] = soundLeft[3]; - soundLeft[3] = soundLeft[2]; - soundLeft[2] = soundLeft[1]; - soundLeft[1] = soundLeft[0]; - soundLeft[0] = res; - res = (soundLeft[4] + 2*soundLeft[3] + 8*soundLeft[2] + 2*soundLeft[1] + - soundLeft[0])/14; - } - - switch(soundVolume) - { - case 0: - case 1: - case 2: - case 3: - res *= (soundVolume+1); - break; - case 4: - res >>= 2; - break; - case 5: - res >>= 1; - break; - } + if(soundLowPass) { + soundLeft[4] = soundLeft[3]; + soundLeft[3] = soundLeft[2]; + soundLeft[2] = soundLeft[1]; + soundLeft[1] = soundLeft[0]; + soundLeft[0] = res; + res = (soundLeft[4] + 2*soundLeft[3] + 8*soundLeft[2] + 2*soundLeft[1] + + soundLeft[0])/14; + } + switch(soundVolume) { + case 0: + case 1: + case 2: + case 3: + res *= (soundVolume+1); + break; + case 4: + res >>= 2; + break; + case 5: + res >>= 1; + break; + } + if(res > 32767) res = 32767; if(res < -32768) @@ -1112,104 +1010,94 @@ void soundMix() soundFinalWave[++soundBufferIndex] = res; else soundFinalWave[soundBufferIndex++] = res; - + res = 0; cgbRes = 0; + + if(soundBalance & 1) { + cgbRes = ((s8)soundBuffer[0][soundIndex]); + } + if(soundBalance & 2) { + cgbRes += ((s8)soundBuffer[1][soundIndex]); + } + if(soundBalance & 4) { + cgbRes += ((s8)soundBuffer[2][soundIndex]); + } + if(soundBalance & 8) { + cgbRes += ((s8)soundBuffer[3][soundIndex]); + } - if(soundBalance & 1) - { - cgbRes = ((s8)soundBuffer[0][soundIndex]); - } - if(soundBalance & 2) - { - cgbRes += ((s8)soundBuffer[1][soundIndex]); - } - if(soundBalance & 4) - { - cgbRes += ((s8)soundBuffer[2][soundIndex]); - } - if(soundBalance & 8) - { - cgbRes += ((s8)soundBuffer[3][soundIndex]); - } - - if((soundControl & 0x0100) && (soundEnableFlag & 0x100)) - { - if(!dsaRatio) - res = ((s8)soundBuffer[4][soundIndex])>>1; - else - res = ((s8)soundBuffer[4][soundIndex]); - } - - if((soundControl & 0x1000) && (soundEnableFlag & 0x200)) - { - if(!dsbRatio) - res += ((s8)soundBuffer[5][soundIndex])>>1; - else - res += ((s8)soundBuffer[5][soundIndex]); - } + if((soundControl & 0x0100) && (soundEnableFlag & 0x100)){ + if(!dsaRatio) + res = ((s8)soundBuffer[4][soundIndex])>>1; + else + res = ((s8)soundBuffer[4][soundIndex]); + } + + if((soundControl & 0x1000) && (soundEnableFlag & 0x200)){ + if(!dsbRatio) + res += ((s8)soundBuffer[5][soundIndex])>>1; + else + res += ((s8)soundBuffer[5][soundIndex]); + } res = (res * 170); cgbRes = (cgbRes * 52 * soundLevel1); - - switch(ratio) - { - case 0: - case 3: // prohibited, but 25% - cgbRes >>= 2; - break; - case 1: - cgbRes >>= 1; - break; - case 2: - break; - } + + switch(ratio) { + case 0: + case 3: // prohibited, but 25% + cgbRes >>= 2; + break; + case 1: + cgbRes >>= 1; + break; + case 2: + break; + } res += cgbRes; + + if(soundEcho) { + res *= 2; + res += soundFilter[soundEchoIndex]; + res /= 2; + soundFilter[soundEchoIndex++] = res; - if(soundEcho) - { - res *= 2; - res += soundFilter[soundEchoIndex]; - res /= 2; - soundFilter[soundEchoIndex++] = res; + if(soundEchoIndex >= 4000) + soundEchoIndex = 0; + } - if(soundEchoIndex >= 4000) - soundEchoIndex = 0; - } - - if(soundLowPass) - { - soundRight[4] = soundRight[3]; - soundRight[3] = soundRight[2]; - soundRight[2] = soundRight[1]; - soundRight[1] = soundRight[0]; - soundRight[0] = res; - res = (soundRight[4] + 2*soundRight[3] + 8*soundRight[2] + 2*soundRight[1] + - soundRight[0])/14; - } - - switch(soundVolume) - { - case 0: - case 1: - case 2: - case 3: - res *= (soundVolume+1); - break; - case 4: - res >>= 2; - break; - case 5: - res >>= 1; - break; - } + if(soundLowPass) { + soundRight[4] = soundRight[3]; + soundRight[3] = soundRight[2]; + soundRight[2] = soundRight[1]; + soundRight[1] = soundRight[0]; + soundRight[0] = res; + res = (soundRight[4] + 2*soundRight[3] + 8*soundRight[2] + 2*soundRight[1] + + soundRight[0])/14; + } + switch(soundVolume) { + case 0: + case 1: + case 2: + case 3: + res *= (soundVolume+1); + break; + case 4: + res >>= 2; + break; + case 5: + res >>= 1; + break; + } + if(res > 32767) res = 32767; if(res < -32768) res = -32768; - + if(soundReverse) soundFinalWave[-1+soundBufferIndex++] = res; else @@ -1218,41 +1106,34 @@ void soundMix() void soundTick() { - if(systemSoundOn) - { - if(soundMasterOn && !stopState) - { - soundChannel1(); - soundChannel2(); - soundChannel3(); - soundChannel4(); - soundDirectSoundA(); - soundDirectSoundB(); - soundMix(); - } - else - { - soundFinalWave[soundBufferIndex++] = 0; - soundFinalWave[soundBufferIndex++] = 0; - } - - soundIndex++; - - if(2*soundBufferIndex >= soundBufferLen) - { - if(systemSoundOn) - { - if(soundPaused) - { - soundResume(); - } - - systemWriteDataToSoundBuffer(); - } - soundIndex = 0; - soundBufferIndex = 0; - } + if(systemSoundOn) { + if(soundMasterOn && !stopState) { + soundChannel1(); + soundChannel2(); + soundChannel3(); + soundChannel4(); + soundDirectSoundA(); + soundDirectSoundB(); + soundMix(); + } else { + soundFinalWave[soundBufferIndex++] = 0; + soundFinalWave[soundBufferIndex++] = 0; } + + soundIndex++; + + if(2*soundBufferIndex >= soundBufferLen) { + if(systemSoundOn) { + if(soundPaused) { + soundResume(); + } + + systemWriteDataToSoundBuffer(); + } + soundIndex = 0; + soundBufferIndex = 0; + } + } } void soundShutdown() @@ -1275,7 +1156,7 @@ void soundResume() void soundEnable(int channels) { int c = channels & 0x0f; - + soundEnableFlag |= ((channels & 0x30f) |c | (c << 4)); if(ioMem) soundBalance = (ioMem[NR51] & soundEnableFlag); @@ -1284,7 +1165,7 @@ void soundEnable(int channels) void soundDisable(int channels) { int c = channels & 0x0f; - + soundEnableFlag &= (~((channels & 0x30f)|c|(c<<4))); if(ioMem) soundBalance = (ioMem[NR51] & soundEnableFlag); @@ -1301,7 +1182,7 @@ void soundReset() soundPaused = 1; soundPlay = 0; - SOUND_CLOCK_TICKS = soundQuality * USE_TICKS_AS; + SOUND_CLOCK_TICKS = soundQuality * USE_TICKS_AS; soundTicks = SOUND_CLOCK_TICKS; soundNextPosition = 0; soundMasterOn = 1; @@ -1309,7 +1190,7 @@ void soundReset() soundBufferIndex = 0; soundLevel1 = 7; soundLevel2 = 7; - + sound1On = 0; sound1ATL = 0; sound1Skip = 0; @@ -1325,7 +1206,7 @@ void soundReset() sound1SweepUpDown = 0; sound1SweepStep = 0; sound1Wave = soundWavePattern[2]; - + sound2On = 0; sound2ATL = 0; sound2Skip = 0; @@ -1336,7 +1217,7 @@ void soundReset() sound2EnvelopeUpDown = 0; sound2EnvelopeATLReload = 0; sound2Wave = soundWavePattern[2]; - + sound3On = 0; sound3ATL = 0; sound3Skip = 0; @@ -1347,7 +1228,7 @@ void soundReset() sound3Bank = 0; sound3DataSize = 0; sound3ForcedOutput = 0; - + sound4On = 0; sound4Clock = 0; sound4ATL = 0; @@ -1366,21 +1247,19 @@ void soundReset() sound2On = 0; sound3On = 0; sound4On = 0; - + int addr = 0x90; - while(addr < 0xA0) - { - ioMem[addr++] = 0x00; - ioMem[addr++] = 0xff; - } + while(addr < 0xA0) { + ioMem[addr++] = 0x00; + ioMem[addr++] = 0xff; + } addr = 0; - while(addr < 0x20) - { - sound3WaveRam[addr++] = 0x00; - sound3WaveRam[addr++] = 0xff; - } + while(addr < 0x20) { + sound3WaveRam[addr++] = 0x00; + sound3WaveRam[addr++] = 0xff; + } memset(soundFinalWave, 0, soundBufferLen); @@ -1390,74 +1269,67 @@ void soundReset() bool soundInit() { - if(systemSoundInit()) - { - memset(soundBuffer[0], 0, 735*2); - memset(soundBuffer[1], 0, 735*2); - memset(soundBuffer[2], 0, 735*2); - memset(soundBuffer[3], 0, 735*2); - - memset(soundFinalWave, 0, soundBufferLen); - - soundPaused = true; - return true; - } + if(systemSoundInit()) { + memset(soundBuffer[0], 0, 735*2); + memset(soundBuffer[1], 0, 735*2); + memset(soundBuffer[2], 0, 735*2); + memset(soundBuffer[3], 0, 735*2); + + memset(soundFinalWave, 0, soundBufferLen); + + soundPaused = true; + return true; + } return false; -} +} void soundSetQuality(int quality) { - if(soundQuality != quality && systemCanChangeSoundQuality()) - { - if(!soundOffFlag) - soundShutdown(); - soundQuality = quality; - soundNextPosition = 0; - if(!soundOffFlag) - soundInit(); - SOUND_CLOCK_TICKS = USE_TICKS_AS * soundQuality; - soundIndex = 0; - soundBufferIndex = 0; - } - else if(soundQuality != quality) - { - soundNextPosition = 0; - SOUND_CLOCK_TICKS = USE_TICKS_AS * soundQuality; - soundIndex = 0; - soundBufferIndex = 0; - } + if(soundQuality != quality && systemCanChangeSoundQuality()) { + if(!soundOffFlag) + soundShutdown(); + soundQuality = quality; + soundNextPosition = 0; + if(!soundOffFlag) + soundInit(); + SOUND_CLOCK_TICKS = USE_TICKS_AS * soundQuality; + soundIndex = 0; + soundBufferIndex = 0; + } else if(soundQuality != quality) { + soundNextPosition = 0; + SOUND_CLOCK_TICKS = USE_TICKS_AS * soundQuality; + soundIndex = 0; + soundBufferIndex = 0; + } } void soundSaveGame(gzFile gzFile) { utilWriteData(gzFile, soundSaveStruct); utilWriteData(gzFile, soundSaveStructV2); - + utilGzWrite(gzFile, &soundQuality, sizeof(int)); } void soundReadGame(gzFile gzFile, int version) { utilReadData(gzFile, soundSaveStruct); - if(version >= SAVE_GAME_VERSION_3) - { - utilReadData(gzFile, soundSaveStructV2); - } - else - { - sound3Bank = (ioMem[NR30] >> 6) & 1; - sound3DataSize = (ioMem[NR30] >> 5) & 1; - sound3ForcedOutput = (ioMem[NR32] >> 7) & 1; - // nothing better to do here... - memcpy(&sound3WaveRam[0x00], &ioMem[0x90], 0x10); - memcpy(&sound3WaveRam[0x10], &ioMem[0x90], 0x10); - } + if(version >= SAVE_GAME_VERSION_3) { + utilReadData(gzFile, soundSaveStructV2); + } else { + sound3Bank = (ioMem[NR30] >> 6) & 1; + sound3DataSize = (ioMem[NR30] >> 5) & 1; + sound3ForcedOutput = (ioMem[NR32] >> 7) & 1; + // nothing better to do here... + memcpy(&sound3WaveRam[0x00], &ioMem[0x90], 0x10); + memcpy(&sound3WaveRam[0x10], &ioMem[0x90], 0x10); + } soundBufferIndex = soundIndex * 2; - + int quality = 1; utilGzRead(gzFile, &quality, sizeof(int)); soundSetQuality(quality); - + sound1Wave = soundWavePattern[ioMem[NR11] >> 6]; sound2Wave = soundWavePattern[ioMem[NR21] >> 6]; } diff --git a/source/vba/Sound.h b/source/vba/Sound.h index 4e1dac7..47a4b3f 100644 --- a/source/vba/Sound.h +++ b/source/vba/Sound.h @@ -1,82 +1,84 @@ -// -*- 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_SOUND_H -#define VBA_SOUND_H - -#define NR10 0x60 -#define NR11 0x62 -#define NR12 0x63 -#define NR13 0x64 -#define NR14 0x65 -#define NR21 0x68 -#define NR22 0x69 -#define NR23 0x6c -#define NR24 0x6d -#define NR30 0x70 -#define NR31 0x72 -#define NR32 0x73 -#define NR33 0x74 -#define NR34 0x75 -#define NR41 0x78 -#define NR42 0x79 -#define NR43 0x7c -#define NR44 0x7d -#define NR50 0x80 -#define NR51 0x81 -#define NR52 0x84 -#define SGCNT0_H 0x82 -#define FIFOA_L 0xa0 -#define FIFOA_H 0xa2 -#define FIFOB_L 0xa4 -#define FIFOB_H 0xa6 - -extern void soundTick(); -extern void soundShutdown(); -extern bool soundInit(); -extern void soundPause(); -extern void soundResume(); -extern void soundEnable(int); -extern void soundDisable(int); -extern int soundGetEnable(); -extern void soundReset(); -extern void soundSaveGame(gzFile); -extern void soundReadGame(gzFile, int); -extern void soundEvent(u32, u8); -extern void soundEvent(u32, u16); -extern void soundTimerOverflow(int); -extern void soundSetQuality(int); - -//extern int SOUND_TICKS; -extern int SOUND_CLOCK_TICKS; -extern int soundTicks; -extern int soundPaused; -extern bool soundOffFlag; -extern int soundQuality; -extern int soundBufferLen; -extern int soundBufferTotalLen; -extern u32 soundNextPosition; -extern u16 soundFinalWave[1470]; -extern int soundVolume; - -extern bool soundEcho; -extern bool soundLowPass; -extern bool soundReverse; - -#endif // VBA_SOUND_H +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team +// Copyright (C) 2004-2006 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_SOUND_H +#define VBA_SOUND_H + +#include "System.h" + +#define NR10 0x60 +#define NR11 0x62 +#define NR12 0x63 +#define NR13 0x64 +#define NR14 0x65 +#define NR21 0x68 +#define NR22 0x69 +#define NR23 0x6c +#define NR24 0x6d +#define NR30 0x70 +#define NR31 0x72 +#define NR32 0x73 +#define NR33 0x74 +#define NR34 0x75 +#define NR41 0x78 +#define NR42 0x79 +#define NR43 0x7c +#define NR44 0x7d +#define NR50 0x80 +#define NR51 0x81 +#define NR52 0x84 +#define SGCNT0_H 0x82 +#define FIFOA_L 0xa0 +#define FIFOA_H 0xa2 +#define FIFOB_L 0xa4 +#define FIFOB_H 0xa6 + +void soundTick(); +void soundShutdown(); +bool soundInit(); +void soundPause(); +void soundResume(); +void soundEnable(int); +void soundDisable(int); +int soundGetEnable(); +void soundReset(); +void soundSaveGame(gzFile); +void soundReadGame(gzFile, int); +void soundEvent(u32, u8); +void soundEvent(u32, u16); +void soundTimerOverflow(int); +void soundSetQuality(int); + +extern int SOUND_CLOCK_TICKS; +extern int soundTicks; +extern int soundPaused; +extern bool soundOffFlag; +extern int soundQuality; +extern int soundBufferLen; +extern int soundBufferTotalLen; +extern u32 soundNextPosition; +extern u16 soundFinalWave[1470]; +extern int soundVolume; + +extern bool soundEcho; +extern bool soundLowPass; +extern bool soundReverse; + +#endif // VBA_SOUND_H diff --git a/source/vba/Sram.cpp b/source/vba/Sram.cpp index 1a46097..dae6be3 100644 --- a/source/vba/Sram.cpp +++ b/source/vba/Sram.cpp @@ -1,32 +1,39 @@ -// 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. - -#include "GBA.h" -#include "Flash.h" -#include "Sram.h" - -u8 sramRead(u32 address) -{ - return flashSaveMemory[address & 0xFFFF]; -} - -void sramWrite(u32 address, u8 byte) -{ - flashSaveMemory[address & 0xFFFF] = byte; - systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; -} +// 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. + +#include "agb/GBA.h" +#include "Globals.h" +#include "Flash.h" +#include "Sram.h" + +u8 sramRead(u32 address) +{ + return flashSaveMemory[address & 0xFFFF]; +} +void sramDelayedWrite(u32 address, u8 byte) +{ + saveType = 1; + cpuSaveGameFunc = sramWrite; + sramWrite(address, byte); +} + +void sramWrite(u32 address, u8 byte) +{ + flashSaveMemory[address & 0xFFFF] = byte; + systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; +} diff --git a/source/vba/Sram.h b/source/vba/Sram.h index f33f4c8..85536ee 100644 --- a/source/vba/Sram.h +++ b/source/vba/Sram.h @@ -1,26 +1,27 @@ -// -*- 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_SRAM_H -#define VBA_SRAM_H - -extern u8 sramRead(u32 address); -extern void sramWrite(u32 address, u8 byte); - -#endif // VBA_SRAM_H +// -*- 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_SRAM_H +#define VBA_SRAM_H + +extern u8 sramRead(u32 address); +extern void sramWrite(u32 address, u8 byte); +extern void sramDelayedWrite(u32 address, u8 byte); + +#endif // VBA_SRAM_H diff --git a/source/vba/System.h b/source/vba/System.h index c58a0fb..f321dbc 100644 --- a/source/vba/System.h +++ b/source/vba/System.h @@ -1,127 +1,135 @@ -// -*- 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_SYSTEM_H -#define VBA_SYSTEM_H - -#include "unzip.h" - -#ifndef NULL -#define NULL 0 -#endif - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; - -#ifdef _MSC_VER -typedef unsigned __int64 u64; -#else -typedef unsigned long long u64; -#endif - -typedef signed char s8; -typedef signed short s16; -typedef signed int s32; - -#ifdef _MSC_VER -typedef signed __int64 s64; -#else -typedef signed long long s64; -#endif - -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 void systemWriteDataToSoundBuffer(); -extern void systemSoundShutdown(); -extern void systemSoundPause(); -extern void systemSoundResume(); -extern void systemSoundReset(); -extern bool systemSoundInit(); -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 bool systemSoundOn; -extern u16 systemColorMap16[0x10000]; -//extern u32 systemColorMap32[0x10000]; -extern u32 *systemColorMap32; -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; - -#define SYSTEM_SAVE_UPDATED 30 -#define SYSTEM_SAVE_NOT_UPDATED 0 - -#endif //VBA_SYSTEM_H +// -*- 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_SYSTEM_H +#define VBA_SYSTEM_H + +#include +#include "unzip.h" + +#ifndef NULL +#define NULL 0 +#endif + + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + + + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +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 void systemWriteDataToSoundBuffer(); +extern void systemSoundShutdown(); +extern void systemSoundPause(); +extern void systemSoundResume(); +extern void systemSoundReset(); +extern bool systemSoundInit(); +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 bool systemSoundOn; // old sound system +extern u16 systemColorMap16[0x10000]; +//extern u32 systemColorMap32[0x10000]; +extern u32 *systemColorMap32; +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; +extern int systemThrottle; + +#define SYSTEM_SAVE_UPDATED 30 +#define SYSTEM_SAVE_NOT_UPDATED 0 + +#endif //VBA_SYSTEM_H diff --git a/source/vba/Text.cpp b/source/vba/Text.cpp deleted file mode 100644 index e9925ea..0000000 --- a/source/vba/Text.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Ben Parnell - * - * 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 of the License, 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 - */ - -/* Code originally from fceu/drawing.h file, adapted by Forgotten - */ -#include "System.h" - -extern int RGB_LOW_BITS_MASK; - -static const u8 fontdata2[2048] = - { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x81,0xa5,0x81,0xbd,0x99,0x81,0x7e,0x7e,0xff,0xdb,0xff,0xc3,0xe7,0xff,0x7e,0x36,0x7f,0x7f,0x7f,0x3e,0x1c,0x08,0x00,0x08,0x1c,0x3e,0x7f,0x3e,0x1c,0x08,0x00,0x1c,0x3e,0x1c,0x7f,0x7f,0x3e,0x1c,0x3e,0x08,0x08,0x1c,0x3e,0x7f,0x3e,0x1c,0x3e,0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00,0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff,0x00,0x3c,0x66,0x42,0x42,0x66,0x3c,0x00,0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff,0xf0,0xe0,0xf0,0xbe,0x33,0x33,0x33,0x1e,0x3c,0x66,0x66,0x66,0x3c,0x18,0x7e,0x18,0xfc,0xcc,0xfc,0x0c,0x0c,0x0e,0x0f,0x07,0xfe,0xc6,0xfe,0xc6,0xc6,0xe6,0x67,0x03,0x99,0x5a,0x3c,0xe7,0xe7,0x3c,0x5a,0x99,0x01,0x07,0x1f,0x7f,0x1f,0x07,0x01,0x00,0x40,0x70,0x7c,0x7f,0x7c,0x70,0x40,0x00,0x18,0x3c,0x7e,0x18,0x18,0x7e,0x3c,0x18,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x00,0xfe,0xdb,0xdb,0xde,0xd8,0xd8,0xd8,0x00,0x7c,0xc6,0x1c,0x36,0x36,0x1c,0x33,0x1e,0x00,0x00,0x00,0x00,0x7e,0x7e,0x7e,0x00,0x18,0x3c,0x7e,0x18,0x7e,0x3c,0x18,0xff,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x18,0x30,0x7f,0x30,0x18,0x00,0x00,0x00,0x0c,0x06,0x7f,0x06,0x0c,0x00,0x00,0x00,0x00,0x03,0x03,0x03,0x7f,0x00,0x00,0x00,0x24,0x66,0xff,0x66,0x24,0x00,0x00,0x00,0x18,0x3c,0x7e,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0x7e,0x3c,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x1e,0x0c,0x0c,0x00,0x0c,0x00,0x36,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x36,0x36,0x7f,0x36,0x7f,0x36,0x36,0x00,0x0c,0x3e,0x03,0x1e,0x30,0x1f,0x0c,0x00,0x00,0x63,0x33,0x18,0x0c,0x66,0x63,0x00,0x1c,0x36,0x1c,0x6e,0x3b,0x33,0x6e,0x00,0x06,0x06,0x03,0x00,0x00,0x00,0x00,0x00,0x18,0x0c,0x06,0x06,0x06,0x0c,0x18,0x00,0x06,0x0c,0x18,0x18,0x18,0x0c,0x06,0x00,0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x0c,0x0c,0x3f,0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x06,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x00,0x60,0x30,0x18,0x0c,0x06,0x03,0x01,0x00,0x3e,0x63,0x73,0x7b,0x6f,0x67,0x3e,0x00,0x0c,0x0e,0x0c,0x0c,0x0c,0x0c,0x3f,0x00,0x1e,0x33,0x30,0x1c,0x06,0x33,0x3f,0x00,0x1e,0x33,0x30,0x1c,0x30,0x33,0x1e,0x00,0x38,0x3c,0x36,0x33,0x7f,0x30,0x78,0x00,0x3f,0x03,0x1f,0x30,0x30,0x33,0x1e,0x00,0x1c,0x06,0x03,0x1f,0x33,0x33,0x1e,0x00,0x3f,0x33,0x30,0x18,0x0c,0x0c,0x0c,0x00,0x1e,0x33,0x33,0x1e,0x33,0x33,0x1e,0x00,0x1e,0x33,0x33,0x3e,0x30,0x18,0x0e,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x06,0x18,0x0c,0x06,0x03,0x06,0x0c,0x18,0x00,0x00,0x00,0x3f,0x00,0x00,0x3f,0x00,0x00,0x06,0x0c,0x18,0x30,0x18,0x0c,0x06,0x00,0x1e,0x33,0x30,0x18,0x0c,0x00,0x0c,0x00, - 0x3e,0x63,0x7b,0x7b,0x7b,0x03,0x1e,0x00,0x0c,0x1e,0x33,0x33,0x3f,0x33,0x33,0x00,0x3f,0x66,0x66,0x3e,0x66,0x66,0x3f,0x00,0x3c,0x66,0x03,0x03,0x03,0x66,0x3c,0x00,0x1f,0x36,0x66,0x66,0x66,0x36,0x1f,0x00,0x7f,0x46,0x16,0x1e,0x16,0x46,0x7f,0x00,0x7f,0x46,0x16,0x1e,0x16,0x06,0x0f,0x00,0x3c,0x66,0x03,0x03,0x73,0x66,0x7c,0x00,0x33,0x33,0x33,0x3f,0x33,0x33,0x33,0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x78,0x30,0x30,0x30,0x33,0x33,0x1e,0x00,0x67,0x66,0x36,0x1e,0x36,0x66,0x67,0x00,0x0f,0x06,0x06,0x06,0x46,0x66,0x7f,0x00,0x63,0x77,0x7f,0x7f,0x6b,0x63,0x63,0x00,0x63,0x67,0x6f,0x7b,0x73,0x63,0x63,0x00,0x1c,0x36,0x63,0x63,0x63,0x36,0x1c,0x00,0x3f,0x66,0x66,0x3e,0x06,0x06,0x0f,0x00,0x1e,0x33,0x33,0x33,0x3b,0x1e,0x38,0x00,0x3f,0x66,0x66,0x3e,0x36,0x66,0x67,0x00,0x1e,0x33,0x07,0x0e,0x38,0x33,0x1e,0x00,0x3f,0x2d,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x33,0x33,0x33,0x33,0x33,0x33,0x3f,0x00,0x33,0x33,0x33,0x33,0x33,0x1e,0x0c,0x00,0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00,0x63,0x63,0x36,0x1c,0x1c,0x36,0x63,0x00,0x33,0x33,0x33,0x1e,0x0c,0x0c,0x1e,0x00,0x7f,0x63,0x31,0x18,0x4c,0x66,0x7f,0x00,0x1e,0x06,0x06,0x06,0x06,0x06,0x1e,0x00,0x03,0x06,0x0c,0x18,0x30,0x60,0x40,0x00,0x1e,0x18,0x18,0x18,0x18,0x18,0x1e,0x00,0x08,0x1c,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff, - 0x0c,0x0c,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x30,0x3e,0x33,0x6e,0x00,0x07,0x06,0x06,0x3e,0x66,0x66,0x3b,0x00,0x00,0x00,0x1e,0x33,0x03,0x33,0x1e,0x00,0x38,0x30,0x30,0x3e,0x33,0x33,0x6e,0x00,0x00,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x1c,0x36,0x06,0x0f,0x06,0x06,0x0f,0x00,0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x1f,0x07,0x06,0x36,0x6e,0x66,0x66,0x67,0x00,0x0c,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x30,0x00,0x30,0x30,0x30,0x33,0x33,0x1e,0x07,0x06,0x66,0x36,0x1e,0x36,0x67,0x00,0x0e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x33,0x7f,0x7f,0x6b,0x63,0x00,0x00,0x00,0x1f,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x1e,0x33,0x33,0x33,0x1e,0x00,0x00,0x00,0x3b,0x66,0x66,0x3e,0x06,0x0f,0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x78,0x00,0x00,0x3b,0x6e,0x66,0x06,0x0f,0x00,0x00,0x00,0x3e,0x03,0x1e,0x30,0x1f,0x00,0x08,0x0c,0x3e,0x0c,0x0c,0x2c,0x18,0x00,0x00,0x00,0x33,0x33,0x33,0x33,0x6e,0x00,0x00,0x00,0x33,0x33,0x33,0x1e,0x0c,0x00,0x00,0x00,0x63,0x6b,0x7f,0x7f,0x36,0x00,0x00,0x00,0x63,0x36,0x1c,0x36,0x63,0x00,0x00,0x00,0x33,0x33,0x33,0x3e,0x30,0x1f,0x00,0x00,0x3f,0x19,0x0c,0x26,0x3f,0x00,0x38,0x0c,0x0c,0x07,0x0c,0x0c,0x38,0x00,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x07,0x0c,0x0c,0x38,0x0c,0x0c,0x07,0x00,0x6e,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1c,0x36,0x63,0x63,0x7f,0x00, - 0x1e,0x33,0x03,0x33,0x1e,0x18,0x30,0x1e,0x00,0x33,0x00,0x33,0x33,0x33,0x7e,0x00,0x38,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x7e,0xc3,0x3c,0x60,0x7c,0x66,0xfc,0x00,0x33,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x07,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x0c,0x0c,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x00,0x00,0x1e,0x03,0x03,0x1e,0x30,0x1c,0x7e,0xc3,0x3c,0x66,0x7e,0x06,0x3c,0x00,0x33,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x07,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x33,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x3e,0x63,0x1c,0x18,0x18,0x18,0x3c,0x00,0x07,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x63,0x1c,0x36,0x63,0x7f,0x63,0x63,0x00,0x0c,0x0c,0x00,0x1e,0x33,0x3f,0x33,0x00,0x38,0x00,0x3f,0x06,0x1e,0x06,0x3f,0x00,0x00,0x00,0xfe,0x30,0xfe,0x33,0xfe,0x00,0x7c,0x36,0x33,0x7f,0x33,0x33,0x73,0x00,0x1e,0x33,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x33,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x07,0x00,0x1e,0x33,0x33,0x1e,0x00,0x1e,0x33,0x00,0x33,0x33,0x33,0x7e,0x00,0x00,0x07,0x00,0x33,0x33,0x33,0x7e,0x00,0x00,0x33,0x00,0x33,0x33,0x3e,0x30,0x1f,0xc3,0x18,0x3c,0x66,0x66,0x3c,0x18,0x00,0x33,0x00,0x33,0x33,0x33,0x33,0x1e,0x00,0x18,0x18,0x7e,0x03,0x03,0x7e,0x18,0x18,0x1c,0x36,0x26,0x0f,0x06,0x67,0x3f,0x00,0x33,0x33,0x1e,0x3f,0x0c,0x3f,0x0c,0x0c,0x1f,0x33,0x33,0x5f,0x63,0xf3,0x63,0xe3,0x70,0xd8,0x18,0x3c,0x18,0x18,0x1b,0x0e, - 0x38,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x1c,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x38,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x38,0x00,0x33,0x33,0x33,0x7e,0x00,0x00,0x1f,0x00,0x1f,0x33,0x33,0x33,0x00,0x3f,0x00,0x33,0x37,0x3f,0x3b,0x33,0x00,0x3c,0x36,0x36,0x7c,0x00,0x7e,0x00,0x00,0x1c,0x36,0x36,0x1c,0x00,0x3e,0x00,0x00,0x0c,0x00,0x0c,0x06,0x03,0x33,0x1e,0x00,0x00,0x00,0x00,0x3f,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x3f,0x30,0x30,0x00,0x00,0xc3,0x63,0x33,0x7b,0xcc,0x66,0x33,0xf0,0xc3,0x63,0x33,0xdb,0xec,0xf6,0xf3,0xc0,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x00,0x00,0xcc,0x66,0x33,0x66,0xcc,0x00,0x00,0x00,0x33,0x66,0xcc,0x66,0x33,0x00,0x00,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xdb,0xee,0xdb,0x77,0xdb,0xee,0xdb,0x77,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x18,0x18,0x18,0x6c,0x6c,0x6c,0x6c,0x6f,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,0x7f,0x6c,0x6c,0x6c,0x00,0x00,0x1f,0x18,0x1f,0x18,0x18,0x18,0x6c,0x6c,0x6f,0x60,0x6f,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x7f,0x60,0x6f,0x6c,0x6c,0x6c,0x6c,0x6c,0x6f,0x60,0x7f,0x00,0x00,0x00,0x6c,0x6c,0x6c,0x6c,0x7f,0x00,0x00,0x00,0x18,0x18,0x1f,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0xf8,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x18,0x18,0x18,0x6c,0x6c,0x6c,0x6c,0xec,0x6c,0x6c,0x6c,0x6c,0x6c,0xec,0x0c,0xfc,0x00,0x00,0x00,0x00,0x00,0xfc,0x0c,0xec,0x6c,0x6c,0x6c,0x6c,0x6c,0xef,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xef,0x6c,0x6c,0x6c,0x6c,0x6c,0xec,0x0c,0xec,0x6c,0x6c,0x6c,0x00,0x00,0xff,0x00,0xff,0x00,0x00,0x00,0x6c,0x6c,0xef,0x00,0xef,0x6c,0x6c,0x6c,0x18,0x18,0xff,0x00,0xff,0x00,0x00,0x00,0x6c,0x6c,0x6c,0x6c,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xff,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0xfc,0x00,0x00,0x00,0x18,0x18,0xf8,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0xf8,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xfc,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0xff,0x6c,0x6c,0x6c,0x18,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0x18,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x00,0x00,0x6e,0x3b,0x13,0x3b,0x6e,0x00,0x00,0x1e,0x33,0x1f,0x33,0x1f,0x03,0x03,0x00,0x3f,0x33,0x03,0x03,0x03,0x03,0x00,0x00,0x7f,0x36,0x36,0x36,0x36,0x36,0x00,0x3f,0x33,0x06,0x0c,0x06,0x33,0x3f,0x00,0x00,0x00,0x7e,0x1b,0x1b,0x1b,0x0e,0x00,0x00,0x66,0x66,0x66,0x66,0x3e,0x06,0x03,0x00,0x6e,0x3b,0x18,0x18,0x18,0x18,0x00,0x3f,0x0c,0x1e,0x33,0x33,0x1e,0x0c,0x3f,0x1c,0x36,0x63,0x7f,0x63,0x36,0x1c,0x00,0x1c,0x36,0x63,0x63,0x36,0x36,0x77,0x00,0x38,0x0c,0x18,0x3e,0x33,0x33,0x1e,0x00,0x00,0x00,0x7e,0xdb,0xdb,0x7e,0x00,0x00,0x60,0x30,0x7e,0xdb,0xdb,0x7e,0x06,0x03,0x1c,0x06,0x03,0x1f,0x03,0x06,0x1c,0x00,0x1e,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x3f,0x00,0x3f,0x00,0x3f,0x00,0x00,0x0c,0x0c,0x3f,0x0c,0x0c,0x00,0x3f,0x00,0x06,0x0c,0x18,0x0c,0x06,0x00,0x3f,0x00,0x18,0x0c,0x06,0x0c,0x18,0x00,0x3f,0x00,0x70,0xd8,0xd8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x0e,0x0c,0x0c,0x00,0x3f,0x00,0x0c,0x0c,0x00,0x00,0x6e,0x3b,0x00,0x6e,0x3b,0x00,0x00,0x1c,0x36,0x36,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xf0,0x30,0x30,0x30,0x37,0x36,0x3c,0x38,0x1e,0x36,0x36,0x36,0x36,0x00,0x00,0x00,0x0e,0x18,0x0c,0x06,0x1e,0x00,0x00,0x00,0x00,0x00,0x3c,0x3c,0x3c,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - }; - -static void drawTextInternal(u8 *screen, int pitch, int x, int y, - const char *string, bool trans) -{ - screen += y*pitch; - int inc = 2; - switch(systemColorDepth) - { - case 24: - inc = 3; - break; - case 32: - inc = 4; - break; - } - screen += x*inc; - - switch(systemColorDepth) - { - case 16: - { - while(*string) - { - char c = *string++; - u8 *scr = screen; - - u16 mask = ~RGB_LOW_BITS_MASK; - int h, w; - u16 *s = (u16 *)scr; - for (h = 0; h < 8; h++) - { - for (w = 0; w < 8; w++, s++) - { - int on = (fontdata2[(c<<3)+h]>>w)&1; - - if(trans) - { - if(on) - *s = ((0xf) << systemRedShift) + - ((*s & mask) >>1); - } - else - { - if(on) - *s = (0x1f) << systemRedShift; - } - } - scr += pitch; - s = (u16 *)scr; - } - screen += inc*8; - } - } - break; - case 24: - { - while(*string) - { - char c = *string++; - u8 *scr = screen; - - int h, w; - u8 *s = (u8 *)scr; - for (h = 0; h < 8; h++) - { - for (w = 0; w < 8; w++, s+=3) - { - int on = (fontdata2[(c<<3)+h]>>w)&1; - - if(trans) - { - if(on) - { - u32 color = (0x1f) << systemRedShift; - *s = ((color & 255)>>1)+(*s>>1); - *(s+1) = (((color >> 8) & 255)>>1)+(*(s+1)>>1); - *(s+2) = (((color >> 16) & 255)>>1)+(*(s+2)>>1); - } - } - else - { - if(on) - { - u32 color = (0x1f) << systemRedShift; - *s = (color & 255); - *(s+1) = (color >> 8) & 255; - *(s+2) = (color >> 16) & 255; - } - } - } - scr += pitch; - s = (u8 *)scr; - } - screen += inc*8; - } - } - break; - case 32: - { - while(*string) - { - char c = *string++; - u8 *scr = screen; - - int h, w; - u32 mask = 0xfefefe; - u32 *s = (u32 *)scr; - for (h = 0; h < 8; h++) - { - for (w = 0; w < 8; w++, s++) - { - int on = (fontdata2[(c<<3)+h]>>w)&1; - - if(trans) - { - if(on) - *s = ((0xf) << systemRedShift) + ((*s & mask)>>1); - } - else - { - if(on) - *s = (0x1f) << systemRedShift; - } - } - scr += pitch; - s = (u32 *)scr; - } - screen += inc*8; - } - } - break; - } -} - -void drawText(u8 *screen, int pitch, int x, int y, const char *string) -{ - drawTextInternal(screen, pitch, x, y, string, false); -} - -void drawTextTransp(u8 *screen, int pitch, int x, int y, const char *string) -{ - drawTextInternal(screen, pitch, x, y, string, true); -} diff --git a/source/vba/Text.h b/source/vba/Text.h deleted file mode 100644 index cbfe8be..0000000 --- a/source/vba/Text.h +++ /dev/null @@ -1,21 +0,0 @@ -// -*- 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. - -extern void drawText(u8 *, int, int, int, const char *); -extern void drawTextTransp(u8 *, int, int, int, const char *); diff --git a/source/vba/Util.cpp b/source/vba/Util.cpp index 2823e54..be3ddaf 100644 --- a/source/vba/Util.cpp +++ b/source/vba/Util.cpp @@ -1,1196 +1,1021 @@ -// 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. - -#include "sdfileio.h" -#include -#include -#include -#include - -extern "C" - { -#include - } - -#if 0 -#include "unrarlib.h" -#endif - -#include "System.h" -#include "NLS.h" -#include "Util.h" -#include "Flash.h" -#include "GBA.h" -#include "Globals.h" -#include "RTC.h" -#include "Port.h" - - -extern "C" - { -#include "memgzio.h" - } - -#ifndef _MSC_VER -#define _stricmp strcasecmp -#endif // ! _MSC_VER - -static int (*utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL; -static int (*utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL; -static int (*utilGzCloseFunc)(gzFile) = NULL; - -bool utilWritePNGFile(const char *fileName, int w, int h, u8 *pix) -{ -#if 0 - u8 writeBuffer[512 * 3]; - - FILE* fp = gen_fopen(fileName,"wb"); - - if(!fp) - { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); - return false; - } - - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, - NULL, - NULL, - NULL); - if(!png_ptr) - { - gen_fclose(fp); - return false; - } - - png_infop info_ptr = png_create_info_struct(png_ptr); - - if(!info_ptr) - { - png_destroy_write_struct(&png_ptr,NULL); - gen_fclose(fp); - return false; - } - - if(setjmp(png_ptr->jmpbuf)) - { - png_destroy_write_struct(&png_ptr,NULL); - gen_fclose(fp); - return false; - } - - png_init_io(png_ptr,fp); - - png_set_IHDR(png_ptr, - info_ptr, - w, - h, - 8, - PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - - png_write_info(png_ptr,info_ptr); - - u8 *b = writeBuffer; - - int sizeX = w; - int sizeY = h; - - switch(systemColorDepth) - { - case 16: - { - u16 *p = (u16 *)(pix+(w+2)*2); // skip first black line - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - u16 v = *p++; - - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B - } - p++; // skip black pixel for filters - p++; // skip black pixel for filters - png_write_row(png_ptr,writeBuffer); - - b = writeBuffer; - } - } - break; - case 24: - { - u8 *pixU8 = (u8 *)pix; - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - if(systemRedShift < systemBlueShift) - { - *b++ = *pixU8++; // R - *b++ = *pixU8++; // G - *b++ = *pixU8++; // B - } - else - { - int blue = *pixU8++; - int green = *pixU8++; - int red = *pixU8++; - - *b++ = red; - *b++ = green; - *b++ = blue; - } - } - png_write_row(png_ptr,writeBuffer); - - b = writeBuffer; - } - } - break; - case 32: - { - u32 *pixU32 = (u32 *)(pix+4*(w+1)); - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - u32 v = *pixU32++; - - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B - } - pixU32++; - - png_write_row(png_ptr,writeBuffer); - - b = writeBuffer; - } - } - break; - } - - png_write_end(png_ptr, info_ptr); - - png_destroy_write_struct(&png_ptr, &info_ptr); - - gen_fclose(fp); - -#endif - return true; -} - -void utilPutDword(u8 *p, u32 value) -{ - *p++ = value & 255; - *p++ = (value >> 8) & 255; - *p++ = (value >> 16) & 255; - *p = (value >> 24) & 255; -} - -void utilPutWord(u8 *p, u16 value) -{ - *p++ = value & 255; - *p = (value >> 8) & 255; -} - -void utilWriteBMP(char *buf, int w, int h, u8 *pix) -{ - u8 *b = (u8 *)buf; - - int sizeX = w; - int sizeY = h; - - switch(systemColorDepth) - { - case 16: - { - u16 *p = (u16 *)(pix+(w+2)*(h)*2); // skip first black line - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - u16 v = *p++; - - *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - } - p++; // skip black pixel for filters - p++; // skip black pixel for filters - p -= 2*(w+2); - } - } - break; - case 24: - { - u8 *pixU8 = (u8 *)pix+3*w*(h-1); - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - if(systemRedShift > systemBlueShift) - { - *b++ = *pixU8++; // B - *b++ = *pixU8++; // G - *b++ = *pixU8++; // R - } - else - { - int red = *pixU8++; - int green = *pixU8++; - int blue = *pixU8++; - - *b++ = blue; - *b++ = green; - *b++ = red; - } - } - pixU8 -= 2*3*w; - } - } - break; - case 32: - { - u32 *pixU32 = (u32 *)(pix+4*(w+1)*(h)); - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - u32 v = *pixU32++; - - *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - } - pixU32++; - pixU32 -= 2*(w+1); - } - } - break; - } -} - -bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix) -{ - u8 writeBuffer[512 * 3]; - - FILE* fp = gen_fopen(fileName,"wb"); - - if(!fp) - { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); - return false; - } - - struct - { - u8 ident[2]; - u8 filesize[4]; - u8 reserved[4]; - u8 dataoffset[4]; - u8 headersize[4]; - u8 width[4]; - u8 height[4]; - u8 planes[2]; - u8 bitsperpixel[2]; - u8 compression[4]; - u8 datasize[4]; - u8 hres[4]; - u8 vres[4]; - u8 colors[4]; - u8 importantcolors[4]; - // u8 pad[2]; - } - bmpheader; - memset(&bmpheader, 0, sizeof(bmpheader)); - - bmpheader.ident[0] = 'B'; - bmpheader.ident[1] = 'M'; - - u32 fsz = sizeof(bmpheader) + w*h*3; - utilPutDword(bmpheader.filesize, fsz); - utilPutDword(bmpheader.dataoffset, 0x36); - utilPutDword(bmpheader.headersize, 0x28); - utilPutDword(bmpheader.width, w); - utilPutDword(bmpheader.height, h); - utilPutDword(bmpheader.planes, 1); - utilPutDword(bmpheader.bitsperpixel, 24); - utilPutDword(bmpheader.datasize, 3*w*h); - - gen_fwrite(&bmpheader, 1, sizeof(bmpheader), fp); - - u8 *b = writeBuffer; - - int sizeX = w; - int sizeY = h; - - switch(systemColorDepth) - { - case 16: - { - u16 *p = (u16 *)(pix+(w+2)*(h)*2); // skip first black line - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - u16 v = *p++; - - *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - } - p++; // skip black pixel for filters - p++; // skip black pixel for filters - p -= 2*(w+2); - gen_fwrite(writeBuffer, 1, 3*w, fp); - - b = writeBuffer; - } - } - break; - case 24: - { - u8 *pixU8 = (u8 *)pix+3*w*(h-1); - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - if(systemRedShift > systemBlueShift) - { - *b++ = *pixU8++; // B - *b++ = *pixU8++; // G - *b++ = *pixU8++; // R - } - else - { - int red = *pixU8++; - int green = *pixU8++; - int blue = *pixU8++; - - *b++ = blue; - *b++ = green; - *b++ = red; - } - } - pixU8 -= 2*3*w; - gen_fwrite(writeBuffer, 1, 3*w, fp); - - b = writeBuffer; - } - } - break; - case 32: - { - u32 *pixU32 = (u32 *)(pix+4*(w+1)*(h)); - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - u32 v = *pixU32++; - - *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - } - pixU32++; - pixU32 -= 2*(w+1); - - gen_fwrite(writeBuffer, 1, 3*w, fp); - - b = writeBuffer; - } - } - break; - } - - gen_fclose(fp); - - return true; -} - -static int utilReadInt2(FILE* f) -{ - int res = 0; - int c = gen_fgetc(f); - if(c == EOF) - return -1; - res = c; - c = gen_fgetc(f); - if(c == EOF) - return -1; - return c + (res<<8); -} - -static int utilReadInt3(FILE* f) -{ - int res = 0; - int c = gen_fgetc(f); - if(c == EOF) - return -1; - res = c; - c = gen_fgetc(f); - if(c == EOF) - return -1; - res = c + (res<<8); - c = gen_fgetc(f); - if(c == EOF) - return -1; - return c + (res<<8); -} - -void utilApplyIPS(const char *ips, u8 **r, int *s) -{ - // from the IPS spec at http://zerosoft.zophar.net/ips.htm - FILE* f = gen_fopen(ips, "rb"); - if(!f) - return; - u8 *rom = *r; - int size = *s; - if(gen_fgetc(f) == 'P' && - gen_fgetc(f) == 'A' && - gen_fgetc(f) == 'T' && - gen_fgetc(f) == 'C' && - gen_fgetc(f) == 'H') - { - int b; - int offset; - int len; - for(;;) - { - // read offset - offset = utilReadInt3(f); - // if offset == EOF, end of patch - if(offset == 0x454f46) - break; - // read length - len = utilReadInt2(f); - if(!len) - { - // len == 0, RLE block - len = utilReadInt2(f); - // byte to fill - int c = gen_fgetc(f); - if(c == -1) - break; - b = (u8)c; - } - else - b= -1; - // check if we need to reallocate our ROM - if((offset + len) >= size) - { - size *= 2; - rom = (u8 *)realloc(rom, size); - *r = rom; - *s = size; - } - if(b == -1) - { - // normal block, just read the data - //if(gen_fread(&rom[offset], 1, len, f) != (size_t)len) - if(gen_fread(&rom[offset], 1, len, f) != (int)len) - break; - } - else - { - // fill the region with the given byte - while(len--) - { - rom[offset++] = b; - } - } - } - } - // close the file - gen_fclose(f); -} - -extern bool cpuIsMultiBoot; - -bool utilIsGBAImage(const char * file) -{ - cpuIsMultiBoot = false; - if(strlen(file) > 4) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".gba") == 0) - return true; - if(_stricmp(p, ".agb") == 0) - return true; - if(_stricmp(p, ".bin") == 0) - return true; - if(_stricmp(p, ".elf") == 0) - return true; - if(_stricmp(p, ".mb") == 0) - { - cpuIsMultiBoot = true; - return true; - } - } - } - - return false; -} - -bool utilIsGBImage(const char * file) -{ - if(strlen(file) > 4) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".gb") == 0) - return true; - if(_stricmp(p, ".gbc") == 0) - return true; - if(_stricmp(p, ".cgb") == 0) - return true; - if(_stricmp(p, ".sgb") == 0) - return true; - } - } - - return false; -} - -bool utilIsZipFile(const char *file) -{ - if(strlen(file) > 4) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".zip") == 0) - return true; - } - } - - return false; -} - -#if 0 -bool utilIsRarFile(const char *file) -{ - if(strlen(file) > 4) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".rar") == 0) - return true; - } - } - - return false; -} -#endif - -bool utilIsGzipFile(const char *file) -{ - if(strlen(file) > 3) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".gz") == 0) - return true; - if(_stricmp(p, ".z") == 0) - return true; - } - } - - return false; -} - -void utilGetBaseName(const char *file, char *buffer) -{ - strcpy(buffer, file); - - if(utilIsGzipFile(file)) - { - char *p = strrchr(buffer, '.'); - - if(p) - *p = 0; - } -} - -IMAGE_TYPE utilFindType(const char *file) -{ - char buffer[2048]; - - if(utilIsZipFile(file)) - { - unzFile unz = unzOpen(file); - - if(unz == NULL) - { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file); - return IMAGE_UNKNOWN; - } - - int r = unzGoToFirstFile(unz); - - if(r != UNZ_OK) - { - unzClose(unz); - systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); - return IMAGE_UNKNOWN; - } - - IMAGE_TYPE found = IMAGE_UNKNOWN; - - unz_file_info info; - - while(true) - { - r = unzGetCurrentFileInfo(unz, - &info, - buffer, - sizeof(buffer), - NULL, - 0, - NULL, - 0); - - if(r != UNZ_OK) - { - unzClose(unz); - systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); - return IMAGE_UNKNOWN; - } - - if(utilIsGBAImage(buffer)) - { - found = IMAGE_GBA; - break; - } - - if(utilIsGBImage(buffer)) - { - found = IMAGE_GB; - break; - } - - r = unzGoToNextFile(unz); - - if(r != UNZ_OK) - break; - } - unzClose(unz); - - if(found == IMAGE_UNKNOWN) - { - systemMessage(MSG_NO_IMAGE_ON_ZIP, - N_("No image found on ZIP file %s"), file); - return found; - } - return found; -#if 0 - } - else if(utilIsRarFile(file)) - { - IMAGE_TYPE found = IMAGE_UNKNOWN; - - ArchiveList_struct *rarList = NULL; - if(urarlib_list((void *)file, (ArchiveList_struct *)&rarList)) - { - ArchiveList_struct *p = rarList; - - while(p) - { - if(utilIsGBAImage(p->item.Name)) - { - found = IMAGE_GBA; - break; - } - - if(utilIsGBImage(p->item.Name)) - { - found = IMAGE_GB; - break; - } - p = p->next; - } - - urarlib_freelist(rarList); - } - return found; -#endif - } - else - { - if(utilIsGzipFile(file)) - utilGetBaseName(file, buffer); - else - strcpy(buffer, file); - - if(utilIsGBAImage(buffer)) - return IMAGE_GBA; - if(utilIsGBImage(buffer)) - return IMAGE_GB; - } - return IMAGE_UNKNOWN; -} - -static int utilGetSize(int size) -{ - int res = 1; - while(res < size) - res <<= 1; - return res; -} - -static u8 *utilLoadFromZip(const char *file, - bool (*accept)(const char *), - u8 *data, - int &size) -{ - char buffer[2048]; - - unzFile unz = unzOpen(file); - - if(unz == NULL) - { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file); - return NULL; - } - int r = unzGoToFirstFile(unz); - - if(r != UNZ_OK) - { - unzClose(unz); - systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); - return NULL; - } - - bool found = false; - - unz_file_info info; - - while(true) - { - r = unzGetCurrentFileInfo(unz, - &info, - buffer, - sizeof(buffer), - NULL, - 0, - NULL, - 0); - - if(r != UNZ_OK) - { - unzClose(unz); - systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); - return NULL; - } - - if(accept(buffer)) - { - found = true; - break; - } - - r = unzGoToNextFile(unz); - - if(r != UNZ_OK) - break; - } - - if(!found) - { - unzClose(unz); - systemMessage(MSG_NO_IMAGE_ON_ZIP, - N_("No image found on ZIP file %s"), file); - return NULL; - } - - int fileSize = info.uncompressed_size; - if(size == 0) - size = fileSize; - r = unzOpenCurrentFile(unz); - - if(r != UNZ_OK) - { - unzClose(unz); - systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), buffer); - return NULL; - } - - u8 *image = data; - - if(image == NULL) - { - image = (u8 *)malloc(utilGetSize(size)); - if(image == NULL) - { - unzCloseCurrentFile(unz); - unzClose(unz); - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "data"); - return NULL; - } - size = fileSize; - } - int read = fileSize <= size ? fileSize : size; - r = unzReadCurrentFile(unz, - image, - read); - - unzCloseCurrentFile(unz); - unzClose(unz); - - if(r != (int)read) - { - systemMessage(MSG_ERROR_READING_IMAGE, - N_("Error reading image %s"), buffer); - if(data == NULL) - free(image); - return NULL; - } - - size = fileSize; - - return image; -} - -static u8 *utilLoadGzipFile(const char *file, - bool (*accept)(const char *), - u8 *data, - int &size) -{ - FILE* f = gen_fopen(file, "rb"); - - if(f == NULL) - { - systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); - return NULL; - } - - gen_fseek(f, -4, SEEK_END); - int fileSize = gen_fgetc(f) | (gen_fgetc(f) << 8) | (gen_fgetc(f) << 16) | (gen_fgetc(f) << 24); - gen_fclose(f); - if(size == 0) - size = fileSize; - - gzFile gz = gzopen(file, "rb"); - - if(gz == NULL) - { - // should not happen, but who knows? - systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); - return NULL; - } - - u8 *image = data; - - if(image == NULL) - { - image = (u8 *)malloc(utilGetSize(size)); - if(image == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "data"); - gen_fclose(f); - return NULL; - } - size = fileSize; - } - int read = fileSize <= size ? fileSize : size; - int r = gzread(gz, image, read); - gzclose(gz); - - if(r != (int)read) - { - systemMessage(MSG_ERROR_READING_IMAGE, - N_("Error reading image %s"), file); - if(data == NULL) - free(image); - return NULL; - } - - size = fileSize; - - return image; -} - -#if 0 -static u8 *utilLoadRarFile(const char *file, - bool (*accept)(const char *), - u8 *data, - int &size) -{ - char buffer[2048]; - - ArchiveList_struct *rarList = NULL; - if(urarlib_list((void *)file, (ArchiveList_struct *)&rarList)) - { - ArchiveList_struct *p = rarList; - - bool found = false; - while(p) - { - if(accept(p->item.Name)) - { - strcpy(buffer, p->item.Name); - found = true; - break; - } - p = p->next; - } - if(found) - { - void *memory = NULL; - unsigned long lsize = 0; - size = p->item.UnpSize; - int r = urarlib_get((void *)&memory, &lsize, buffer, (void *)file, ""); - if(!r) - { - systemMessage(MSG_ERROR_READING_IMAGE, - N_("Error reading image %s"), buffer); - urarlib_freelist(rarList); - return NULL; - } - u8 *image = (u8 *)memory; - if(data != NULL) - { - memcpy(image, data, size); - } - urarlib_freelist(rarList); - return image; - } - systemMessage(MSG_NO_IMAGE_ON_ZIP, - N_("No image found on RAR file %s"), file); - urarlib_freelist(rarList); - return NULL; - } - // nothing found - return NULL; -} -#endif - -u8 *utilLoad(const char *file, - bool (*accept)(const char *), - u8 *data, - int &size) -{ - if(utilIsZipFile(file)) - { - return utilLoadFromZip(file, accept, data, size); - } - if(utilIsGzipFile(file)) - { - return utilLoadGzipFile(file, accept, data, size); - } -#if 0 - if(utilIsRarFile(file)) - { - return utilLoadRarFile(file, accept, data, size); - } -#endif - - u8 *image = data; - - FILE* f = gen_fopen(file, "rb"); - - if(!f) - { - systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); - return NULL; - } - - gen_fseek(f,0,SEEK_END); - int fileSize = ftell(f); - - gen_fseek(f,0,SEEK_SET); - if(size == 0) - size = fileSize; - - if(image == NULL) - { - image = (u8 *)malloc(utilGetSize(size)); - if(image == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "data"); - gen_fclose(f); - return NULL; - } - size = fileSize; - } - int read = fileSize <= size ? fileSize : size; - int r = gen_fread(image, 1, read, f); - gen_fclose(f); - - if(r != (int)read) - { - systemMessage(MSG_ERROR_READING_IMAGE, - N_("Error reading image %s"), file); - if(data == NULL) - free(image); - return NULL; - } - - size = fileSize; - - return image; -} - -void utilWriteInt(gzFile gzFile, int i) -{ - utilGzWrite(gzFile, &i, sizeof(int)); -} - -int utilReadInt(gzFile gzFile) -{ - int i = 0; - utilGzRead(gzFile, &i, sizeof(int)); - return i; -} - -void utilReadData(gzFile gzFile, variable_desc* data) -{ - while(data->address) - { - utilGzRead(gzFile, data->address, data->size); - data++; - } -} - -void utilWriteData(gzFile gzFile, variable_desc *data) -{ - while(data->address) - { - utilGzWrite(gzFile, data->address, data->size); - data++; - } -} - -gzFile utilGzOpen(const char *file, const char *mode) -{ - utilGzWriteFunc = (int (*)(void *,void * const, unsigned int))gzwrite; - utilGzReadFunc = gzread; - utilGzCloseFunc = gzclose; - - return gzopen(file, mode); -} - -gzFile utilMemGzOpen(char *memory, int available, char *mode) -{ - utilGzWriteFunc = memgzwrite; - utilGzReadFunc = memgzread; - utilGzCloseFunc = memgzclose; - - return memgzopen(memory, available, mode); -} - -int utilGzWrite(gzFile file, const voidp buffer, unsigned int len) -{ - return utilGzWriteFunc(file, buffer, len); -} - -int utilGzRead(gzFile file, voidp buffer, unsigned int len) -{ - return utilGzReadFunc(file, buffer, len); -} - -int utilGzClose(gzFile file) -{ - return utilGzCloseFunc(file); -} - -long utilGzMemTell(gzFile file) -{ - return memtell(file); -} - -void utilGBAFindSave(const u8 *data, const int size) -{ - u32 *p = (u32 *)data; - u32 *end = (u32 *)(data + size); - int saveType = 0; - int flashSize = 0x10000; - bool rtcFound = false; - - while(p < end) - { - u32 d = READ32LE(p); - - if(d == 0x52504545) - { - if(memcmp(p, "EEPROM_", 7) == 0) - { - if(saveType == 0) - saveType = 1; - } - } - else if (d == 0x4D415253) - { - if(memcmp(p, "SRAM_", 5) == 0) - { - if(saveType == 0) - saveType = 2; - } - } - else if (d == 0x53414C46) - { - if(memcmp(p, "FLASH1M_", 8) == 0) - { - if(saveType == 0) - { - saveType = 3; - flashSize = 0x20000; - } - } - else if(memcmp(p, "FLASH", 5) == 0) - { - if(saveType == 0) - { - saveType = 3; - flashSize = 0x10000; - } - } - } - else if (d == 0x52494953) - { - if(memcmp(p, "SIIRTC_V", 8) == 0) - rtcFound = true; - } - p++; - } - // if no matches found, then set it to NONE - if(saveType == 0) - { - saveType = 5; - } - rtcEnable(rtcFound); - cpuSaveType = saveType; - flashSetSize(flashSize); -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004-2006 Forgotten and the VBA development team +// Copyright (C) 2007-2008 VBA-M development team and Shay Green +// 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. + +#include "sdfileio.h" +#include +#include +#include +#include + +#ifndef NO_PNG +extern "C" { +#include +} +#endif + +#include "System.h" +#include "NLS.h" +#include "Util.h" +#include "Flash.h" +#include "agb/GBA.h" +#include "Globals.h" +#include "RTC.h" +#include "Port.h" + +extern "C" { +#include "memgzio.h" +} + +#ifndef _MSC_VER +#define _stricmp strcasecmp +#endif // ! _MSC_VER + +extern int systemColorDepth; +extern int systemRedShift; +extern int systemGreenShift; +extern int systemBlueShift; + +extern u16 systemColorMap16[0x10000]; +//extern u32 systemColorMap32[0x10000]; +extern u32 *systemColorMap32; + +static int (*utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL; +static int (*utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL; +static int (*utilGzCloseFunc)(gzFile) = NULL; +static z_off_t (*utilGzSeekFunc)(gzFile, z_off_t, int) = NULL; + +bool utilWritePNGFile(const char *fileName, int w, int h, u8 *pix) +{ +#ifndef NO_PNG + u8 writeBuffer[512 * 3]; + + FILE *fp = fopen(fileName,"wb"); + + if(!fp) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); + return false; + } + + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, + NULL, + NULL); + if(!png_ptr) { + gen_fclose(fp); + return false; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + + if(!info_ptr) { + png_destroy_write_struct(&png_ptr,NULL); + gen_fclose(fp); + return false; + } + + if(setjmp(png_ptr->jmpbuf)) { + png_destroy_write_struct(&png_ptr,NULL); + gen_fclose(fp); + return false; + } + + png_init_io(png_ptr,fp); + + png_set_IHDR(png_ptr, + info_ptr, + w, + h, + 8, + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + png_write_info(png_ptr,info_ptr); + + u8 *b = writeBuffer; + + int sizeX = w; + int sizeY = h; + + switch(systemColorDepth) { + case 16: + { + u16 *p = (u16 *)(pix+(w+2)*2); // skip first black line + for(int y = 0; y < sizeY; y++) { + for(int x = 0; x < sizeX; x++) { + u16 v = *p++; + + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B + } + p++; // skip black pixel for filters + p++; // skip black pixel for filters + png_write_row(png_ptr,writeBuffer); + + b = writeBuffer; + } + } + break; + case 24: + { + u8 *pixU8 = (u8 *)pix; + for(int y = 0; y < sizeY; y++) { + for(int x = 0; x < sizeX; x++) { + if(systemRedShift < systemBlueShift) { + *b++ = *pixU8++; // R + *b++ = *pixU8++; // G + *b++ = *pixU8++; // B + } else { + int blue = *pixU8++; + int green = *pixU8++; + int red = *pixU8++; + + *b++ = red; + *b++ = green; + *b++ = blue; + } + } + png_write_row(png_ptr,writeBuffer); + + b = writeBuffer; + } + } + break; + case 32: + { + u32 *pixU32 = (u32 *)(pix+4*(w+1)); + for(int y = 0; y < sizeY; y++) { + for(int x = 0; x < sizeX; x++) { + u32 v = *pixU32++; + + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B + } + pixU32++; + + png_write_row(png_ptr,writeBuffer); + + b = writeBuffer; + } + } + break; + } + + png_write_end(png_ptr, info_ptr); + + png_destroy_write_struct(&png_ptr, &info_ptr); + + gen_fclose(fp); + + return true; +#else + return false; +#endif +} + +void utilPutDword(u8 *p, u32 value) +{ + *p++ = value & 255; + *p++ = (value >> 8) & 255; + *p++ = (value >> 16) & 255; + *p = (value >> 24) & 255; +} + +void utilPutWord(u8 *p, u16 value) +{ + *p++ = value & 255; + *p = (value >> 8) & 255; +} + +bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix) +{ + u8 writeBuffer[512 * 3]; + + FILE *fp = gen_fopen(fileName,"wb"); + + if(!fp) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); + return false; + } + + struct { + u8 ident[2]; + u8 filesize[4]; + u8 reserved[4]; + u8 dataoffset[4]; + u8 headersize[4]; + u8 width[4]; + u8 height[4]; + u8 planes[2]; + u8 bitsperpixel[2]; + u8 compression[4]; + u8 datasize[4]; + u8 hres[4]; + u8 vres[4]; + u8 colors[4]; + u8 importantcolors[4]; + // u8 pad[2]; + } bmpheader; + memset(&bmpheader, 0, sizeof(bmpheader)); + + bmpheader.ident[0] = 'B'; + bmpheader.ident[1] = 'M'; + + u32 fsz = sizeof(bmpheader) + w*h*3; + utilPutDword(bmpheader.filesize, fsz); + utilPutDword(bmpheader.dataoffset, 0x36); + utilPutDword(bmpheader.headersize, 0x28); + utilPutDword(bmpheader.width, w); + utilPutDword(bmpheader.height, h); + utilPutDword(bmpheader.planes, 1); + utilPutDword(bmpheader.bitsperpixel, 24); + utilPutDword(bmpheader.datasize, 3*w*h); + + gen_fwrite(&bmpheader, 1, sizeof(bmpheader), fp); + + u8 *b = writeBuffer; + + int sizeX = w; + int sizeY = h; + + switch(systemColorDepth) { + case 16: + { + u16 *p = (u16 *)(pix+(w+2)*(h)*2); // skip first black line + for(int y = 0; y < sizeY; y++) { + for(int x = 0; x < sizeX; x++) { + u16 v = *p++; + + *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + } + p++; // skip black pixel for filters + p++; // skip black pixel for filters + p -= 2*(w+2); + gen_fwrite(writeBuffer, 1, 3*w, fp); + + b = writeBuffer; + } + } + break; + case 24: + { + u8 *pixU8 = (u8 *)pix+3*w*(h-1); + for(int y = 0; y < sizeY; y++) { + for(int x = 0; x < sizeX; x++) { + if(systemRedShift > systemBlueShift) { + *b++ = *pixU8++; // B + *b++ = *pixU8++; // G + *b++ = *pixU8++; // R + } else { + int red = *pixU8++; + int green = *pixU8++; + int blue = *pixU8++; + + *b++ = blue; + *b++ = green; + *b++ = red; + } + } + pixU8 -= 2*3*w; + gen_fwrite(writeBuffer, 1, 3*w, fp); + + b = writeBuffer; + } + } + break; + case 32: + { + u32 *pixU32 = (u32 *)(pix+4*(w+1)*(h)); + for(int y = 0; y < sizeY; y++) { + for(int x = 0; x < sizeX; x++) { + u32 v = *pixU32++; + + *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + } + pixU32++; + pixU32 -= 2*(w+1); + + gen_fwrite(writeBuffer, 1, 3*w, fp); + + b = writeBuffer; + } + } + break; + } + + gen_fclose(fp); + + return true; +} + +static int utilReadInt2(FILE *f) +{ + int res = 0; + int c = gen_fgetc(f); + if(c == EOF) + return -1; + res = c; + c = gen_fgetc(f); + if(c == EOF) + return -1; + return c + (res<<8); +} + +static int utilReadInt3(FILE *f) +{ + int res = 0; + int c = gen_fgetc(f); + if(c == EOF) + return -1; + res = c; + c = gen_fgetc(f); + if(c == EOF) + return -1; + res = c + (res<<8); + c = gen_fgetc(f); + if(c == EOF) + return -1; + return c + (res<<8); +} + +void utilApplyIPS(const char *ips, u8 **r, int *s) +{ + // from the IPS spec at http://zerosoft.zophar.net/ips.htm + FILE *f = gen_fopen(ips, "rb"); + if(!f) + return; + u8 *rom = *r; + int size = *s; + if(gen_fgetc(f) == 'P' && + gen_fgetc(f) == 'A' && + gen_fgetc(f) == 'T' && + gen_fgetc(f) == 'C' && + gen_fgetc(f) == 'H') { + int b; + int offset; + int len; + for(;;) { + // read offset + offset = utilReadInt3(f); + // if offset == EOF, end of patch + if(offset == 0x454f46) + break; + // read length + len = utilReadInt2(f); + if(!len) { + // len == 0, RLE block + len = utilReadInt2(f); + // byte to fill + int c = gen_fgetc(f); + if(c == -1) + break; + b = (u8)c; + } else + b= -1; + // check if we need to reallocate our ROM + if((offset + len) >= size) { + size *= 2; + rom = (u8 *)realloc(rom, size); + *r = rom; + *s = size; + } + if(b == -1) { + // normal block, just read the data + if(gen_fread(&rom[offset], 1, len, f) != (int)len) + break; + } else { + // fill the region with the given byte + while(len--) { + rom[offset++] = b; + } + } + } + } + // close the file + gen_fclose(f); +} + +//TODO: Modify ZSNES code for this +void utilApplyUPS(const char *ips, u8 **r, int *s) +{ +} + +extern bool cpuIsMultiBoot; + +bool utilIsGBAImage(const char * file) +{ + cpuIsMultiBoot = false; + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if((_stricmp(p, ".agb") == 0) || + (_stricmp(p, ".gba") == 0) || + (_stricmp(p, ".bin") == 0) || + (_stricmp(p, ".elf") == 0)) + return true; + if(_stricmp(p, ".mb") == 0) { + cpuIsMultiBoot = true; + return true; + } + } + } + + return false; +} + +bool utilIsGBImage(const char * file) +{ + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if((_stricmp(p, ".dmg") == 0) || + (_stricmp(p, ".gb") == 0) || + (_stricmp(p, ".gbc") == 0) || + (_stricmp(p, ".cgb") == 0) || + (_stricmp(p, ".sgb") == 0)) + return true; + } + } + + return false; +} + +bool utilIsZipFile(const char *file) +{ + if(strlen(file) > 4) + { + char * p = strrchr(file,'.'); + + if(p != NULL) + { + if(_stricmp(p, ".zip") == 0) + return true; + } + } + + return false; +} +bool utilIsGzipFile(const char *file) +{ + if(strlen(file) > 3) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".gz") == 0) + return true; + if(_stricmp(p, ".z") == 0) + return true; + } + } + + return false; +} + +// strip .gz or .z off end +void utilStripDoubleExtension(const char *file, char *buffer) +{ + if(buffer != file) // allows conversion in place + strcpy(buffer, file); + + if(utilIsGzipFile(file)) { + char *p = strrchr(buffer, '.'); + + if(p) + *p = 0; + } +} + +static bool utilIsImage(const char *file) +{ + return utilIsGBAImage(file) || utilIsGBImage(file); +} + + +IMAGE_TYPE utilFindType(const char *file) +{ + char buffer[2048]; + + if(utilIsZipFile(file)) + { + unzFile unz = unzOpen(file); + + if(unz == NULL) + { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file); + return IMAGE_UNKNOWN; + } + + int r = unzGoToFirstFile(unz); + + if(r != UNZ_OK) + + { + unzClose(unz); + systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); + return IMAGE_UNKNOWN; + + } + + IMAGE_TYPE found = IMAGE_UNKNOWN; + + unz_file_info info; + + while(true) + + { + r = unzGetCurrentFileInfo(unz, + &info, + buffer, + sizeof(buffer), + NULL, + 0, + NULL, + 0); + + if(r != UNZ_OK) + + + { + unzClose(unz); + systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); + + + return IMAGE_UNKNOWN; + } + + if(utilIsGBAImage(buffer)) + { + found = IMAGE_GBA; + break; + } + + if(utilIsGBImage(buffer)) + { + found = IMAGE_GB; + break; + } + + r = unzGoToNextFile(unz); + + if(r != UNZ_OK) + break; + } + unzClose(unz); + + if(found == IMAGE_UNKNOWN) + { + systemMessage(MSG_NO_IMAGE_ON_ZIP, + N_("No image found on ZIP file %s"), file); + return found; + } + return found; + } + else + { + if(utilIsGzipFile(file)) + utilStripDoubleExtension(file, buffer); + else + strcpy(buffer, file); + + if(utilIsGBAImage(buffer)) + return IMAGE_GBA; + if(utilIsGBImage(buffer)) + return IMAGE_GB; + } + return IMAGE_UNKNOWN; +} + +static int utilGetSize(int size) +{ + int res = 1; + while(res < size) + res <<= 1; + return res; +} + +static u8 *utilLoadFromZip(const char *file, + + bool (*accept)(const char *), + u8 *data, + int &size) +{ + + char buffer[2048]; + + unzFile unz = unzOpen(file); + + if(unz == NULL) + { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file); + return NULL; + } + int r = unzGoToFirstFile(unz); + + if(r != UNZ_OK) + { + unzClose(unz); + systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); + return NULL; + } + + bool found = false; + + unz_file_info info; + + while(true) + { + r = unzGetCurrentFileInfo(unz, + &info, + buffer, + sizeof(buffer), + NULL, + 0, + NULL, + 0); + + if(r != UNZ_OK) + { + unzClose(unz); + systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); + return NULL; + } + + if(accept(buffer)) + { + found = true; + break; + } + + r = unzGoToNextFile(unz); + + if(r != UNZ_OK) + break; + } + + if(!found) + { + unzClose(unz); + systemMessage(MSG_NO_IMAGE_ON_ZIP, + N_("No image found on ZIP file %s"), file); + return NULL; + } + + int fileSize = info.uncompressed_size; + if(size == 0) + size = fileSize; + r = unzOpenCurrentFile(unz); + + if(r != UNZ_OK) + { + unzClose(unz); + systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), buffer); + return NULL; + } + + u8 *image = data; + + if(image == NULL) + { + image = (u8 *)malloc(utilGetSize(size)); + if(image == NULL) + { + unzCloseCurrentFile(unz); + unzClose(unz); + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "data"); + return NULL; + } + size = fileSize; + } + int read = fileSize <= size ? fileSize : size; + r = unzReadCurrentFile(unz, + image, + read); + + unzCloseCurrentFile(unz); + unzClose(unz); + + if(r != (int)read) + { + systemMessage(MSG_ERROR_READING_IMAGE, + N_("Error reading image %s"), buffer); + if(data == NULL) + free(image); + return NULL; + } + + size = fileSize; + + return image; +} + +static u8 *utilLoadGzipFile(const char *file, + bool (*accept)(const char *), + u8 *data, + int &size) +{ + FILE* f = gen_fopen(file, "rb"); + + if(f == NULL) + { + systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); + + + return NULL; + } + + gen_fseek(f, -4, SEEK_END); + int fileSize = gen_fgetc(f) | (gen_fgetc(f) << 8) | (gen_fgetc(f) << 16) | (gen_fgetc(f) << 24); + gen_fclose(f); + + + if(size == 0) + size = fileSize; + + gzFile gz = gzopen(file, "rb"); + + if(gz == NULL) + { + // should not happen, but who knows? + systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); + return NULL; + } + + u8 *image = data; + + if(image == NULL) + { + image = (u8 *)malloc(utilGetSize(size)); + if(image == NULL) + { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "data"); + gen_fclose(f); + return NULL; + } + size = fileSize; + } + int read = fileSize <= size ? fileSize : size; + int r = gzread(gz, image, read); + gzclose(gz); + + if(r != (int)read) + { + systemMessage(MSG_ERROR_READING_IMAGE, + N_("Error reading image %s"), file); + if(data == NULL) + free(image); + return NULL; + } + + size = fileSize; + + return image; +} + +u8 *utilLoad(const char *file, + bool (*accept)(const char *), + u8 *data, + int &size) +{ + if(utilIsZipFile(file)) + { + return utilLoadFromZip(file, accept, data, size); + } + if(utilIsGzipFile(file)) + { + return utilLoadGzipFile(file, accept, data, size); + } + + u8 *image = data; + + FILE* f = gen_fopen(file, "rb"); + + if(!f) + { + systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); + return NULL; + } + + gen_fseek(f,0,SEEK_END); + int fileSize = ftell(f); + + gen_fseek(f,0,SEEK_SET); + if(size == 0) + size = fileSize; + + if(image == NULL) + { + + + image = (u8 *)malloc(utilGetSize(size)); + if(image == NULL) + { + + + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "data"); + gen_fclose(f); + return NULL; + } + size = fileSize; + } + int read = fileSize <= size ? fileSize : size; + int r = gen_fread(image, 1, read, f); + gen_fclose(f); + + if(r != (int)read) + { + + + + + + systemMessage(MSG_ERROR_READING_IMAGE, + N_("Error reading image %s"), file); + if(data == NULL) + free(image); + return NULL; + } + + size = fileSize; + + return image; +} + +void utilWriteInt(gzFile gzFile, int i) +{ + utilGzWrite(gzFile, &i, sizeof(int)); +} + +int utilReadInt(gzFile gzFile) +{ + int i = 0; + utilGzRead(gzFile, &i, sizeof(int)); + return i; +} + +void utilReadData(gzFile gzFile, variable_desc* data) +{ + while(data->address) { + utilGzRead(gzFile, data->address, data->size); + data++; + } +} + +void utilReadDataSkip(gzFile gzFile, variable_desc* data) +{ + while(data->address) { + utilGzSeek(gzFile, data->size, SEEK_CUR); + data++; + } +} + +void utilWriteData(gzFile gzFile, variable_desc *data) +{ + while(data->address) { + utilGzWrite(gzFile, data->address, data->size); + data++; + } +} + +gzFile utilGzOpen(const char *file, const char *mode) +{ + utilGzWriteFunc = (int (*)(void *,void * const, unsigned int))gzwrite; + utilGzReadFunc = gzread; + utilGzCloseFunc = gzclose; + utilGzSeekFunc = gzseek; + + return gzopen(file, mode); +} + +gzFile utilMemGzOpen(char *memory, int available, const char *mode) +{ + utilGzWriteFunc = memgzwrite; + utilGzReadFunc = memgzread; + utilGzCloseFunc = memgzclose; + + return memgzopen(memory, available, mode); +} + +int utilGzWrite(gzFile file, const voidp buffer, unsigned int len) +{ + return utilGzWriteFunc(file, buffer, len); +} + +int utilGzRead(gzFile file, voidp buffer, unsigned int len) +{ + return utilGzReadFunc(file, buffer, len); +} + +int utilGzClose(gzFile file) +{ + return utilGzCloseFunc(file); +} + +z_off_t utilGzSeek(gzFile file, z_off_t offset, int whence) +{ + return utilGzSeekFunc(file, offset, whence); +} + +long utilGzMemTell(gzFile file) +{ + return memtell(file); +} + +void utilGBAFindSave(const u8 *data, const int size) +{ + u32 *p = (u32 *)data; + u32 *end = (u32 *)(data + size); + int saveType = 0; + int flashSize = 0x10000; + bool rtcFound = false; + + while(p < end) { + u32 d = READ32LE(p); + + if(d == 0x52504545) { + if(memcmp(p, "EEPROM_", 7) == 0) { + if(saveType == 0) + saveType = 3; + } + } else if (d == 0x4D415253) { + if(memcmp(p, "SRAM_", 5) == 0) { + if(saveType == 0) + saveType = 1; + } + } else if (d == 0x53414C46) { + if(memcmp(p, "FLASH1M_", 8) == 0) { + if(saveType == 0) { + saveType = 2; + flashSize = 0x20000; + } + } else if(memcmp(p, "FLASH", 5) == 0) { + if(saveType == 0) { + saveType = 2; + flashSize = 0x10000; + } + } + } else if (d == 0x52494953) { + if(memcmp(p, "SIIRTC_V", 8) == 0) + rtcFound = true; + } + p++; + } + // if no matches found, then set it to NONE + if(saveType == 0) { + saveType = 5; + } + rtcEnable(rtcFound); + cpuSaveType = saveType; + flashSetSize(flashSize); +} + +void utilUpdateSystemColorMaps() +{ + switch(systemColorDepth) { + case 16: + { + for(int i = 0; i < 0x10000; i++) { + systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | + (((i & 0x3e0) >> 5) << systemGreenShift) | + (((i & 0x7c00) >> 10) << systemBlueShift); + } + } + break; + case 24: + case 32: + { + for(int i = 0; i < 0x10000; i++) { + systemColorMap32[i] = ((i & 0x1f) << systemRedShift) | + (((i & 0x3e0) >> 5) << systemGreenShift) | + (((i & 0x7c00) >> 10) << systemBlueShift); + } + } + break; + } +} diff --git a/source/vba/Util.h b/source/vba/Util.h index 66a0807..6e51802 100644 --- a/source/vba/Util.h +++ b/source/vba/Util.h @@ -19,6 +19,9 @@ #ifndef VBA_UTIL_H #define VBA_UTIL_H + +#include "System.h" + enum IMAGE_TYPE { IMAGE_UNKNOWN = -1, IMAGE_GBA = 0, @@ -27,40 +30,38 @@ enum IMAGE_TYPE { // save game -typedef struct - { - void *address; - int size; - } -variable_desc; +typedef struct { + void *address; + int size; +} variable_desc; extern bool utilWritePNGFile(const char *, int, int, u8 *); extern bool utilWriteBMPFile(const char *, int, int, u8 *); extern void utilApplyIPS(const char *ips, u8 **rom, int *size); -extern void utilWriteBMP(char *, int, int, u8 *); extern bool utilIsGBAImage(const char *); extern bool utilIsGBImage(const char *); -extern bool utilIsZipFile(const char *); extern bool utilIsGzipFile(const char *); -extern bool utilIsRarFile(const char *); -extern void utilGetBaseName(const char *, char *); +extern void utilStripDoubleExtension(const char *, char *); extern IMAGE_TYPE utilFindType(const char *); extern u8 *utilLoad(const char *, - bool (*)(const char*), - u8 *, - int &); + bool (*)(const char*), + u8 *, + int &); extern void utilPutDword(u8 *, u32); extern void utilPutWord(u8 *, u16); extern void utilWriteData(gzFile, variable_desc *); extern void utilReadData(gzFile, variable_desc *); +extern void utilReadDataSkip(gzFile, variable_desc *); extern int utilReadInt(gzFile); extern void utilWriteInt(gzFile, int); extern gzFile utilGzOpen(const char *file, const char *mode); -extern gzFile utilMemGzOpen(char *memory, int available, char *mode); +extern gzFile utilMemGzOpen(char *memory, int available, const char *mode); extern int utilGzWrite(gzFile file, const voidp buffer, unsigned int len); extern int utilGzRead(gzFile file, voidp buffer, unsigned int len); extern int utilGzClose(gzFile file); +extern z_off_t utilGzSeek(gzFile file, z_off_t offset, int whence); extern long utilGzMemTell(gzFile file); extern void utilGBAFindSave(const u8 *, const int); +extern void utilUpdateSystemColorMaps(); #endif diff --git a/source/vba/admame.cpp b/source/vba/admame.cpp index afb8202..5dd717b 100644 --- a/source/vba/admame.cpp +++ b/source/vba/admame.cpp @@ -1,1033 +1,1010 @@ -/* - * This file is part of the Advance project. - * - * Copyright (C) 1999-2002 Andrea Mazzoleni - * - * 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * In addition, as a special exception, Andrea Mazzoleni - * gives permission to link the code of this program with - * the MAME library (or with modified versions of MAME that use the - * same license as MAME), and distribute linked combinations including - * the two. You must obey the GNU General Public License in all - * respects for all of the code used other than MAME. If you modify - * this file, you may extend this exception to your version of the - * file, but you are not obligated to do so. If you do not wish to - * do so, delete this exception statement from your version. - */ - -/* - * Alternatively at the previous license terms, you are allowed to use this - * code in your program with these conditions: - * - the program is not used in commercial activities. - * - the whole source code of the program is released with the binary. - */ - -#include "System.h" - -#ifdef MMX -extern "C" bool cpu_mmx; -#endif - -static void internal_scale2x_16_def(u16 *dst, const u16* src0, const u16* src1, const u16* src2, unsigned count) -{ - /* first pixel */ - dst[0] = src1[0]; - if (src1[1] == src0[0] && src2[0] != src0[0]) - dst[1] = src0[0]; - else - dst[1] = src1[0]; - ++src0; - ++src1; - ++src2; - dst += 2; - - /* central pixels */ - count -= 2; - while (count) - { - if (src0[0] != src2[0] && src1[-1] != src1[1]) - { - dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; - dst[1] = src1[1] == src0[0] ? src0[0] : src1[0]; - } - else - { - dst[0] = src1[0]; - dst[1] = src1[0]; - } - - ++src0; - ++src1; - ++src2; - dst += 2; - --count; - } - - /* last pixel */ - if (src1[-1] == src0[0] && src2[0] != src0[0]) - dst[0] = src0[0]; - else - dst[0] = src1[0]; - dst[1] = src1[0]; -} - -static void internal_scale2x_32_def(u32* dst, - const u32* src0, - const u32* src1, - const u32* src2, - unsigned count) -{ - /* first pixel */ - dst[0] = src1[0]; - if (src1[1] == src0[0] && src2[0] != src0[0]) - dst[1] = src0[0]; - else - dst[1] = src1[0]; - ++src0; - ++src1; - ++src2; - dst += 2; - - /* central pixels */ - count -= 2; - while (count) - { - if (src0[0] != src2[0] && src1[-1] != src1[1]) - { - dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; - dst[1] = src1[1] == src0[0] ? src0[0] : src1[0]; - } - else - { - dst[0] = src1[0]; - dst[1] = src1[0]; - } - - ++src0; - ++src1; - ++src2; - dst += 2; - --count; - } - - /* last pixel */ - if (src1[-1] == src0[0] && src2[0] != src0[0]) - dst[0] = src0[0]; - else - dst[0] = src1[0]; - dst[1] = src1[0]; -} - -#ifdef MMX -static void internal_scale2x_16_mmx_single(u16* dst, const u16* src0, const u16* src1, const u16* src2, unsigned count) -{ - /* always do the first and last run */ - count -= 2*4; - -#ifdef __GNUC__ - __asm__ __volatile__( - /* first run */ - /* set the current, current_pre, current_next registers */ - "movq 0(%1), %%mm0\n" - "movq 0(%1),%%mm7\n" - "movq 8(%1),%%mm1\n" - "psllq $48,%%mm0\n" - "psllq $48,%%mm1\n" - "psrlq $48, %%mm0\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $16,%%mm2\n" - "psrlq $16,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqw %%mm6,%%mm2\n" - "pcmpeqw %%mm6,%%mm4\n" - "pcmpeqw (%2),%%mm3\n" - "pcmpeqw (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqw %%mm1,%%mm2\n" - "pcmpeqw %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpcklwd %%mm4,%%mm2\n" - "punpckhwd %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - - /* next */ - "addl $8,%0\n" - "addl $8,%1\n" - "addl $8,%2\n" - "addl $16,%3\n" - - /* central runs */ - "shrl $2,%4\n" - "jz 1f\n" - - "0:\n" - - /* set the current, current_pre, current_next registers */ - "movq -8(%1),%%mm0\n" - "movq (%1),%%mm7\n" - "movq 8(%1),%%mm1\n" - "psrlq $48,%%mm0\n" - "psllq $48,%%mm1\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $16,%%mm2\n" - "psrlq $16,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqw %%mm6,%%mm2\n" - "pcmpeqw %%mm6,%%mm4\n" - "pcmpeqw (%2),%%mm3\n" - "pcmpeqw (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqw %%mm1,%%mm2\n" - "pcmpeqw %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpcklwd %%mm4,%%mm2\n" - "punpckhwd %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - - /* next */ - "addl $8,%0\n" - "addl $8,%1\n" - "addl $8,%2\n" - "addl $16,%3\n" - - "decl %4\n" - "jnz 0b\n" - "1:\n" - - /* final run */ - /* set the current, current_pre, current_next registers */ - "movq (%1),%%mm1\n" - "movq (%1),%%mm7\n" - "movq -8(%1),%%mm0\n" - "psrlq $48,%%mm1\n" - "psrlq $48,%%mm0\n" - "psllq $48,%%mm1\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $16,%%mm2\n" - "psrlq $16,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqw %%mm6,%%mm2\n" - "pcmpeqw %%mm6,%%mm4\n" - "pcmpeqw (%2),%%mm3\n" - "pcmpeqw (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqw %%mm1,%%mm2\n" - "pcmpeqw %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpcklwd %%mm4,%%mm2\n" - "punpckhwd %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - "emms\n" - - : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) - : - : "cc" - ); -#else - __asm { - mov eax, src0; - mov ebx, src1; - mov ecx, src2; - mov edx, dst; - mov esi, count; - - /* first run */ - /* set the current, current_pre, current_next registers */ - movq mm0, qword ptr [ebx]; - movq mm7, qword ptr [ebx]; - movq mm1, qword ptr [ebx + 8]; - psllq mm0, 48; - psllq mm1, 48; - psrlq mm0, 48; - movq mm2, mm7; - movq mm3, mm7; - psllq mm2, 16; - psrlq mm3, 16; - por mm0, mm2; - por mm1, mm3; - - /* current_upper */ - movq mm6, qword ptr [eax]; - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - movq mm2, mm0; - movq mm4, mm1; - movq mm3, mm0; - movq mm5, mm1; - pcmpeqw mm2, mm6; - pcmpeqw mm4, mm6; - pcmpeqw mm3, qword ptr [ecx]; - pcmpeqw mm5, qword ptr [ecx]; - pandn mm3,mm2; - pandn mm5,mm4; - movq mm2,mm0; - movq mm4,mm1; - pcmpeqw mm2,mm1; - pcmpeqw mm4,mm0; - pandn mm2,mm3; - pandn mm4,mm5; - movq mm3,mm2; - movq mm5,mm4; - pand mm2,mm6; - pand mm4,mm6; - pandn mm3,mm7; - pandn mm5,mm7; - por mm2,mm3; - por mm4,mm5; - - /* set *dst0 */ - movq mm3,mm2; - punpcklwd mm2,mm4; - punpckhwd mm3,mm4; - movq qword ptr [edx], mm2; - movq qword ptr [edx + 8], mm3; - - /* next */ - add eax, 8; - add ebx, 8; - add ecx, 8; - add edx, 16; - - /* central runs */ - shr esi, 2; - jz label1; - align 4; - label0: - - /* set the current, current_pre, current_next registers */ - movq mm0, qword ptr [ebx-8]; - movq mm7, qword ptr [ebx]; - movq mm1, qword ptr [ebx+8]; - psrlq mm0,48; - psllq mm1,48; - movq mm2,mm7; - movq mm3,mm7; - psllq mm2,16; - psrlq mm3,16; - por mm0,mm2; - por mm1,mm3; - - /* current_upper */ - movq mm6, qword ptr [eax]; - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - movq mm2,mm0; - movq mm4,mm1; - movq mm3,mm0; - movq mm5,mm1; - pcmpeqw mm2,mm6; - pcmpeqw mm4,mm6; - pcmpeqw mm3, qword ptr [ecx]; - pcmpeqw mm5, qword ptr [ecx]; - pandn mm3,mm2; - pandn mm5,mm4; - movq mm2,mm0; - movq mm4,mm1; - pcmpeqw mm2,mm1; - pcmpeqw mm4,mm0; - pandn mm2,mm3; - pandn mm4,mm5; - movq mm3,mm2; - movq mm5,mm4; - pand mm2,mm6; - pand mm4,mm6; - pandn mm3,mm7; - pandn mm5,mm7; - por mm2,mm3; - por mm4,mm5; - - /* set *dst */ - movq mm3,mm2; - punpcklwd mm2,mm4; - punpckhwd mm3,mm4; - movq qword ptr [edx], mm2; - movq qword ptr [edx+8], mm3; - - /* next */ - add eax,8; - add ebx,8; - add ecx,8; - add edx,16; - - dec esi; - jnz label0; - label1: - - /* final run */ - /* set the current, current_pre, current_next registers */ - movq mm1, qword ptr [ebx]; - movq mm7, qword ptr [ebx]; - movq mm0, qword ptr [ebx-8]; - psrlq mm1,48; - psrlq mm0,48; - psllq mm1,48; - movq mm2,mm7; - movq mm3,mm7; - psllq mm2,16; - psrlq mm3,16; - por mm0,mm2; - por mm1,mm3; - - /* current_upper */ - movq mm6, qword ptr [eax]; - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - movq mm2,mm0; - movq mm4,mm1; - movq mm3,mm0; - movq mm5,mm1; - pcmpeqw mm2,mm6; - pcmpeqw mm4,mm6; - pcmpeqw mm3, qword ptr [ecx]; - pcmpeqw mm5, qword ptr [ecx]; - pandn mm3,mm2; - pandn mm5,mm4; - movq mm2,mm0; - movq mm4,mm1; - pcmpeqw mm2,mm1; - pcmpeqw mm4,mm0; - pandn mm2,mm3; - pandn mm4,mm5; - movq mm3,mm2; - movq mm5,mm4; - pand mm2,mm6; - pand mm4,mm6; - pandn mm3,mm7; - pandn mm5,mm7; - por mm2,mm3; - por mm4,mm5; - - /* set *dst */ - movq mm3,mm2; - punpcklwd mm2,mm4; - punpckhwd mm3,mm4; - movq qword ptr [edx], mm2; - movq qword ptr [edx+8], mm3; - - mov src0, eax; - mov src1, ebx; - mov src2, ecx; - mov dst, edx; - mov count, esi; - - emms; - } -#endif -} - -static void internal_scale2x_32_mmx_single(u32* dst, const u32* src0, const u32* src1, const u32* src2, unsigned count) -{ - /* always do the first and last run */ - count -= 2*2; - -#ifdef __GNUC__ - __asm__ __volatile__( - /* first run */ - /* set the current, current_pre, current_next registers */ - "movq 0(%1),%%mm0\n" - "movq 0(%1),%%mm7\n" - "movq 8(%1),%%mm1\n" - "psllq $32,%%mm0\n" - "psllq $32,%%mm1\n" - "psrlq $32,%%mm0\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $32,%%mm2\n" - "psrlq $32,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqd %%mm6,%%mm2\n" - "pcmpeqd %%mm6,%%mm4\n" - "pcmpeqd (%2),%%mm3\n" - "pcmpeqd (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqd %%mm1,%%mm2\n" - "pcmpeqd %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpckldq %%mm4,%%mm2\n" - "punpckhdq %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3, 8(%3)\n" - - /* next */ - "addl $8,%0\n" - "addl $8,%1\n" - "addl $8,%2\n" - "addl $16,%3\n" - - /* central runs */ - "shrl $1,%4\n" - "jz 1f\n" - - "0:\n" - - /* set the current, current_pre, current_next registers */ - "movq -8(%1),%%mm0\n" - "movq (%1),%%mm7\n" - "movq 8(%1),%%mm1\n" - "psrlq $32,%%mm0\n" - "psllq $32,%%mm1\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $32,%%mm2\n" - "psrlq $32,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqd %%mm6,%%mm2\n" - "pcmpeqd %%mm6,%%mm4\n" - "pcmpeqd (%2),%%mm3\n" - "pcmpeqd (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqd %%mm1,%%mm2\n" - "pcmpeqd %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpckldq %%mm4,%%mm2\n" - "punpckhdq %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - - /* next */ - "addl $8,%0\n" - "addl $8,%1\n" - "addl $8,%2\n" - "addl $16,%3\n" - - "decl %4\n" - "jnz 0b\n" - "1:\n" - - /* final run */ - /* set the current, current_pre, current_next registers */ - "movq (%1),%%mm1\n" - "movq (%1),%%mm7\n" - "movq -8(%1), %%mm0\n" - "psrlq $32,%%mm1\n" - "psrlq $32,%%mm0\n" - "psllq $32,%%mm1\n" - "movq %%mm7,%%mm2\n" - "movq %%mm7,%%mm3\n" - "psllq $32,%%mm2\n" - "psrlq $32,%%mm3\n" - "por %%mm2,%%mm0\n" - "por %%mm3,%%mm1\n" - - /* current_upper */ - "movq (%0),%%mm6\n" - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "movq %%mm0,%%mm3\n" - "movq %%mm1,%%mm5\n" - "pcmpeqd %%mm6,%%mm2\n" - "pcmpeqd %%mm6,%%mm4\n" - "pcmpeqd (%2),%%mm3\n" - "pcmpeqd (%2),%%mm5\n" - "pandn %%mm2,%%mm3\n" - "pandn %%mm4,%%mm5\n" - "movq %%mm0,%%mm2\n" - "movq %%mm1,%%mm4\n" - "pcmpeqd %%mm1,%%mm2\n" - "pcmpeqd %%mm0,%%mm4\n" - "pandn %%mm3,%%mm2\n" - "pandn %%mm5,%%mm4\n" - "movq %%mm2,%%mm3\n" - "movq %%mm4,%%mm5\n" - "pand %%mm6,%%mm2\n" - "pand %%mm6,%%mm4\n" - "pandn %%mm7,%%mm3\n" - "pandn %%mm7,%%mm5\n" - "por %%mm3,%%mm2\n" - "por %%mm5,%%mm4\n" - - /* set *dst */ - "movq %%mm2,%%mm3\n" - "punpckldq %%mm4,%%mm2\n" - "punpckhdq %%mm4,%%mm3\n" - "movq %%mm2,(%3)\n" - "movq %%mm3,8(%3)\n" - "emms\n" - - : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) - : - : "cc" - ); -#else - __asm { - mov eax, src0; - mov ebx, src1; - mov ecx, src2; - mov edx, dst; - mov esi, count; - - /* first run */ - /* set the current, current_pre, current_next registers */ - movq mm0,qword ptr [ebx]; - movq mm7,qword ptr [ebx]; - movq mm1,qword ptr [ebx + 8]; - psllq mm0,32; - psllq mm1,32; - psrlq mm0,32; - movq mm2,mm7; - movq mm3,mm7; - psllq mm2,32; - psrlq mm3,32; - por mm0,mm2; - por mm1,mm3; - - /* current_upper */ - movq mm6,qword ptr [eax]; - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - movq mm2,mm0; - movq mm4,mm1; - movq mm3,mm0; - movq mm5,mm1; - pcmpeqd mm2,mm6; - pcmpeqd mm4,mm6; - pcmpeqd mm3,qword ptr [ecx]; - pcmpeqd mm5,qword ptr [ecx]; - pandn mm3,mm2; - pandn mm5,mm4; - movq mm2,mm0; - movq mm4,mm1; - pcmpeqd mm2,mm1; - pcmpeqd mm4,mm0; - pandn mm2,mm3; - pandn mm4,mm5; - movq mm3,mm2; - movq mm5,mm4; - pand mm2,mm6; - pand mm4,mm6; - pandn mm3,mm7; - pandn mm5,mm7; - por mm2,mm3; - por mm4,mm5; - - /* set *dst */ - movq mm3,mm2; - punpckldq mm2,mm4; - punpckhdq mm3,mm4; - movq qword ptr [edx],mm2; - movq qword ptr [edx+8],mm3; - - /* next */ - add eax,8; - add ebx,8; - add ecx,8; - add edx,16; - - /* central runs */ - shr esi,1; - jz label1; - label0: - - /* set the current, current_pre, current_next registers */ - movq mm0,qword ptr [ebx-8]; - movq mm7,qword ptr [ebx]; - movq mm1,qword ptr [ebx+8]; - psrlq mm0,32; - psllq mm1,32; - movq mm2,mm7; - movq mm3,mm7; - psllq mm2,32; - psrlq mm3,32; - por mm0,mm2; - por mm1,mm3; - - /* current_upper */ - movq mm6,qword ptr[eax]; - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - movq mm2,mm0; - movq mm4,mm1; - movq mm3,mm0; - movq mm5,mm1; - pcmpeqd mm2,mm6; - pcmpeqd mm4,mm6; - pcmpeqd mm3,qword ptr[ecx]; - pcmpeqd mm5,qword ptr[ecx]; - pandn mm3,mm2; - pandn mm5,mm4; - movq mm2,mm0; - movq mm4,mm1; - pcmpeqd mm2,mm1; - pcmpeqd mm4,mm0; - pandn mm2,mm3; - pandn mm4,mm5; - movq mm3,mm2; - movq mm5,mm4; - pand mm2,mm6; - pand mm4,mm6; - pandn mm3,mm7; - pandn mm5,mm7; - por mm2,mm3; - por mm4,mm5; - - /* set *dst */ - movq mm3,mm2; - punpckldq mm2,mm4; - punpckhdq mm3,mm4; - movq qword ptr [edx],mm2; - movq qword ptr [edx+8],mm3; - - /* next */ - add eax,8; - add ebx,8; - add ecx,8; - add edx,16; - - dec esi; - jnz label0; - label1: - - /* final run */ - /* set the current, current_pre, current_next registers */ - movq mm1,qword ptr [ebx]; - movq mm7,qword ptr [ebx]; - movq mm0,qword ptr [ebx-8]; - psrlq mm1,32; - psrlq mm0,32; - psllq mm1,32; - movq mm2,mm7; - movq mm3,mm7; - psllq mm2,32; - psrlq mm3,32; - por mm0,mm2; - por mm1,mm3; - - /* current_upper */ - movq mm6,qword ptr [eax]; - - /* compute the upper-left pixel for dst on %%mm2 */ - /* compute the upper-right pixel for dst on %%mm4 */ - movq mm2,mm0; - movq mm4,mm1; - movq mm3,mm0; - movq mm5,mm1; - pcmpeqd mm2,mm6; - pcmpeqd mm4,mm6; - pcmpeqd mm3,qword ptr [ecx]; - pcmpeqd mm5,qword ptr [ecx]; - pandn mm3,mm2; - pandn mm5,mm4; - movq mm2,mm0; - movq mm4,mm1; - pcmpeqd mm2,mm1; - pcmpeqd mm4,mm0; - pandn mm2,mm3; - pandn mm4,mm5; - movq mm3,mm2; - movq mm5,mm4; - pand mm2,mm6; - pand mm4,mm6; - pandn mm3,mm7; - pandn mm5,mm7; - por mm2,mm3; - por mm4,mm5; - - /* set *dst */ - movq mm3,mm2; - punpckldq mm2,mm4; - punpckhdq mm3,mm4; - movq qword ptr [edx],mm2; - movq qword ptr [edx+8],mm3; - - mov src0, eax; - mov src1, ebx; - mov src2, ecx; - mov dst, edx; - mov count, esi; - - emms; - } -#endif -} - -static void internal_scale2x_16_mmx(u16* dst0, u16* dst1, const u16* src0, const u16* src1, const u16* src2, unsigned count) -{ - // assert( count >= 2*4 ); - internal_scale2x_16_mmx_single(dst0, src0, src1, src2, count); - internal_scale2x_16_mmx_single(dst1, src2, src1, src0, count); -} - -static void internal_scale2x_32_mmx(u32* dst0, u32* dst1, const u32* src0, const u32* src1, const u32* src2, unsigned count) -{ - // assert( count >= 2*2 ); - internal_scale2x_32_mmx_single(dst0, src0, src1, src2, count); - internal_scale2x_32_mmx_single(dst1, src2, src1, src0, count); -} -#endif - -void AdMame2x(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, - u8 *dstPtr, u32 dstPitch, int width, int height) -{ - u16 *dst0 = (u16 *)dstPtr; - u16 *dst1 = dst0 + (dstPitch >> 1); - - u16 *src0 = (u16 *)srcPtr; - u16 *src1 = src0 + (srcPitch >> 1); - u16 *src2 = src1 + (srcPitch >> 1); -#ifdef MMX - if(cpu_mmx) - { - internal_scale2x_16_mmx(dst0, dst1, src0, src0, src1, width); - - int count = height; - - count -= 2; - while(count) - { - dst0 += dstPitch; - dst1 += dstPitch; - internal_scale2x_16_mmx(dst0, dst1, src0, src1, src2, width); - src0 = src1; - src1 = src2; - src2 += srcPitch >> 1; - --count; - } - dst0 += dstPitch; - dst1 += dstPitch; - internal_scale2x_16_mmx(dst0, dst1, src0, src1, src1, width); - } - else - { -#endif - internal_scale2x_16_def(dst0, src0, src0, src1, width); - internal_scale2x_16_def(dst1, src1, src0, src0, width); - - int count = height; - - count -= 2; - while(count) - { - dst0 += dstPitch; - dst1 += dstPitch; - internal_scale2x_16_def(dst0, src0, src1, src2, width); - internal_scale2x_16_def(dst1, src2, src1, src0, width); - src0 = src1; - src1 = src2; - src2 += srcPitch >> 1; - --count; - } - dst0 += dstPitch; - dst1 += dstPitch; - internal_scale2x_16_def(dst0, src0, src1, src1, width); - internal_scale2x_16_def(dst1, src1, src1, src0, width); -#ifdef MMX - } -#endif -} - -void AdMame2x32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, - u8 *dstPtr, u32 dstPitch, int width, int height) -{ - u32 *dst0 = (u32 *)dstPtr; - u32 *dst1 = dst0 + (dstPitch >> 2); - - u32 *src0 = (u32 *)srcPtr; - u32 *src1 = src0 + (srcPitch >> 2); - u32 *src2 = src1 + (srcPitch >> 2); -#ifdef MMX - if(cpu_mmx) - { - internal_scale2x_32_mmx(dst0, dst1, src0, src0, src1, width); - - int count = height; - - count -= 2; - while(count) - { - dst0 += dstPitch >> 1; - dst1 += dstPitch >> 1; - internal_scale2x_32_mmx(dst0, dst1, src0, src1, src2, width); - src0 = src1; - src1 = src2; - src2 += srcPitch >> 2; - --count; - } - dst0 += dstPitch >> 1; - dst1 += dstPitch >> 1; - internal_scale2x_32_mmx(dst0, dst1, src0, src1, src1, width); - } - else - { -#endif - internal_scale2x_32_def(dst0, src0, src0, src1, width); - internal_scale2x_32_def(dst1, src1, src0, src0, width); - - int count = height; - - count -= 2; - while(count) - { - dst0 += dstPitch >> 1; - dst1 += dstPitch >> 1; - internal_scale2x_32_def(dst0, src0, src1, src2, width); - internal_scale2x_32_def(dst1, src2, src1, src0, width); - src0 = src1; - src1 = src2; - src2 += srcPitch >> 2; - --count; - } - dst0 += dstPitch >> 1; - dst1 += dstPitch >> 1; - internal_scale2x_32_def(dst0, src0, src1, src1, width); - internal_scale2x_32_def(dst1, src1, src1, src0, width); -#ifdef MMX - } -#endif -} +/* + * This file is part of the Advance project. + * + * Copyright (C) 1999-2002 Andrea Mazzoleni + * + * 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * In addition, as a special exception, Andrea Mazzoleni + * gives permission to link the code of this program with + * the MAME library (or with modified versions of MAME that use the + * same license as MAME), and distribute linked combinations including + * the two. You must obey the GNU General Public License in all + * respects for all of the code used other than MAME. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +/* + * Alternatively at the previous license terms, you are allowed to use this + * code in your program with these conditions: + * - the program is not used in commercial activities. + * - the whole source code of the program is released with the binary. + */ + +#include "System.h" + +#ifdef MMX +extern "C" bool cpu_mmx; +#endif + +static void internal_scale2x_16_def(u16 *dst, const u16* src0, const u16* src1, const u16* src2, unsigned count) { + /* first pixel */ + dst[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0]) + dst[1] = src0[0]; + else + dst[1] = src1[0]; + ++src0; + ++src1; + ++src2; + dst += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src0[0] != src2[0] && src1[-1] != src1[1]) { + dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst[1] = src1[1] == src0[0] ? src0[0] : src1[0]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + } + + ++src0; + ++src1; + ++src2; + dst += 2; + --count; + } + + /* last pixel */ + if (src1[-1] == src0[0] && src2[0] != src0[0]) + dst[0] = src0[0]; + else + dst[0] = src1[0]; + dst[1] = src1[0]; +} + +static void internal_scale2x_32_def(u32* dst, + const u32* src0, + const u32* src1, + const u32* src2, + unsigned count) +{ + /* first pixel */ + dst[0] = src1[0]; + if (src1[1] == src0[0] && src2[0] != src0[0]) + dst[1] = src0[0]; + else + dst[1] = src1[0]; + ++src0; + ++src1; + ++src2; + dst += 2; + + /* central pixels */ + count -= 2; + while (count) { + if (src0[0] != src2[0] && src1[-1] != src1[1]) { + dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst[1] = src1[1] == src0[0] ? src0[0] : src1[0]; + } else { + dst[0] = src1[0]; + dst[1] = src1[0]; + } + + ++src0; + ++src1; + ++src2; + dst += 2; + --count; + } + + /* last pixel */ + if (src1[-1] == src0[0] && src2[0] != src0[0]) + dst[0] = src0[0]; + else + dst[0] = src1[0]; + dst[1] = src1[0]; +} + +#ifdef MMX +static void internal_scale2x_16_mmx_single(u16* dst, const u16* src0, const u16* src1, const u16* src2, unsigned count) { + /* always do the first and last run */ + count -= 2*4; + +#ifdef __GNUC__ + __asm__ __volatile__( + /* first run */ + /* set the current, current_pre, current_next registers */ + "movq 0(%1), %%mm0\n" + "movq 0(%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psllq $48,%%mm0\n" + "psllq $48,%%mm1\n" + "psrlq $48, %%mm0\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $16,%%mm2\n" + "psrlq $16,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqw %%mm6,%%mm2\n" + "pcmpeqw %%mm6,%%mm4\n" + "pcmpeqw (%2),%%mm3\n" + "pcmpeqw (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqw %%mm1,%%mm2\n" + "pcmpeqw %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpcklwd %%mm4,%%mm2\n" + "punpckhwd %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + /* central runs */ + "shrl $2,%4\n" + "jz 1f\n" + + "0:\n" + + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $48,%%mm0\n" + "psllq $48,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $16,%%mm2\n" + "psrlq $16,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqw %%mm6,%%mm2\n" + "pcmpeqw %%mm6,%%mm4\n" + "pcmpeqw (%2),%%mm3\n" + "pcmpeqw (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqw %%mm1,%%mm2\n" + "pcmpeqw %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpcklwd %%mm4,%%mm2\n" + "punpckhwd %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + "decl %4\n" + "jnz 0b\n" + "1:\n" + + /* final run */ + /* set the current, current_pre, current_next registers */ + "movq (%1),%%mm1\n" + "movq (%1),%%mm7\n" + "movq -8(%1),%%mm0\n" + "psrlq $48,%%mm1\n" + "psrlq $48,%%mm0\n" + "psllq $48,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $16,%%mm2\n" + "psrlq $16,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqw %%mm6,%%mm2\n" + "pcmpeqw %%mm6,%%mm4\n" + "pcmpeqw (%2),%%mm3\n" + "pcmpeqw (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqw %%mm1,%%mm2\n" + "pcmpeqw %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpcklwd %%mm4,%%mm2\n" + "punpckhwd %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + "emms\n" + + : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) + : + : "cc" + ); +#else + __asm { + mov eax, src0; + mov ebx, src1; + mov ecx, src2; + mov edx, dst; + mov esi, count; + + /* first run */ + /* set the current, current_pre, current_next registers */ + movq mm0, qword ptr [ebx]; + movq mm7, qword ptr [ebx]; + movq mm1, qword ptr [ebx + 8]; + psllq mm0, 48; + psllq mm1, 48; + psrlq mm0, 48; + movq mm2, mm7; + movq mm3, mm7; + psllq mm2, 16; + psrlq mm3, 16; + por mm0, mm2; + por mm1, mm3; + + /* current_upper */ + movq mm6, qword ptr [eax]; + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + movq mm2, mm0; + movq mm4, mm1; + movq mm3, mm0; + movq mm5, mm1; + pcmpeqw mm2, mm6; + pcmpeqw mm4, mm6; + pcmpeqw mm3, qword ptr [ecx]; + pcmpeqw mm5, qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqw mm2,mm1; + pcmpeqw mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst0 */ + movq mm3,mm2; + punpcklwd mm2,mm4; + punpckhwd mm3,mm4; + movq qword ptr [edx], mm2; + movq qword ptr [edx + 8], mm3; + + /* next */ + add eax, 8; + add ebx, 8; + add ecx, 8; + add edx, 16; + + /* central runs */ + shr esi, 2; + jz label1; + align 4; + label0: + + /* set the current, current_pre, current_next registers */ + movq mm0, qword ptr [ebx-8]; + movq mm7, qword ptr [ebx]; + movq mm1, qword ptr [ebx+8]; + psrlq mm0,48; + psllq mm1,48; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,16; + psrlq mm3,16; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6, qword ptr [eax]; + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqw mm2,mm6; + pcmpeqw mm4,mm6; + pcmpeqw mm3, qword ptr [ecx]; + pcmpeqw mm5, qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqw mm2,mm1; + pcmpeqw mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst */ + movq mm3,mm2; + punpcklwd mm2,mm4; + punpckhwd mm3,mm4; + movq qword ptr [edx], mm2; + movq qword ptr [edx+8], mm3; + + /* next */ + add eax,8; + add ebx,8; + add ecx,8; + add edx,16; + + dec esi; + jnz label0; + label1: + + /* final run */ + /* set the current, current_pre, current_next registers */ + movq mm1, qword ptr [ebx]; + movq mm7, qword ptr [ebx]; + movq mm0, qword ptr [ebx-8]; + psrlq mm1,48; + psrlq mm0,48; + psllq mm1,48; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,16; + psrlq mm3,16; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6, qword ptr [eax]; + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqw mm2,mm6; + pcmpeqw mm4,mm6; + pcmpeqw mm3, qword ptr [ecx]; + pcmpeqw mm5, qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqw mm2,mm1; + pcmpeqw mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst */ + movq mm3,mm2; + punpcklwd mm2,mm4; + punpckhwd mm3,mm4; + movq qword ptr [edx], mm2; + movq qword ptr [edx+8], mm3; + + mov src0, eax; + mov src1, ebx; + mov src2, ecx; + mov dst, edx; + mov count, esi; + + emms; + } +#endif +} + +static void internal_scale2x_32_mmx_single(u32* dst, const u32* src0, const u32* src1, const u32* src2, unsigned count) { + /* always do the first and last run */ + count -= 2*2; + +#ifdef __GNUC__ + __asm__ __volatile__( + /* first run */ + /* set the current, current_pre, current_next registers */ + "movq 0(%1),%%mm0\n" + "movq 0(%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psllq $32,%%mm0\n" + "psllq $32,%%mm1\n" + "psrlq $32,%%mm0\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $32,%%mm2\n" + "psrlq $32,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqd %%mm6,%%mm2\n" + "pcmpeqd %%mm6,%%mm4\n" + "pcmpeqd (%2),%%mm3\n" + "pcmpeqd (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqd %%mm1,%%mm2\n" + "pcmpeqd %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpckldq %%mm4,%%mm2\n" + "punpckhdq %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3, 8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + /* central runs */ + "shrl $1,%4\n" + "jz 1f\n" + + "0:\n" + + /* set the current, current_pre, current_next registers */ + "movq -8(%1),%%mm0\n" + "movq (%1),%%mm7\n" + "movq 8(%1),%%mm1\n" + "psrlq $32,%%mm0\n" + "psllq $32,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $32,%%mm2\n" + "psrlq $32,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqd %%mm6,%%mm2\n" + "pcmpeqd %%mm6,%%mm4\n" + "pcmpeqd (%2),%%mm3\n" + "pcmpeqd (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqd %%mm1,%%mm2\n" + "pcmpeqd %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpckldq %%mm4,%%mm2\n" + "punpckhdq %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + + /* next */ + "addl $8,%0\n" + "addl $8,%1\n" + "addl $8,%2\n" + "addl $16,%3\n" + + "decl %4\n" + "jnz 0b\n" + "1:\n" + + /* final run */ + /* set the current, current_pre, current_next registers */ + "movq (%1),%%mm1\n" + "movq (%1),%%mm7\n" + "movq -8(%1), %%mm0\n" + "psrlq $32,%%mm1\n" + "psrlq $32,%%mm0\n" + "psllq $32,%%mm1\n" + "movq %%mm7,%%mm2\n" + "movq %%mm7,%%mm3\n" + "psllq $32,%%mm2\n" + "psrlq $32,%%mm3\n" + "por %%mm2,%%mm0\n" + "por %%mm3,%%mm1\n" + + /* current_upper */ + "movq (%0),%%mm6\n" + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "movq %%mm0,%%mm3\n" + "movq %%mm1,%%mm5\n" + "pcmpeqd %%mm6,%%mm2\n" + "pcmpeqd %%mm6,%%mm4\n" + "pcmpeqd (%2),%%mm3\n" + "pcmpeqd (%2),%%mm5\n" + "pandn %%mm2,%%mm3\n" + "pandn %%mm4,%%mm5\n" + "movq %%mm0,%%mm2\n" + "movq %%mm1,%%mm4\n" + "pcmpeqd %%mm1,%%mm2\n" + "pcmpeqd %%mm0,%%mm4\n" + "pandn %%mm3,%%mm2\n" + "pandn %%mm5,%%mm4\n" + "movq %%mm2,%%mm3\n" + "movq %%mm4,%%mm5\n" + "pand %%mm6,%%mm2\n" + "pand %%mm6,%%mm4\n" + "pandn %%mm7,%%mm3\n" + "pandn %%mm7,%%mm5\n" + "por %%mm3,%%mm2\n" + "por %%mm5,%%mm4\n" + + /* set *dst */ + "movq %%mm2,%%mm3\n" + "punpckldq %%mm4,%%mm2\n" + "punpckhdq %%mm4,%%mm3\n" + "movq %%mm2,(%3)\n" + "movq %%mm3,8(%3)\n" + "emms\n" + + : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count) + : + : "cc" + ); +#else + __asm { + mov eax, src0; + mov ebx, src1; + mov ecx, src2; + mov edx, dst; + mov esi, count; + + /* first run */ + /* set the current, current_pre, current_next registers */ + movq mm0,qword ptr [ebx]; + movq mm7,qword ptr [ebx]; + movq mm1,qword ptr [ebx + 8]; + psllq mm0,32; + psllq mm1,32; + psrlq mm0,32; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,32; + psrlq mm3,32; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6,qword ptr [eax]; + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqd mm2,mm6; + pcmpeqd mm4,mm6; + pcmpeqd mm3,qword ptr [ecx]; + pcmpeqd mm5,qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqd mm2,mm1; + pcmpeqd mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst */ + movq mm3,mm2; + punpckldq mm2,mm4; + punpckhdq mm3,mm4; + movq qword ptr [edx],mm2; + movq qword ptr [edx+8],mm3; + + /* next */ + add eax,8; + add ebx,8; + add ecx,8; + add edx,16; + + /* central runs */ + shr esi,1; + jz label1; +label0: + + /* set the current, current_pre, current_next registers */ + movq mm0,qword ptr [ebx-8]; + movq mm7,qword ptr [ebx]; + movq mm1,qword ptr [ebx+8]; + psrlq mm0,32; + psllq mm1,32; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,32; + psrlq mm3,32; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6,qword ptr[eax]; + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqd mm2,mm6; + pcmpeqd mm4,mm6; + pcmpeqd mm3,qword ptr[ecx]; + pcmpeqd mm5,qword ptr[ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqd mm2,mm1; + pcmpeqd mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst */ + movq mm3,mm2; + punpckldq mm2,mm4; + punpckhdq mm3,mm4; + movq qword ptr [edx],mm2; + movq qword ptr [edx+8],mm3; + + /* next */ + add eax,8; + add ebx,8; + add ecx,8; + add edx,16; + + dec esi; + jnz label0; +label1: + + /* final run */ + /* set the current, current_pre, current_next registers */ + movq mm1,qword ptr [ebx]; + movq mm7,qword ptr [ebx]; + movq mm0,qword ptr [ebx-8]; + psrlq mm1,32; + psrlq mm0,32; + psllq mm1,32; + movq mm2,mm7; + movq mm3,mm7; + psllq mm2,32; + psrlq mm3,32; + por mm0,mm2; + por mm1,mm3; + + /* current_upper */ + movq mm6,qword ptr [eax]; + + /* compute the upper-left pixel for dst on %%mm2 */ + /* compute the upper-right pixel for dst on %%mm4 */ + movq mm2,mm0; + movq mm4,mm1; + movq mm3,mm0; + movq mm5,mm1; + pcmpeqd mm2,mm6; + pcmpeqd mm4,mm6; + pcmpeqd mm3,qword ptr [ecx]; + pcmpeqd mm5,qword ptr [ecx]; + pandn mm3,mm2; + pandn mm5,mm4; + movq mm2,mm0; + movq mm4,mm1; + pcmpeqd mm2,mm1; + pcmpeqd mm4,mm0; + pandn mm2,mm3; + pandn mm4,mm5; + movq mm3,mm2; + movq mm5,mm4; + pand mm2,mm6; + pand mm4,mm6; + pandn mm3,mm7; + pandn mm5,mm7; + por mm2,mm3; + por mm4,mm5; + + /* set *dst */ + movq mm3,mm2; + punpckldq mm2,mm4; + punpckhdq mm3,mm4; + movq qword ptr [edx],mm2; + movq qword ptr [edx+8],mm3; + + mov src0, eax; + mov src1, ebx; + mov src2, ecx; + mov dst, edx; + mov count, esi; + + emms; + } +#endif +} + +static void internal_scale2x_16_mmx(u16* dst0, u16* dst1, const u16* src0, const u16* src1, const u16* src2, unsigned count) { + // assert( count >= 2*4 ); + internal_scale2x_16_mmx_single(dst0, src0, src1, src2, count); + internal_scale2x_16_mmx_single(dst1, src2, src1, src0, count); +} + +static void internal_scale2x_32_mmx(u32* dst0, u32* dst1, const u32* src0, const u32* src1, const u32* src2, unsigned count) { + // assert( count >= 2*2 ); + internal_scale2x_32_mmx_single(dst0, src0, src1, src2, count); + internal_scale2x_32_mmx_single(dst1, src2, src1, src0, count); +} +#endif + +void AdMame2x(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, + u8 *dstPtr, u32 dstPitch, int width, int height) +{ + u16 *dst0 = (u16 *)dstPtr; + u16 *dst1 = dst0 + (dstPitch >> 1); + + u16 *src0 = (u16 *)srcPtr; + u16 *src1 = src0 + (srcPitch >> 1); + u16 *src2 = src1 + (srcPitch >> 1); +#ifdef MMX + if(cpu_mmx) { + internal_scale2x_16_mmx(dst0, dst1, src0, src0, src1, width); + + int count = height; + + count -= 2; + while(count) { + dst0 += dstPitch; + dst1 += dstPitch; + internal_scale2x_16_mmx(dst0, dst1, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcPitch >> 1; + --count; + } + dst0 += dstPitch; + dst1 += dstPitch; + internal_scale2x_16_mmx(dst0, dst1, src0, src1, src1, width); + } else { +#endif + internal_scale2x_16_def(dst0, src0, src0, src1, width); + internal_scale2x_16_def(dst1, src1, src0, src0, width); + + int count = height; + + count -= 2; + while(count) { + dst0 += dstPitch; + dst1 += dstPitch; + internal_scale2x_16_def(dst0, src0, src1, src2, width); + internal_scale2x_16_def(dst1, src2, src1, src0, width); + src0 = src1; + src1 = src2; + src2 += srcPitch >> 1; + --count; + } + dst0 += dstPitch; + dst1 += dstPitch; + internal_scale2x_16_def(dst0, src0, src1, src1, width); + internal_scale2x_16_def(dst1, src1, src1, src0, width); +#ifdef MMX + } +#endif +} + +void AdMame2x32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, + u8 *dstPtr, u32 dstPitch, int width, int height) +{ + u32 *dst0 = (u32 *)dstPtr; + u32 *dst1 = dst0 + (dstPitch >> 2); + + u32 *src0 = (u32 *)srcPtr; + u32 *src1 = src0 + (srcPitch >> 2); + u32 *src2 = src1 + (srcPitch >> 2); +#ifdef MMX + if(cpu_mmx) { + internal_scale2x_32_mmx(dst0, dst1, src0, src0, src1, width); + + int count = height; + + count -= 2; + while(count) { + dst0 += dstPitch >> 1; + dst1 += dstPitch >> 1; + internal_scale2x_32_mmx(dst0, dst1, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcPitch >> 2; + --count; + } + dst0 += dstPitch >> 1; + dst1 += dstPitch >> 1; + internal_scale2x_32_mmx(dst0, dst1, src0, src1, src1, width); + } else { +#endif + internal_scale2x_32_def(dst0, src0, src0, src1, width); + internal_scale2x_32_def(dst1, src1, src0, src0, width); + + int count = height; + + count -= 2; + while(count) { + dst0 += dstPitch >> 1; + dst1 += dstPitch >> 1; + internal_scale2x_32_def(dst0, src0, src1, src2, width); + internal_scale2x_32_def(dst1, src2, src1, src0, width); + src0 = src1; + src1 = src2; + src2 += srcPitch >> 2; + --count; + } + dst0 += dstPitch >> 1; + dst1 += dstPitch >> 1; + internal_scale2x_32_def(dst0, src0, src1, src1, width); + internal_scale2x_32_def(dst1, src1, src1, src0, width); +#ifdef MMX + } +#endif +} diff --git a/source/vba/agb/GBA-arm.cpp b/source/vba/agb/GBA-arm.cpp new file mode 100644 index 0000000..4e320aa --- /dev/null +++ b/source/vba/agb/GBA-arm.cpp @@ -0,0 +1,2967 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 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. + +#include +#include +#include +#include + +#include "GBA.h" +#include "GBAcpu.h" +#include "GBAinline.h" +#include "../Globals.h" +#include "../EEprom.h" +#include "../Flash.h" +#include "../Sound.h" +#include "../Sram.h" +#include "../bios.h" +#include "../Cheats.h" +#include "../NLS.h" +#include "../elf.h" +#include "../Util.h" +#include "../Port.h" +#include "../System.h" +#include "agbprint.h" +#ifdef PROFILING +#include "prof/prof.h" +#endif + +#ifdef _MSC_VER + // Disable "empty statement" warnings + #pragma warning(disable: 4390) + // Visual C's inline assembler treats "offset" as a reserved word, so we + // tell it otherwise. If you want to use it, write "OFFSET" in capitals. + #define offset offset_ +#endif + +/////////////////////////////////////////////////////////////////////////// + +static int clockTicks; + +static INSN_REGPARM void armUnknownInsn(u32 opcode) +{ +#ifdef GBA_LOGGING + if (systemVerbose & VERBOSE_UNDEFINED) { + log("Undefined ARM instruction %08x at %08x\n", opcode, + armNextPC-4); + } +#endif + CPUUndefinedException(); +} + +#ifdef BKPT_SUPPORT +static INSN_REGPARM void armBreakpoint(u32 opcode) +{ + reg[15].I -= 4; + armNextPC -= 4; + dbgSignal(5, (opcode & 0x0f) | ((opcode>>4) & 0xfff0)); + clockTicks = -1; +} +#endif + + +// Subroutine to count instructions (for debugging/optimizing) +//#define INSN_COUNTER // comment out if you don't want it +#ifdef INSN_COUNTER +static void count(u32 opcode, int cond_res) +{ + static int insncount = 0; // number of insns seen + static int executed = 0; // number of insns executed + static int mergewith[4096]; // map instructions to routines + static int count[4096]; // count of each 12-bit code + int index = ((opcode>>16)&0xFF0) | ((opcode>>4)&0x0F); + static FILE *outfile = NULL; + + if (!insncount) { + for (int i = 0; i < 4096; i++) { + for (int j = 0; j < i; j++) { + if (armInsnTable[i] == armInsnTable[j]) + break; + } + mergewith[i] = j; + } + outfile = fopen("VBA-armcount.txt", "w"); + } + if (cond_res) { + count[mergewith[index]]++; + executed++; + } + insncount++; + if (outfile && insncount%1000000 == 0) { + fprintf(outfile, "Total instructions: %d\n", insncount); + fprintf(outfile, "Instructions executed: %d\n", executed); + for (int i = 0; i < 4096; i++) { + if (count[i]) + fprintf(outfile, "arm%03X: %d\n", i, count[i]); + } + } +} +#endif + +// Common macros ////////////////////////////////////////////////////////// + +#ifdef BKPT_SUPPORT +#define CONSOLE_OUTPUT(a,b) do { \ + if ((opcode == 0xe0000000) && (reg[0].I == 0xC0DED00D)) { \ + dbgOutput((a), (b)); \ +} while (0) +#else +#define CONSOLE_OUTPUT(a,b) /* nothing */ +#endif + +#define NEG(i) ((i) >> 31) +#define POS(i) ((~(i)) >> 31) + +// The following macros are used for optimization; any not defined for a +// particular compiler/CPU combination default to the C core versions. +// +// ALU_INIT_C: Used at the beginning of ALU instructions (AND/EOR/...). +// (ALU_INIT_NC) Can consist of variable declarations, like the C core, +// or the start of a continued assembly block, like the +// x86-optimized version. The _C version is used when the +// carry flag from the shift operation is needed (logical +// operations that set condition codes, like ANDS); the +// _NC version is used when the carry result is ignored. +// VALUE_XXX: Retrieve the second operand's value for an ALU instruction. +// The _C and _NC versions are used the same way as ALU_INIT. +// OP_XXX: ALU operations. XXX is the instruction name. +// ALU_FINISH: Appended to all ALU instructions. Usually empty, but if +// ALU_INIT started a block ALU_FINISH can be used to end it +// (as with the asm(...) statement in the x86 core). +// SETCOND_NONE: Used in multiply instructions in place of SETCOND_MUL +// when the condition codes are not set. Usually empty. +// SETCOND_MUL: Used in multiply instructions to set the condition codes. +// ROR_IMM_MSR: Used to rotate the immediate operand for MSR. +// ROR_OFFSET: Used to rotate the `offset' parameter for LDR and STR +// instructions. +// RRX_OFFSET: Used to rotate (RRX) the `offset' parameter for LDR and +// STR instructions. + +#ifndef C_CORE + +#if 0 // definitions have changed +//#ifdef __POWERPC__ + #define OP_SUBS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_RSBS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subfco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_ADDS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("addco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_ADCS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("mtspr xer, %4\n" \ + "addeo. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value), \ + "r" (C_FLAG << 29) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_SBCS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("mtspr xer, %4\n" \ + "subfeo. %0, %3, %2\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value), \ + "r" (C_FLAG << 29) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_RSCS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("mtspr xer, %4\n" \ + "subfeo. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value), \ + "r" (C_FLAG << 29) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_CMP \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value) \ + ); \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define OP_CMN \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("addco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[base].I), \ + "r" (value) \ + ); \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + +#else // !__POWERPC__ + +// Macros to emit instructions in the format used by the particular compiler. +// We use GNU assembler syntax: "op src, dest" rather than "op dest, src" + +#ifdef __GNUC__ + #define ALU_HEADER asm("mov %%ecx, %%edi; " + #define ALU_TRAILER : "=D" (opcode) : "c" (opcode) : "eax", "ebx", "edx", "esi") + #define EMIT0(op) #op"; " + #define EMIT1(op,arg) #op" "arg"; " + #define EMIT2(op,src,dest) #op" "src", "dest"; " + #define CONST(val) "$"#val + #define ASMVAR(cvar) ASMVAR2 (__USER_LABEL_PREFIX__, cvar) + #define ASMVAR2(prefix,cvar) STRING (prefix) cvar + #define STRING(x) #x + #define VAR(var) ASMVAR(#var) + #define VARL(var) ASMVAR(#var) + #define REGREF1(index) ASMVAR("reg("index")") + #define REGREF2(index,scale) ASMVAR("reg(,"index","#scale")") + #define LABEL(n) #n": " + #define LABELREF(n,dir) #n#dir + #define al "%%al" + #define ah "%%ah" + #define eax "%%eax" + #define bl "%%bl" + #define bh "%%bh" + #define ebx "%%ebx" + #define cl "%%cl" + #define ch "%%ch" + #define ecx "%%ecx" + #define dl "%%dl" + #define dh "%%dh" + #define edx "%%edx" + #define esp "%%esp" + #define ebp "%%ebp" + #define esi "%%esi" + #define edi "%%edi" + #define movzx movzb +#else + #define ALU_HEADER __asm { __asm mov ecx, opcode + #define ALU_TRAILER } + #define EMIT0(op) __asm op + #define EMIT1(op,arg) __asm op arg + #define EMIT2(op,src,dest) __asm op dest, src + #define CONST(val) val + #define VAR(var) var + #define VARL(var) dword ptr var + #define REGREF1(index) reg[index] + #define REGREF2(index,scale) reg[index*scale] + #define LABEL(n) __asm l##n: + #define LABELREF(n,dir) l##n +#endif + +//X//#ifndef _MSC_VER +// ALU op register usage: +// EAX -> 2nd operand value, result (RSB/RSC) +// EBX -> C_OUT (carry flag from shift/rotate) +// ECX -> opcode (input), shift/rotate count +// EDX -> Rn (base) value, result (all except RSB/RSC) +// ESI -> Rd (destination) index * 4 + +// Helper macros for loading value / shift count +#define VALUE_LOAD_IMM \ + EMIT2(and, CONST(0x0F), eax) \ + EMIT2(mov, REGREF2(eax,4), eax) \ + EMIT2(shr, CONST(7), ecx) \ + EMIT2(and, CONST(0x1F), ecx) +#define VALUE_LOAD_REG \ + EMIT2(and, CONST(0x0F), eax) \ + EMIT2(mov, REGREF2(eax,4), eax) \ + EMIT2(movzx, ch, ecx) \ + EMIT2(and, CONST(0x0F), ecx) \ + EMIT2(mov, REGREF2(ecx,4), ecx) + +// Helper macros for setting flags +#define SETCOND_LOGICAL \ + EMIT1(sets, VAR(N_FLAG)) \ + EMIT1(setz, VAR(Z_FLAG)) \ + EMIT2(mov, bl, VAR(C_FLAG)) +#define SETCOND_ADD \ + EMIT1(sets, VAR(N_FLAG)) \ + EMIT1(setz, VAR(Z_FLAG)) \ + EMIT1(seto, VAR(V_FLAG)) \ + EMIT1(setc, VAR(C_FLAG)) +#define SETCOND_SUB \ + EMIT1(sets, VAR(N_FLAG)) \ + EMIT1(setz, VAR(Z_FLAG)) \ + EMIT1(seto, VAR(V_FLAG)) \ + EMIT1(setnc, VAR(C_FLAG)) + +// ALU initialization +#define ALU_INIT(LOAD_C_FLAG) \ + ALU_HEADER \ + LOAD_C_FLAG \ + EMIT2(mov, ecx, edx) \ + EMIT2(shr, CONST(14), edx) \ + EMIT2(mov, ecx, eax) \ + EMIT2(mov, ecx, esi) \ + EMIT2(shr, CONST(10), esi) \ + EMIT2(and, CONST(0x3C), edx) \ + EMIT2(mov, REGREF1(edx), edx) \ + EMIT2(and, CONST(0x3C), esi) + +#define LOAD_C_FLAG_YES EMIT2(mov, VAR(C_FLAG), bl) +#define LOAD_C_FLAG_NO /*nothing*/ +#define ALU_INIT_C ALU_INIT(LOAD_C_FLAG_YES) +#define ALU_INIT_NC ALU_INIT(LOAD_C_FLAG_NO) + +// Macros to load the value operand for an ALU op; these all set N/Z +// according to the value + +// OP Rd,Rb,Rm LSL # +#define VALUE_LSL_IMM_C \ + VALUE_LOAD_IMM \ + EMIT1(jnz, LABELREF(1,f)) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(shl, cl, eax) \ + EMIT1(setc, bl) \ + LABEL(0) +#define VALUE_LSL_IMM_NC \ + VALUE_LOAD_IMM \ + EMIT2(shl, cl, eax) + +// OP Rd,Rb,Rm LSL Rs +#define VALUE_LSL_REG_C \ + VALUE_LOAD_REG \ + EMIT2(test, cl, cl) \ + EMIT1(jz, LABELREF(0,f)) \ + EMIT2(cmp, CONST(0x20), cl) \ + EMIT1(je, LABELREF(1,f)) \ + EMIT1(ja, LABELREF(2,f)) \ + EMIT2(shl, cl, eax) \ + EMIT1(setc, bl) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(test, CONST(1), al) \ + EMIT1(setnz, bl) \ + EMIT2(xor, eax, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(2) \ + EMIT2(xor, ebx, ebx) \ + EMIT2(xor, eax, eax) \ + LABEL(0) +#define VALUE_LSL_REG_NC \ + VALUE_LOAD_REG \ + EMIT2(cmp, CONST(0x20), cl) \ + EMIT1(jae, LABELREF(1,f)) \ + EMIT2(shl, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(xor, eax, eax) \ + LABEL(0) + +// OP Rd,Rb,Rm LSR # +#define VALUE_LSR_IMM_C \ + VALUE_LOAD_IMM \ + EMIT1(jz, LABELREF(1,f)) \ + EMIT2(shr, cl, eax) \ + EMIT1(setc, bl) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(test, eax, eax) \ + EMIT1(sets, bl) \ + EMIT2(xor, eax, eax) \ + LABEL(0) +#define VALUE_LSR_IMM_NC \ + VALUE_LOAD_IMM \ + EMIT1(jz, LABELREF(1,f)) \ + EMIT2(shr, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(xor, eax, eax) \ + LABEL(0) + +// OP Rd,Rb,Rm LSR Rs +#define VALUE_LSR_REG_C \ + VALUE_LOAD_REG \ + EMIT2(test, cl, cl) \ + EMIT1(jz, LABELREF(0,f)) \ + EMIT2(cmp, CONST(0x20), cl) \ + EMIT1(je, LABELREF(1,f)) \ + EMIT1(ja, LABELREF(2,f)) \ + EMIT2(shr, cl, eax) \ + EMIT1(setc, bl) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(test, eax, eax) \ + EMIT1(sets, bl) \ + EMIT2(xor, eax, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(2) \ + EMIT2(xor, ebx, ebx) \ + EMIT2(xor, eax, eax) \ + LABEL(0) +#define VALUE_LSR_REG_NC \ + VALUE_LOAD_REG \ + EMIT2(cmp, CONST(0x20), cl) \ + EMIT1(jae, LABELREF(1,f)) \ + EMIT2(shr, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(xor, eax, eax) \ + LABEL(0) + +// OP Rd,Rb,Rm ASR # +#define VALUE_ASR_IMM_C \ + VALUE_LOAD_IMM \ + EMIT1(jz, LABELREF(1,f)) \ + EMIT2(sar, cl, eax) \ + EMIT1(setc, bl) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(sar, CONST(31), eax) \ + EMIT1(sets, bl) \ + LABEL(0) +#define VALUE_ASR_IMM_NC \ + VALUE_LOAD_IMM \ + EMIT1(jz, LABELREF(1,f)) \ + EMIT2(sar, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(sar, CONST(31), eax) \ + LABEL(0) + +// OP Rd,Rb,Rm ASR Rs +#define VALUE_ASR_REG_C \ + VALUE_LOAD_REG \ + EMIT2(test, cl, cl) \ + EMIT1(jz, LABELREF(0,f)) \ + EMIT2(cmp, CONST(0x20), cl) \ + EMIT1(jae, LABELREF(1,f)) \ + EMIT2(sar, cl, eax) \ + EMIT1(setc, bl) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(sar, CONST(31), eax) \ + EMIT1(sets, bl) \ + LABEL(0) +#define VALUE_ASR_REG_NC \ + VALUE_LOAD_REG \ + EMIT2(cmp, CONST(0x20), cl) \ + EMIT1(jae, LABELREF(1,f)) \ + EMIT2(sar, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(sar, CONST(31), eax) \ + LABEL(0) + +// OP Rd,Rb,Rm ROR # +#define VALUE_ROR_IMM_C \ + VALUE_LOAD_IMM \ + EMIT1(jz, LABELREF(1,f)) \ + EMIT2(ror, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(bt, CONST(0), ebx) \ + EMIT2(rcr, CONST(1), eax) \ + LABEL(0) \ + EMIT1(setc, bl) +#define VALUE_ROR_IMM_NC \ + VALUE_LOAD_IMM \ + EMIT1(jz, LABELREF(1,f)) \ + EMIT2(ror, cl, eax) \ + EMIT1(jmp, LABELREF(0,f)) \ + LABEL(1) \ + EMIT2(bt, CONST(0), VARL(C_FLAG)) \ + EMIT2(rcr, CONST(1), eax) \ + LABEL(0) + +// OP Rd,Rb,Rm ROR Rs +#define VALUE_ROR_REG_C \ + VALUE_LOAD_REG \ + EMIT2(bt, CONST(0), ebx) \ + EMIT2(ror, cl, eax) \ + EMIT1(setc, bl) +#define VALUE_ROR_REG_NC \ + VALUE_LOAD_REG \ + EMIT2(ror, cl, eax) + +// OP Rd,Rb,# ROR # +#define VALUE_IMM_C \ + EMIT2(movzx, ch, ecx) \ + EMIT2(add, ecx, ecx) \ + EMIT2(movzx, al, eax) \ + EMIT2(bt, CONST(0), ebx) \ + EMIT2(ror, cl, eax) \ + EMIT1(setc, bl) +#define VALUE_IMM_NC \ + EMIT2(movzx, ch, ecx) \ + EMIT2(add, ecx, ecx) \ + EMIT2(movzx, al, eax) \ + EMIT2(ror, cl, eax) + +// Macros to perform ALU ops + +// Set condition codes iff the destination register is not R15 (PC) +#define CHECK_PC(OP, SETCOND) \ + EMIT2(cmp, CONST(0x3C), esi) \ + EMIT1(je, LABELREF(8,f)) \ + OP SETCOND \ + EMIT1(jmp, LABELREF(9,f)) \ + LABEL(8) \ + OP \ + LABEL(9) + +#define OP_AND \ + EMIT2(and, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_ANDS CHECK_PC(OP_AND, SETCOND_LOGICAL) +#define OP_EOR \ + EMIT2(xor, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_EORS CHECK_PC(OP_EOR, SETCOND_LOGICAL) +#define OP_SUB \ + EMIT2(sub, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_SUBS CHECK_PC(OP_SUB, SETCOND_SUB) +#define OP_RSB \ + EMIT2(sub, edx, eax) \ + EMIT2(mov, eax, REGREF1(esi)) +#define OP_RSBS CHECK_PC(OP_RSB, SETCOND_SUB) +#define OP_ADD \ + EMIT2(add, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_ADDS CHECK_PC(OP_ADD, SETCOND_ADD) +#define OP_ADC \ + EMIT2(bt, CONST(0), VARL(C_FLAG)) \ + EMIT2(adc, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_ADCS CHECK_PC(OP_ADC, SETCOND_ADD) +#define OP_SBC \ + EMIT2(bt, CONST(0), VARL(C_FLAG)) \ + EMIT0(cmc) \ + EMIT2(sbb, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_SBCS CHECK_PC(OP_SBC, SETCOND_SUB) +#define OP_RSC \ + EMIT2(bt, CONST(0), VARL(C_FLAG)) \ + EMIT0(cmc) \ + EMIT2(sbb, edx, eax) \ + EMIT2(mov, eax, REGREF1(esi)) +#define OP_RSCS CHECK_PC(OP_RSC, SETCOND_SUB) +#define OP_TST \ + EMIT2(and, eax, edx) \ + SETCOND_LOGICAL +#define OP_TEQ \ + EMIT2(xor, eax, edx) \ + SETCOND_LOGICAL +#define OP_CMP \ + EMIT2(sub, eax, edx) \ + SETCOND_SUB +#define OP_CMN \ + EMIT2(add, eax, edx) \ + SETCOND_ADD +#define OP_ORR \ + EMIT2(or, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_ORRS CHECK_PC(OP_ORR, SETCOND_LOGICAL) +#define OP_MOV \ + EMIT2(mov, eax, REGREF1(esi)) +#define OP_MOVS CHECK_PC(EMIT2(test,eax,eax) EMIT2(mov,eax,REGREF1(esi)), SETCOND_LOGICAL) +#define OP_BIC \ + EMIT1(not, eax) \ + EMIT2(and, eax, edx) \ + EMIT2(mov, edx, REGREF1(esi)) +#define OP_BICS CHECK_PC(OP_BIC, SETCOND_LOGICAL) +#define OP_MVN \ + EMIT1(not, eax) \ + EMIT2(mov, eax, REGREF1(esi)) +#define OP_MVNS CHECK_PC(OP_MVN, SETCOND_LOGICAL) + +// ALU cleanup macro +#define ALU_FINISH ALU_TRAILER + +// End of ALU macros +//X//#endif //_MSC_VER + +#ifdef __GNUC__ + +#define ROR_IMM_MSR \ + asm ("ror %%cl, %%eax;" \ + : "=a" (value) \ + : "a" (opcode & 0xFF), "c" (shift)); + +#define ROR_OFFSET \ + asm("ror %%cl, %0" \ + : "=r" (offset) \ + : "0" (offset), "c" (shift)); + +#define RRX_OFFSET \ + asm(EMIT2(btl,CONST(0),VAR(C_FLAG)) \ + "rcr $1, %0" \ + : "=r" (offset) \ + : "0" (offset)); + +#else // !__GNUC__, i.e. Visual C++ + +#define ROR_IMM_MSR \ + __asm { \ + __asm mov ecx, shift \ + __asm ror value, cl \ + } + + +#define ROR_OFFSET \ + __asm { \ + __asm mov ecx, shift \ + __asm ror offset, cl \ + } + +#define RRX_OFFSET \ + __asm { \ + __asm bt dword ptr C_FLAG, 0 \ + __asm rcr offset, 1 \ + } + +#endif // !__GNUC__ + +#endif // !__POWERPC__ +#endif // !C_CORE + +// C core + +#define C_SETCOND_LOGICAL \ + N_FLAG = ((s32)res < 0) ? true : false; \ + Z_FLAG = (res == 0) ? true : false; \ + C_FLAG = C_OUT; +#define C_SETCOND_ADD \ + N_FLAG = ((s32)res < 0) ? true : false; \ + Z_FLAG = (res == 0) ? true : false; \ + V_FLAG = ((NEG(lhs) & NEG(rhs) & POS(res)) | \ + (POS(lhs) & POS(rhs) & NEG(res))) ? true : false;\ + C_FLAG = ((NEG(lhs) & NEG(rhs)) | \ + (NEG(lhs) & POS(res)) | \ + (NEG(rhs) & POS(res))) ? true : false; +#define C_SETCOND_SUB \ + N_FLAG = ((s32)res < 0) ? true : false; \ + Z_FLAG = (res == 0) ? true : false; \ + V_FLAG = ((NEG(lhs) & POS(rhs) & POS(res)) | \ + (POS(lhs) & NEG(rhs) & NEG(res))) ? true : false;\ + C_FLAG = ((NEG(lhs) & POS(rhs)) | \ + (NEG(lhs) & POS(res)) | \ + (POS(rhs) & POS(res))) ? true : false; + +#ifndef ALU_INIT_C + #define ALU_INIT_C \ + int dest = (opcode>>12) & 15; \ + bool C_OUT = C_FLAG; \ + u32 value; +#endif +// OP Rd,Rb,Rm LSL # +#ifndef VALUE_LSL_IMM_C + #define VALUE_LSL_IMM_C \ + unsigned int shift = (opcode >> 7) & 0x1F; \ + if (LIKELY(!shift)) { /* LSL #0 most common? */ \ + value = reg[opcode & 0x0F].I; \ + } else { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (32 - shift)) & 1 ? true : false; \ + value = v << shift; \ + } +#endif +// OP Rd,Rb,Rm LSL Rs +#ifndef VALUE_LSL_REG_C + #define VALUE_LSL_REG_C \ + unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ + if (LIKELY(shift)) { \ + if (shift == 32) { \ + value = 0; \ + C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false);\ + } else if (LIKELY(shift < 32)) { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (32 - shift)) & 1 ? true : false;\ + value = v << shift; \ + } else { \ + value = 0; \ + C_OUT = false; \ + } \ + } else { \ + value = reg[opcode & 0x0F].I; \ + } +#endif +// OP Rd,Rb,Rm LSR # +#ifndef VALUE_LSR_IMM_C + #define VALUE_LSR_IMM_C \ + unsigned int shift = (opcode >> 7) & 0x1F; \ + if (LIKELY(shift)) { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ + value = v >> shift; \ + } else { \ + value = 0; \ + C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false;\ + } +#endif +// OP Rd,Rb,Rm LSR Rs +#ifndef VALUE_LSR_REG_C + #define VALUE_LSR_REG_C \ + unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ + if (LIKELY(shift)) { \ + if (shift == 32) { \ + value = 0; \ + C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false);\ + } else if (LIKELY(shift < 32)) { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (shift - 1)) & 1 ? true : false;\ + value = v >> shift; \ + } else { \ + value = 0; \ + C_OUT = false; \ + } \ + } else { \ + value = reg[opcode & 0x0F].I; \ + } +#endif +// OP Rd,Rb,Rm ASR # +#ifndef VALUE_ASR_IMM_C + #define VALUE_ASR_IMM_C \ + unsigned int shift = (opcode >> 7) & 0x1F; \ + if (LIKELY(shift)) { \ + /* VC++ BUG: u32 v; (s32)v>>n is optimized to shr! */ \ + s32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\ + value = v >> (int)shift; \ + } else { \ + if (reg[opcode & 0x0F].I & 0x80000000) { \ + value = 0xFFFFFFFF; \ + C_OUT = true; \ + } else { \ + value = 0; \ + C_OUT = false; \ + } \ + } +#endif +// OP Rd,Rb,Rm ASR Rs +#ifndef VALUE_ASR_REG_C + #define VALUE_ASR_REG_C \ + unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ + if (LIKELY(shift < 32)) { \ + if (LIKELY(shift)) { \ + s32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\ + value = v >> (int)shift; \ + } else { \ + value = reg[opcode & 0x0F].I; \ + } \ + } else { \ + if (reg[opcode & 0x0F].I & 0x80000000) { \ + value = 0xFFFFFFFF; \ + C_OUT = true; \ + } else { \ + value = 0; \ + C_OUT = false; \ + } \ + } +#endif +// OP Rd,Rb,Rm ROR # +#ifndef VALUE_ROR_IMM_C + #define VALUE_ROR_IMM_C \ + unsigned int shift = (opcode >> 7) & 0x1F; \ + if (LIKELY(shift)) { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ + value = ((v << (32 - shift)) | \ + (v >> shift)); \ + } else { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v & 1) ? true : false; \ + value = ((v >> 1) | \ + (C_FLAG << 31)); \ + } +#endif +// OP Rd,Rb,Rm ROR Rs +#ifndef VALUE_ROR_REG_C + #define VALUE_ROR_REG_C \ + unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ + if (LIKELY(shift & 0x1F)) { \ + u32 v = reg[opcode & 0x0F].I; \ + C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ + value = ((v << (32 - shift)) | \ + (v >> shift)); \ + } else { \ + value = reg[opcode & 0x0F].I; \ + if (shift) \ + C_OUT = (value & 0x80000000 ? true : false);\ + } +#endif +// OP Rd,Rb,# ROR # +#ifndef VALUE_IMM_C + #define VALUE_IMM_C \ + int shift = (opcode & 0xF00) >> 7; \ + if (UNLIKELY(shift)) { \ + u32 v = opcode & 0xFF; \ + C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ + value = ((v << (32 - shift)) | \ + (v >> shift)); \ + } else { \ + value = opcode & 0xFF; \ + } +#endif + +// Make the non-carry versions default to the carry versions +// (this is fine for C--the compiler will optimize the dead code out) +#ifndef ALU_INIT_NC + #define ALU_INIT_NC ALU_INIT_C +#endif +#ifndef VALUE_LSL_IMM_NC + #define VALUE_LSL_IMM_NC VALUE_LSL_IMM_C +#endif +#ifndef VALUE_LSL_REG_NC + #define VALUE_LSL_REG_NC VALUE_LSL_REG_C +#endif +#ifndef VALUE_LSR_IMM_NC + #define VALUE_LSR_IMM_NC VALUE_LSR_IMM_C +#endif +#ifndef VALUE_LSR_REG_NC + #define VALUE_LSR_REG_NC VALUE_LSR_REG_C +#endif +#ifndef VALUE_ASR_IMM_NC + #define VALUE_ASR_IMM_NC VALUE_ASR_IMM_C +#endif +#ifndef VALUE_ASR_REG_NC + #define VALUE_ASR_REG_NC VALUE_ASR_REG_C +#endif +#ifndef VALUE_ROR_IMM_NC + #define VALUE_ROR_IMM_NC VALUE_ROR_IMM_C +#endif +#ifndef VALUE_ROR_REG_NC + #define VALUE_ROR_REG_NC VALUE_ROR_REG_C +#endif +#ifndef VALUE_IMM_NC + #define VALUE_IMM_NC VALUE_IMM_C +#endif + +#define C_CHECK_PC(SETCOND) if (LIKELY(dest != 15)) { SETCOND } +#ifndef OP_AND + #define OP_AND \ + u32 res = reg[(opcode>>16)&15].I & value; \ + reg[dest].I = res; +#endif +#ifndef OP_ANDS + #define OP_ANDS OP_AND C_CHECK_PC(C_SETCOND_LOGICAL) +#endif +#ifndef OP_EOR + #define OP_EOR \ + u32 res = reg[(opcode>>16)&15].I ^ value; \ + reg[dest].I = res; +#endif +#ifndef OP_EORS + #define OP_EORS OP_EOR C_CHECK_PC(C_SETCOND_LOGICAL) +#endif +#ifndef OP_SUB + #define OP_SUB \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = lhs - rhs; \ + reg[dest].I = res; +#endif +#ifndef OP_SUBS + #define OP_SUBS OP_SUB C_CHECK_PC(C_SETCOND_SUB) +#endif +#ifndef OP_RSB + #define OP_RSB \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = rhs - lhs; \ + reg[dest].I = res; +#endif +#ifndef OP_RSBS + #define OP_RSBS OP_RSB C_CHECK_PC(C_SETCOND_SUB) +#endif +#ifndef OP_ADD + #define OP_ADD \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = lhs + rhs; \ + reg[dest].I = res; +#endif +#ifndef OP_ADDS + #define OP_ADDS OP_ADD C_CHECK_PC(C_SETCOND_ADD) +#endif +#ifndef OP_ADC + #define OP_ADC \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = lhs + rhs + (u32)C_FLAG; \ + reg[dest].I = res; +#endif +#ifndef OP_ADCS + #define OP_ADCS OP_ADC C_CHECK_PC(C_SETCOND_ADD) +#endif +#ifndef OP_SBC + #define OP_SBC \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = lhs - rhs - !((u32)C_FLAG); \ + reg[dest].I = res; +#endif +#ifndef OP_SBCS + #define OP_SBCS OP_SBC C_CHECK_PC(C_SETCOND_SUB) +#endif +#ifndef OP_RSC + #define OP_RSC \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = rhs - lhs - !((u32)C_FLAG); \ + reg[dest].I = res; +#endif +#ifndef OP_RSCS + #define OP_RSCS OP_RSC C_CHECK_PC(C_SETCOND_SUB) +#endif +#ifndef OP_TST + #define OP_TST \ + u32 res = reg[(opcode >> 16) & 0x0F].I & value; \ + C_SETCOND_LOGICAL; +#endif +#ifndef OP_TEQ + #define OP_TEQ \ + u32 res = reg[(opcode >> 16) & 0x0F].I ^ value; \ + C_SETCOND_LOGICAL; +#endif +#ifndef OP_CMP + #define OP_CMP \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = lhs - rhs; \ + C_SETCOND_SUB; +#endif +#ifndef OP_CMN + #define OP_CMN \ + u32 lhs = reg[(opcode>>16)&15].I; \ + u32 rhs = value; \ + u32 res = lhs + rhs; \ + C_SETCOND_ADD; +#endif +#ifndef OP_ORR + #define OP_ORR \ + u32 res = reg[(opcode >> 16) & 0x0F].I | value; \ + reg[dest].I = res; +#endif +#ifndef OP_ORRS + #define OP_ORRS OP_ORR C_CHECK_PC(C_SETCOND_LOGICAL) +#endif +#ifndef OP_MOV + #define OP_MOV \ + u32 res = value; \ + reg[dest].I = res; +#endif +#ifndef OP_MOVS + #define OP_MOVS OP_MOV C_CHECK_PC(C_SETCOND_LOGICAL) +#endif +#ifndef OP_BIC + #define OP_BIC \ + u32 res = reg[(opcode >> 16) & 0x0F].I & (~value); \ + reg[dest].I = res; +#endif +#ifndef OP_BICS + #define OP_BICS OP_BIC C_CHECK_PC(C_SETCOND_LOGICAL) +#endif +#ifndef OP_MVN + #define OP_MVN \ + u32 res = ~value; \ + reg[dest].I = res; +#endif +#ifndef OP_MVNS + #define OP_MVNS OP_MVN C_CHECK_PC(C_SETCOND_LOGICAL) +#endif + +#ifndef SETCOND_NONE + #define SETCOND_NONE /*nothing*/ +#endif +#ifndef SETCOND_MUL + #define SETCOND_MUL \ + N_FLAG = ((s32)reg[dest].I < 0) ? true : false; \ + Z_FLAG = reg[dest].I ? false : true; +#endif +#ifndef SETCOND_MULL + #define SETCOND_MULL \ + N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\ + Z_FLAG = reg[dest].I || reg[acc].I ? false : true; +#endif + +#ifndef ALU_FINISH + #define ALU_FINISH /*nothing*/ +#endif + +#ifndef ROR_IMM_MSR + #define ROR_IMM_MSR \ + u32 v = opcode & 0xff; \ + value = ((v << (32 - shift)) | (v >> shift)); +#endif +#ifndef ROR_OFFSET + #define ROR_OFFSET \ + offset = ((offset << (32 - shift)) | (offset >> shift)); +#endif +#ifndef RRX_OFFSET + #define RRX_OFFSET \ + offset = ((offset >> 1) | ((int)C_FLAG << 31)); +#endif + +// ALU ops (except multiply) ////////////////////////////////////////////// + +// ALU_INIT: init code (ALU_INIT_C or ALU_INIT_NC) +// GETVALUE: load value and shift/rotate (VALUE_XXX) +// OP: ALU operation (OP_XXX) +// MODECHANGE: MODECHANGE_NO or MODECHANGE_YES +// ISREGSHIFT: 1 for insns of the form ...,Rn LSL/etc Rs; 0 otherwise +// ALU_INIT, GETVALUE, OP, and ALU_FINISH are concatenated in order. +#define ALU_INSN(ALU_INIT, GETVALUE, OP, MODECHANGE, ISREGSHIFT) \ + ALU_INIT GETVALUE OP ALU_FINISH; \ + if (LIKELY((opcode & 0x0000F000) != 0x0000F000)) { \ + clockTicks = 1 + ISREGSHIFT \ + + codeTicksAccessSeq32(armNextPC); \ + } else { \ + MODECHANGE; \ + if (armState) { \ + reg[15].I &= 0xFFFFFFFC; \ + armNextPC = reg[15].I; \ + reg[15].I += 4; \ + ARM_PREFETCH; \ + } else { \ + reg[15].I &= 0xFFFFFFFE; \ + armNextPC = reg[15].I; \ + reg[15].I += 2; \ + THUMB_PREFETCH; \ + } \ + clockTicks = 3 + ISREGSHIFT \ + + codeTicksAccess32(armNextPC) \ + + codeTicksAccessSeq32(armNextPC) \ + + codeTicksAccessSeq32(armNextPC); \ + } + +#define MODECHANGE_NO /*nothing*/ +#define MODECHANGE_YES CPUSwitchMode(reg[17].I & 0x1f, false); + +#define DEFINE_ALU_INSN_C(CODE1, CODE2, OP, MODECHANGE) \ + static INSN_REGPARM void arm##CODE1##0(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSL_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##1(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSL_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE1##2(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##3(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE1##4(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ASR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##5(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ASR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE1##6(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ROR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##7(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ROR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE2##0(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); } +#define DEFINE_ALU_INSN_NC(CODE1, CODE2, OP, MODECHANGE) \ + static INSN_REGPARM void arm##CODE1##0(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSL_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##1(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSL_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE1##2(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##3(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE1##4(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ASR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##5(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ASR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE1##6(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ROR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\ + static INSN_REGPARM void arm##CODE1##7(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ROR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\ + static INSN_REGPARM void arm##CODE2##0(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); } + +// AND +DEFINE_ALU_INSN_NC(00, 20, AND, NO) +// ANDS +DEFINE_ALU_INSN_C (01, 21, ANDS, YES) + +// EOR +DEFINE_ALU_INSN_NC(02, 22, EOR, NO) +// EORS +DEFINE_ALU_INSN_C (03, 23, EORS, YES) + +// SUB +DEFINE_ALU_INSN_NC(04, 24, SUB, NO) +// SUBS +DEFINE_ALU_INSN_NC(05, 25, SUBS, YES) + +// RSB +DEFINE_ALU_INSN_NC(06, 26, RSB, NO) +// RSBS +DEFINE_ALU_INSN_NC(07, 27, RSBS, YES) + +// ADD +DEFINE_ALU_INSN_NC(08, 28, ADD, NO) +// ADDS +DEFINE_ALU_INSN_NC(09, 29, ADDS, YES) + +// ADC +DEFINE_ALU_INSN_NC(0A, 2A, ADC, NO) +// ADCS +DEFINE_ALU_INSN_NC(0B, 2B, ADCS, YES) + +// SBC +DEFINE_ALU_INSN_NC(0C, 2C, SBC, NO) +// SBCS +DEFINE_ALU_INSN_NC(0D, 2D, SBCS, YES) + +// RSC +DEFINE_ALU_INSN_NC(0E, 2E, RSC, NO) +// RSCS +DEFINE_ALU_INSN_NC(0F, 2F, RSCS, YES) + +// TST +DEFINE_ALU_INSN_C (11, 31, TST, NO) + +// TEQ +DEFINE_ALU_INSN_C (13, 33, TEQ, NO) + +// CMP +DEFINE_ALU_INSN_NC(15, 35, CMP, NO) + +// CMN +DEFINE_ALU_INSN_NC(17, 37, CMN, NO) + +// ORR +DEFINE_ALU_INSN_NC(18, 38, ORR, NO) +// ORRS +DEFINE_ALU_INSN_C (19, 39, ORRS, YES) + +// MOV +DEFINE_ALU_INSN_NC(1A, 3A, MOV, NO) +// MOVS +DEFINE_ALU_INSN_C (1B, 3B, MOVS, YES) + +// BIC +DEFINE_ALU_INSN_NC(1C, 3C, BIC, NO) +// BICS +DEFINE_ALU_INSN_C (1D, 3D, BICS, YES) + +// MVN +DEFINE_ALU_INSN_NC(1E, 3E, MVN, NO) +// MVNS +DEFINE_ALU_INSN_C (1F, 3F, MVNS, YES) + +// Multiply instructions ////////////////////////////////////////////////// + +// OP: OP_MUL, OP_MLA etc. +// SETCOND: SETCOND_NONE, SETCOND_MUL, or SETCOND_MULL +// CYCLES: base cycle count (1, 2, or 3) +#define MUL_INSN(OP, SETCOND, CYCLES) \ + int mult = (opcode & 0x0F); \ + u32 rs = reg[(opcode >> 8) & 0x0F].I; \ + int acc = (opcode >> 12) & 0x0F; /* or destLo */ \ + int dest = (opcode >> 16) & 0x0F; /* or destHi */ \ + OP; \ + SETCOND; \ + if ((s32)rs < 0) \ + rs = ~rs; \ + if ((rs & 0xFFFFFF00) == 0) \ + clockTicks += 0; \ + else if ((rs & 0xFFFF0000) == 0) \ + clockTicks += 1; \ + else if ((rs & 0xFF000000) == 0) \ + clockTicks += 2; \ + else \ + clockTicks += 3; \ + if (busPrefetchCount == 0) \ + busPrefetchCount = ((busPrefetchCount+1)<> 32); +#define OP_MLAL(SIGN) \ + SIGN##64 res = ((SIGN##64)reg[dest].I<<32 | reg[acc].I)\ + + ((SIGN##64)(SIGN##32)reg[mult].I \ + * (SIGN##64)(SIGN##32)rs); \ + reg[acc].I = (u32)res; \ + reg[dest].I = (u32)(res >> 32); +#define OP_UMULL OP_MULL(u) +#define OP_UMLAL OP_MLAL(u) +#define OP_SMULL OP_MULL(s) +#define OP_SMLAL OP_MLAL(s) + +// MUL Rd, Rm, Rs +static INSN_REGPARM void arm009(u32 opcode) { MUL_INSN(OP_MUL, SETCOND_NONE, 1); } +// MULS Rd, Rm, Rs +static INSN_REGPARM void arm019(u32 opcode) { MUL_INSN(OP_MUL, SETCOND_MUL, 1); } + +// MLA Rd, Rm, Rs, Rn +static INSN_REGPARM void arm029(u32 opcode) { MUL_INSN(OP_MLA, SETCOND_NONE, 2); } +// MLAS Rd, Rm, Rs, Rn +static INSN_REGPARM void arm039(u32 opcode) { MUL_INSN(OP_MLA, SETCOND_MUL, 2); } + +// UMULL RdLo, RdHi, Rn, Rs +static INSN_REGPARM void arm089(u32 opcode) { MUL_INSN(OP_UMULL, SETCOND_NONE, 2); } +// UMULLS RdLo, RdHi, Rn, Rs +static INSN_REGPARM void arm099(u32 opcode) { MUL_INSN(OP_UMULL, SETCOND_MULL, 2); } + +// UMLAL RdLo, RdHi, Rn, Rs +static INSN_REGPARM void arm0A9(u32 opcode) { MUL_INSN(OP_UMLAL, SETCOND_NONE, 3); } +// UMLALS RdLo, RdHi, Rn, Rs +static INSN_REGPARM void arm0B9(u32 opcode) { MUL_INSN(OP_UMLAL, SETCOND_MULL, 3); } + +// SMULL RdLo, RdHi, Rm, Rs +static INSN_REGPARM void arm0C9(u32 opcode) { MUL_INSN(OP_SMULL, SETCOND_NONE, 2); } +// SMULLS RdLo, RdHi, Rm, Rs +static INSN_REGPARM void arm0D9(u32 opcode) { MUL_INSN(OP_SMULL, SETCOND_MULL, 2); } + +// SMLAL RdLo, RdHi, Rm, Rs +static INSN_REGPARM void arm0E9(u32 opcode) { MUL_INSN(OP_SMLAL, SETCOND_NONE, 3); } +// SMLALS RdLo, RdHi, Rm, Rs +static INSN_REGPARM void arm0F9(u32 opcode) { MUL_INSN(OP_SMLAL, SETCOND_MULL, 3); } + +// Misc instructions ////////////////////////////////////////////////////// + +// SWP Rd, Rm, [Rn] +static INSN_REGPARM void arm109(u32 opcode) +{ + u32 address = reg[(opcode >> 16) & 15].I; + u32 temp = CPUReadMemory(address); + CPUWriteMemory(address, reg[opcode&15].I); + reg[(opcode >> 12) & 15].I = temp; + clockTicks = 4 + dataTicksAccess32(address) + dataTicksAccess32(address) + + codeTicksAccess32(armNextPC); +} + +// SWPB Rd, Rm, [Rn] +static INSN_REGPARM void arm149(u32 opcode) +{ + u32 address = reg[(opcode >> 16) & 15].I; + u32 temp = CPUReadByte(address); + CPUWriteByte(address, reg[opcode&15].B.B0); + reg[(opcode>>12)&15].I = temp; + clockTicks = 4 + dataTicksAccess32(address) + dataTicksAccess32(address) + + codeTicksAccess32(armNextPC); +} + +// MRS Rd, CPSR +static INSN_REGPARM void arm100(u32 opcode) +{ + if (LIKELY((opcode & 0x0FFF0FFF) == 0x010F0000)) { + CPUUpdateCPSR(); + reg[(opcode >> 12) & 0x0F].I = reg[16].I; + } else { + armUnknownInsn(opcode); + } +} + +// MRS Rd, SPSR +static INSN_REGPARM void arm140(u32 opcode) +{ + if (LIKELY((opcode & 0x0FFF0FFF) == 0x014F0000)) { + reg[(opcode >> 12) & 0x0F].I = reg[17].I; + } else { + armUnknownInsn(opcode); + } +} + +// MSR CPSR_fields, Rm +static INSN_REGPARM void arm120(u32 opcode) +{ + if (LIKELY((opcode & 0x0FF0FFF0) == 0x0120F000)) { + CPUUpdateCPSR(); + u32 value = reg[opcode & 15].I; + u32 newValue = reg[16].I; + if (armMode > 0x10) { + if (opcode & 0x00010000) + newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF); + if (opcode & 0x00020000) + newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00); + if (opcode & 0x00040000) + newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000); + } + if (opcode & 0x00080000) + newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000); + newValue |= 0x10; + CPUSwitchMode(newValue & 0x1F, false); + reg[16].I = newValue; + CPUUpdateFlags(); + if (!armState) { // this should not be allowed, but it seems to work + THUMB_PREFETCH; + reg[15].I = armNextPC + 2; + } + } else { + armUnknownInsn(opcode); + } +} + +// MSR SPSR_fields, Rm +static INSN_REGPARM void arm160(u32 opcode) +{ + if (LIKELY((opcode & 0x0FF0FFF0) == 0x0160F000)) { + u32 value = reg[opcode & 15].I; + if (armMode > 0x10 && armMode < 0x1F) { + if (opcode & 0x00010000) + reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF); + if (opcode & 0x00020000) + reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00); + if (opcode & 0x00040000) + reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000); + if (opcode & 0x00080000) + reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000); + } + } else { + armUnknownInsn(opcode); + } +} + +// MSR CPSR_fields, # +static INSN_REGPARM void arm320(u32 opcode) +{ + if (LIKELY((opcode & 0x0FF0F000) == 0x0320F000)) { + CPUUpdateCPSR(); + u32 value = opcode & 0xFF; + int shift = (opcode & 0xF00) >> 7; + if (shift) { + ROR_IMM_MSR; + } + u32 newValue = reg[16].I; + if (armMode > 0x10) { + if (opcode & 0x00010000) + newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF); + if (opcode & 0x00020000) + newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00); + if (opcode & 0x00040000) + newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000); + } + if (opcode & 0x00080000) + newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000); + + newValue |= 0x10; + + CPUSwitchMode(newValue & 0x1F, false); + reg[16].I = newValue; + CPUUpdateFlags(); + if (!armState) { // this should not be allowed, but it seems to work + THUMB_PREFETCH; + reg[15].I = armNextPC + 2; + } + } else { + armUnknownInsn(opcode); + } +} + +// MSR SPSR_fields, # +static INSN_REGPARM void arm360(u32 opcode) +{ + if (LIKELY((opcode & 0x0FF0F000) == 0x0360F000)) { + if (armMode > 0x10 && armMode < 0x1F) { + u32 value = opcode & 0xFF; + int shift = (opcode & 0xF00) >> 7; + if (shift) { + ROR_IMM_MSR; + } + if (opcode & 0x00010000) + reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF); + if (opcode & 0x00020000) + reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00); + if (opcode & 0x00040000) + reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000); + if (opcode & 0x00080000) + reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000); + } + } else { + armUnknownInsn(opcode); + } +} + +// BX Rm +static INSN_REGPARM void arm121(u32 opcode) +{ + if (LIKELY((opcode & 0x0FFFFFF0) == 0x012FFF10)) { + int base = opcode & 0x0F; + busPrefetchCount = 0; + armState = reg[base].I & 1 ? false : true; + if (armState) { + reg[15].I = reg[base].I & 0xFFFFFFFC; + armNextPC = reg[15].I; + reg[15].I += 4; + ARM_PREFETCH; + clockTicks = 3 + codeTicksAccessSeq32(armNextPC) + + codeTicksAccessSeq32(armNextPC) + + codeTicksAccess32(armNextPC); + } else { + reg[15].I = reg[base].I & 0xFFFFFFFE; + armNextPC = reg[15].I; + reg[15].I += 2; + THUMB_PREFETCH; + clockTicks = 3 + codeTicksAccessSeq16(armNextPC) + + codeTicksAccessSeq16(armNextPC) + + codeTicksAccess16(armNextPC); + } + } else { + armUnknownInsn(opcode); + } +} + +// Load/store ///////////////////////////////////////////////////////////// + +#define OFFSET_IMM \ + int offset = opcode & 0xFFF; +#define OFFSET_IMM8 \ + int offset = ((opcode & 0x0F) | ((opcode>>4) & 0xF0)); +#define OFFSET_REG \ + int offset = reg[opcode & 15].I; +#define OFFSET_LSL \ + int offset = reg[opcode & 15].I << ((opcode>>7) & 31); +#define OFFSET_LSR \ + int shift = (opcode >> 7) & 31; \ + int offset = shift ? reg[opcode & 15].I >> shift : 0; +#define OFFSET_ASR \ + int shift = (opcode >> 7) & 31; \ + int offset; \ + if (shift) \ + offset = (int)((s32)reg[opcode & 15].I >> shift);\ + else if (reg[opcode & 15].I & 0x80000000) \ + offset = 0xFFFFFFFF; \ + else \ + offset = 0; +#define OFFSET_ROR \ + int shift = (opcode >> 7) & 31; \ + u32 offset = reg[opcode & 15].I; \ + if (shift) { \ + ROR_OFFSET; \ + } else { \ + RRX_OFFSET; \ + } + +#define ADDRESS_POST (reg[base].I) +#define ADDRESS_PREDEC (reg[base].I - offset) +#define ADDRESS_PREINC (reg[base].I + offset) + +#define OP_STR CPUWriteMemory(address, reg[dest].I) +#define OP_STRH CPUWriteHalfWord(address, reg[dest].W.W0) +#define OP_STRB CPUWriteByte(address, reg[dest].B.B0) +#define OP_LDR reg[dest].I = CPUReadMemory(address) +#define OP_LDRH reg[dest].I = CPUReadHalfWord(address) +#define OP_LDRB reg[dest].I = CPUReadByte(address) +#define OP_LDRSH reg[dest].I = (s16)CPUReadHalfWordSigned(address) +#define OP_LDRSB reg[dest].I = (s8)CPUReadByte(address) + +#define WRITEBACK_NONE /*nothing*/ +#define WRITEBACK_PRE reg[base].I = address +#define WRITEBACK_POSTDEC reg[base].I = address - offset +#define WRITEBACK_POSTINC reg[base].I = address + offset + +#define LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS) \ + if (busPrefetchCount == 0) \ + busPrefetch = busPrefetchEnable; \ + int dest = (opcode >> 12) & 15; \ + int base = (opcode >> 16) & 15; \ + CALC_OFFSET; \ + u32 address = CALC_ADDRESS; + +#define STR(CALC_OFFSET, CALC_ADDRESS, STORE_DATA, WRITEBACK1, WRITEBACK2, SIZE) \ + LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS); \ + WRITEBACK1; \ + STORE_DATA; \ + WRITEBACK2; \ + clockTicks = 2 + dataTicksAccess##SIZE(address) \ + + codeTicksAccess32(armNextPC); +#define LDR(CALC_OFFSET, CALC_ADDRESS, LOAD_DATA, WRITEBACK, SIZE) \ + LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS); \ + LOAD_DATA; \ + if (dest != base) \ + { \ + WRITEBACK; \ + } \ + clockTicks = 0; \ + if (dest == 15) { \ + reg[15].I &= 0xFFFFFFFC; \ + armNextPC = reg[15].I; \ + reg[15].I += 4; \ + ARM_PREFETCH; \ + clockTicks += 2 + dataTicksAccessSeq32(address) \ + + dataTicksAccessSeq32(address);\ + } \ + clockTicks += 3 + dataTicksAccess##SIZE(address) \ + + codeTicksAccess32(armNextPC); +#define STR_POSTDEC(CALC_OFFSET, STORE_DATA, SIZE) \ + STR(CALC_OFFSET, ADDRESS_POST, STORE_DATA, WRITEBACK_NONE, WRITEBACK_POSTDEC, SIZE) +#define STR_POSTINC(CALC_OFFSET, STORE_DATA, SIZE) \ + STR(CALC_OFFSET, ADDRESS_POST, STORE_DATA, WRITEBACK_NONE, WRITEBACK_POSTINC, SIZE) +#define STR_PREDEC(CALC_OFFSET, STORE_DATA, SIZE) \ + STR(CALC_OFFSET, ADDRESS_PREDEC, STORE_DATA, WRITEBACK_NONE, WRITEBACK_NONE, SIZE) +#define STR_PREDEC_WB(CALC_OFFSET, STORE_DATA, SIZE) \ + STR(CALC_OFFSET, ADDRESS_PREDEC, STORE_DATA, WRITEBACK_PRE, WRITEBACK_NONE, SIZE) +#define STR_PREINC(CALC_OFFSET, STORE_DATA, SIZE) \ + STR(CALC_OFFSET, ADDRESS_PREINC, STORE_DATA, WRITEBACK_NONE, WRITEBACK_NONE, SIZE) +#define STR_PREINC_WB(CALC_OFFSET, STORE_DATA, SIZE) \ + STR(CALC_OFFSET, ADDRESS_PREINC, STORE_DATA, WRITEBACK_PRE, WRITEBACK_NONE, SIZE) +#define LDR_POSTDEC(CALC_OFFSET, LOAD_DATA, SIZE) \ + LDR(CALC_OFFSET, ADDRESS_POST, LOAD_DATA, WRITEBACK_POSTDEC, SIZE) +#define LDR_POSTINC(CALC_OFFSET, LOAD_DATA, SIZE) \ + LDR(CALC_OFFSET, ADDRESS_POST, LOAD_DATA, WRITEBACK_POSTINC, SIZE) +#define LDR_PREDEC(CALC_OFFSET, LOAD_DATA, SIZE) \ + LDR(CALC_OFFSET, ADDRESS_PREDEC, LOAD_DATA, WRITEBACK_NONE, SIZE) +#define LDR_PREDEC_WB(CALC_OFFSET, LOAD_DATA, SIZE) \ + LDR(CALC_OFFSET, ADDRESS_PREDEC, LOAD_DATA, WRITEBACK_PRE, SIZE) +#define LDR_PREINC(CALC_OFFSET, LOAD_DATA, SIZE) \ + LDR(CALC_OFFSET, ADDRESS_PREINC, LOAD_DATA, WRITEBACK_NONE, SIZE) +#define LDR_PREINC_WB(CALC_OFFSET, LOAD_DATA, SIZE) \ + LDR(CALC_OFFSET, ADDRESS_PREINC, LOAD_DATA, WRITEBACK_PRE, SIZE) + +// STRH Rd, [Rn], -Rm +static INSN_REGPARM void arm00B(u32 opcode) { STR_POSTDEC(OFFSET_REG, OP_STRH, 16); } +// STRH Rd, [Rn], #-offset +static INSN_REGPARM void arm04B(u32 opcode) { STR_POSTDEC(OFFSET_IMM8, OP_STRH, 16); } +// STRH Rd, [Rn], Rm +static INSN_REGPARM void arm08B(u32 opcode) { STR_POSTINC(OFFSET_REG, OP_STRH, 16); } +// STRH Rd, [Rn], #offset +static INSN_REGPARM void arm0CB(u32 opcode) { STR_POSTINC(OFFSET_IMM8, OP_STRH, 16); } +// STRH Rd, [Rn, -Rm] +static INSN_REGPARM void arm10B(u32 opcode) { STR_PREDEC(OFFSET_REG, OP_STRH, 16); } +// STRH Rd, [Rn, -Rm]! +static INSN_REGPARM void arm12B(u32 opcode) { STR_PREDEC_WB(OFFSET_REG, OP_STRH, 16); } +// STRH Rd, [Rn, -#offset] +static INSN_REGPARM void arm14B(u32 opcode) { STR_PREDEC(OFFSET_IMM8, OP_STRH, 16); } +// STRH Rd, [Rn, -#offset]! +static INSN_REGPARM void arm16B(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM8, OP_STRH, 16); } +// STRH Rd, [Rn, Rm] +static INSN_REGPARM void arm18B(u32 opcode) { STR_PREINC(OFFSET_REG, OP_STRH, 16); } +// STRH Rd, [Rn, Rm]! +static INSN_REGPARM void arm1AB(u32 opcode) { STR_PREINC_WB(OFFSET_REG, OP_STRH, 16); } +// STRH Rd, [Rn, #offset] +static INSN_REGPARM void arm1CB(u32 opcode) { STR_PREINC(OFFSET_IMM8, OP_STRH, 16); } +// STRH Rd, [Rn, #offset]! +static INSN_REGPARM void arm1EB(u32 opcode) { STR_PREINC_WB(OFFSET_IMM8, OP_STRH, 16); } + +// LDRH Rd, [Rn], -Rm +static INSN_REGPARM void arm01B(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRH, 16); } +// LDRH Rd, [Rn], #-offset +static INSN_REGPARM void arm05B(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRH, 16); } +// LDRH Rd, [Rn], Rm +static INSN_REGPARM void arm09B(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRH, 16); } +// LDRH Rd, [Rn], #offset +static INSN_REGPARM void arm0DB(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRH, 16); } +// LDRH Rd, [Rn, -Rm] +static INSN_REGPARM void arm11B(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRH, 16); } +// LDRH Rd, [Rn, -Rm]! +static INSN_REGPARM void arm13B(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRH, 16); } +// LDRH Rd, [Rn, -#offset] +static INSN_REGPARM void arm15B(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRH, 16); } +// LDRH Rd, [Rn, -#offset]! +static INSN_REGPARM void arm17B(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRH, 16); } +// LDRH Rd, [Rn, Rm] +static INSN_REGPARM void arm19B(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRH, 16); } +// LDRH Rd, [Rn, Rm]! +static INSN_REGPARM void arm1BB(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRH, 16); } +// LDRH Rd, [Rn, #offset] +static INSN_REGPARM void arm1DB(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRH, 16); } +// LDRH Rd, [Rn, #offset]! +static INSN_REGPARM void arm1FB(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRH, 16); } + +// LDRSB Rd, [Rn], -Rm +static INSN_REGPARM void arm01D(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRSB, 16); } +// LDRSB Rd, [Rn], #-offset +static INSN_REGPARM void arm05D(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRSB, 16); } +// LDRSB Rd, [Rn], Rm +static INSN_REGPARM void arm09D(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRSB, 16); } +// LDRSB Rd, [Rn], #offset +static INSN_REGPARM void arm0DD(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, -Rm] +static INSN_REGPARM void arm11D(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, -Rm]! +static INSN_REGPARM void arm13D(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, -#offset] +static INSN_REGPARM void arm15D(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, -#offset]! +static INSN_REGPARM void arm17D(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, Rm] +static INSN_REGPARM void arm19D(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, Rm]! +static INSN_REGPARM void arm1BD(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, #offset] +static INSN_REGPARM void arm1DD(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRSB, 16); } +// LDRSB Rd, [Rn, #offset]! +static INSN_REGPARM void arm1FD(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRSB, 16); } + +// LDRSH Rd, [Rn], -Rm +static INSN_REGPARM void arm01F(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRSH, 16); } +// LDRSH Rd, [Rn], #-offset +static INSN_REGPARM void arm05F(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRSH, 16); } +// LDRSH Rd, [Rn], Rm +static INSN_REGPARM void arm09F(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRSH, 16); } +// LDRSH Rd, [Rn], #offset +static INSN_REGPARM void arm0DF(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, -Rm] +static INSN_REGPARM void arm11F(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, -Rm]! +static INSN_REGPARM void arm13F(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, -#offset] +static INSN_REGPARM void arm15F(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, -#offset]! +static INSN_REGPARM void arm17F(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, Rm] +static INSN_REGPARM void arm19F(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, Rm]! +static INSN_REGPARM void arm1BF(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, #offset] +static INSN_REGPARM void arm1DF(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRSH, 16); } +// LDRSH Rd, [Rn, #offset]! +static INSN_REGPARM void arm1FF(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRSH, 16); } + +// STR[T] Rd, [Rn], -# +// Note: STR and STRT do the same thing on the GBA (likewise for LDR/LDRT etc) +static INSN_REGPARM void arm400(u32 opcode) { STR_POSTDEC(OFFSET_IMM, OP_STR, 32); } +// LDR[T] Rd, [Rn], -# +static INSN_REGPARM void arm410(u32 opcode) { LDR_POSTDEC(OFFSET_IMM, OP_LDR, 32); } +// STRB[T] Rd, [Rn], -# +static INSN_REGPARM void arm440(u32 opcode) { STR_POSTDEC(OFFSET_IMM, OP_STRB, 16); } +// LDRB[T] Rd, [Rn], -# +static INSN_REGPARM void arm450(u32 opcode) { LDR_POSTDEC(OFFSET_IMM, OP_LDRB, 16); } +// STR[T] Rd, [Rn], # +static INSN_REGPARM void arm480(u32 opcode) { STR_POSTINC(OFFSET_IMM, OP_STR, 32); } +// LDR Rd, [Rn], # +static INSN_REGPARM void arm490(u32 opcode) { LDR_POSTINC(OFFSET_IMM, OP_LDR, 32); } +// STRB[T] Rd, [Rn], # +static INSN_REGPARM void arm4C0(u32 opcode) { STR_POSTINC(OFFSET_IMM, OP_STRB, 16); } +// LDRB[T] Rd, [Rn], # +static INSN_REGPARM void arm4D0(u32 opcode) { LDR_POSTINC(OFFSET_IMM, OP_LDRB, 16); } +// STR Rd, [Rn, -#] +static INSN_REGPARM void arm500(u32 opcode) { STR_PREDEC(OFFSET_IMM, OP_STR, 32); } +// LDR Rd, [Rn, -#] +static INSN_REGPARM void arm510(u32 opcode) { LDR_PREDEC(OFFSET_IMM, OP_LDR, 32); } +// STR Rd, [Rn, -#]! +static INSN_REGPARM void arm520(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM, OP_STR, 32); } +// LDR Rd, [Rn, -#]! +static INSN_REGPARM void arm530(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM, OP_LDR, 32); } +// STRB Rd, [Rn, -#] +static INSN_REGPARM void arm540(u32 opcode) { STR_PREDEC(OFFSET_IMM, OP_STRB, 16); } +// LDRB Rd, [Rn, -#] +static INSN_REGPARM void arm550(u32 opcode) { LDR_PREDEC(OFFSET_IMM, OP_LDRB, 16); } +// STRB Rd, [Rn, -#]! +static INSN_REGPARM void arm560(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM, OP_STRB, 16); } +// LDRB Rd, [Rn, -#]! +static INSN_REGPARM void arm570(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM, OP_LDRB, 16); } +// STR Rd, [Rn, #] +static INSN_REGPARM void arm580(u32 opcode) { STR_PREINC(OFFSET_IMM, OP_STR, 32); } +// LDR Rd, [Rn, #] +static INSN_REGPARM void arm590(u32 opcode) { LDR_PREINC(OFFSET_IMM, OP_LDR, 32); } +// STR Rd, [Rn, #]! +static INSN_REGPARM void arm5A0(u32 opcode) { STR_PREINC_WB(OFFSET_IMM, OP_STR, 32); } +// LDR Rd, [Rn, #]! +static INSN_REGPARM void arm5B0(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM, OP_LDR, 32); } +// STRB Rd, [Rn, #] +static INSN_REGPARM void arm5C0(u32 opcode) { STR_PREINC(OFFSET_IMM, OP_STRB, 16); } +// LDRB Rd, [Rn, #] +static INSN_REGPARM void arm5D0(u32 opcode) { LDR_PREINC(OFFSET_IMM, OP_LDRB, 16); } +// STRB Rd, [Rn, #]! +static INSN_REGPARM void arm5E0(u32 opcode) { STR_PREINC_WB(OFFSET_IMM, OP_STRB, 16); } +// LDRB Rd, [Rn, #]! +static INSN_REGPARM void arm5F0(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM, OP_LDRB, 16); } + +// STR[T] Rd, [Rn], -Rm, LSL # +static INSN_REGPARM void arm600(u32 opcode) { STR_POSTDEC(OFFSET_LSL, OP_STR, 32); } +// STR[T] Rd, [Rn], -Rm, LSR # +static INSN_REGPARM void arm602(u32 opcode) { STR_POSTDEC(OFFSET_LSR, OP_STR, 32); } +// STR[T] Rd, [Rn], -Rm, ASR # +static INSN_REGPARM void arm604(u32 opcode) { STR_POSTDEC(OFFSET_ASR, OP_STR, 32); } +// STR[T] Rd, [Rn], -Rm, ROR # +static INSN_REGPARM void arm606(u32 opcode) { STR_POSTDEC(OFFSET_ROR, OP_STR, 32); } +// LDR[T] Rd, [Rn], -Rm, LSL # +static INSN_REGPARM void arm610(u32 opcode) { LDR_POSTDEC(OFFSET_LSL, OP_LDR, 32); } +// LDR[T] Rd, [Rn], -Rm, LSR # +static INSN_REGPARM void arm612(u32 opcode) { LDR_POSTDEC(OFFSET_LSR, OP_LDR, 32); } +// LDR[T] Rd, [Rn], -Rm, ASR # +static INSN_REGPARM void arm614(u32 opcode) { LDR_POSTDEC(OFFSET_ASR, OP_LDR, 32); } +// LDR[T] Rd, [Rn], -Rm, ROR # +static INSN_REGPARM void arm616(u32 opcode) { LDR_POSTDEC(OFFSET_ROR, OP_LDR, 32); } +// STRB[T] Rd, [Rn], -Rm, LSL # +static INSN_REGPARM void arm640(u32 opcode) { STR_POSTDEC(OFFSET_LSL, OP_STRB, 16); } +// STRB[T] Rd, [Rn], -Rm, LSR # +static INSN_REGPARM void arm642(u32 opcode) { STR_POSTDEC(OFFSET_LSR, OP_STRB, 16); } +// STRB[T] Rd, [Rn], -Rm, ASR # +static INSN_REGPARM void arm644(u32 opcode) { STR_POSTDEC(OFFSET_ASR, OP_STRB, 16); } +// STRB[T] Rd, [Rn], -Rm, ROR # +static INSN_REGPARM void arm646(u32 opcode) { STR_POSTDEC(OFFSET_ROR, OP_STRB, 16); } +// LDRB[T] Rd, [Rn], -Rm, LSL # +static INSN_REGPARM void arm650(u32 opcode) { LDR_POSTDEC(OFFSET_LSL, OP_LDRB, 16); } +// LDRB[T] Rd, [Rn], -Rm, LSR # +static INSN_REGPARM void arm652(u32 opcode) { LDR_POSTDEC(OFFSET_LSR, OP_LDRB, 16); } +// LDRB[T] Rd, [Rn], -Rm, ASR # +static INSN_REGPARM void arm654(u32 opcode) { LDR_POSTDEC(OFFSET_ASR, OP_LDRB, 16); } +// LDRB Rd, [Rn], -Rm, ROR # +static INSN_REGPARM void arm656(u32 opcode) { LDR_POSTDEC(OFFSET_ROR, OP_LDRB, 16); } +// STR[T] Rd, [Rn], Rm, LSL # +static INSN_REGPARM void arm680(u32 opcode) { STR_POSTINC(OFFSET_LSL, OP_STR, 32); } +// STR[T] Rd, [Rn], Rm, LSR # +static INSN_REGPARM void arm682(u32 opcode) { STR_POSTINC(OFFSET_LSR, OP_STR, 32); } +// STR[T] Rd, [Rn], Rm, ASR # +static INSN_REGPARM void arm684(u32 opcode) { STR_POSTINC(OFFSET_ASR, OP_STR, 32); } +// STR[T] Rd, [Rn], Rm, ROR # +static INSN_REGPARM void arm686(u32 opcode) { STR_POSTINC(OFFSET_ROR, OP_STR, 32); } +// LDR[T] Rd, [Rn], Rm, LSL # +static INSN_REGPARM void arm690(u32 opcode) { LDR_POSTINC(OFFSET_LSL, OP_LDR, 32); } +// LDR[T] Rd, [Rn], Rm, LSR # +static INSN_REGPARM void arm692(u32 opcode) { LDR_POSTINC(OFFSET_LSR, OP_LDR, 32); } +// LDR[T] Rd, [Rn], Rm, ASR # +static INSN_REGPARM void arm694(u32 opcode) { LDR_POSTINC(OFFSET_ASR, OP_LDR, 32); } +// LDR[T] Rd, [Rn], Rm, ROR # +static INSN_REGPARM void arm696(u32 opcode) { LDR_POSTINC(OFFSET_ROR, OP_LDR, 32); } +// STRB[T] Rd, [Rn], Rm, LSL # +static INSN_REGPARM void arm6C0(u32 opcode) { STR_POSTINC(OFFSET_LSL, OP_STRB, 16); } +// STRB[T] Rd, [Rn], Rm, LSR # +static INSN_REGPARM void arm6C2(u32 opcode) { STR_POSTINC(OFFSET_LSR, OP_STRB, 16); } +// STRB[T] Rd, [Rn], Rm, ASR # +static INSN_REGPARM void arm6C4(u32 opcode) { STR_POSTINC(OFFSET_ASR, OP_STRB, 16); } +// STRB[T] Rd, [Rn], Rm, ROR # +static INSN_REGPARM void arm6C6(u32 opcode) { STR_POSTINC(OFFSET_ROR, OP_STRB, 16); } +// LDRB[T] Rd, [Rn], Rm, LSL # +static INSN_REGPARM void arm6D0(u32 opcode) { LDR_POSTINC(OFFSET_LSL, OP_LDRB, 16); } +// LDRB[T] Rd, [Rn], Rm, LSR # +static INSN_REGPARM void arm6D2(u32 opcode) { LDR_POSTINC(OFFSET_LSR, OP_LDRB, 16); } +// LDRB[T] Rd, [Rn], Rm, ASR # +static INSN_REGPARM void arm6D4(u32 opcode) { LDR_POSTINC(OFFSET_ASR, OP_LDRB, 16); } +// LDRB[T] Rd, [Rn], Rm, ROR # +static INSN_REGPARM void arm6D6(u32 opcode) { LDR_POSTINC(OFFSET_ROR, OP_LDRB, 16); } +// STR Rd, [Rn, -Rm, LSL #] +static INSN_REGPARM void arm700(u32 opcode) { STR_PREDEC(OFFSET_LSL, OP_STR, 32); } +// STR Rd, [Rn, -Rm, LSR #] +static INSN_REGPARM void arm702(u32 opcode) { STR_PREDEC(OFFSET_LSR, OP_STR, 32); } +// STR Rd, [Rn, -Rm, ASR #] +static INSN_REGPARM void arm704(u32 opcode) { STR_PREDEC(OFFSET_ASR, OP_STR, 32); } +// STR Rd, [Rn, -Rm, ROR #] +static INSN_REGPARM void arm706(u32 opcode) { STR_PREDEC(OFFSET_ROR, OP_STR, 32); } +// LDR Rd, [Rn, -Rm, LSL #] +static INSN_REGPARM void arm710(u32 opcode) { LDR_PREDEC(OFFSET_LSL, OP_LDR, 32); } +// LDR Rd, [Rn, -Rm, LSR #] +static INSN_REGPARM void arm712(u32 opcode) { LDR_PREDEC(OFFSET_LSR, OP_LDR, 32); } +// LDR Rd, [Rn, -Rm, ASR #] +static INSN_REGPARM void arm714(u32 opcode) { LDR_PREDEC(OFFSET_ASR, OP_LDR, 32); } +// LDR Rd, [Rn, -Rm, ROR #] +static INSN_REGPARM void arm716(u32 opcode) { LDR_PREDEC(OFFSET_ROR, OP_LDR, 32); } +// STR Rd, [Rn, -Rm, LSL #]! +static INSN_REGPARM void arm720(u32 opcode) { STR_PREDEC_WB(OFFSET_LSL, OP_STR, 32); } +// STR Rd, [Rn, -Rm, LSR #]! +static INSN_REGPARM void arm722(u32 opcode) { STR_PREDEC_WB(OFFSET_LSR, OP_STR, 32); } +// STR Rd, [Rn, -Rm, ASR #]! +static INSN_REGPARM void arm724(u32 opcode) { STR_PREDEC_WB(OFFSET_ASR, OP_STR, 32); } +// STR Rd, [Rn, -Rm, ROR #]! +static INSN_REGPARM void arm726(u32 opcode) { STR_PREDEC_WB(OFFSET_ROR, OP_STR, 32); } +// LDR Rd, [Rn, -Rm, LSL #]! +static INSN_REGPARM void arm730(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSL, OP_LDR, 32); } +// LDR Rd, [Rn, -Rm, LSR #]! +static INSN_REGPARM void arm732(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSR, OP_LDR, 32); } +// LDR Rd, [Rn, -Rm, ASR #]! +static INSN_REGPARM void arm734(u32 opcode) { LDR_PREDEC_WB(OFFSET_ASR, OP_LDR, 32); } +// LDR Rd, [Rn, -Rm, ROR #]! +static INSN_REGPARM void arm736(u32 opcode) { LDR_PREDEC_WB(OFFSET_ROR, OP_LDR, 32); } +// STRB Rd, [Rn, -Rm, LSL #] +static INSN_REGPARM void arm740(u32 opcode) { STR_PREDEC(OFFSET_LSL, OP_STRB, 16); } +// STRB Rd, [Rn, -Rm, LSR #] +static INSN_REGPARM void arm742(u32 opcode) { STR_PREDEC(OFFSET_LSR, OP_STRB, 16); } +// STRB Rd, [Rn, -Rm, ASR #] +static INSN_REGPARM void arm744(u32 opcode) { STR_PREDEC(OFFSET_ASR, OP_STRB, 16); } +// STRB Rd, [Rn, -Rm, ROR #] +static INSN_REGPARM void arm746(u32 opcode) { STR_PREDEC(OFFSET_ROR, OP_STRB, 16); } +// LDRB Rd, [Rn, -Rm, LSL #] +static INSN_REGPARM void arm750(u32 opcode) { LDR_PREDEC(OFFSET_LSL, OP_LDRB, 16); } +// LDRB Rd, [Rn, -Rm, LSR #] +static INSN_REGPARM void arm752(u32 opcode) { LDR_PREDEC(OFFSET_LSR, OP_LDRB, 16); } +// LDRB Rd, [Rn, -Rm, ASR #] +static INSN_REGPARM void arm754(u32 opcode) { LDR_PREDEC(OFFSET_ASR, OP_LDRB, 16); } +// LDRB Rd, [Rn, -Rm, ROR #] +static INSN_REGPARM void arm756(u32 opcode) { LDR_PREDEC(OFFSET_ROR, OP_LDRB, 16); } +// STRB Rd, [Rn, -Rm, LSL #]! +static INSN_REGPARM void arm760(u32 opcode) { STR_PREDEC_WB(OFFSET_LSL, OP_STRB, 16); } +// STRB Rd, [Rn, -Rm, LSR #]! +static INSN_REGPARM void arm762(u32 opcode) { STR_PREDEC_WB(OFFSET_LSR, OP_STRB, 16); } +// STRB Rd, [Rn, -Rm, ASR #]! +static INSN_REGPARM void arm764(u32 opcode) { STR_PREDEC_WB(OFFSET_ASR, OP_STRB, 16); } +// STRB Rd, [Rn, -Rm, ROR #]! +static INSN_REGPARM void arm766(u32 opcode) { STR_PREDEC_WB(OFFSET_ROR, OP_STRB, 16); } +// LDRB Rd, [Rn, -Rm, LSL #]! +static INSN_REGPARM void arm770(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSL, OP_LDRB, 16); } +// LDRB Rd, [Rn, -Rm, LSR #]! +static INSN_REGPARM void arm772(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSR, OP_LDRB, 16); } +// LDRB Rd, [Rn, -Rm, ASR #]! +static INSN_REGPARM void arm774(u32 opcode) { LDR_PREDEC_WB(OFFSET_ASR, OP_LDRB, 16); } +// LDRB Rd, [Rn, -Rm, ROR #]! +static INSN_REGPARM void arm776(u32 opcode) { LDR_PREDEC_WB(OFFSET_ROR, OP_LDRB, 16); } +// STR Rd, [Rn, Rm, LSL #] +static INSN_REGPARM void arm780(u32 opcode) { STR_PREINC(OFFSET_LSL, OP_STR, 32); } +// STR Rd, [Rn, Rm, LSR #] +static INSN_REGPARM void arm782(u32 opcode) { STR_PREINC(OFFSET_LSR, OP_STR, 32); } +// STR Rd, [Rn, Rm, ASR #] +static INSN_REGPARM void arm784(u32 opcode) { STR_PREINC(OFFSET_ASR, OP_STR, 32); } +// STR Rd, [Rn, Rm, ROR #] +static INSN_REGPARM void arm786(u32 opcode) { STR_PREINC(OFFSET_ROR, OP_STR, 32); } +// LDR Rd, [Rn, Rm, LSL #] +static INSN_REGPARM void arm790(u32 opcode) { LDR_PREINC(OFFSET_LSL, OP_LDR, 32); } +// LDR Rd, [Rn, Rm, LSR #] +static INSN_REGPARM void arm792(u32 opcode) { LDR_PREINC(OFFSET_LSR, OP_LDR, 32); } +// LDR Rd, [Rn, Rm, ASR #] +static INSN_REGPARM void arm794(u32 opcode) { LDR_PREINC(OFFSET_ASR, OP_LDR, 32); } +// LDR Rd, [Rn, Rm, ROR #] +static INSN_REGPARM void arm796(u32 opcode) { LDR_PREINC(OFFSET_ROR, OP_LDR, 32); } +// STR Rd, [Rn, Rm, LSL #]! +static INSN_REGPARM void arm7A0(u32 opcode) { STR_PREINC_WB(OFFSET_LSL, OP_STR, 32); } +// STR Rd, [Rn, Rm, LSR #]! +static INSN_REGPARM void arm7A2(u32 opcode) { STR_PREINC_WB(OFFSET_LSR, OP_STR, 32); } +// STR Rd, [Rn, Rm, ASR #]! +static INSN_REGPARM void arm7A4(u32 opcode) { STR_PREINC_WB(OFFSET_ASR, OP_STR, 32); } +// STR Rd, [Rn, Rm, ROR #]! +static INSN_REGPARM void arm7A6(u32 opcode) { STR_PREINC_WB(OFFSET_ROR, OP_STR, 32); } +// LDR Rd, [Rn, Rm, LSL #]! +static INSN_REGPARM void arm7B0(u32 opcode) { LDR_PREINC_WB(OFFSET_LSL, OP_LDR, 32); } +// LDR Rd, [Rn, Rm, LSR #]! +static INSN_REGPARM void arm7B2(u32 opcode) { LDR_PREINC_WB(OFFSET_LSR, OP_LDR, 32); } +// LDR Rd, [Rn, Rm, ASR #]! +static INSN_REGPARM void arm7B4(u32 opcode) { LDR_PREINC_WB(OFFSET_ASR, OP_LDR, 32); } +// LDR Rd, [Rn, Rm, ROR #]! +static INSN_REGPARM void arm7B6(u32 opcode) { LDR_PREINC_WB(OFFSET_ROR, OP_LDR, 32); } +// STRB Rd, [Rn, Rm, LSL #] +static INSN_REGPARM void arm7C0(u32 opcode) { STR_PREINC(OFFSET_LSL, OP_STRB, 16); } +// STRB Rd, [Rn, Rm, LSR #] +static INSN_REGPARM void arm7C2(u32 opcode) { STR_PREINC(OFFSET_LSR, OP_STRB, 16); } +// STRB Rd, [Rn, Rm, ASR #] +static INSN_REGPARM void arm7C4(u32 opcode) { STR_PREINC(OFFSET_ASR, OP_STRB, 16); } +// STRB Rd, [Rn, Rm, ROR #] +static INSN_REGPARM void arm7C6(u32 opcode) { STR_PREINC(OFFSET_ROR, OP_STRB, 16); } +// LDRB Rd, [Rn, Rm, LSL #] +static INSN_REGPARM void arm7D0(u32 opcode) { LDR_PREINC(OFFSET_LSL, OP_LDRB, 16); } +// LDRB Rd, [Rn, Rm, LSR #] +static INSN_REGPARM void arm7D2(u32 opcode) { LDR_PREINC(OFFSET_LSR, OP_LDRB, 16); } +// LDRB Rd, [Rn, Rm, ASR #] +static INSN_REGPARM void arm7D4(u32 opcode) { LDR_PREINC(OFFSET_ASR, OP_LDRB, 16); } +// LDRB Rd, [Rn, Rm, ROR #] +static INSN_REGPARM void arm7D6(u32 opcode) { LDR_PREINC(OFFSET_ROR, OP_LDRB, 16); } +// STRB Rd, [Rn, Rm, LSL #]! +static INSN_REGPARM void arm7E0(u32 opcode) { STR_PREINC_WB(OFFSET_LSL, OP_STRB, 16); } +// STRB Rd, [Rn, Rm, LSR #]! +static INSN_REGPARM void arm7E2(u32 opcode) { STR_PREINC_WB(OFFSET_LSR, OP_STRB, 16); } +// STRB Rd, [Rn, Rm, ASR #]! +static INSN_REGPARM void arm7E4(u32 opcode) { STR_PREINC_WB(OFFSET_ASR, OP_STRB, 16); } +// STRB Rd, [Rn, Rm, ROR #]! +static INSN_REGPARM void arm7E6(u32 opcode) { STR_PREINC_WB(OFFSET_ROR, OP_STRB, 16); } +// LDRB Rd, [Rn, Rm, LSL #]! +static INSN_REGPARM void arm7F0(u32 opcode) { LDR_PREINC_WB(OFFSET_LSL, OP_LDRB, 16); } +// LDRB Rd, [Rn, Rm, LSR #]! +static INSN_REGPARM void arm7F2(u32 opcode) { LDR_PREINC_WB(OFFSET_LSR, OP_LDRB, 16); } +// LDRB Rd, [Rn, Rm, ASR #]! +static INSN_REGPARM void arm7F4(u32 opcode) { LDR_PREINC_WB(OFFSET_ASR, OP_LDRB, 16); } +// LDRB Rd, [Rn, Rm, ROR #]! +static INSN_REGPARM void arm7F6(u32 opcode) { LDR_PREINC_WB(OFFSET_ROR, OP_LDRB, 16); } + +// STM/LDM //////////////////////////////////////////////////////////////// + +#define STM_REG(bit,num) \ + if (opcode & (1U<<(bit))) { \ + CPUWriteMemory(address, reg[(num)].I); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address);\ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address);\ + } \ + count++; \ + address += 4; \ + } +#define STMW_REG(bit,num) \ + if (opcode & (1U<<(bit))) { \ + CPUWriteMemory(address, reg[(num)].I); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address);\ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address);\ + } \ + reg[base].I = temp; \ + count++; \ + address += 4; \ + } +#define LDM_REG(bit,num) \ + if (opcode & (1U<<(bit))) { \ + reg[(num)].I = CPUReadMemory(address); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address);\ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address);\ + } \ + count++; \ + address += 4; \ + } +#define STM_LOW(STORE_REG) \ + STORE_REG(0, 0); \ + STORE_REG(1, 1); \ + STORE_REG(2, 2); \ + STORE_REG(3, 3); \ + STORE_REG(4, 4); \ + STORE_REG(5, 5); \ + STORE_REG(6, 6); \ + STORE_REG(7, 7); +#define STM_HIGH(STORE_REG) \ + STORE_REG(8, 8); \ + STORE_REG(9, 9); \ + STORE_REG(10, 10); \ + STORE_REG(11, 11); \ + STORE_REG(12, 12); \ + STORE_REG(13, 13); \ + STORE_REG(14, 14); +#define STM_HIGH_2(STORE_REG) \ + if (armMode == 0x11) { \ + STORE_REG(8, R8_FIQ); \ + STORE_REG(9, R9_FIQ); \ + STORE_REG(10, R10_FIQ); \ + STORE_REG(11, R11_FIQ); \ + STORE_REG(12, R12_FIQ); \ + } else { \ + STORE_REG(8, 8); \ + STORE_REG(9, 9); \ + STORE_REG(10, 10); \ + STORE_REG(11, 11); \ + STORE_REG(12, 12); \ + } \ + if (armMode != 0x10 && armMode != 0x1F) { \ + STORE_REG(13, R13_USR); \ + STORE_REG(14, R14_USR); \ + } else { \ + STORE_REG(13, 13); \ + STORE_REG(14, 14); \ + } +#define STM_PC \ + if (opcode & (1U<<15)) { \ + CPUWriteMemory(address, reg[15].I+4); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address);\ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address);\ + } \ + count++; \ + } +#define STMW_PC \ + if (opcode & (1U<<15)) { \ + CPUWriteMemory(address, reg[15].I+4); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address);\ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address);\ + } \ + reg[base].I = temp; \ + count++; \ + } +#define LDM_LOW \ + LDM_REG(0, 0); \ + LDM_REG(1, 1); \ + LDM_REG(2, 2); \ + LDM_REG(3, 3); \ + LDM_REG(4, 4); \ + LDM_REG(5, 5); \ + LDM_REG(6, 6); \ + LDM_REG(7, 7); +#define LDM_HIGH \ + LDM_REG(8, 8); \ + LDM_REG(9, 9); \ + LDM_REG(10, 10); \ + LDM_REG(11, 11); \ + LDM_REG(12, 12); \ + LDM_REG(13, 13); \ + LDM_REG(14, 14); +#define LDM_HIGH_2 \ + if (armMode == 0x11) { \ + LDM_REG(8, R8_FIQ); \ + LDM_REG(9, R9_FIQ); \ + LDM_REG(10, R10_FIQ); \ + LDM_REG(11, R11_FIQ); \ + LDM_REG(12, R12_FIQ); \ + } else { \ + LDM_REG(8, 8); \ + LDM_REG(9, 9); \ + LDM_REG(10, 10); \ + LDM_REG(11, 11); \ + LDM_REG(12, 12); \ + } \ + if (armMode != 0x10 && armMode != 0x1F) { \ + LDM_REG(13, R13_USR); \ + LDM_REG(14, R14_USR); \ + } else { \ + LDM_REG(13, 13); \ + LDM_REG(14, 14); \ + } +#define STM_ALL \ + STM_LOW(STM_REG); \ + STM_HIGH(STM_REG); \ + STM_PC; +#define STMW_ALL \ + STM_LOW(STMW_REG); \ + STM_HIGH(STMW_REG); \ + STMW_PC; +#define LDM_ALL \ + LDM_LOW; \ + LDM_HIGH; \ + if (opcode & (1U<<15)) { \ + reg[15].I = CPUReadMemory(address); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address);\ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address);\ + } \ + count++; \ + } \ + if (opcode & (1U<<15)) { \ + armNextPC = reg[15].I; \ + reg[15].I += 4; \ + ARM_PREFETCH; \ + clockTicks += 1 + codeTicksAccessSeq32(armNextPC);\ + } +#define STM_ALL_2 \ + STM_LOW(STM_REG); \ + STM_HIGH_2(STM_REG); \ + STM_PC; +#define STMW_ALL_2 \ + STM_LOW(STMW_REG); \ + STM_HIGH_2(STMW_REG); \ + STMW_PC; +#define LDM_ALL_2 \ + LDM_LOW; \ + if (opcode & (1U<<15)) { \ + LDM_HIGH; \ + reg[15].I = CPUReadMemory(address); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address); \ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address); \ + } \ + count++; \ + } else { \ + LDM_HIGH_2; \ + } +#define LDM_ALL_2B \ + if (opcode & (1U<<15)) { \ + CPUSwitchMode(reg[17].I & 0x1F, false); \ + if (armState) { \ + armNextPC = reg[15].I & 0xFFFFFFFC; \ + reg[15].I = armNextPC + 4; \ + ARM_PREFETCH; \ + } else { \ + armNextPC = reg[15].I & 0xFFFFFFFE; \ + reg[15].I = armNextPC + 2; \ + THUMB_PREFETCH; \ + } \ + clockTicks += 1 + codeTicksAccessSeq32(armNextPC);\ + } + + +// STMDA Rn, {Rlist} +static INSN_REGPARM void arm800(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp + 4) & 0xFFFFFFFC; + int count = 0; + STM_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDA Rn, {Rlist} +static INSN_REGPARM void arm810(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp + 4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMDA Rn!, {Rlist} +static INSN_REGPARM void arm820(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp+4) & 0xFFFFFFFC; + int count = 0; + STMW_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDA Rn!, {Rlist} +static INSN_REGPARM void arm830(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp + 4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); + if (!(opcode & (1U << base))) + reg[base].I = temp; +} + +// STMDA Rn, {Rlist}^ +static INSN_REGPARM void arm840(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp+4) & 0xFFFFFFFC; + int count = 0; + STM_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDA Rn, {Rlist}^ +static INSN_REGPARM void arm850(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp + 4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMDA Rn!, {Rlist}^ +static INSN_REGPARM void arm860(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp+4) & 0xFFFFFFFC; + int count = 0; + STMW_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDA Rn!, {Rlist}^ +static INSN_REGPARM void arm870(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (temp + 4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + if (!(opcode & (1U << base))) + reg[base].I = temp; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMIA Rn, {Rlist} +static INSN_REGPARM void arm880(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + STM_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIA Rn, {Rlist} +static INSN_REGPARM void arm890(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMIA Rn!, {Rlist} +static INSN_REGPARM void arm8A0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); + STMW_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIA Rn!, {Rlist} +static INSN_REGPARM void arm8B0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); + if (!(opcode & (1U << base))) + reg[base].I = temp; +} + +// STMIA Rn, {Rlist}^ +static INSN_REGPARM void arm8C0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + STM_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIA Rn, {Rlist}^ +static INSN_REGPARM void arm8D0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMIA Rn!, {Rlist}^ +static INSN_REGPARM void arm8E0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); + STMW_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIA Rn!, {Rlist}^ +static INSN_REGPARM void arm8F0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = reg[base].I & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + if (!(opcode & (1U << base))) + reg[base].I = temp; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMDB Rn, {Rlist} +static INSN_REGPARM void arm900(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + STM_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDB Rn, {Rlist} +static INSN_REGPARM void arm910(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMDB Rn!, {Rlist} +static INSN_REGPARM void arm920(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + STMW_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDB Rn!, {Rlist} +static INSN_REGPARM void arm930(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); + if (!(opcode & (1U << base))) + reg[base].I = temp; +} + +// STMDB Rn, {Rlist}^ +static INSN_REGPARM void arm940(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + STM_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDB Rn, {Rlist}^ +static INSN_REGPARM void arm950(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMDB Rn!, {Rlist}^ +static INSN_REGPARM void arm960(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + STMW_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMDB Rn!, {Rlist}^ +static INSN_REGPARM void arm970(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I - + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = temp & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + if (!(opcode & (1U << base))) + reg[base].I = temp; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMIB Rn, {Rlist} +static INSN_REGPARM void arm980(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + STM_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIB Rn, {Rlist} +static INSN_REGPARM void arm990(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMIB Rn!, {Rlist} +static INSN_REGPARM void arm9A0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); + STMW_ALL; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIB Rn!, {Rlist} +static INSN_REGPARM void arm9B0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL; + clockTicks += 2 + codeTicksAccess32(armNextPC); + if (!(opcode & (1U << base))) + reg[base].I = temp; +} + +// STMIB Rn, {Rlist}^ +static INSN_REGPARM void arm9C0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + STM_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIB Rn, {Rlist}^ +static INSN_REGPARM void arm9D0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// STMIB Rn!, {Rlist}^ +static INSN_REGPARM void arm9E0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]); + STMW_ALL_2; + clockTicks += 1 + codeTicksAccess32(armNextPC); +} + +// LDMIB Rn!, {Rlist}^ +static INSN_REGPARM void arm9F0(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int base = (opcode & 0x000F0000) >> 16; + u32 temp = reg[base].I + + 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); + u32 address = (reg[base].I+4) & 0xFFFFFFFC; + int count = 0; + LDM_ALL_2; + if (!(opcode & (1U << base))) + reg[base].I = temp; + LDM_ALL_2B; + clockTicks += 2 + codeTicksAccess32(armNextPC); +} + +// B/BL/SWI and (unimplemented) coproc support //////////////////////////// + +// B +static INSN_REGPARM void armA00(u32 opcode) +{ + int offset = opcode & 0x00FFFFFF; + if (offset & 0x00800000) + offset |= 0xFF000000; // negative offset + reg[15].I += offset<<2; + armNextPC = reg[15].I; + reg[15].I += 4; + ARM_PREFETCH; + clockTicks = codeTicksAccessSeq32(armNextPC) + 1; + clockTicks += 2 + codeTicksAccess32(armNextPC) + + codeTicksAccessSeq32(armNextPC); + busPrefetchCount = 0; +} + +// BL +static INSN_REGPARM void armB00(u32 opcode) +{ + int offset = opcode & 0x00FFFFFF; + if (offset & 0x00800000) + offset |= 0xFF000000; // negative offset + reg[14].I = reg[15].I - 4; + reg[15].I += offset<<2; + armNextPC = reg[15].I; + reg[15].I += 4; + ARM_PREFETCH; + clockTicks = codeTicksAccessSeq32(armNextPC) + 1; + clockTicks += 2 + codeTicksAccess32(armNextPC) + + codeTicksAccessSeq32(armNextPC); + busPrefetchCount = 0; +} + + +#ifdef GP_SUPPORT +// MRC +static INSN_REGPARM void armE01(u32 opcode) +{ +} +#else + #define armE01 armUnknownInsn +#endif + + +// SWI +static INSN_REGPARM void armF00(u32 opcode) +{ + clockTicks = codeTicksAccessSeq32(armNextPC) + 1; + clockTicks += 2 + codeTicksAccess32(armNextPC) + + codeTicksAccessSeq32(armNextPC); + busPrefetchCount = 0; + CPUSoftwareInterrupt(opcode & 0x00FFFFFF); +} + +// Instruction table ////////////////////////////////////////////////////// + +typedef INSN_REGPARM void (*insnfunc_t)(u32 opcode); +#define REP16(insn) \ + insn,insn,insn,insn,insn,insn,insn,insn,\ + insn,insn,insn,insn,insn,insn,insn,insn +#define REP256(insn) \ + REP16(insn),REP16(insn),REP16(insn),REP16(insn),\ + REP16(insn),REP16(insn),REP16(insn),REP16(insn),\ + REP16(insn),REP16(insn),REP16(insn),REP16(insn),\ + REP16(insn),REP16(insn),REP16(insn),REP16(insn) +#define arm_UI armUnknownInsn +#ifdef BKPT_SUPPORT + #define arm_BP armBreakpoint +#else + #define arm_BP armUnknownInsn +#endif +static insnfunc_t armInsnTable[4096] = { + arm000,arm001,arm002,arm003,arm004,arm005,arm006,arm007, // 000 + arm000,arm009,arm002,arm00B,arm004,arm_UI,arm006,arm_UI, // 008 + arm010,arm011,arm012,arm013,arm014,arm015,arm016,arm017, // 010 + arm010,arm019,arm012,arm01B,arm014,arm01D,arm016,arm01F, // 018 + arm020,arm021,arm022,arm023,arm024,arm025,arm026,arm027, // 020 + arm020,arm029,arm022,arm_UI,arm024,arm_UI,arm026,arm_UI, // 028 + arm030,arm031,arm032,arm033,arm034,arm035,arm036,arm037, // 030 + arm030,arm039,arm032,arm_UI,arm034,arm01D,arm036,arm01F, // 038 + arm040,arm041,arm042,arm043,arm044,arm045,arm046,arm047, // 040 + arm040,arm_UI,arm042,arm04B,arm044,arm_UI,arm046,arm_UI, // 048 + arm050,arm051,arm052,arm053,arm054,arm055,arm056,arm057, // 050 + arm050,arm_UI,arm052,arm05B,arm054,arm05D,arm056,arm05F, // 058 + arm060,arm061,arm062,arm063,arm064,arm065,arm066,arm067, // 060 + arm060,arm_UI,arm062,arm_UI,arm064,arm_UI,arm066,arm_UI, // 068 + arm070,arm071,arm072,arm073,arm074,arm075,arm076,arm077, // 070 + arm070,arm_UI,arm072,arm_UI,arm074,arm05D,arm076,arm05F, // 078 + arm080,arm081,arm082,arm083,arm084,arm085,arm086,arm087, // 080 + arm080,arm089,arm082,arm08B,arm084,arm_UI,arm086,arm_UI, // 088 + arm090,arm091,arm092,arm093,arm094,arm095,arm096,arm097, // 090 + arm090,arm099,arm092,arm09B,arm094,arm09D,arm096,arm09F, // 098 + arm0A0,arm0A1,arm0A2,arm0A3,arm0A4,arm0A5,arm0A6,arm0A7, // 0A0 + arm0A0,arm0A9,arm0A2,arm_UI,arm0A4,arm_UI,arm0A6,arm_UI, // 0A8 + arm0B0,arm0B1,arm0B2,arm0B3,arm0B4,arm0B5,arm0B6,arm0B7, // 0B0 + arm0B0,arm0B9,arm0B2,arm_UI,arm0B4,arm09D,arm0B6,arm09F, // 0B8 + arm0C0,arm0C1,arm0C2,arm0C3,arm0C4,arm0C5,arm0C6,arm0C7, // 0C0 + arm0C0,arm0C9,arm0C2,arm0CB,arm0C4,arm_UI,arm0C6,arm_UI, // 0C8 + arm0D0,arm0D1,arm0D2,arm0D3,arm0D4,arm0D5,arm0D6,arm0D7, // 0D0 + arm0D0,arm0D9,arm0D2,arm0DB,arm0D4,arm0DD,arm0D6,arm0DF, // 0D8 + arm0E0,arm0E1,arm0E2,arm0E3,arm0E4,arm0E5,arm0E6,arm0E7, // 0E0 + arm0E0,arm0E9,arm0E2,arm_UI,arm0E4,arm_UI,arm0E6,arm_UI, // 0E8 + arm0F0,arm0F1,arm0F2,arm0F3,arm0F4,arm0F5,arm0F6,arm0F7, // 0F0 + arm0F0,arm0F9,arm0F2,arm_UI,arm0F4,arm0DD,arm0F6,arm0DF, // 0F8 + + arm100,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 100 + arm_UI,arm109,arm_UI,arm10B,arm_UI,arm_UI,arm_UI,arm_UI, // 108 + arm110,arm111,arm112,arm113,arm114,arm115,arm116,arm117, // 110 + arm110,arm_UI,arm112,arm11B,arm114,arm11D,arm116,arm11F, // 118 + arm120,arm121,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_BP, // 120 + arm_UI,arm_UI,arm_UI,arm12B,arm_UI,arm_UI,arm_UI,arm_UI, // 128 + arm130,arm131,arm132,arm133,arm134,arm135,arm136,arm137, // 130 + arm130,arm_UI,arm132,arm13B,arm134,arm13D,arm136,arm13F, // 138 + arm140,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 140 + arm_UI,arm149,arm_UI,arm14B,arm_UI,arm_UI,arm_UI,arm_UI, // 148 + arm150,arm151,arm152,arm153,arm154,arm155,arm156,arm157, // 150 + arm150,arm_UI,arm152,arm15B,arm154,arm15D,arm156,arm15F, // 158 + arm160,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 160 + arm_UI,arm_UI,arm_UI,arm16B,arm_UI,arm_UI,arm_UI,arm_UI, // 168 + arm170,arm171,arm172,arm173,arm174,arm175,arm176,arm177, // 170 + arm170,arm_UI,arm172,arm17B,arm174,arm17D,arm176,arm17F, // 178 + arm180,arm181,arm182,arm183,arm184,arm185,arm186,arm187, // 180 + arm180,arm_UI,arm182,arm18B,arm184,arm_UI,arm186,arm_UI, // 188 + arm190,arm191,arm192,arm193,arm194,arm195,arm196,arm197, // 190 + arm190,arm_UI,arm192,arm19B,arm194,arm19D,arm196,arm19F, // 198 + arm1A0,arm1A1,arm1A2,arm1A3,arm1A4,arm1A5,arm1A6,arm1A7, // 1A0 + arm1A0,arm_UI,arm1A2,arm1AB,arm1A4,arm_UI,arm1A6,arm_UI, // 1A8 + arm1B0,arm1B1,arm1B2,arm1B3,arm1B4,arm1B5,arm1B6,arm1B7, // 1B0 + arm1B0,arm_UI,arm1B2,arm1BB,arm1B4,arm1BD,arm1B6,arm1BF, // 1B8 + arm1C0,arm1C1,arm1C2,arm1C3,arm1C4,arm1C5,arm1C6,arm1C7, // 1C0 + arm1C0,arm_UI,arm1C2,arm1CB,arm1C4,arm_UI,arm1C6,arm_UI, // 1C8 + arm1D0,arm1D1,arm1D2,arm1D3,arm1D4,arm1D5,arm1D6,arm1D7, // 1D0 + arm1D0,arm_UI,arm1D2,arm1DB,arm1D4,arm1DD,arm1D6,arm1DF, // 1D8 + arm1E0,arm1E1,arm1E2,arm1E3,arm1E4,arm1E5,arm1E6,arm1E7, // 1E0 + arm1E0,arm_UI,arm1E2,arm1EB,arm1E4,arm_UI,arm1E6,arm_UI, // 1E8 + arm1F0,arm1F1,arm1F2,arm1F3,arm1F4,arm1F5,arm1F6,arm1F7, // 1F0 + arm1F0,arm_UI,arm1F2,arm1FB,arm1F4,arm1FD,arm1F6,arm1FF, // 1F8 + + REP16(arm200),REP16(arm210),REP16(arm220),REP16(arm230), // 200 + REP16(arm240),REP16(arm250),REP16(arm260),REP16(arm270), // 240 + REP16(arm280),REP16(arm290),REP16(arm2A0),REP16(arm2B0), // 280 + REP16(arm2C0),REP16(arm2D0),REP16(arm2E0),REP16(arm2F0), // 2C0 + REP16(arm_UI),REP16(arm310),REP16(arm320),REP16(arm330), // 300 + REP16(arm_UI),REP16(arm350),REP16(arm360),REP16(arm370), // 340 + REP16(arm380),REP16(arm390),REP16(arm3A0),REP16(arm3B0), // 380 + REP16(arm3C0),REP16(arm3D0),REP16(arm3E0),REP16(arm3F0), // 3C0 + + REP16(arm400),REP16(arm410),REP16(arm400),REP16(arm410), // 400 + REP16(arm440),REP16(arm450),REP16(arm440),REP16(arm450), // 440 + REP16(arm480),REP16(arm490),REP16(arm480),REP16(arm490), // 480 + REP16(arm4C0),REP16(arm4D0),REP16(arm4C0),REP16(arm4D0), // 4C0 + REP16(arm500),REP16(arm510),REP16(arm520),REP16(arm530), // 500 + REP16(arm540),REP16(arm550),REP16(arm560),REP16(arm570), // 540 + REP16(arm580),REP16(arm590),REP16(arm5A0),REP16(arm5B0), // 580 + REP16(arm5C0),REP16(arm5D0),REP16(arm5E0),REP16(arm5F0), // 5C0 + + arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 600 + arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 608 + arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 610 + arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 618 + arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 620 + arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 628 + arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 630 + arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 638 + arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 640 + arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 648 + arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 650 + arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 658 + arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 660 + arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 668 + arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 670 + arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 678 + arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 680 + arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 688 + arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 690 + arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 698 + arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 6A0 + arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 6A8 + arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 6B0 + arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 6B8 + arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6C0 + arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6C8 + arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6D0 + arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6D8 + arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6E0 + arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6E8 + arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6F0 + arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6F8 + + arm700,arm_UI,arm702,arm_UI,arm704,arm_UI,arm706,arm_UI, // 700 + arm700,arm_UI,arm702,arm_UI,arm704,arm_UI,arm706,arm_UI, // 708 + arm710,arm_UI,arm712,arm_UI,arm714,arm_UI,arm716,arm_UI, // 710 + arm710,arm_UI,arm712,arm_UI,arm714,arm_UI,arm716,arm_UI, // 718 + arm720,arm_UI,arm722,arm_UI,arm724,arm_UI,arm726,arm_UI, // 720 + arm720,arm_UI,arm722,arm_UI,arm724,arm_UI,arm726,arm_UI, // 728 + arm730,arm_UI,arm732,arm_UI,arm734,arm_UI,arm736,arm_UI, // 730 + arm730,arm_UI,arm732,arm_UI,arm734,arm_UI,arm736,arm_UI, // 738 + arm740,arm_UI,arm742,arm_UI,arm744,arm_UI,arm746,arm_UI, // 740 + arm740,arm_UI,arm742,arm_UI,arm744,arm_UI,arm746,arm_UI, // 748 + arm750,arm_UI,arm752,arm_UI,arm754,arm_UI,arm756,arm_UI, // 750 + arm750,arm_UI,arm752,arm_UI,arm754,arm_UI,arm756,arm_UI, // 758 + arm760,arm_UI,arm762,arm_UI,arm764,arm_UI,arm766,arm_UI, // 760 + arm760,arm_UI,arm762,arm_UI,arm764,arm_UI,arm766,arm_UI, // 768 + arm770,arm_UI,arm772,arm_UI,arm774,arm_UI,arm776,arm_UI, // 770 + arm770,arm_UI,arm772,arm_UI,arm774,arm_UI,arm776,arm_UI, // 778 + arm780,arm_UI,arm782,arm_UI,arm784,arm_UI,arm786,arm_UI, // 780 + arm780,arm_UI,arm782,arm_UI,arm784,arm_UI,arm786,arm_UI, // 788 + arm790,arm_UI,arm792,arm_UI,arm794,arm_UI,arm796,arm_UI, // 790 + arm790,arm_UI,arm792,arm_UI,arm794,arm_UI,arm796,arm_UI, // 798 + arm7A0,arm_UI,arm7A2,arm_UI,arm7A4,arm_UI,arm7A6,arm_UI, // 7A0 + arm7A0,arm_UI,arm7A2,arm_UI,arm7A4,arm_UI,arm7A6,arm_UI, // 7A8 + arm7B0,arm_UI,arm7B2,arm_UI,arm7B4,arm_UI,arm7B6,arm_UI, // 7B0 + arm7B0,arm_UI,arm7B2,arm_UI,arm7B4,arm_UI,arm7B6,arm_UI, // 7B8 + arm7C0,arm_UI,arm7C2,arm_UI,arm7C4,arm_UI,arm7C6,arm_UI, // 7C0 + arm7C0,arm_UI,arm7C2,arm_UI,arm7C4,arm_UI,arm7C6,arm_UI, // 7C8 + arm7D0,arm_UI,arm7D2,arm_UI,arm7D4,arm_UI,arm7D6,arm_UI, // 7D0 + arm7D0,arm_UI,arm7D2,arm_UI,arm7D4,arm_UI,arm7D6,arm_UI, // 7D8 + arm7E0,arm_UI,arm7E2,arm_UI,arm7E4,arm_UI,arm7E6,arm_UI, // 7E0 + arm7E0,arm_UI,arm7E2,arm_UI,arm7E4,arm_UI,arm7E6,arm_UI, // 7E8 + arm7F0,arm_UI,arm7F2,arm_UI,arm7F4,arm_UI,arm7F6,arm_UI, // 7F0 + arm7F0,arm_UI,arm7F2,arm_UI,arm7F4,arm_UI,arm7F6,arm_BP, // 7F8 + + REP16(arm800),REP16(arm810),REP16(arm820),REP16(arm830), // 800 + REP16(arm840),REP16(arm850),REP16(arm860),REP16(arm870), // 840 + REP16(arm880),REP16(arm890),REP16(arm8A0),REP16(arm8B0), // 880 + REP16(arm8C0),REP16(arm8D0),REP16(arm8E0),REP16(arm8F0), // 8C0 + REP16(arm900),REP16(arm910),REP16(arm920),REP16(arm930), // 900 + REP16(arm940),REP16(arm950),REP16(arm960),REP16(arm970), // 940 + REP16(arm980),REP16(arm990),REP16(arm9A0),REP16(arm9B0), // 980 + REP16(arm9C0),REP16(arm9D0),REP16(arm9E0),REP16(arm9F0), // 9C0 + + REP256(armA00), // A00 + REP256(armB00), // B00 + REP256(arm_UI), // C00 + REP256(arm_UI), // D00 + + arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E00 + arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E08 + arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E10 + arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E18 + REP16(arm_UI), // E20 + REP16(arm_UI), // E30 + REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // E40 + REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // E80 + REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // EC0 + + REP256(armF00), // F00 +}; + +// Wrapper routine (execution loop) /////////////////////////////////////// + +#include +static void tester(void) { + static int ran=0;if(ran)return;ran=1; + FILE*f=fopen("p:\\timing.txt","w");if(!f)return; + for (int op=/*0*/9; op> 28; + bool cond_res = true; + if (UNLIKELY(cond != 0x0E)) { // most opcodes are AL (always) + switch(cond) { + case 0x00: // EQ + cond_res = Z_FLAG; + break; + case 0x01: // NE + cond_res = !Z_FLAG; + break; + case 0x02: // CS + cond_res = C_FLAG; + break; + case 0x03: // CC + cond_res = !C_FLAG; + break; + case 0x04: // MI + cond_res = N_FLAG; + break; + case 0x05: // PL + cond_res = !N_FLAG; + break; + case 0x06: // VS + cond_res = V_FLAG; + break; + case 0x07: // VC + cond_res = !V_FLAG; + break; + case 0x08: // HI + cond_res = C_FLAG && !Z_FLAG; + break; + case 0x09: // LS + cond_res = !C_FLAG || Z_FLAG; + break; + case 0x0A: // GE + cond_res = N_FLAG == V_FLAG; + break; + case 0x0B: // LT + cond_res = N_FLAG != V_FLAG; + break; + case 0x0C: // GT + cond_res = !Z_FLAG &&(N_FLAG == V_FLAG); + break; + case 0x0D: // LE + cond_res = Z_FLAG || (N_FLAG != V_FLAG); + break; + case 0x0E: // AL (impossible, checked above) + cond_res = true; + break; + case 0x0F: + default: + // ??? + cond_res = false; + break; + } + } + + if (cond_res) + (*armInsnTable[((opcode>>16)&0xFF0) | ((opcode>>4)&0x0F)])(opcode); +#ifdef INSN_COUNTER + count(opcode, cond_res); +#endif + if (clockTicks < 0) + return 0; + if (clockTicks == 0) + clockTicks = 1 + codeTicksAccessSeq32(oldArmNextPC); + cpuTotalTicks += clockTicks; + + } while (cpuTotalTicks +#include +//#include +#include +#include + +#include "GBA.h" +#include "GBAcpu.h" +#include "GBAinline.h" +#include "../Globals.h" +#include "../EEprom.h" +#include "../Flash.h" +#include "../Sound.h" +#include "../Sram.h" +#include "../bios.h" +#include "../Cheats.h" +#include "../NLS.h" +#include "../elf.h" +#include "../Util.h" +#include "../Port.h" +#include "../System.h" +#include "agbprint.h" +#ifdef PROFILING +#include "prof/prof.h" +#endif + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + + +static int clockTicks; + +static INSN_REGPARM void thumbUnknownInsn(u32 opcode) +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_UNDEFINED) + log("Undefined THUMB instruction %04x at %08x\n", opcode, armNextPC-2); +#endif + CPUUndefinedException(); +} + +#ifdef BKPT_SUPPORT +static INSN_REGPARM void thumbBreakpoint(u32 opcode) +{ + reg[15].I -= 2; + armNextPC -= 2; + dbgSignal(5, opcode & 255); + clockTicks = -1; +} +#endif + +// Common macros ////////////////////////////////////////////////////////// + +#ifdef BKPT_SUPPORT +# define THUMB_CONSOLE_OUTPUT(a,b) do { \ + if ((opcode == 0x4000) && (reg[0].I == 0xC0DED00D)) { \ + dbgOutput((a), (b)); \ + } \ +} while (0) +# define UPDATE_OLDREG do { \ + if (debugger_last) { \ + snprintf(oldbuffer, sizeof(oldbuffer), "%08X", \ + armState ? reg[15].I - 4 : reg[15].I - 2); \ + int i; \ + for (i = 0; i < 18; i++) { \ + oldreg[i] = reg[i].I; \ + } \ + } \ +} while (0) +#else +# define THUMB_CONSOLE_OUTPUT(a,b) +# define UPDATE_OLDREG +#endif + +#define NEG(i) ((i) >> 31) +#define POS(i) ((~(i)) >> 31) + +#ifndef C_CORE +#ifdef __GNUC__ +#ifdef __POWERPC__ + #define ADD_RD_RS_RN(N) \ + { \ + register int Flags; \ + register int Result; \ + asm volatile("addco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[source].I), \ + "r" (reg[N].I) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define ADD_RD_RS_O3(N) \ + { \ + register int Flags; \ + register int Result; \ + asm volatile("addco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[source].I), \ + "r" (N) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define ADD_RD_RS_O3_0 ADD_RD_RS_O3 + #define ADD_RN_O8(d) \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("addco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[(d)].I), \ + "r" (opcode & 255) \ + ); \ + reg[(d)].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define CMN_RD_RS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("addco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[dest].I), \ + "r" (value) \ + ); \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define ADC_RD_RS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("mtspr xer, %4\n" \ + "addeo. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[dest].I), \ + "r" (value), \ + "r" (C_FLAG << 29) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define SUB_RD_RS_RN(N) \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[source].I), \ + "r" (reg[N].I) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define SUB_RD_RS_O3(N) \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[source].I), \ + "r" (N) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define SUB_RD_RS_O3_0 SUB_RD_RS_O3 + #define SUB_RN_O8(d) \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[(d)].I), \ + "r" (opcode & 255) \ + ); \ + reg[(d)].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define CMP_RN_O8(d) \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[(d)].I), \ + "r" (opcode & 255) \ + ); \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define SBC_RD_RS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("mtspr xer, %4\n" \ + "subfeo. %0, %3, %2\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[dest].I), \ + "r" (value), \ + "r" (C_FLAG << 29) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define NEG_RD_RS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subfco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[source].I), \ + "r" (0) \ + ); \ + reg[dest].I = Result; \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } + #define CMP_RD_RS \ + {\ + register int Flags; \ + register int Result; \ + asm volatile("subco. %0, %2, %3\n" \ + "mcrxr cr1\n" \ + "mfcr %1\n" \ + : "=r" (Result), \ + "=r" (Flags) \ + : "r" (reg[dest].I), \ + "r" (value) \ + ); \ + Z_FLAG = (Flags >> 29) & 1; \ + N_FLAG = (Flags >> 31) & 1; \ + C_FLAG = (Flags >> 25) & 1; \ + V_FLAG = (Flags >> 26) & 1; \ + } +#else + #define EMIT1(op,arg) #op" "arg"; " + #define EMIT2(op,src,dest) #op" "src", "dest"; " + #define CONST(val) "$"#val + #define ASMVAR(cvar) ASMVAR2 (__USER_LABEL_PREFIX__, cvar) + #define ASMVAR2(prefix,cvar) STRING (prefix) cvar + #define STRING(x) #x + #define VAR(var) ASMVAR(#var) + #define REGREF1(index) ASMVAR("reg("index")") + #define REGREF2(index,scale) ASMVAR("reg(,"index","#scale")") + #define eax "%%eax" + #define ecx "%%ecx" + #define edx "%%edx" + #define ADD_RN_O8(d) \ + asm ("andl $0xFF, %%eax;"\ + "addl %%eax, %0;"\ + EMIT1(setsb, VAR(N_FLAG)) \ + EMIT1(setzb, VAR(Z_FLAG)) \ + EMIT1(setcb, VAR(C_FLAG)) \ + EMIT1(setob, VAR(V_FLAG)) \ + : "=m" (reg[(d)].I)); + #define CMN_RD_RS \ + asm ("add %0, %1;"\ + EMIT1(setsb, VAR(N_FLAG)) \ + EMIT1(setzb, VAR(Z_FLAG)) \ + EMIT1(setcb, VAR(C_FLAG)) \ + EMIT1(setob, VAR(V_FLAG)) \ + : \ + : "r" (value), "r" (reg[dest].I):"1"); + #define ADC_RD_RS \ + asm (EMIT2(bt,CONST(0),VAR(C_FLAG)) \ + "adc %1, %%ebx;"\ + EMIT1(setsb, VAR(N_FLAG)) \ + EMIT1(setzb, VAR(Z_FLAG)) \ + EMIT1(setcb, VAR(C_FLAG)) \ + EMIT1(setob, VAR(V_FLAG)) \ + : "=b" (reg[dest].I)\ + : "r" (value), "b" (reg[dest].I)); + #define SUB_RN_O8(d) \ + asm ("andl $0xFF, %%eax;"\ + "subl %%eax, %0;"\ + EMIT1(setsb, VAR(N_FLAG)) \ + EMIT1(setzb, VAR(Z_FLAG)) \ + EMIT1(setncb, VAR(C_FLAG)) \ + EMIT1(setob, VAR(V_FLAG)) \ + : "=m" (reg[(d)].I)); + #define MOV_RN_O8(d) \ + asm ("andl $0xFF, %%eax;"\ + EMIT2(movb,CONST(0),VAR(N_FLAG)) \ + "movl %%eax, %0;"\ + EMIT1(setzb, VAR(Z_FLAG)) \ + : "=m" (reg[(d)].I)); + #define CMP_RN_O8(d) \ + asm ("andl $0xFF, %%eax;"\ + "cmpl %%eax, %0;"\ + EMIT1(setsb, VAR(N_FLAG)) \ + EMIT1(setzb, VAR(Z_FLAG)) \ + EMIT1(setncb, VAR(C_FLAG)) \ + EMIT1(setob, VAR(V_FLAG)) \ + : \ + : "m" (reg[(d)].I)); + #define SBC_RD_RS \ + asm volatile (EMIT2(bt,CONST(0),VAR(C_FLAG)) \ + "cmc;"\ + "sbb %1, %%ebx;"\ + EMIT1(setsb, VAR(N_FLAG)) \ + EMIT1(setzb, VAR(Z_FLAG)) \ + EMIT1(setncb, VAR(C_FLAG)) \ + EMIT1(setob, VAR(V_FLAG)) \ + : "=b" (reg[dest].I)\ + : "r" (value), "b" (reg[dest].I) : "cc", "memory"); + #define LSL_RD_RS \ + asm ("shl %%cl, %%eax;"\ + EMIT1(setcb, VAR(C_FLAG)) \ + : "=a" (value)\ + : "a" (reg[dest].I), "c" (value)); + #define LSR_RD_RS \ + asm ("shr %%cl, %%eax;"\ + EMIT1(setcb, VAR(C_FLAG)) \ + : "=a" (value)\ + : "a" (reg[dest].I), "c" (value)); + #define ASR_RD_RS \ + asm ("sar %%cl, %%eax;"\ + EMIT1(setcb, VAR(C_FLAG)) \ + : "=a" (value)\ + : "a" (reg[dest].I), "c" (value)); + #define ROR_RD_RS \ + asm ("ror %%cl, %%eax;"\ + EMIT1(setcb, VAR(C_FLAG)) \ + : "=a" (value)\ + : "a" (reg[dest].I), "c" (value)); + #define NEG_RD_RS \ + asm ("neg %%ebx;"\ + EMIT1(setsb, VAR(N_FLAG)) \ + EMIT1(setzb, VAR(Z_FLAG)) \ + EMIT1(setncb, VAR(C_FLAG)) \ + EMIT1(setob, VAR(V_FLAG)) \ + : "=b" (reg[dest].I)\ + : "b" (reg[source].I)); + #define CMP_RD_RS \ + asm ("sub %0, %1;"\ + EMIT1(setsb, VAR(N_FLAG)) \ + EMIT1(setzb, VAR(Z_FLAG)) \ + EMIT1(setncb, VAR(C_FLAG)) \ + EMIT1(setob, VAR(V_FLAG)) \ + : \ + : "r" (value), "r" (reg[dest].I):"1"); + #define IMM5_INSN(OP,N) \ + asm("movl %%eax,%%ecx;" \ + "shrl $1,%%eax;" \ + "andl $7,%%ecx;" \ + "andl $0x1C,%%eax;" \ + EMIT2(movl, REGREF1(eax), edx) \ + OP \ + EMIT1(setsb, VAR(N_FLAG)) \ + EMIT1(setzb, VAR(Z_FLAG)) \ + EMIT2(movl, edx, REGREF2(ecx,4)) \ + : : "i" (N)) + #define IMM5_INSN_0(OP) \ + asm("movl %%eax,%%ecx;" \ + "shrl $1,%%eax;" \ + "andl $7,%%ecx;" \ + "andl $0x1C,%%eax;" \ + EMIT2(movl, REGREF1(eax), edx) \ + OP \ + EMIT1(setsb, VAR(N_FLAG)) \ + EMIT1(setzb, VAR(Z_FLAG)) \ + EMIT2(movl, edx, REGREF2(ecx,4)) \ + : : ) + #define IMM5_LSL \ + "shll %0,%%edx;"\ + EMIT1(setcb, VAR(C_FLAG)) + #define IMM5_LSL_0 \ + "testl %%edx,%%edx;" + #define IMM5_LSR \ + "shrl %0,%%edx;"\ + EMIT1(setcb, VAR(C_FLAG)) + #define IMM5_LSR_0 \ + "testl %%edx,%%edx;"\ + EMIT1(setsb, VAR(C_FLAG)) \ + "xorl %%edx,%%edx;" + #define IMM5_ASR \ + "sarl %0,%%edx;"\ + EMIT1(setcb, VAR(C_FLAG)) + #define IMM5_ASR_0 \ + "sarl $31,%%edx;"\ + EMIT1(setsb, VAR(C_FLAG)) + #define THREEARG_INSN(OP,N) \ + asm("movl %%eax,%%edx;" \ + "shrl $1,%%edx;" \ + "andl $0x1C,%%edx;" \ + "andl $7,%%eax;" \ + EMIT2(movl, REGREF1(edx), ecx) \ + OP(N) \ + EMIT1(setsb, VAR(N_FLAG)) \ + EMIT1(setzb, VAR(Z_FLAG)) \ + EMIT2(movl, ecx, REGREF2(eax,4)) \ + : : ) + #define ADD_RD_RS_RN(N) \ + EMIT2(add,VAR(reg)"+"#N"*4",ecx) \ + EMIT1(setcb, VAR(C_FLAG)) \ + EMIT1(setob, VAR(V_FLAG)) + #define ADD_RD_RS_O3(N) \ + "add $"#N",%%ecx;" \ + EMIT1(setcb, VAR(C_FLAG)) \ + EMIT1(setob, VAR(V_FLAG)) + #define ADD_RD_RS_O3_0(N) \ + EMIT2(movb,CONST(0),VAR(C_FLAG)) \ + "add $0,%%ecx;" \ + EMIT2(movb,CONST(0),VAR(V_FLAG)) + #define SUB_RD_RS_RN(N) \ + EMIT2(sub,VAR(reg)"+"#N"*4",ecx) \ + EMIT1(setncb, VAR(C_FLAG)) \ + EMIT1(setob, VAR(V_FLAG)) + #define SUB_RD_RS_O3(N) \ + "sub $"#N",%%ecx;" \ + EMIT1(setncb, VAR(C_FLAG)) \ + EMIT1(setob, VAR(V_FLAG)) + #define SUB_RD_RS_O3_0(N) \ + EMIT2(movb,CONST(1),VAR(C_FLAG)) \ + "sub $0,%%ecx;" \ + EMIT2(movb,CONST(0),VAR(V_FLAG)) +#endif +#else // !__GNUC__ + #define ADD_RD_RS_RN(N) \ + {\ + __asm mov eax, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm add ebx, dword ptr [OFFSET reg+4*N]\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define ADD_RD_RS_O3(N) \ + {\ + __asm mov eax, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm add ebx, N\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define ADD_RD_RS_O3_0 \ + {\ + __asm mov eax, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm add ebx, 0\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm mov byte ptr C_FLAG, 0\ + __asm mov byte ptr V_FLAG, 0\ + } + #define ADD_RN_O8(d) \ + {\ + __asm mov ebx, opcode\ + __asm and ebx, 255\ + __asm add dword ptr [OFFSET reg+4*(d)], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define CMN_RD_RS \ + {\ + __asm mov eax, dest\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm add ebx, value\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define ADC_RD_RS \ + {\ + __asm mov ebx, dest\ + __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ + __asm bt word ptr C_FLAG, 0\ + __asm adc ebx, value\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define SUB_RD_RS_RN(N) \ + {\ + __asm mov eax, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm sub ebx, dword ptr [OFFSET reg+4*N]\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define SUB_RD_RS_O3(N) \ + {\ + __asm mov eax, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm sub ebx, N\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define SUB_RD_RS_O3_0 \ + {\ + __asm mov eax, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm sub ebx, 0\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm mov byte ptr C_FLAG, 1\ + __asm mov byte ptr V_FLAG, 0\ + } + #define SUB_RN_O8(d) \ + {\ + __asm mov ebx, opcode\ + __asm and ebx, 255\ + __asm sub dword ptr [OFFSET reg + 4*(d)], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define MOV_RN_O8(d) \ + {\ + __asm mov eax, opcode\ + __asm and eax, 255\ + __asm mov dword ptr [OFFSET reg+4*(d)], eax\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + } + #define CMP_RN_O8(d) \ + {\ + __asm mov eax, dword ptr [OFFSET reg+4*(d)]\ + __asm mov ebx, opcode\ + __asm and ebx, 255\ + __asm sub eax, ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define SBC_RD_RS \ + {\ + __asm mov ebx, dest\ + __asm mov ebx, dword ptr [OFFSET reg + 4*ebx]\ + __asm mov eax, value\ + __asm bt word ptr C_FLAG, 0\ + __asm cmc\ + __asm sbb ebx, eax\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg + 4*eax], ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define LSL_RD_RM_I5 \ + {\ + __asm mov eax, source\ + __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ + __asm mov cl, byte ptr shift\ + __asm shl eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define LSL_RD_RS \ + {\ + __asm mov eax, dest\ + __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ + __asm mov cl, byte ptr value\ + __asm shl eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define LSR_RD_RM_I5 \ + {\ + __asm mov eax, source\ + __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ + __asm mov cl, byte ptr shift\ + __asm shr eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define LSR_RD_RS \ + {\ + __asm mov eax, dest\ + __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ + __asm mov cl, byte ptr value\ + __asm shr eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define ASR_RD_RM_I5 \ + {\ + __asm mov eax, source\ + __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ + __asm mov cl, byte ptr shift\ + __asm sar eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define ASR_RD_RS \ + {\ + __asm mov eax, dest\ + __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ + __asm mov cl, byte ptr value\ + __asm sar eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define ROR_RD_RS \ + {\ + __asm mov eax, dest\ + __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ + __asm mov cl, byte ptr value\ + __asm ror eax, cl\ + __asm mov value, eax\ + __asm setc byte ptr C_FLAG\ + } + #define NEG_RD_RS \ + {\ + __asm mov ebx, source\ + __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ + __asm neg ebx\ + __asm mov eax, dest\ + __asm mov dword ptr [OFFSET reg+4*eax],ebx\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } + #define CMP_RD_RS \ + {\ + __asm mov eax, dest\ + __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ + __asm sub ebx, value\ + __asm sets byte ptr N_FLAG\ + __asm setz byte ptr Z_FLAG\ + __asm setnc byte ptr C_FLAG\ + __asm seto byte ptr V_FLAG\ + } +#endif +#endif + +// C core +#ifndef ADDCARRY + #define ADDCARRY(a, b, c) \ + C_FLAG = ((NEG(a) & NEG(b)) |\ + (NEG(a) & POS(c)) |\ + (NEG(b) & POS(c))) ? true : false; +#endif +#ifndef ADDOVERFLOW + #define ADDOVERFLOW(a, b, c) \ + V_FLAG = ((NEG(a) & NEG(b) & POS(c)) |\ + (POS(a) & POS(b) & NEG(c))) ? true : false; +#endif +#ifndef SUBCARRY + #define SUBCARRY(a, b, c) \ + C_FLAG = ((NEG(a) & POS(b)) |\ + (NEG(a) & POS(c)) |\ + (POS(b) & POS(c))) ? true : false; +#endif +#ifndef SUBOVERFLOW + #define SUBOVERFLOW(a, b, c)\ + V_FLAG = ((NEG(a) & POS(b) & POS(c)) |\ + (POS(a) & NEG(b) & NEG(c))) ? true : false; +#endif +#ifndef ADD_RD_RS_RN + #define ADD_RD_RS_RN(N) \ + {\ + u32 lhs = reg[source].I;\ + u32 rhs = reg[N].I;\ + u32 res = lhs + rhs;\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + ADDCARRY(lhs, rhs, res);\ + ADDOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef ADD_RD_RS_O3 + #define ADD_RD_RS_O3(N) \ + {\ + u32 lhs = reg[source].I;\ + u32 rhs = N;\ + u32 res = lhs + rhs;\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + ADDCARRY(lhs, rhs, res);\ + ADDOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef ADD_RD_RS_O3_0 +# define ADD_RD_RS_O3_0 ADD_RD_RS_O3 +#endif +#ifndef ADD_RN_O8 + #define ADD_RN_O8(d) \ + {\ + u32 lhs = reg[(d)].I;\ + u32 rhs = (opcode & 255);\ + u32 res = lhs + rhs;\ + reg[(d)].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + ADDCARRY(lhs, rhs, res);\ + ADDOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef CMN_RD_RS + #define CMN_RD_RS \ + {\ + u32 lhs = reg[dest].I;\ + u32 rhs = value;\ + u32 res = lhs + rhs;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + ADDCARRY(lhs, rhs, res);\ + ADDOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef ADC_RD_RS + #define ADC_RD_RS \ + {\ + u32 lhs = reg[dest].I;\ + u32 rhs = value;\ + u32 res = lhs + rhs + (u32)C_FLAG;\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + ADDCARRY(lhs, rhs, res);\ + ADDOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef SUB_RD_RS_RN + #define SUB_RD_RS_RN(N) \ + {\ + u32 lhs = reg[source].I;\ + u32 rhs = reg[N].I;\ + u32 res = lhs - rhs;\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(lhs, rhs, res);\ + SUBOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef SUB_RD_RS_O3 + #define SUB_RD_RS_O3(N) \ + {\ + u32 lhs = reg[source].I;\ + u32 rhs = N;\ + u32 res = lhs - rhs;\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(lhs, rhs, res);\ + SUBOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef SUB_RD_RS_O3_0 +# define SUB_RD_RS_O3_0 SUB_RD_RS_O3 +#endif +#ifndef SUB_RN_O8 + #define SUB_RN_O8(d) \ + {\ + u32 lhs = reg[(d)].I;\ + u32 rhs = (opcode & 255);\ + u32 res = lhs - rhs;\ + reg[(d)].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(lhs, rhs, res);\ + SUBOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef MOV_RN_O8 + #define MOV_RN_O8(d) \ + {\ + reg[d].I = opcode & 255;\ + N_FLAG = false;\ + Z_FLAG = (reg[d].I ? false : true);\ + } +#endif +#ifndef CMP_RN_O8 + #define CMP_RN_O8(d) \ + {\ + u32 lhs = reg[(d)].I;\ + u32 rhs = (opcode & 255);\ + u32 res = lhs - rhs;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(lhs, rhs, res);\ + SUBOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef SBC_RD_RS + #define SBC_RD_RS \ + {\ + u32 lhs = reg[dest].I;\ + u32 rhs = value;\ + u32 res = lhs - rhs - !((u32)C_FLAG);\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(lhs, rhs, res);\ + SUBOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef LSL_RD_RM_I5 + #define LSL_RD_RM_I5 \ + {\ + C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false;\ + value = reg[source].I << shift;\ + } +#endif +#ifndef LSL_RD_RS + #define LSL_RD_RS \ + {\ + C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false;\ + value = reg[dest].I << value;\ + } +#endif +#ifndef LSR_RD_RM_I5 + #define LSR_RD_RM_I5 \ + {\ + C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false;\ + value = reg[source].I >> shift;\ + } +#endif +#ifndef LSR_RD_RS + #define LSR_RD_RS \ + {\ + C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\ + value = reg[dest].I >> value;\ + } +#endif +#ifndef ASR_RD_RM_I5 + #define ASR_RD_RM_I5 \ + {\ + C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false;\ + value = (s32)reg[source].I >> (int)shift;\ + } +#endif +#ifndef ASR_RD_RS + #define ASR_RD_RS \ + {\ + C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false;\ + value = (s32)reg[dest].I >> (int)value;\ + } +#endif +#ifndef ROR_RD_RS + #define ROR_RD_RS \ + {\ + C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\ + value = ((reg[dest].I << (32 - value)) |\ + (reg[dest].I >> value));\ + } +#endif +#ifndef NEG_RD_RS + #define NEG_RD_RS \ + {\ + u32 lhs = reg[source].I;\ + u32 rhs = 0;\ + u32 res = rhs - lhs;\ + reg[dest].I = res;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(rhs, lhs, res);\ + SUBOVERFLOW(rhs, lhs, res);\ + } +#endif +#ifndef CMP_RD_RS + #define CMP_RD_RS \ + {\ + u32 lhs = reg[dest].I;\ + u32 rhs = value;\ + u32 res = lhs - rhs;\ + Z_FLAG = (res == 0) ? true : false;\ + N_FLAG = NEG(res) ? true : false;\ + SUBCARRY(lhs, rhs, res);\ + SUBOVERFLOW(lhs, rhs, res);\ + } +#endif +#ifndef IMM5_INSN + #define IMM5_INSN(OP,N) \ + int dest = opcode & 0x07;\ + int source = (opcode >> 3) & 0x07;\ + u32 value;\ + OP(N);\ + reg[dest].I = value;\ + N_FLAG = (value & 0x80000000 ? true : false);\ + Z_FLAG = (value ? false : true); + #define IMM5_INSN_0(OP) \ + int dest = opcode & 0x07;\ + int source = (opcode >> 3) & 0x07;\ + u32 value;\ + OP;\ + reg[dest].I = value;\ + N_FLAG = (value & 0x80000000 ? true : false);\ + Z_FLAG = (value ? false : true); + #define IMM5_LSL(N) \ + int shift = N;\ + LSL_RD_RM_I5; + #define IMM5_LSL_0 \ + value = reg[source].I; + #define IMM5_LSR(N) \ + int shift = N;\ + LSR_RD_RM_I5; + #define IMM5_LSR_0 \ + C_FLAG = reg[source].I & 0x80000000 ? true : false;\ + value = 0; + #define IMM5_ASR(N) \ + int shift = N;\ + ASR_RD_RM_I5; + #define IMM5_ASR_0 \ + if(reg[source].I & 0x80000000) {\ + value = 0xFFFFFFFF;\ + C_FLAG = true;\ + } else {\ + value = 0;\ + C_FLAG = false;\ + } +#endif +#ifndef THREEARG_INSN + #define THREEARG_INSN(OP,N) \ + int dest = opcode & 0x07; \ + int source = (opcode >> 3) & 0x07; \ + OP(N); +#endif + +// Shift instructions ///////////////////////////////////////////////////// + +#define DEFINE_IMM5_INSN(OP,BASE) \ + static INSN_REGPARM void thumb##BASE##_00(u32 opcode) { IMM5_INSN_0(OP##_0); } \ + static INSN_REGPARM void thumb##BASE##_01(u32 opcode) { IMM5_INSN(OP, 1); } \ + static INSN_REGPARM void thumb##BASE##_02(u32 opcode) { IMM5_INSN(OP, 2); } \ + static INSN_REGPARM void thumb##BASE##_03(u32 opcode) { IMM5_INSN(OP, 3); } \ + static INSN_REGPARM void thumb##BASE##_04(u32 opcode) { IMM5_INSN(OP, 4); } \ + static INSN_REGPARM void thumb##BASE##_05(u32 opcode) { IMM5_INSN(OP, 5); } \ + static INSN_REGPARM void thumb##BASE##_06(u32 opcode) { IMM5_INSN(OP, 6); } \ + static INSN_REGPARM void thumb##BASE##_07(u32 opcode) { IMM5_INSN(OP, 7); } \ + static INSN_REGPARM void thumb##BASE##_08(u32 opcode) { IMM5_INSN(OP, 8); } \ + static INSN_REGPARM void thumb##BASE##_09(u32 opcode) { IMM5_INSN(OP, 9); } \ + static INSN_REGPARM void thumb##BASE##_0A(u32 opcode) { IMM5_INSN(OP,10); } \ + static INSN_REGPARM void thumb##BASE##_0B(u32 opcode) { IMM5_INSN(OP,11); } \ + static INSN_REGPARM void thumb##BASE##_0C(u32 opcode) { IMM5_INSN(OP,12); } \ + static INSN_REGPARM void thumb##BASE##_0D(u32 opcode) { IMM5_INSN(OP,13); } \ + static INSN_REGPARM void thumb##BASE##_0E(u32 opcode) { IMM5_INSN(OP,14); } \ + static INSN_REGPARM void thumb##BASE##_0F(u32 opcode) { IMM5_INSN(OP,15); } \ + static INSN_REGPARM void thumb##BASE##_10(u32 opcode) { IMM5_INSN(OP,16); } \ + static INSN_REGPARM void thumb##BASE##_11(u32 opcode) { IMM5_INSN(OP,17); } \ + static INSN_REGPARM void thumb##BASE##_12(u32 opcode) { IMM5_INSN(OP,18); } \ + static INSN_REGPARM void thumb##BASE##_13(u32 opcode) { IMM5_INSN(OP,19); } \ + static INSN_REGPARM void thumb##BASE##_14(u32 opcode) { IMM5_INSN(OP,20); } \ + static INSN_REGPARM void thumb##BASE##_15(u32 opcode) { IMM5_INSN(OP,21); } \ + static INSN_REGPARM void thumb##BASE##_16(u32 opcode) { IMM5_INSN(OP,22); } \ + static INSN_REGPARM void thumb##BASE##_17(u32 opcode) { IMM5_INSN(OP,23); } \ + static INSN_REGPARM void thumb##BASE##_18(u32 opcode) { IMM5_INSN(OP,24); } \ + static INSN_REGPARM void thumb##BASE##_19(u32 opcode) { IMM5_INSN(OP,25); } \ + static INSN_REGPARM void thumb##BASE##_1A(u32 opcode) { IMM5_INSN(OP,26); } \ + static INSN_REGPARM void thumb##BASE##_1B(u32 opcode) { IMM5_INSN(OP,27); } \ + static INSN_REGPARM void thumb##BASE##_1C(u32 opcode) { IMM5_INSN(OP,28); } \ + static INSN_REGPARM void thumb##BASE##_1D(u32 opcode) { IMM5_INSN(OP,29); } \ + static INSN_REGPARM void thumb##BASE##_1E(u32 opcode) { IMM5_INSN(OP,30); } \ + static INSN_REGPARM void thumb##BASE##_1F(u32 opcode) { IMM5_INSN(OP,31); } + +// LSL Rd, Rm, #Imm 5 +DEFINE_IMM5_INSN(IMM5_LSL,00) +// LSR Rd, Rm, #Imm 5 +DEFINE_IMM5_INSN(IMM5_LSR,08) +// ASR Rd, Rm, #Imm 5 +DEFINE_IMM5_INSN(IMM5_ASR,10) + +// 3-argument ADD/SUB ///////////////////////////////////////////////////// + +#define DEFINE_REG3_INSN(OP,BASE) \ + static INSN_REGPARM void thumb##BASE##_0(u32 opcode) { THREEARG_INSN(OP,0); } \ + static INSN_REGPARM void thumb##BASE##_1(u32 opcode) { THREEARG_INSN(OP,1); } \ + static INSN_REGPARM void thumb##BASE##_2(u32 opcode) { THREEARG_INSN(OP,2); } \ + static INSN_REGPARM void thumb##BASE##_3(u32 opcode) { THREEARG_INSN(OP,3); } \ + static INSN_REGPARM void thumb##BASE##_4(u32 opcode) { THREEARG_INSN(OP,4); } \ + static INSN_REGPARM void thumb##BASE##_5(u32 opcode) { THREEARG_INSN(OP,5); } \ + static INSN_REGPARM void thumb##BASE##_6(u32 opcode) { THREEARG_INSN(OP,6); } \ + static INSN_REGPARM void thumb##BASE##_7(u32 opcode) { THREEARG_INSN(OP,7); } + +#define DEFINE_IMM3_INSN(OP,BASE) \ + static INSN_REGPARM void thumb##BASE##_0(u32 opcode) { THREEARG_INSN(OP##_0,0); } \ + static INSN_REGPARM void thumb##BASE##_1(u32 opcode) { THREEARG_INSN(OP,1); } \ + static INSN_REGPARM void thumb##BASE##_2(u32 opcode) { THREEARG_INSN(OP,2); } \ + static INSN_REGPARM void thumb##BASE##_3(u32 opcode) { THREEARG_INSN(OP,3); } \ + static INSN_REGPARM void thumb##BASE##_4(u32 opcode) { THREEARG_INSN(OP,4); } \ + static INSN_REGPARM void thumb##BASE##_5(u32 opcode) { THREEARG_INSN(OP,5); } \ + static INSN_REGPARM void thumb##BASE##_6(u32 opcode) { THREEARG_INSN(OP,6); } \ + static INSN_REGPARM void thumb##BASE##_7(u32 opcode) { THREEARG_INSN(OP,7); } + +// ADD Rd, Rs, Rn +DEFINE_REG3_INSN(ADD_RD_RS_RN,18) +// SUB Rd, Rs, Rn +DEFINE_REG3_INSN(SUB_RD_RS_RN,1A) +// ADD Rd, Rs, #Offset3 +DEFINE_IMM3_INSN(ADD_RD_RS_O3,1C) +// SUB Rd, Rs, #Offset3 +DEFINE_IMM3_INSN(SUB_RD_RS_O3,1E) + +// MOV/CMP/ADD/SUB immediate ////////////////////////////////////////////// + +// MOV R0, #Offset8 +static INSN_REGPARM void thumb20(u32 opcode) { MOV_RN_O8(0); } +// MOV R1, #Offset8 +static INSN_REGPARM void thumb21(u32 opcode) { MOV_RN_O8(1); } +// MOV R2, #Offset8 +static INSN_REGPARM void thumb22(u32 opcode) { MOV_RN_O8(2); } +// MOV R3, #Offset8 +static INSN_REGPARM void thumb23(u32 opcode) { MOV_RN_O8(3); } +// MOV R4, #Offset8 +static INSN_REGPARM void thumb24(u32 opcode) { MOV_RN_O8(4); } +// MOV R5, #Offset8 +static INSN_REGPARM void thumb25(u32 opcode) { MOV_RN_O8(5); } +// MOV R6, #Offset8 +static INSN_REGPARM void thumb26(u32 opcode) { MOV_RN_O8(6); } +// MOV R7, #Offset8 +static INSN_REGPARM void thumb27(u32 opcode) { MOV_RN_O8(7); } + +// CMP R0, #Offset8 +static INSN_REGPARM void thumb28(u32 opcode) { CMP_RN_O8(0); } +// CMP R1, #Offset8 +static INSN_REGPARM void thumb29(u32 opcode) { CMP_RN_O8(1); } +// CMP R2, #Offset8 +static INSN_REGPARM void thumb2A(u32 opcode) { CMP_RN_O8(2); } +// CMP R3, #Offset8 +static INSN_REGPARM void thumb2B(u32 opcode) { CMP_RN_O8(3); } +// CMP R4, #Offset8 +static INSN_REGPARM void thumb2C(u32 opcode) { CMP_RN_O8(4); } +// CMP R5, #Offset8 +static INSN_REGPARM void thumb2D(u32 opcode) { CMP_RN_O8(5); } +// CMP R6, #Offset8 +static INSN_REGPARM void thumb2E(u32 opcode) { CMP_RN_O8(6); } +// CMP R7, #Offset8 +static INSN_REGPARM void thumb2F(u32 opcode) { CMP_RN_O8(7); } + +// ADD R0,#Offset8 +static INSN_REGPARM void thumb30(u32 opcode) { ADD_RN_O8(0); } +// ADD R1,#Offset8 +static INSN_REGPARM void thumb31(u32 opcode) { ADD_RN_O8(1); } +// ADD R2,#Offset8 +static INSN_REGPARM void thumb32(u32 opcode) { ADD_RN_O8(2); } +// ADD R3,#Offset8 +static INSN_REGPARM void thumb33(u32 opcode) { ADD_RN_O8(3); } +// ADD R4,#Offset8 +static INSN_REGPARM void thumb34(u32 opcode) { ADD_RN_O8(4); } +// ADD R5,#Offset8 +static INSN_REGPARM void thumb35(u32 opcode) { ADD_RN_O8(5); } +// ADD R6,#Offset8 +static INSN_REGPARM void thumb36(u32 opcode) { ADD_RN_O8(6); } +// ADD R7,#Offset8 +static INSN_REGPARM void thumb37(u32 opcode) { ADD_RN_O8(7); } + +// SUB R0,#Offset8 +static INSN_REGPARM void thumb38(u32 opcode) { SUB_RN_O8(0); } +// SUB R1,#Offset8 +static INSN_REGPARM void thumb39(u32 opcode) { SUB_RN_O8(1); } +// SUB R2,#Offset8 +static INSN_REGPARM void thumb3A(u32 opcode) { SUB_RN_O8(2); } +// SUB R3,#Offset8 +static INSN_REGPARM void thumb3B(u32 opcode) { SUB_RN_O8(3); } +// SUB R4,#Offset8 +static INSN_REGPARM void thumb3C(u32 opcode) { SUB_RN_O8(4); } +// SUB R5,#Offset8 +static INSN_REGPARM void thumb3D(u32 opcode) { SUB_RN_O8(5); } +// SUB R6,#Offset8 +static INSN_REGPARM void thumb3E(u32 opcode) { SUB_RN_O8(6); } +// SUB R7,#Offset8 +static INSN_REGPARM void thumb3F(u32 opcode) { SUB_RN_O8(7); } + +// ALU operations ///////////////////////////////////////////////////////// + +// AND Rd, Rs +static INSN_REGPARM void thumb40_0(u32 opcode) +{ + int dest = opcode & 7; + reg[dest].I &= reg[(opcode >> 3)&7].I; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; + Z_FLAG = reg[dest].I ? false : true; + THUMB_CONSOLE_OUTPUT(NULL, reg[2].I); +} + +// EOR Rd, Rs +static INSN_REGPARM void thumb40_1(u32 opcode) +{ + int dest = opcode & 7; + reg[dest].I ^= reg[(opcode >> 3)&7].I; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; + Z_FLAG = reg[dest].I ? false : true; +} + +// LSL Rd, Rs +static INSN_REGPARM void thumb40_2(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[(opcode >> 3)&7].B.B0; + if(value) { + if(value == 32) { + value = 0; + C_FLAG = (reg[dest].I & 1 ? true : false); + } else if(value < 32) { + LSL_RD_RS; + } else { + value = 0; + C_FLAG = false; + } + reg[dest].I = value; + } + N_FLAG = reg[dest].I & 0x80000000 ? true : false; + Z_FLAG = reg[dest].I ? false : true; + clockTicks = codeTicksAccess16(armNextPC)+2; +} + +// LSR Rd, Rs +static INSN_REGPARM void thumb40_3(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[(opcode >> 3)&7].B.B0; + if(value) { + if(value == 32) { + value = 0; + C_FLAG = (reg[dest].I & 0x80000000 ? true : false); + } else if(value < 32) { + LSR_RD_RS; + } else { + value = 0; + C_FLAG = false; + } + reg[dest].I = value; + } + N_FLAG = reg[dest].I & 0x80000000 ? true : false; + Z_FLAG = reg[dest].I ? false : true; + clockTicks = codeTicksAccess16(armNextPC)+2; +} + +// ASR Rd, Rs +static INSN_REGPARM void thumb41_0(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[(opcode >> 3)&7].B.B0; + if(value) { + if(value < 32) { + ASR_RD_RS; + reg[dest].I = value; + } else { + if(reg[dest].I & 0x80000000){ + reg[dest].I = 0xFFFFFFFF; + C_FLAG = true; + } else { + reg[dest].I = 0x00000000; + C_FLAG = false; + } + } + } + N_FLAG = reg[dest].I & 0x80000000 ? true : false; + Z_FLAG = reg[dest].I ? false : true; + clockTicks = codeTicksAccess16(armNextPC)+2; +} + +// ADC Rd, Rs +static INSN_REGPARM void thumb41_1(u32 opcode) +{ + int dest = opcode & 0x07; + u32 value = reg[(opcode >> 3)&7].I; + ADC_RD_RS; +} + +// SBC Rd, Rs +static INSN_REGPARM void thumb41_2(u32 opcode) +{ + int dest = opcode & 0x07; + u32 value = reg[(opcode >> 3)&7].I; + SBC_RD_RS; +} + +// ROR Rd, Rs +static INSN_REGPARM void thumb41_3(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[(opcode >> 3)&7].B.B0; + + if(value) { + value = value & 0x1f; + if(value == 0) { + C_FLAG = (reg[dest].I & 0x80000000 ? true : false); + } else { + ROR_RD_RS; + reg[dest].I = value; + } + } + clockTicks = codeTicksAccess16(armNextPC)+2; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; + Z_FLAG = reg[dest].I ? false : true; +} + +// TST Rd, Rs +static INSN_REGPARM void thumb42_0(u32 opcode) +{ + u32 value = reg[opcode & 7].I & reg[(opcode >> 3) & 7].I; + N_FLAG = value & 0x80000000 ? true : false; + Z_FLAG = value ? false : true; +} + +// NEG Rd, Rs +static INSN_REGPARM void thumb42_1(u32 opcode) +{ + int dest = opcode & 7; + int source = (opcode >> 3) & 7; + NEG_RD_RS; +} + +// CMP Rd, Rs +static INSN_REGPARM void thumb42_2(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[(opcode >> 3)&7].I; + CMP_RD_RS; +} + +// CMN Rd, Rs +static INSN_REGPARM void thumb42_3(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[(opcode >> 3)&7].I; + CMN_RD_RS; +} + +// ORR Rd, Rs +static INSN_REGPARM void thumb43_0(u32 opcode) +{ + int dest = opcode & 7; + reg[dest].I |= reg[(opcode >> 3) & 7].I; + Z_FLAG = reg[dest].I ? false : true; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; +} + +// MUL Rd, Rs +static INSN_REGPARM void thumb43_1(u32 opcode) +{ + clockTicks = 1; + int dest = opcode & 7; + u32 rm = reg[dest].I; + reg[dest].I = reg[(opcode >> 3) & 7].I * rm; + if (((s32)rm) < 0) + rm = ~rm; + if ((rm & 0xFFFFFF00) == 0) + clockTicks += 0; + else if ((rm & 0xFFFF0000) == 0) + clockTicks += 1; + else if ((rm & 0xFF000000) == 0) + clockTicks += 2; + else + clockTicks += 3; + busPrefetchCount = (busPrefetchCount<>(8-clockTicks)); + clockTicks += codeTicksAccess16(armNextPC) + 1; + Z_FLAG = reg[dest].I ? false : true; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; +} + +// BIC Rd, Rs +static INSN_REGPARM void thumb43_2(u32 opcode) +{ + int dest = opcode & 7; + reg[dest].I &= (~reg[(opcode >> 3) & 7].I); + Z_FLAG = reg[dest].I ? false : true; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; +} + +// MVN Rd, Rs +static INSN_REGPARM void thumb43_3(u32 opcode) +{ + int dest = opcode & 7; + reg[dest].I = ~reg[(opcode >> 3) & 7].I; + Z_FLAG = reg[dest].I ? false : true; + N_FLAG = reg[dest].I & 0x80000000 ? true : false; +} + +// High-register instructions and BX ////////////////////////////////////// + +// ADD Rd, Hs +static INSN_REGPARM void thumb44_1(u32 opcode) +{ + reg[opcode&7].I += reg[((opcode>>3)&7)+8].I; +} + +// ADD Hd, Rs +static INSN_REGPARM void thumb44_2(u32 opcode) +{ + reg[(opcode&7)+8].I += reg[(opcode>>3)&7].I; + if((opcode&7) == 7) { + reg[15].I &= 0xFFFFFFFE; + armNextPC = reg[15].I; + reg[15].I += 2; + THUMB_PREFETCH; + clockTicks = codeTicksAccessSeq16(armNextPC)*2 + + codeTicksAccess16(armNextPC) + 3; + } +} + +// ADD Hd, Hs +static INSN_REGPARM void thumb44_3(u32 opcode) +{ + reg[(opcode&7)+8].I += reg[((opcode>>3)&7)+8].I; + if((opcode&7) == 7) { + reg[15].I &= 0xFFFFFFFE; + armNextPC = reg[15].I; + reg[15].I += 2; + THUMB_PREFETCH; + clockTicks = codeTicksAccessSeq16(armNextPC)*2 + + codeTicksAccess16(armNextPC) + 3; + } +} + +// CMP Rd, Hs +static INSN_REGPARM void thumb45_1(u32 opcode) +{ + int dest = opcode & 7; + u32 value = reg[((opcode>>3)&7)+8].I; + CMP_RD_RS; +} + +// CMP Hd, Rs +static INSN_REGPARM void thumb45_2(u32 opcode) +{ + int dest = (opcode & 7) + 8; + u32 value = reg[(opcode>>3)&7].I; + CMP_RD_RS; +} + +// CMP Hd, Hs +static INSN_REGPARM void thumb45_3(u32 opcode) +{ + int dest = (opcode & 7) + 8; + u32 value = reg[((opcode>>3)&7)+8].I; + CMP_RD_RS; +} + +// MOV Rd, Hs +static INSN_REGPARM void thumb46_1(u32 opcode) +{ + reg[opcode&7].I = reg[((opcode>>3)&7)+8].I; +} + +// MOV Hd, Rs +static INSN_REGPARM void thumb46_2(u32 opcode) +{ + reg[(opcode&7)+8].I = reg[(opcode>>3)&7].I; + if((opcode&7) == 7) { + UPDATE_OLDREG; + reg[15].I &= 0xFFFFFFFE; + armNextPC = reg[15].I; + reg[15].I += 2; + THUMB_PREFETCH; + clockTicks = codeTicksAccessSeq16(armNextPC)*2 + + codeTicksAccess16(armNextPC) + 3; + } +} + +// MOV Hd, Hs +static INSN_REGPARM void thumb46_3(u32 opcode) +{ + reg[(opcode&7)+8].I = reg[((opcode>>3)&7)+8].I; + if((opcode&7) == 7) { + UPDATE_OLDREG; + reg[15].I &= 0xFFFFFFFE; + armNextPC = reg[15].I; + reg[15].I += 2; + THUMB_PREFETCH; + clockTicks = codeTicksAccessSeq16(armNextPC)*2 + + codeTicksAccess16(armNextPC) + 3; + } +} + + +// BX Rs +static INSN_REGPARM void thumb47(u32 opcode) +{ + int base = (opcode >> 3) & 15; + busPrefetchCount=0; + UPDATE_OLDREG; + reg[15].I = reg[base].I; + if(reg[base].I & 1) { + armState = false; + reg[15].I &= 0xFFFFFFFE; + armNextPC = reg[15].I; + reg[15].I += 2; + THUMB_PREFETCH; + clockTicks = codeTicksAccessSeq16(armNextPC) + + codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 3; + } else { + armState = true; + reg[15].I &= 0xFFFFFFFC; + armNextPC = reg[15].I; + reg[15].I += 4; + ARM_PREFETCH; + clockTicks = codeTicksAccessSeq32(armNextPC) + + codeTicksAccessSeq32(armNextPC) + codeTicksAccess32(armNextPC) + 3; + } +} + +// Load/store instructions //////////////////////////////////////////////// + +// LDR R0~R7,[PC, #Imm] +static INSN_REGPARM void thumb48(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); + reg[regist].I = CPUReadMemoryQuick(address); + busPrefetchCount=0; + clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); +} + +// STR Rd, [Rs, Rn] +static INSN_REGPARM void thumb50(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + CPUWriteMemory(address, reg[opcode & 7].I); + clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2; +} + +// STRH Rd, [Rs, Rn] +static INSN_REGPARM void thumb52(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + CPUWriteHalfWord(address, reg[opcode&7].W.W0); + clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2; +} + +// STRB Rd, [Rs, Rn] +static INSN_REGPARM void thumb54(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode >>6)&7].I; + CPUWriteByte(address, reg[opcode & 7].B.B0); + clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2; +} + +// LDSB Rd, [Rs, Rn] +static INSN_REGPARM void thumb56(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + reg[opcode&7].I = (s8)CPUReadByte(address); + clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); +} + +// LDR Rd, [Rs, Rn] +static INSN_REGPARM void thumb58(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + reg[opcode&7].I = CPUReadMemory(address); + clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); +} + +// LDRH Rd, [Rs, Rn] +static INSN_REGPARM void thumb5A(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + reg[opcode&7].I = CPUReadHalfWord(address); + clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); +} + +// LDRB Rd, [Rs, Rn] +static INSN_REGPARM void thumb5C(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + reg[opcode&7].I = CPUReadByte(address); + clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); +} + +// LDSH Rd, [Rs, Rn] +static INSN_REGPARM void thumb5E(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; + reg[opcode&7].I = (s16)CPUReadHalfWordSigned(address); + clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); +} + +// STR Rd, [Rs, #Imm] +static INSN_REGPARM void thumb60(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2); + CPUWriteMemory(address, reg[opcode&7].I); + clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2; +} + +// LDR Rd, [Rs, #Imm] +static INSN_REGPARM void thumb68(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2); + reg[opcode&7].I = CPUReadMemory(address); + clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); +} + +// STRB Rd, [Rs, #Imm] +static INSN_REGPARM void thumb70(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)); + CPUWriteByte(address, reg[opcode&7].B.B0); + clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2; +} + +// LDRB Rd, [Rs, #Imm] +static INSN_REGPARM void thumb78(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)); + reg[opcode&7].I = CPUReadByte(address); + clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); +} + +// STRH Rd, [Rs, #Imm] +static INSN_REGPARM void thumb80(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1); + CPUWriteHalfWord(address, reg[opcode&7].W.W0); + clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2; +} + +// LDRH Rd, [Rs, #Imm] +static INSN_REGPARM void thumb88(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1); + reg[opcode&7].I = CPUReadHalfWord(address); + clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); +} + +// STR R0~R7, [SP, #Imm] +static INSN_REGPARM void thumb90(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[13].I + ((opcode&255)<<2); + CPUWriteMemory(address, reg[regist].I); + clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2; +} + +// LDR R0~R7, [SP, #Imm] +static INSN_REGPARM void thumb98(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[13].I + ((opcode&255)<<2); + reg[regist].I = CPUReadMemoryQuick(address); + clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC); +} + +// PC/stack-related /////////////////////////////////////////////////////// + +// ADD R0~R7, PC, Imm +static INSN_REGPARM void thumbA0(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + reg[regist].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); +} + +// ADD R0~R7, SP, Imm +static INSN_REGPARM void thumbA8(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + reg[regist].I = reg[13].I + ((opcode&255)<<2); +} + +// ADD SP, Imm +static INSN_REGPARM void thumbB0(u32 opcode) +{ + int offset = (opcode & 127) << 2; + if(opcode & 0x80) + offset = -offset; + reg[13].I += offset; +} + +// Push and pop /////////////////////////////////////////////////////////// + +#define PUSH_REG(val, r) \ + if (opcode & (val)) { \ + CPUWriteMemory(address, reg[(r)].I); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address); \ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address); \ + } \ + count++; \ + address += 4; \ + } + +#define POP_REG(val, r) \ + if (opcode & (val)) { \ + reg[(r)].I = CPUReadMemory(address); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address); \ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address); \ + } \ + count++; \ + address += 4; \ + } + +// PUSH {Rlist} +static INSN_REGPARM void thumbB4(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int count = 0; + u32 temp = reg[13].I - 4 * cpuBitsSet[opcode & 0xff]; + u32 address = temp & 0xFFFFFFFC; + PUSH_REG(1, 0); + PUSH_REG(2, 1); + PUSH_REG(4, 2); + PUSH_REG(8, 3); + PUSH_REG(16, 4); + PUSH_REG(32, 5); + PUSH_REG(64, 6); + PUSH_REG(128, 7); + clockTicks += 1 + codeTicksAccess16(armNextPC); + reg[13].I = temp; +} + +// PUSH {Rlist, LR} +static INSN_REGPARM void thumbB5(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int count = 0; + u32 temp = reg[13].I - 4 - 4 * cpuBitsSet[opcode & 0xff]; + u32 address = temp & 0xFFFFFFFC; + PUSH_REG(1, 0); + PUSH_REG(2, 1); + PUSH_REG(4, 2); + PUSH_REG(8, 3); + PUSH_REG(16, 4); + PUSH_REG(32, 5); + PUSH_REG(64, 6); + PUSH_REG(128, 7); + PUSH_REG(256, 14); + clockTicks += 1 + codeTicksAccess16(armNextPC); + reg[13].I = temp; +} + +// POP {Rlist} +static INSN_REGPARM void thumbBC(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int count = 0; + u32 address = reg[13].I & 0xFFFFFFFC; + u32 temp = reg[13].I + 4*cpuBitsSet[opcode & 0xFF]; + POP_REG(1, 0); + POP_REG(2, 1); + POP_REG(4, 2); + POP_REG(8, 3); + POP_REG(16, 4); + POP_REG(32, 5); + POP_REG(64, 6); + POP_REG(128, 7); + reg[13].I = temp; + clockTicks = 2 + codeTicksAccess16(armNextPC); +} + +// POP {Rlist, PC} +static INSN_REGPARM void thumbBD(u32 opcode) +{ + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + int count = 0; + u32 address = reg[13].I & 0xFFFFFFFC; + u32 temp = reg[13].I + 4 + 4*cpuBitsSet[opcode & 0xFF]; + POP_REG(1, 0); + POP_REG(2, 1); + POP_REG(4, 2); + POP_REG(8, 3); + POP_REG(16, 4); + POP_REG(32, 5); + POP_REG(64, 6); + POP_REG(128, 7); + reg[15].I = (CPUReadMemory(address) & 0xFFFFFFFE); + if (!count) { + clockTicks += 1 + dataTicksAccess32(address); + } else { + clockTicks += 1 + dataTicksAccessSeq32(address); + } + count++; + armNextPC = reg[15].I; + reg[15].I += 2; + reg[13].I = temp; + THUMB_PREFETCH; + busPrefetchCount = 0; + clockTicks += 3 + codeTicksAccess16(armNextPC) + codeTicksAccess16(armNextPC); +} + +// Load/store multiple //////////////////////////////////////////////////// + +#define THUMB_STM_REG(val,r,b) \ + if(opcode & (val)) { \ + CPUWriteMemory(address, reg[(r)].I); \ + reg[(b)].I = temp; \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address); \ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address); \ + } \ + count++; \ + address += 4; \ + } + +#define THUMB_LDM_REG(val,r) \ + if(opcode & (val)) { \ + reg[(r)].I = CPUReadMemory(address); \ + if (!count) { \ + clockTicks += 1 + dataTicksAccess32(address); \ + } else { \ + clockTicks += 1 + dataTicksAccessSeq32(address); \ + } \ + count++; \ + address += 4; \ + } + +// STM R0~7!, {Rlist} +static INSN_REGPARM void thumbC0(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[regist].I & 0xFFFFFFFC; + u32 temp = reg[regist].I + 4*cpuBitsSet[opcode & 0xff]; + int count = 0; + // store + THUMB_STM_REG(1, 0, regist); + THUMB_STM_REG(2, 1, regist); + THUMB_STM_REG(4, 2, regist); + THUMB_STM_REG(8, 3, regist); + THUMB_STM_REG(16, 4, regist); + THUMB_STM_REG(32, 5, regist); + THUMB_STM_REG(64, 6, regist); + THUMB_STM_REG(128, 7, regist); + clockTicks = 1 + codeTicksAccess16(armNextPC); +} + +// LDM R0~R7!, {Rlist} +static INSN_REGPARM void thumbC8(u32 opcode) +{ + u8 regist = (opcode >> 8) & 7; + if (busPrefetchCount == 0) + busPrefetch = busPrefetchEnable; + u32 address = reg[regist].I & 0xFFFFFFFC; + u32 temp = reg[regist].I + 4*cpuBitsSet[opcode & 0xFF]; + int count = 0; + // load + THUMB_LDM_REG(1, 0); + THUMB_LDM_REG(2, 1); + THUMB_LDM_REG(4, 2); + THUMB_LDM_REG(8, 3); + THUMB_LDM_REG(16, 4); + THUMB_LDM_REG(32, 5); + THUMB_LDM_REG(64, 6); + THUMB_LDM_REG(128, 7); + clockTicks = 2 + codeTicksAccess16(armNextPC); + if(!(opcode & (1<>6])(opcode); + + if (clockTicks < 0) + return 0; + if (clockTicks==0) + clockTicks = codeTicksAccessSeq16(oldArmNextPC) + 1; + cpuTotalTicks += clockTicks; + + } while (cpuTotalTicks < cpuNextEvent && !armState && !holdState && !SWITicks); + return 1; +} diff --git a/source/vba/agb/GBA.cpp b/source/vba/agb/GBA.cpp new file mode 100644 index 0000000..5ce6663 --- /dev/null +++ b/source/vba/agb/GBA.cpp @@ -0,0 +1,3994 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 Forgotten and the VBA development team +// Copyright (C) VBA-M 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. + +#include "sdfileio.h" +#include +#include +#include +#include +#include "GBA.h" +#include "GBAcpu.h" +#include "GBAinline.h" +#include "../Globals.h" +#include "GBAGfx.h" +#include "../EEprom.h" +#include "../Flash.h" +#include "../Sound.h" +#include "../Sram.h" +#include "../bios.h" +#include "../Cheats.h" +#include "../NLS.h" +#include "../elf.h" +#include "../Util.h" +#include "../Port.h" +#include "../System.h" +#include "agbprint.h" +#ifdef PROFILING +#include "prof/prof.h" +#endif + +#ifdef __GNUC__ +#define _stricmp strcasecmp +#endif + + +extern int emulating; +#ifdef LINK_EMULATION +extern int linktime; +extern void StartLink(u16); +extern void StartJOYLink(u16); +extern void StartGPLink(u16); +extern void LinkSSend(u16); +extern void LinkUpdate(int); +extern int linktime2; +#endif +int SWITicks = 0; +int IRQTicks = 0; + +u32 mastercode = 0; +int layerEnableDelay = 0; +bool busPrefetch = false; +bool busPrefetchEnable = false; +u32 busPrefetchCount = 0; +int cpuDmaTicksToUpdate = 0; +int cpuDmaCount = 0; +bool cpuDmaHack = false; +u32 cpuDmaLast = 0; +int dummyAddress = 0; + +bool cpuBreakLoop = false; +int cpuNextEvent = 0; + +int gbaSaveType = 0; // used to remember the save type on reset +bool intState = false; +bool stopState = false; +bool holdState = false; +int holdType = 0; +bool cpuSramEnabled = true; +bool cpuFlashEnabled = true; +bool cpuEEPROMEnabled = true; +bool cpuEEPROMSensorEnabled = false; + +u32 cpuPrefetch[2]; + +int cpuTotalTicks = 0; +#ifdef PROFILING +int profilingTicks = 0; +int profilingTicksReload = 0; +static profile_segment *profilSegment = NULL; +#endif + +#ifdef BKPT_SUPPORT +u8 freezeWorkRAM[0x40000]; +u8 freezeInternalRAM[0x8000]; +u8 freezeVRAM[0x18000]; +u8 freezePRAM[0x400]; +u8 freezeOAM[0x400]; +bool debugger_last; +#endif + +int lcdTicks = (useBios && !skipBios) ? 1008 : 208; +u8 timerOnOffDelay = 0; +u16 timer0Value = 0; +bool timer0On = false; +int timer0Ticks = 0; +int timer0Reload = 0; +int timer0ClockReload = 0; +u16 timer1Value = 0; +bool timer1On = false; +int timer1Ticks = 0; +int timer1Reload = 0; +int timer1ClockReload = 0; +u16 timer2Value = 0; +bool timer2On = false; +int timer2Ticks = 0; +int timer2Reload = 0; +int timer2ClockReload = 0; +u16 timer3Value = 0; +bool timer3On = false; +int timer3Ticks = 0; +int timer3Reload = 0; +int timer3ClockReload = 0; +u32 dma0Source = 0; +u32 dma0Dest = 0; +u32 dma1Source = 0; +u32 dma1Dest = 0; +u32 dma2Source = 0; +u32 dma2Dest = 0; +u32 dma3Source = 0; +u32 dma3Dest = 0; +void (*cpuSaveGameFunc)(u32,u8) = flashSaveDecide; +void (*renderLine)() = mode0RenderLine; +bool fxOn = false; +bool windowOn = false; +int frameCount = 0; +char buffer[1024]; +FILE *out = NULL; +u32 lastTime = 0; +int count = 0; + +int capture = 0; +int capturePrevious = 0; +int captureNumber = 0; + +const int TIMER_TICKS[4] = { + 0, + 6, + 8, + 10 +}; + +const u32 objTilesAddress [3] = {0x010000, 0x014000, 0x014000}; +const u8 gamepakRamWaitState[4] = { 4, 3, 2, 8 }; +const u8 gamepakWaitState[4] = { 4, 3, 2, 8 }; +const u8 gamepakWaitState0[2] = { 2, 1 }; +const u8 gamepakWaitState1[2] = { 4, 1 }; +const u8 gamepakWaitState2[2] = { 8, 1 }; +const bool isInRom [16]= + { false, false, false, false, false, false, false, false, + true, true, true, true, true, true, false, false }; + +u8 memoryWait[16] = + { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 }; +u8 memoryWait32[16] = + { 0, 0, 5, 0, 0, 1, 1, 0, 7, 7, 9, 9, 13, 13, 4, 0 }; +u8 memoryWaitSeq[16] = + { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 }; +u8 memoryWaitSeq32[16] = + { 0, 0, 5, 0, 0, 1, 1, 0, 5, 5, 9, 9, 17, 17, 4, 0 }; + +// The videoMemoryWait constants are used to add some waitstates +// if the opcode access video memory data outside of vblank/hblank +// It seems to happen on only one ticks for each pixel. +// Not used for now (too problematic with current code). +//const u8 videoMemoryWait[16] = +// {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + +u8 biosProtected[4]; + +#ifdef WORDS_BIGENDIAN +bool cpuBiosSwapped = false; +#endif + +u32 myROM[] = { +0xEA000006, +0xEA000093, +0xEA000006, +0x00000000, +0x00000000, +0x00000000, +0xEA000088, +0x00000000, +0xE3A00302, +0xE1A0F000, +0xE92D5800, +0xE55EC002, +0xE28FB03C, +0xE79BC10C, +0xE14FB000, +0xE92D0800, +0xE20BB080, +0xE38BB01F, +0xE129F00B, +0xE92D4004, +0xE1A0E00F, +0xE12FFF1C, +0xE8BD4004, +0xE3A0C0D3, +0xE129F00C, +0xE8BD0800, +0xE169F00B, +0xE8BD5800, +0xE1B0F00E, +0x0000009C, +0x0000009C, +0x0000009C, +0x0000009C, +0x000001F8, +0x000001F0, +0x000000AC, +0x000000A0, +0x000000FC, +0x00000168, +0xE12FFF1E, +0xE1A03000, +0xE1A00001, +0xE1A01003, +0xE2113102, +0x42611000, +0xE033C040, +0x22600000, +0xE1B02001, +0xE15200A0, +0x91A02082, +0x3AFFFFFC, +0xE1500002, +0xE0A33003, +0x20400002, +0xE1320001, +0x11A020A2, +0x1AFFFFF9, +0xE1A01000, +0xE1A00003, +0xE1B0C08C, +0x22600000, +0x42611000, +0xE12FFF1E, +0xE92D0010, +0xE1A0C000, +0xE3A01001, +0xE1500001, +0x81A000A0, +0x81A01081, +0x8AFFFFFB, +0xE1A0000C, +0xE1A04001, +0xE3A03000, +0xE1A02001, +0xE15200A0, +0x91A02082, +0x3AFFFFFC, +0xE1500002, +0xE0A33003, +0x20400002, +0xE1320001, +0x11A020A2, +0x1AFFFFF9, +0xE0811003, +0xE1B010A1, +0xE1510004, +0x3AFFFFEE, +0xE1A00004, +0xE8BD0010, +0xE12FFF1E, +0xE0010090, +0xE1A01741, +0xE2611000, +0xE3A030A9, +0xE0030391, +0xE1A03743, +0xE2833E39, +0xE0030391, +0xE1A03743, +0xE2833C09, +0xE283301C, +0xE0030391, +0xE1A03743, +0xE2833C0F, +0xE28330B6, +0xE0030391, +0xE1A03743, +0xE2833C16, +0xE28330AA, +0xE0030391, +0xE1A03743, +0xE2833A02, +0xE2833081, +0xE0030391, +0xE1A03743, +0xE2833C36, +0xE2833051, +0xE0030391, +0xE1A03743, +0xE2833CA2, +0xE28330F9, +0xE0000093, +0xE1A00840, +0xE12FFF1E, +0xE3A00001, +0xE3A01001, +0xE92D4010, +0xE3A03000, +0xE3A04001, +0xE3500000, +0x1B000004, +0xE5CC3301, +0xEB000002, +0x0AFFFFFC, +0xE8BD4010, +0xE12FFF1E, +0xE3A0C301, +0xE5CC3208, +0xE15C20B8, +0xE0110002, +0x10222000, +0x114C20B8, +0xE5CC4208, +0xE12FFF1E, +0xE92D500F, +0xE3A00301, +0xE1A0E00F, +0xE510F004, +0xE8BD500F, +0xE25EF004, +0xE59FD044, +0xE92D5000, +0xE14FC000, +0xE10FE000, +0xE92D5000, +0xE3A0C302, +0xE5DCE09C, +0xE35E00A5, +0x1A000004, +0x05DCE0B4, +0x021EE080, +0xE28FE004, +0x159FF018, +0x059FF018, +0xE59FD018, +0xE8BD5000, +0xE169F00C, +0xE8BD5000, +0xE25EF004, +0x03007FF0, +0x09FE2000, +0x09FFC000, +0x03007FE0 +}; + +variable_desc saveGameStruct[] = { + { &DISPCNT , sizeof(u16) }, + { &DISPSTAT , sizeof(u16) }, + { &VCOUNT , sizeof(u16) }, + { &BG0CNT , sizeof(u16) }, + { &BG1CNT , sizeof(u16) }, + { &BG2CNT , sizeof(u16) }, + { &BG3CNT , sizeof(u16) }, + { &BG0HOFS , sizeof(u16) }, + { &BG0VOFS , sizeof(u16) }, + { &BG1HOFS , sizeof(u16) }, + { &BG1VOFS , sizeof(u16) }, + { &BG2HOFS , sizeof(u16) }, + { &BG2VOFS , sizeof(u16) }, + { &BG3HOFS , sizeof(u16) }, + { &BG3VOFS , sizeof(u16) }, + { &BG2PA , sizeof(u16) }, + { &BG2PB , sizeof(u16) }, + { &BG2PC , sizeof(u16) }, + { &BG2PD , sizeof(u16) }, + { &BG2X_L , sizeof(u16) }, + { &BG2X_H , sizeof(u16) }, + { &BG2Y_L , sizeof(u16) }, + { &BG2Y_H , sizeof(u16) }, + { &BG3PA , sizeof(u16) }, + { &BG3PB , sizeof(u16) }, + { &BG3PC , sizeof(u16) }, + { &BG3PD , sizeof(u16) }, + { &BG3X_L , sizeof(u16) }, + { &BG3X_H , sizeof(u16) }, + { &BG3Y_L , sizeof(u16) }, + { &BG3Y_H , sizeof(u16) }, + { &WIN0H , sizeof(u16) }, + { &WIN1H , sizeof(u16) }, + { &WIN0V , sizeof(u16) }, + { &WIN1V , sizeof(u16) }, + { &WININ , sizeof(u16) }, + { &WINOUT , sizeof(u16) }, + { &MOSAIC , sizeof(u16) }, + { &BLDMOD , sizeof(u16) }, + { &COLEV , sizeof(u16) }, + { &COLY , sizeof(u16) }, + { &DM0SAD_L , sizeof(u16) }, + { &DM0SAD_H , sizeof(u16) }, + { &DM0DAD_L , sizeof(u16) }, + { &DM0DAD_H , sizeof(u16) }, + { &DM0CNT_L , sizeof(u16) }, + { &DM0CNT_H , sizeof(u16) }, + { &DM1SAD_L , sizeof(u16) }, + { &DM1SAD_H , sizeof(u16) }, + { &DM1DAD_L , sizeof(u16) }, + { &DM1DAD_H , sizeof(u16) }, + { &DM1CNT_L , sizeof(u16) }, + { &DM1CNT_H , sizeof(u16) }, + { &DM2SAD_L , sizeof(u16) }, + { &DM2SAD_H , sizeof(u16) }, + { &DM2DAD_L , sizeof(u16) }, + { &DM2DAD_H , sizeof(u16) }, + { &DM2CNT_L , sizeof(u16) }, + { &DM2CNT_H , sizeof(u16) }, + { &DM3SAD_L , sizeof(u16) }, + { &DM3SAD_H , sizeof(u16) }, + { &DM3DAD_L , sizeof(u16) }, + { &DM3DAD_H , sizeof(u16) }, + { &DM3CNT_L , sizeof(u16) }, + { &DM3CNT_H , sizeof(u16) }, + { &TM0D , sizeof(u16) }, + { &TM0CNT , sizeof(u16) }, + { &TM1D , sizeof(u16) }, + { &TM1CNT , sizeof(u16) }, + { &TM2D , sizeof(u16) }, + { &TM2CNT , sizeof(u16) }, + { &TM3D , sizeof(u16) }, + { &TM3CNT , sizeof(u16) }, + { &P1 , sizeof(u16) }, + { &IE , sizeof(u16) }, + { &IF , sizeof(u16) }, + { &IME , sizeof(u16) }, + { &holdState, sizeof(bool) }, + { &holdType, sizeof(int) }, + { &lcdTicks, sizeof(int) }, + { &timer0On , sizeof(bool) }, + { &timer0Ticks , sizeof(int) }, + { &timer0Reload , sizeof(int) }, + { &timer0ClockReload , sizeof(int) }, + { &timer1On , sizeof(bool) }, + { &timer1Ticks , sizeof(int) }, + { &timer1Reload , sizeof(int) }, + { &timer1ClockReload , sizeof(int) }, + { &timer2On , sizeof(bool) }, + { &timer2Ticks , sizeof(int) }, + { &timer2Reload , sizeof(int) }, + { &timer2ClockReload , sizeof(int) }, + { &timer3On , sizeof(bool) }, + { &timer3Ticks , sizeof(int) }, + { &timer3Reload , sizeof(int) }, + { &timer3ClockReload , sizeof(int) }, + { &dma0Source , sizeof(u32) }, + { &dma0Dest , sizeof(u32) }, + { &dma1Source , sizeof(u32) }, + { &dma1Dest , sizeof(u32) }, + { &dma2Source , sizeof(u32) }, + { &dma2Dest , sizeof(u32) }, + { &dma3Source , sizeof(u32) }, + { &dma3Dest , sizeof(u32) }, + { &fxOn, sizeof(bool) }, + { &windowOn, sizeof(bool) }, + { &N_FLAG , sizeof(bool) }, + { &C_FLAG , sizeof(bool) }, + { &Z_FLAG , sizeof(bool) }, + { &V_FLAG , sizeof(bool) }, + { &armState , sizeof(bool) }, + { &armIrqEnable , sizeof(bool) }, + { &armNextPC , sizeof(u32) }, + { &armMode , sizeof(int) }, + { &saveType , sizeof(int) }, + { NULL, 0 } +}; + +static int romSize = 0x2000000; + +#ifdef PROFILING +void cpuProfil(profile_segment *seg) +{ + profilSegment = seg; +} + +void cpuEnableProfiling(int hz) +{ + if(hz == 0) + hz = 100; + profilingTicks = profilingTicksReload = 16777216 / hz; + profSetHertz(hz); +} +#endif + + +inline int CPUUpdateTicks() +{ + int cpuLoopTicks = lcdTicks; + + if(soundTicks < cpuLoopTicks) + cpuLoopTicks = soundTicks; + + if(timer0On && (timer0Ticks < cpuLoopTicks)) { + cpuLoopTicks = timer0Ticks; + } + if(timer1On && !(TM1CNT & 4) && (timer1Ticks < cpuLoopTicks)) { + cpuLoopTicks = timer1Ticks; + } + if(timer2On && !(TM2CNT & 4) && (timer2Ticks < cpuLoopTicks)) { + cpuLoopTicks = timer2Ticks; + } + if(timer3On && !(TM3CNT & 4) && (timer3Ticks < cpuLoopTicks)) { + cpuLoopTicks = timer3Ticks; + } +#ifdef PROFILING + if(profilingTicksReload != 0) { + if(profilingTicks < cpuLoopTicks) { + cpuLoopTicks = profilingTicks; + } + } +#endif + + if (SWITicks) { + if (SWITicks < cpuLoopTicks) + cpuLoopTicks = SWITicks; + } + + if (IRQTicks) { + if (IRQTicks < cpuLoopTicks) + cpuLoopTicks = IRQTicks; + } + + return cpuLoopTicks; +} + +void CPUUpdateWindow0() +{ + int x00 = WIN0H>>8; + int x01 = WIN0H & 255; + + if(x00 <= x01) { + for(int i = 0; i < 240; i++) { + gfxInWin0[i] = (i >= x00 && i < x01); + } + } else { + for(int i = 0; i < 240; i++) { + gfxInWin0[i] = (i >= x00 || i < x01); + } + } +} + +void CPUUpdateWindow1() +{ + int x00 = WIN1H>>8; + int x01 = WIN1H & 255; + + if(x00 <= x01) { + for(int i = 0; i < 240; i++) { + gfxInWin1[i] = (i >= x00 && i < x01); + } + } else { + for(int i = 0; i < 240; i++) { + gfxInWin1[i] = (i >= x00 || i < x01); + } + } +} + +extern u32 line0[240]; +extern u32 line1[240]; +extern u32 line2[240]; +extern u32 line3[240]; + +#define CLEAR_ARRAY(a) \ + {\ + u32 *array = (a);\ + for(int i = 0; i < 240; i++) {\ + *array++ = 0x80000000;\ + }\ + }\ + +void CPUUpdateRenderBuffers(bool force) +{ + if(!(layerEnable & 0x0100) || force) { + CLEAR_ARRAY(line0); + } + if(!(layerEnable & 0x0200) || force) { + CLEAR_ARRAY(line1); + } + if(!(layerEnable & 0x0400) || force) { + CLEAR_ARRAY(line2); + } + if(!(layerEnable & 0x0800) || force) { + CLEAR_ARRAY(line3); + } +} + +static bool CPUWriteState(gzFile gzFile) +{ + utilWriteInt(gzFile, SAVE_GAME_VERSION); + + utilGzWrite(gzFile, &rom[0xa0], 16); + + utilWriteInt(gzFile, useBios); + + utilGzWrite(gzFile, ®[0], sizeof(reg)); + + utilWriteData(gzFile, saveGameStruct); + + // new to version 0.7.1 + utilWriteInt(gzFile, stopState); + // new to version 0.8 + utilWriteInt(gzFile, IRQTicks); + + utilGzWrite(gzFile, internalRAM, 0x8000); + utilGzWrite(gzFile, paletteRAM, 0x400); + utilGzWrite(gzFile, workRAM, 0x40000); + utilGzWrite(gzFile, vram, 0x20000); + utilGzWrite(gzFile, oam, 0x400); + utilGzWrite(gzFile, pix, 4*241*162); + utilGzWrite(gzFile, ioMem, 0x400); + + eepromSaveGame(gzFile); + flashSaveGame(gzFile); + soundSaveGame(gzFile); + + cheatsSaveGame(gzFile); + + // version 1.5 + rtcSaveGame(gzFile); + + return true; +} + +bool CPUWriteState(const char *file) +{ + gzFile gzFile = utilGzOpen(file, "wb"); + + if(gzFile == NULL) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), file); + return false; + } + + bool res = CPUWriteState(gzFile); + + utilGzClose(gzFile); + + return res; +} + +bool CPUWriteMemState(char *memory, int available) +{ + gzFile gzFile = utilMemGzOpen(memory, available, "w"); + + if(gzFile == NULL) { + return false; + } + + bool res = CPUWriteState(gzFile); + + long pos = utilGzMemTell(gzFile)+8; + + if(pos >= (available)) + res = false; + + utilGzClose(gzFile); + + return res; +} + +static bool CPUReadState(gzFile gzFile) +{ + int version = utilReadInt(gzFile); + + if(version > SAVE_GAME_VERSION || version < SAVE_GAME_VERSION_1) { + systemMessage(MSG_UNSUPPORTED_VBA_SGM, + N_("Unsupported VisualBoyAdvance save game version %d"), + version); + return false; + } + + u8 romname[17]; + + utilGzRead(gzFile, romname, 16); + + if(memcmp(&rom[0xa0], romname, 16) != 0) { + romname[16]=0; + for(int i = 0; i < 16; i++) + if(romname[i] < 32) + romname[i] = 32; + systemMessage(MSG_CANNOT_LOAD_SGM, N_("Cannot load save game for %s"), romname); + return false; + } + + bool ub = utilReadInt(gzFile) ? true : false; + + if(ub != useBios) { + if(useBios) + systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS, + N_("Save game is not using the BIOS files")); + else + systemMessage(MSG_SAVE_GAME_USING_BIOS, + N_("Save game is using the BIOS file")); + return false; + } + + utilGzRead(gzFile, ®[0], sizeof(reg)); + + utilReadData(gzFile, saveGameStruct); + + if(version < SAVE_GAME_VERSION_3) + stopState = false; + else + stopState = utilReadInt(gzFile) ? true : false; + + if(version < SAVE_GAME_VERSION_4) + { + IRQTicks = 0; + intState = false; + } + else + { + IRQTicks = utilReadInt(gzFile); + if (IRQTicks>0) + intState = true; + else + { + intState = false; + IRQTicks = 0; + } + } + + utilGzRead(gzFile, internalRAM, 0x8000); + utilGzRead(gzFile, paletteRAM, 0x400); + utilGzRead(gzFile, workRAM, 0x40000); + utilGzRead(gzFile, vram, 0x20000); + utilGzRead(gzFile, oam, 0x400); + if(version < SAVE_GAME_VERSION_6) + utilGzRead(gzFile, pix, 4*240*160); + else + utilGzRead(gzFile, pix, 4*241*162); + utilGzRead(gzFile, ioMem, 0x400); + + if(skipSaveGameBattery) { + // skip eeprom data + eepromReadGameSkip(gzFile, version); + // skip flash data + flashReadGameSkip(gzFile, version); + } else { + eepromReadGame(gzFile, version); + flashReadGame(gzFile, version); + } + soundReadGame(gzFile, version); + + if(version > SAVE_GAME_VERSION_1) { + cheatsReadGame(gzFile, version); + } + if(version > SAVE_GAME_VERSION_6) { + rtcReadGame(gzFile); + } + + if(version <= SAVE_GAME_VERSION_7) { + u32 temp; +#define SWAP(a,b,c) \ + temp = (a);\ + (a) = (b)<<16|(c);\ + (b) = (temp) >> 16;\ + (c) = (temp) & 0xFFFF; + + SWAP(dma0Source, DM0SAD_H, DM0SAD_L); + SWAP(dma0Dest, DM0DAD_H, DM0DAD_L); + SWAP(dma1Source, DM1SAD_H, DM1SAD_L); + SWAP(dma1Dest, DM1DAD_H, DM1DAD_L); + SWAP(dma2Source, DM2SAD_H, DM2SAD_L); + SWAP(dma2Dest, DM2DAD_H, DM2DAD_L); + SWAP(dma3Source, DM3SAD_H, DM3SAD_L); + SWAP(dma3Dest, DM3DAD_H, DM3DAD_L); + } + + if(version <= SAVE_GAME_VERSION_8) { + timer0ClockReload = TIMER_TICKS[TM0CNT & 3]; + timer1ClockReload = TIMER_TICKS[TM1CNT & 3]; + timer2ClockReload = TIMER_TICKS[TM2CNT & 3]; + timer3ClockReload = TIMER_TICKS[TM3CNT & 3]; + + timer0Ticks = ((0x10000 - TM0D) << timer0ClockReload) - timer0Ticks; + timer1Ticks = ((0x10000 - TM1D) << timer1ClockReload) - timer1Ticks; + timer2Ticks = ((0x10000 - TM2D) << timer2ClockReload) - timer2Ticks; + timer3Ticks = ((0x10000 - TM3D) << timer3ClockReload) - timer3Ticks; +// interp_rate(); + } + + // set pointers! + layerEnable = layerSettings & DISPCNT; + + CPUUpdateRender(); + CPUUpdateRenderBuffers(true); + CPUUpdateWindow0(); + CPUUpdateWindow1(); + gbaSaveType = 0; + switch(saveType) { + case 0: + cpuSaveGameFunc = flashSaveDecide; + break; + case 1: + cpuSaveGameFunc = sramWrite; + gbaSaveType = 1; + break; + case 2: + cpuSaveGameFunc = flashWrite; + gbaSaveType = 2; + break; + case 3: + break; + case 5: + gbaSaveType = 5; + break; + default: + systemMessage(MSG_UNSUPPORTED_SAVE_TYPE, + N_("Unsupported save type %d"), saveType); + break; + } + if(eepromInUse) + gbaSaveType = 3; + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + if(armState) { + ARM_PREFETCH; + } else { + THUMB_PREFETCH; + } + + CPUUpdateRegister(0x204, CPUReadHalfWordQuick(0x4000204)); + + return true; +} + +bool CPUReadMemState(char *memory, int available) +{ + gzFile gzFile = utilMemGzOpen(memory, available, "r"); + + bool res = CPUReadState(gzFile); + + utilGzClose(gzFile); + + return res; +} + +bool CPUReadState(const char * file) +{ + gzFile gzFile = utilGzOpen(file, "rb"); + + if(gzFile == NULL) + return false; + + bool res = CPUReadState(gzFile); + + utilGzClose(gzFile); + + return res; +} + +bool CPUExportEepromFile(const char *fileName) +{ + if(eepromInUse) { + FILE *file = fopen(fileName, "wb"); + + if(!file) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), + fileName); + return false; + } + + for(int i = 0; i < eepromSize;) { + for(int j = 0; j < 8; j++) { + if(fwrite(&eepromData[i+7-j], 1, 1, file) != 1) { + fclose(file); + return false; + } + } + i += 8; + } + fclose(file); + } + return true; +} + +bool CPUWriteBatteryFile(const char *fileName) +{ + if(gbaSaveType == 0) { + if(eepromInUse) + gbaSaveType = 3; + else switch(saveType) { + case 1: + gbaSaveType = 1; + break; + case 2: + gbaSaveType = 2; + break; + } + } + + if((gbaSaveType) && (gbaSaveType!=5)) { + FILE *file = fopen(fileName, "wb"); + + if(!file) { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), + fileName); + return false; + } + + // only save if Flash/Sram in use or EEprom in use + if(gbaSaveType != 3) { + if(gbaSaveType == 2) { + if(fwrite(flashSaveMemory, 1, flashSize, file) != (size_t)flashSize) { + fclose(file); + return false; + } + } else { + if(fwrite(flashSaveMemory, 1, 0x10000, file) != 0x10000) { + fclose(file); + return false; + } + } + } else { + if(fwrite(eepromData, 1, eepromSize, file) != (size_t)eepromSize) { + fclose(file); + return false; + } + } + fclose(file); + } + return true; +} + +bool CPUReadGSASnapshot(const char *fileName) +{ + int i; + FILE *file = fopen(fileName, "rb"); + + if(!file) { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); + return false; + } + + // check file size to know what we should read + fseek(file, 0, SEEK_END); + + // long size = ftell(file); + fseek(file, 0x0, SEEK_SET); + fread(&i, 1, 4, file); + fseek(file, i, SEEK_CUR); // Skip SharkPortSave + fseek(file, 4, SEEK_CUR); // skip some sort of flag + fread(&i, 1, 4, file); // name length + fseek(file, i, SEEK_CUR); // skip name + fread(&i, 1, 4, file); // desc length + fseek(file, i, SEEK_CUR); // skip desc + fread(&i, 1, 4, file); // notes length + fseek(file, i, SEEK_CUR); // skip notes + int saveSize; + fread(&saveSize, 1, 4, file); // read length + saveSize -= 0x1c; // remove header size + char buffer[17]; + char buffer2[17]; + fread(buffer, 1, 16, file); + buffer[16] = 0; + for(i = 0; i < 16; i++) + if(buffer[i] < 32) + buffer[i] = 32; + memcpy(buffer2, &rom[0xa0], 16); + buffer2[16] = 0; + for(i = 0; i < 16; i++) + if(buffer2[i] < 32) + buffer2[i] = 32; + if(memcmp(buffer, buffer2, 16)) { + systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, + N_("Cannot import snapshot for %s. Current game is %s"), + buffer, + buffer2); + fclose(file); + return false; + } + fseek(file, 12, SEEK_CUR); // skip some flags + if(saveSize >= 65536) { + if(fread(flashSaveMemory, 1, saveSize, file) != (size_t)saveSize) { + fclose(file); + return false; + } + } else { + systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, + N_("Unsupported snapshot file %s"), + fileName); + fclose(file); + return false; + } + fclose(file); + CPUReset(); + return true; +} + +bool CPUWriteGSASnapshot(const char *fileName, + const char *title, + const char *desc, + const char *notes) +{ + FILE *file = fopen(fileName, "wb"); + + if(!file) { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); + return false; + } + + u8 buffer[17]; + + utilPutDword(buffer, 0x0d); // SharkPortSave length + fwrite(buffer, 1, 4, file); + fwrite("SharkPortSave", 1, 0x0d, file); + utilPutDword(buffer, 0x000f0000); + fwrite(buffer, 1, 4, file); // save type 0x000f0000 = GBA save + utilPutDword(buffer, (u32)strlen(title)); + fwrite(buffer, 1, 4, file); // title length + fwrite(title, 1, strlen(title), file); + utilPutDword(buffer, (u32)strlen(desc)); + fwrite(buffer, 1, 4, file); // desc length + fwrite(desc, 1, strlen(desc), file); + utilPutDword(buffer, (u32)strlen(notes)); + fwrite(buffer, 1, 4, file); // notes length + fwrite(notes, 1, strlen(notes), file); + int saveSize = 0x10000; + if(gbaSaveType == 2) + saveSize = flashSize; + int totalSize = saveSize + 0x1c; + + utilPutDword(buffer, totalSize); // length of remainder of save - CRC + fwrite(buffer, 1, 4, file); + + char temp[0x2001c]; + memset(temp, 0, 28); + memcpy(temp, &rom[0xa0], 16); // copy internal name + temp[0x10] = rom[0xbe]; // reserved area (old checksum) + temp[0x11] = rom[0xbf]; // reserved area (old checksum) + temp[0x12] = rom[0xbd]; // complement check + temp[0x13] = rom[0xb0]; // maker + temp[0x14] = 1; // 1 save ? + memcpy(&temp[0x1c], flashSaveMemory, saveSize); // copy save + fwrite(temp, 1, totalSize, file); // write save + header + u32 crc = 0; + + for(int i = 0; i < totalSize; i++) { + crc += ((u32)temp[i] << (crc % 0x18)); + } + + utilPutDword(buffer, crc); + fwrite(buffer, 1, 4, file); // CRC? + + fclose(file); + return true; +} + +bool CPUImportEepromFile(const char *fileName) +{ + FILE *file = fopen(fileName, "rb"); + + if(!file) + return false; + + // check file size to know what we should read + fseek(file, 0, SEEK_END); + + long size = ftell(file); + fseek(file, 0, SEEK_SET); + if(size == 512 || size == 0x2000) { + if(fread(eepromData, 1, size, file) != (size_t)size) { + fclose(file); + return false; + } + for(int i = 0; i < size;) { + u8 tmp = eepromData[i]; + eepromData[i] = eepromData[7-i]; + eepromData[7-i] = tmp; + i++; + tmp = eepromData[i]; + eepromData[i] = eepromData[7-i]; + eepromData[7-i] = tmp; + i++; + tmp = eepromData[i]; + eepromData[i] = eepromData[7-i]; + eepromData[7-i] = tmp; + i++; + tmp = eepromData[i]; + eepromData[i] = eepromData[7-i]; + eepromData[7-i] = tmp; + i++; + i += 4; + } + } else + return false; + fclose(file); + return true; +} + +bool CPUReadBatteryFile(const char *fileName) +{ + FILE *file = fopen(fileName, "rb"); + + if(!file) + return false; + + // check file size to know what we should read + fseek(file, 0, SEEK_END); + + long size = ftell(file); + fseek(file, 0, SEEK_SET); + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + if(size == 512 || size == 0x2000) { + if(fread(eepromData, 1, size, file) != (size_t)size) { + fclose(file); + return false; + } + } else { + if(size == 0x20000) { + if(fread(flashSaveMemory, 1, 0x20000, file) != 0x20000) { + fclose(file); + return false; + } + flashSetSize(0x20000); + } else { + if(fread(flashSaveMemory, 1, 0x10000, file) != 0x10000) { + fclose(file); + return false; + } + flashSetSize(0x10000); + } + } + fclose(file); + return true; +} + +bool CPUWritePNGFile(const char *fileName) +{ + return utilWritePNGFile(fileName, 240, 160, pix); +} + +bool CPUWriteBMPFile(const char *fileName) +{ + return utilWriteBMPFile(fileName, 240, 160, pix); +} + +bool CPUIsZipFile(const char * file) +{ + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".zip") == 0) + return true; + } + } + + return false; +} + +bool CPUIsGBAImage(const char * file) +{ + cpuIsMultiBoot = false; + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".gba") == 0) + return true; + if(_stricmp(p, ".agb") == 0) + return true; + if(_stricmp(p, ".bin") == 0) + return true; + if(_stricmp(p, ".elf") == 0) + return true; + if(_stricmp(p, ".mb") == 0) { + cpuIsMultiBoot = true; + return true; + } + } + } + + return false; +} + +bool CPUIsGBABios(const char * file) +{ + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".gba") == 0) + return true; + if(_stricmp(p, ".agb") == 0) + return true; + if(_stricmp(p, ".bin") == 0) + return true; + if(_stricmp(p, ".bios") == 0) + return true; + if(_stricmp(p, ".rom") == 0) + return true; + } + } + + return false; +} + +bool CPUIsELF(const char *file) +{ + if(strlen(file) > 4) { + const char * p = strrchr(file,'.'); + + if(p != NULL) { + if(_stricmp(p, ".elf") == 0) + return true; + } + } + return false; +} + +void CPUCleanUp() +{ +#ifdef PROFILING + if(profilingTicksReload) { + profCleanup(); + } +#endif + + if(rom != NULL) { + free(rom); + rom = NULL; + } + + if(vram != NULL) { + free(vram); + vram = NULL; + } + + if(paletteRAM != NULL) { + free(paletteRAM); + paletteRAM = NULL; + } + + if(internalRAM != NULL) { + free(internalRAM); + internalRAM = NULL; + } + + if(workRAM != NULL) { + free(workRAM); + workRAM = NULL; + } + + if(bios != NULL) { + free(bios); + bios = NULL; + } + + if(pix != NULL) { + free(pix); + pix = NULL; + } + + if(oam != NULL) { + free(oam); + oam = NULL; + } + + if(ioMem != NULL) { + free(ioMem); + ioMem = NULL; + } + +#ifndef NO_DEBUGGER + elfCleanUp(); +#endif //NO_DEBUGGER + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + emulating = 0; +} + +int CPULoadRom(const char *szFile) +{ + romSize = 0x2000000; + if(rom != NULL) { + CPUCleanUp(); + } + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + rom = (u8 *)malloc(0x2000000); + if(rom == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "ROM"); + return 0; + } + workRAM = (u8 *)calloc(1, 0x40000); + if(workRAM == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "WRAM"); + return 0; + } + + u8 *whereToLoad = cpuIsMultiBoot ? workRAM : rom; + +#ifndef NO_DEBUGGER + if(CPUIsELF(szFile)) { + FILE *f = fopen(szFile, "rb"); + if(!f) { + systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), + szFile); + free(rom); + rom = NULL; + free(workRAM); + workRAM = NULL; + return 0; + } + bool res = elfRead(szFile, romSize, f); + if(!res || romSize == 0) { + free(rom); + rom = NULL; + free(workRAM); + workRAM = NULL; + elfCleanUp(); + return 0; + } + } else +#endif //NO_DEBUGGER + if(!utilLoad(szFile, + utilIsGBAImage, + whereToLoad, + romSize)) { + free(rom); + rom = NULL; + free(workRAM); + workRAM = NULL; + return 0; + } + + u16 *temp = (u16 *)(rom+((romSize+1)&~1)); + int i; + for(i = (romSize+1)&~1; i < 0x2000000; i+=2) { + WRITE16LE(temp, (i >> 1) & 0xFFFF); + temp++; + } + + bios = (u8 *)calloc(1,0x4000); + if(bios == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "BIOS"); + CPUCleanUp(); + return 0; + } + internalRAM = (u8 *)calloc(1,0x8000); + if(internalRAM == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "IRAM"); + CPUCleanUp(); + return 0; + } + paletteRAM = (u8 *)calloc(1,0x400); + if(paletteRAM == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "PRAM"); + CPUCleanUp(); + return 0; + } + vram = (u8 *)calloc(1, 0x20000); + if(vram == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "VRAM"); + CPUCleanUp(); + return 0; + } + oam = (u8 *)calloc(1, 0x400); + if(oam == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "OAM"); + CPUCleanUp(); + return 0; + } + pix = (u8 *)calloc(1, 4 * 241 * 162); + if(pix == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "PIX"); + CPUCleanUp(); + return 0; + } + ioMem = (u8 *)calloc(1, 0x400); + if(ioMem == NULL) { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "IO"); + CPUCleanUp(); + return 0; + } + + flashInit(); + eepromInit(); + + CPUUpdateRenderBuffers(true); + + return romSize; +} + +void doMirroring (bool b) +{ + u32 mirroredRomSize = (((romSize)>>20) & 0x3F)<<20; + u32 mirroredRomAddress = romSize; + if ((mirroredRomSize <=0x800000) && (b)) + { + mirroredRomAddress = mirroredRomSize; + if (mirroredRomSize==0) + mirroredRomSize=0x100000; + while (mirroredRomAddress<0x01000000) + { + memcpy ((u16 *)(rom+mirroredRomAddress), (u16 *)(rom), mirroredRomSize); + mirroredRomAddress+=mirroredRomSize; + } + } +} + +void CPUUpdateRender() +{ + switch(DISPCNT & 7) { + case 0: + if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || + cpuDisableSfx) + renderLine = mode0RenderLine; + else if(fxOn && !windowOn && !(layerEnable & 0x8000)) + renderLine = mode0RenderLineNoWindow; + else + renderLine = mode0RenderLineAll; + break; + case 1: + if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || + cpuDisableSfx) + renderLine = mode1RenderLine; + else if(fxOn && !windowOn && !(layerEnable & 0x8000)) + renderLine = mode1RenderLineNoWindow; + else + renderLine = mode1RenderLineAll; + break; + case 2: + if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || + cpuDisableSfx) + renderLine = mode2RenderLine; + else if(fxOn && !windowOn && !(layerEnable & 0x8000)) + renderLine = mode2RenderLineNoWindow; + else + renderLine = mode2RenderLineAll; + break; + case 3: + if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || + cpuDisableSfx) + renderLine = mode3RenderLine; + else if(fxOn && !windowOn && !(layerEnable & 0x8000)) + renderLine = mode3RenderLineNoWindow; + else + renderLine = mode3RenderLineAll; + break; + case 4: + if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || + cpuDisableSfx) + renderLine = mode4RenderLine; + else if(fxOn && !windowOn && !(layerEnable & 0x8000)) + renderLine = mode4RenderLineNoWindow; + else + renderLine = mode4RenderLineAll; + break; + case 5: + if((!fxOn && !windowOn && !(layerEnable & 0x8000)) || + cpuDisableSfx) + renderLine = mode5RenderLine; + else if(fxOn && !windowOn && !(layerEnable & 0x8000)) + renderLine = mode5RenderLineNoWindow; + else + renderLine = mode5RenderLineAll; + default: + break; + } +} + +void CPUUpdateCPSR() +{ + u32 CPSR = reg[16].I & 0x40; + if(N_FLAG) + CPSR |= 0x80000000; + if(Z_FLAG) + CPSR |= 0x40000000; + if(C_FLAG) + CPSR |= 0x20000000; + if(V_FLAG) + CPSR |= 0x10000000; + if(!armState) + CPSR |= 0x00000020; + if(!armIrqEnable) + CPSR |= 0x80; + CPSR |= (armMode & 0x1F); + reg[16].I = CPSR; +} + +void CPUUpdateFlags(bool breakLoop) +{ + u32 CPSR = reg[16].I; + + N_FLAG = (CPSR & 0x80000000) ? true: false; + Z_FLAG = (CPSR & 0x40000000) ? true: false; + C_FLAG = (CPSR & 0x20000000) ? true: false; + V_FLAG = (CPSR & 0x10000000) ? true: false; + armState = (CPSR & 0x20) ? false : true; + armIrqEnable = (CPSR & 0x80) ? false : true; + if(breakLoop) { + if (armIrqEnable && (IF & IE) && (IME & 1)) + cpuNextEvent = cpuTotalTicks; + } +} + +void CPUUpdateFlags() +{ + CPUUpdateFlags(true); +} + +#ifdef WORDS_BIGENDIAN +static void CPUSwap(volatile u32 *a, volatile u32 *b) +{ + volatile u32 c = *b; + *b = *a; + *a = c; +} +#else +static void CPUSwap(u32 *a, u32 *b) +{ + u32 c = *b; + *b = *a; + *a = c; +} +#endif + +void CPUSwitchMode(int mode, bool saveState, bool breakLoop) +{ + // if(armMode == mode) + // return; + + CPUUpdateCPSR(); + + switch(armMode) { + case 0x10: + case 0x1F: + reg[R13_USR].I = reg[13].I; + reg[R14_USR].I = reg[14].I; + reg[17].I = reg[16].I; + break; + case 0x11: + CPUSwap(®[R8_FIQ].I, ®[8].I); + CPUSwap(®[R9_FIQ].I, ®[9].I); + CPUSwap(®[R10_FIQ].I, ®[10].I); + CPUSwap(®[R11_FIQ].I, ®[11].I); + CPUSwap(®[R12_FIQ].I, ®[12].I); + reg[R13_FIQ].I = reg[13].I; + reg[R14_FIQ].I = reg[14].I; + reg[SPSR_FIQ].I = reg[17].I; + break; + case 0x12: + reg[R13_IRQ].I = reg[13].I; + reg[R14_IRQ].I = reg[14].I; + reg[SPSR_IRQ].I = reg[17].I; + break; + case 0x13: + reg[R13_SVC].I = reg[13].I; + reg[R14_SVC].I = reg[14].I; + reg[SPSR_SVC].I = reg[17].I; + break; + case 0x17: + reg[R13_ABT].I = reg[13].I; + reg[R14_ABT].I = reg[14].I; + reg[SPSR_ABT].I = reg[17].I; + break; + case 0x1b: + reg[R13_UND].I = reg[13].I; + reg[R14_UND].I = reg[14].I; + reg[SPSR_UND].I = reg[17].I; + break; + } + + u32 CPSR = reg[16].I; + u32 SPSR = reg[17].I; + + switch(mode) { + case 0x10: + case 0x1F: + reg[13].I = reg[R13_USR].I; + reg[14].I = reg[R14_USR].I; + reg[16].I = SPSR; + break; + case 0x11: + CPUSwap(®[8].I, ®[R8_FIQ].I); + CPUSwap(®[9].I, ®[R9_FIQ].I); + CPUSwap(®[10].I, ®[R10_FIQ].I); + CPUSwap(®[11].I, ®[R11_FIQ].I); + CPUSwap(®[12].I, ®[R12_FIQ].I); + reg[13].I = reg[R13_FIQ].I; + reg[14].I = reg[R14_FIQ].I; + if(saveState) + reg[17].I = CPSR; + else + reg[17].I = reg[SPSR_FIQ].I; + break; + case 0x12: + reg[13].I = reg[R13_IRQ].I; + reg[14].I = reg[R14_IRQ].I; + reg[16].I = SPSR; + if(saveState) + reg[17].I = CPSR; + else + reg[17].I = reg[SPSR_IRQ].I; + break; + case 0x13: + reg[13].I = reg[R13_SVC].I; + reg[14].I = reg[R14_SVC].I; + reg[16].I = SPSR; + if(saveState) + reg[17].I = CPSR; + else + reg[17].I = reg[SPSR_SVC].I; + break; + case 0x17: + reg[13].I = reg[R13_ABT].I; + reg[14].I = reg[R14_ABT].I; + reg[16].I = SPSR; + if(saveState) + reg[17].I = CPSR; + else + reg[17].I = reg[SPSR_ABT].I; + break; + case 0x1b: + reg[13].I = reg[R13_UND].I; + reg[14].I = reg[R14_UND].I; + reg[16].I = SPSR; + if(saveState) + reg[17].I = CPSR; + else + reg[17].I = reg[SPSR_UND].I; + break; + default: + systemMessage(MSG_UNSUPPORTED_ARM_MODE, N_("Unsupported ARM mode %02x"), mode); + break; + } + armMode = mode; + CPUUpdateFlags(breakLoop); + CPUUpdateCPSR(); +} + +void CPUSwitchMode(int mode, bool saveState) +{ + CPUSwitchMode(mode, saveState, true); +} + +void CPUUndefinedException() +{ + u32 PC = reg[15].I; + bool savedArmState = armState; + CPUSwitchMode(0x1b, true, false); + reg[14].I = PC - (savedArmState ? 4 : 2); + reg[15].I = 0x04; + armState = true; + armIrqEnable = false; + armNextPC = 0x04; + ARM_PREFETCH; + reg[15].I += 4; +} + +void CPUSoftwareInterrupt() +{ + u32 PC = reg[15].I; + bool savedArmState = armState; + CPUSwitchMode(0x13, true, false); + reg[14].I = PC - (savedArmState ? 4 : 2); + reg[15].I = 0x08; + armState = true; + armIrqEnable = false; + armNextPC = 0x08; + ARM_PREFETCH; + reg[15].I += 4; +} + +void CPUSoftwareInterrupt(int comment) +{ + static bool disableMessage = false; + if(armState) comment >>= 16; +#ifdef BKPT_SUPPORT + if(comment == 0xff) { + dbgOutput(NULL, reg[0].I); + return; + } +#endif +#ifdef PROFILING + if(comment == 0xfe) { + profStartup(reg[0].I, reg[1].I); + return; + } + if(comment == 0xfd) { + profControl(reg[0].I); + return; + } + if(comment == 0xfc) { + profCleanup(); + return; + } + if(comment == 0xfb) { + profCount(); + return; + } +#endif + if(comment == 0xfa) { + agbPrintFlush(); + return; + } +#ifdef SDL + if(comment == 0xf9) { + emulating = 0; + cpuNextEvent = cpuTotalTicks; + cpuBreakLoop = true; + return; + } +#endif + if(useBios) { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, + armState ? armNextPC - 4: armNextPC -2, + reg[0].I, + reg[1].I, + reg[2].I, + VCOUNT); + } +#endif + CPUSoftwareInterrupt(); + return; + } + // This would be correct, but it causes problems if uncommented + // else { + // biosProtected = 0xe3a02004; + // } + + switch(comment) { + case 0x00: + BIOS_SoftReset(); + ARM_PREFETCH; + break; + case 0x01: + BIOS_RegisterRamReset(); + break; + case 0x02: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("Halt: (VCOUNT = %2d)\n", + VCOUNT); + } +#endif + holdState = true; + holdType = -1; + cpuNextEvent = cpuTotalTicks; + break; + case 0x03: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("Stop: (VCOUNT = %2d)\n", + VCOUNT); + } +#endif + holdState = true; + holdType = -1; + stopState = true; + cpuNextEvent = cpuTotalTicks; + break; + case 0x04: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n", + reg[0].I, + reg[1].I, + VCOUNT); + } +#endif + CPUSoftwareInterrupt(); + break; + case 0x05: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("VBlankIntrWait: (VCOUNT = %2d)\n", + VCOUNT); + } +#endif + CPUSoftwareInterrupt(); + break; + case 0x06: + CPUSoftwareInterrupt(); + break; + case 0x07: + CPUSoftwareInterrupt(); + break; + case 0x08: + BIOS_Sqrt(); + break; + case 0x09: + BIOS_ArcTan(); + break; + case 0x0A: + BIOS_ArcTan2(); + break; + case 0x0B: + { + int len = (reg[2].I & 0x1FFFFF) >>1; + if (!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + len) & 0xe000000) == 0)) + { + if ((reg[2].I >> 24) & 1) + { + if ((reg[2].I >> 26) & 1) + SWITicks = (7 + memoryWait32[(reg[1].I>>24) & 0xF]) * (len>>1); + else + SWITicks = (8 + memoryWait[(reg[1].I>>24) & 0xF]) * (len); + } + else + { + if ((reg[2].I >> 26) & 1) + SWITicks = (10 + memoryWait32[(reg[0].I>>24) & 0xF] + + memoryWait32[(reg[1].I>>24) & 0xF]) * (len>>1); + else + SWITicks = (11 + memoryWait[(reg[0].I>>24) & 0xF] + + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + } + } + BIOS_CpuSet(); + break; + case 0x0C: + { + int len = (reg[2].I & 0x1FFFFF) >>5; + if (!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + len) & 0xe000000) == 0)) + { + if ((reg[2].I >> 24) & 1) + SWITicks = (6 + memoryWait32[(reg[1].I>>24) & 0xF] + + 7 * (memoryWaitSeq32[(reg[1].I>>24) & 0xF] + 1)) * len; + else + SWITicks = (9 + memoryWait32[(reg[0].I>>24) & 0xF] + + memoryWait32[(reg[1].I>>24) & 0xF] + + 7 * (memoryWaitSeq32[(reg[0].I>>24) & 0xF] + + memoryWaitSeq32[(reg[1].I>>24) & 0xF] + 2)) * len; + } + } + BIOS_CpuFastSet(); + break; + case 0x0D: + BIOS_GetBiosChecksum(); + break; + case 0x0E: + BIOS_BgAffineSet(); + break; + case 0x0F: + BIOS_ObjAffineSet(); + break; + case 0x10: + { + int len = CPUReadHalfWord(reg[2].I); + if (!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + len) & 0xe000000) == 0)) + SWITicks = (32 + memoryWait[(reg[0].I>>24) & 0xF]) * len; + } + BIOS_BitUnPack(); + break; + case 0x11: + { + u32 len = CPUReadMemory(reg[0].I) >> 8; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (9 + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_LZ77UnCompWram(); + break; + case 0x12: + { + u32 len = CPUReadMemory(reg[0].I) >> 8; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (19 + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_LZ77UnCompVram(); + break; + case 0x13: + { + u32 len = CPUReadMemory(reg[0].I) >> 8; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (29 + (memoryWait[(reg[0].I>>24) & 0xF]<<1)) * len; + } + BIOS_HuffUnComp(); + break; + case 0x14: + { + u32 len = CPUReadMemory(reg[0].I) >> 8; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (11 + memoryWait[(reg[0].I>>24) & 0xF] + + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_RLUnCompWram(); + break; + case 0x15: + { + u32 len = CPUReadMemory(reg[0].I) >> 9; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (34 + (memoryWait[(reg[0].I>>24) & 0xF] << 1) + + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_RLUnCompVram(); + break; + case 0x16: + { + u32 len = CPUReadMemory(reg[0].I) >> 8; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (13 + memoryWait[(reg[0].I>>24) & 0xF] + + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_Diff8bitUnFilterWram(); + break; + case 0x17: + { + u32 len = CPUReadMemory(reg[0].I) >> 9; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (39 + (memoryWait[(reg[0].I>>24) & 0xF]<<1) + + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_Diff8bitUnFilterVram(); + break; + case 0x18: + { + u32 len = CPUReadMemory(reg[0].I) >> 9; + if(!(((reg[0].I & 0xe000000) == 0) || + ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0)) + SWITicks = (13 + memoryWait[(reg[0].I>>24) & 0xF] + + memoryWait[(reg[1].I>>24) & 0xF]) * len; + } + BIOS_Diff16bitUnFilter(); + break; + case 0x19: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n", + reg[0].I, + VCOUNT); + } +#endif + if(reg[0].I) + systemSoundPause(); + else + systemSoundResume(); + break; + case 0x1F: + BIOS_MidiKey2Freq(); + break; + case 0x2A: + BIOS_SndDriverJmpTableCopy(); + // let it go, because we don't really emulate this function + default: +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, + armState ? armNextPC - 4: armNextPC -2, + reg[0].I, + reg[1].I, + reg[2].I, + VCOUNT); + } +#endif + + if(!disableMessage) { + systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION, + N_("Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."), + comment, + armMode ? armNextPC - 4: armNextPC - 2); + disableMessage = true; + } + break; + } +} + +void CPUCompareVCOUNT() +{ + if(VCOUNT == (DISPSTAT >> 8)) { + DISPSTAT |= 4; + UPDATE_REG(0x04, DISPSTAT); + + if(DISPSTAT & 0x20) { + IF |= 4; + UPDATE_REG(0x202, IF); + } + } else { + DISPSTAT &= 0xFFFB; + UPDATE_REG(0x4, DISPSTAT); + } + if (layerEnableDelay>0) + { + layerEnableDelay--; + if (layerEnableDelay==1) + layerEnable = layerSettings & DISPCNT; + } + +} + +void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32) +{ + int sm = s >> 24; + int dm = d >> 24; + int sw = 0; + int dw = 0; + int sc = c; + + cpuDmaCount = c; + // This is done to get the correct waitstates. + if (sm>15) + sm=15; + if (dm>15) + dm=15; + + //if ((sm>=0x05) && (sm<=0x07) || (dm>=0x05) && (dm <=0x07)) + // blank = (((DISPSTAT | ((DISPSTAT>>1)&1))==1) ? true : false); + + if(transfer32) { + s &= 0xFFFFFFFC; + if(s < 0x02000000 && (reg[15].I >> 24)) { + while(c != 0) { + CPUWriteMemory(d, 0); + d += di; + c--; + } + } else { + while(c != 0) { + cpuDmaLast = CPUReadMemory(s); + CPUWriteMemory(d, cpuDmaLast); + d += di; + s += si; + c--; + } + } + } else { + s &= 0xFFFFFFFE; + si = (int)si >> 1; + di = (int)di >> 1; + if(s < 0x02000000 && (reg[15].I >> 24)) { + while(c != 0) { + CPUWriteHalfWord(d, 0); + d += di; + c--; + } + } else { + while(c != 0) { + cpuDmaLast = CPUReadHalfWord(s); + CPUWriteHalfWord(d, cpuDmaLast); + cpuDmaLast |= (cpuDmaLast<<16); + d += di; + s += si; + c--; + } + } + } + + cpuDmaCount = 0; + + int totalTicks = 0; + + if(transfer32) { + sw =1+memoryWaitSeq32[sm & 15]; + dw =1+memoryWaitSeq32[dm & 15]; + totalTicks = (sw+dw)*(sc-1) + 6 + memoryWait32[sm & 15] + + memoryWaitSeq32[dm & 15]; + } + else + { + sw = 1+memoryWaitSeq[sm & 15]; + dw = 1+memoryWaitSeq[dm & 15]; + totalTicks = (sw+dw)*(sc-1) + 6 + memoryWait[sm & 15] + + memoryWaitSeq[dm & 15]; + } + + cpuDmaTicksToUpdate += totalTicks; + +} + +void CPUCheckDMA(int reason, int dmamask) +{ + // DMA 0 + if((DM0CNT_H & 0x8000) && (dmamask & 1)) { + if(((DM0CNT_H >> 12) & 3) == reason) { + u32 sourceIncrement = 4; + u32 destIncrement = 4; + switch((DM0CNT_H >> 7) & 3) { + case 0: + break; + case 1: + sourceIncrement = (u32)-4; + break; + case 2: + sourceIncrement = 0; + break; + } + switch((DM0CNT_H >> 5) & 3) { + case 0: + break; + case 1: + destIncrement = (u32)-4; + break; + case 2: + destIncrement = 0; + break; + } +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_DMA0) { + int count = (DM0CNT_L ? DM0CNT_L : 0x4000) << 1; + if(DM0CNT_H & 0x0400) + count <<= 1; + log("DMA0: s=%08x d=%08x c=%04x count=%08x\n", dma0Source, dma0Dest, + DM0CNT_H, + count); + } +#endif + doDMA(dma0Source, dma0Dest, sourceIncrement, destIncrement, + DM0CNT_L ? DM0CNT_L : 0x4000, + DM0CNT_H & 0x0400); + cpuDmaHack = true; + + if(DM0CNT_H & 0x4000) { + IF |= 0x0100; + UPDATE_REG(0x202, IF); + cpuNextEvent = cpuTotalTicks; + } + + if(((DM0CNT_H >> 5) & 3) == 3) { + dma0Dest = DM0DAD_L | (DM0DAD_H << 16); + } + + if(!(DM0CNT_H & 0x0200) || (reason == 0)) { + DM0CNT_H &= 0x7FFF; + UPDATE_REG(0xBA, DM0CNT_H); + } + } + } + + // DMA 1 + if((DM1CNT_H & 0x8000) && (dmamask & 2)) { + if(((DM1CNT_H >> 12) & 3) == reason) { + u32 sourceIncrement = 4; + u32 destIncrement = 4; + switch((DM1CNT_H >> 7) & 3) { + case 0: + break; + case 1: + sourceIncrement = (u32)-4; + break; + case 2: + sourceIncrement = 0; + break; + } + switch((DM1CNT_H >> 5) & 3) { + case 0: + break; + case 1: + destIncrement = (u32)-4; + break; + case 2: + destIncrement = 0; + break; + } + if(reason == 3) { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_DMA1) { + log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest, + DM1CNT_H, + 16); + } +#endif + doDMA(dma1Source, dma1Dest, sourceIncrement, 0, 4, + 0x0400); + } else { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_DMA1) { + int count = (DM1CNT_L ? DM1CNT_L : 0x4000) << 1; + if(DM1CNT_H & 0x0400) + count <<= 1; + log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest, + DM1CNT_H, + count); + } +#endif + doDMA(dma1Source, dma1Dest, sourceIncrement, destIncrement, + DM1CNT_L ? DM1CNT_L : 0x4000, + DM1CNT_H & 0x0400); + } + cpuDmaHack = true; + + if(DM1CNT_H & 0x4000) { + IF |= 0x0200; + UPDATE_REG(0x202, IF); + cpuNextEvent = cpuTotalTicks; + } + + if(((DM1CNT_H >> 5) & 3) == 3) { + dma1Dest = DM1DAD_L | (DM1DAD_H << 16); + } + + if(!(DM1CNT_H & 0x0200) || (reason == 0)) { + DM1CNT_H &= 0x7FFF; + UPDATE_REG(0xC6, DM1CNT_H); + } + } + } + + // DMA 2 + if((DM2CNT_H & 0x8000) && (dmamask & 4)) { + if(((DM2CNT_H >> 12) & 3) == reason) { + u32 sourceIncrement = 4; + u32 destIncrement = 4; + switch((DM2CNT_H >> 7) & 3) { + case 0: + break; + case 1: + sourceIncrement = (u32)-4; + break; + case 2: + sourceIncrement = 0; + break; + } + switch((DM2CNT_H >> 5) & 3) { + case 0: + break; + case 1: + destIncrement = (u32)-4; + break; + case 2: + destIncrement = 0; + break; + } + if(reason == 3) { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_DMA2) { + int count = (4) << 2; + log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest, + DM2CNT_H, + count); + } +#endif + doDMA(dma2Source, dma2Dest, sourceIncrement, 0, 4, + 0x0400); + } else { +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_DMA2) { + int count = (DM2CNT_L ? DM2CNT_L : 0x4000) << 1; + if(DM2CNT_H & 0x0400) + count <<= 1; + log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest, + DM2CNT_H, + count); + } +#endif + doDMA(dma2Source, dma2Dest, sourceIncrement, destIncrement, + DM2CNT_L ? DM2CNT_L : 0x4000, + DM2CNT_H & 0x0400); + } + cpuDmaHack = true; + + if(DM2CNT_H & 0x4000) { + IF |= 0x0400; + UPDATE_REG(0x202, IF); + cpuNextEvent = cpuTotalTicks; + } + + if(((DM2CNT_H >> 5) & 3) == 3) { + dma2Dest = DM2DAD_L | (DM2DAD_H << 16); + } + + if(!(DM2CNT_H & 0x0200) || (reason == 0)) { + DM2CNT_H &= 0x7FFF; + UPDATE_REG(0xD2, DM2CNT_H); + } + } + } + + // DMA 3 + if((DM3CNT_H & 0x8000) && (dmamask & 8)) { + if(((DM3CNT_H >> 12) & 3) == reason) { + u32 sourceIncrement = 4; + u32 destIncrement = 4; + switch((DM3CNT_H >> 7) & 3) { + case 0: + break; + case 1: + sourceIncrement = (u32)-4; + break; + case 2: + sourceIncrement = 0; + break; + } + switch((DM3CNT_H >> 5) & 3) { + case 0: + break; + case 1: + destIncrement = (u32)-4; + break; + case 2: + destIncrement = 0; + break; + } +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_DMA3) { + int count = (DM3CNT_L ? DM3CNT_L : 0x10000) << 1; + if(DM3CNT_H & 0x0400) + count <<= 1; + log("DMA3: s=%08x d=%08x c=%04x count=%08x\n", dma3Source, dma3Dest, + DM3CNT_H, + count); + } +#endif + doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement, + DM3CNT_L ? DM3CNT_L : 0x10000, + DM3CNT_H & 0x0400); + if(DM3CNT_H & 0x4000) { + IF |= 0x0800; + UPDATE_REG(0x202, IF); + cpuNextEvent = cpuTotalTicks; + } + + if(((DM3CNT_H >> 5) & 3) == 3) { + dma3Dest = DM3DAD_L | (DM3DAD_H << 16); + } + + if(!(DM3CNT_H & 0x0200) || (reason == 0)) { + DM3CNT_H &= 0x7FFF; + UPDATE_REG(0xDE, DM3CNT_H); + } + } + } +} + +void CPUUpdateRegister(u32 address, u16 value) +{ + switch(address) { + case 0x00: + { + if ((value & 7) >5) + DISPCNT = (value &7); + bool change = ((DISPCNT ^ value) & 0x80) ? true : false; + bool changeBG = ((DISPCNT ^ value) & 0x0F00) ? true : false; + u16 changeBGon = (((~DISPCNT) & value) & 0x0F00); + DISPCNT = (value & 0xFFF7); + UPDATE_REG(0x00, DISPCNT); + + if (changeBGon) + { + layerEnableDelay=4; + layerEnable = layerSettings & value & (~changeBGon); + } + else + layerEnable = layerSettings & value; + // CPUUpdateTicks(); + + windowOn = (layerEnable & 0x6000) ? true : false; + if(change && !((value & 0x80))) { + if(!(DISPSTAT & 1)) { + lcdTicks = 1008; + // VCOUNT = 0; + // UPDATE_REG(0x06, VCOUNT); + DISPSTAT &= 0xFFFC; + UPDATE_REG(0x04, DISPSTAT); + CPUCompareVCOUNT(); + } + // (*renderLine)(); + } + CPUUpdateRender(); + // we only care about changes in BG0-BG3 + if(changeBG) + CPUUpdateRenderBuffers(false); + } + break; + case 0x04: + DISPSTAT = (value & 0xFF38) | (DISPSTAT & 7); + UPDATE_REG(0x04, DISPSTAT); + break; + case 0x06: + // not writable + break; + case 0x08: + BG0CNT = (value & 0xDFCF); + UPDATE_REG(0x08, BG0CNT); + break; + case 0x0A: + BG1CNT = (value & 0xDFCF); + UPDATE_REG(0x0A, BG1CNT); + break; + case 0x0C: + BG2CNT = (value & 0xFFCF); + UPDATE_REG(0x0C, BG2CNT); + break; + case 0x0E: + BG3CNT = (value & 0xFFCF); + UPDATE_REG(0x0E, BG3CNT); + break; + case 0x10: + BG0HOFS = value & 511; + UPDATE_REG(0x10, BG0HOFS); + break; + case 0x12: + BG0VOFS = value & 511; + UPDATE_REG(0x12, BG0VOFS); + break; + case 0x14: + BG1HOFS = value & 511; + UPDATE_REG(0x14, BG1HOFS); + break; + case 0x16: + BG1VOFS = value & 511; + UPDATE_REG(0x16, BG1VOFS); + break; + case 0x18: + BG2HOFS = value & 511; + UPDATE_REG(0x18, BG2HOFS); + break; + case 0x1A: + BG2VOFS = value & 511; + UPDATE_REG(0x1A, BG2VOFS); + break; + case 0x1C: + BG3HOFS = value & 511; + UPDATE_REG(0x1C, BG3HOFS); + break; + case 0x1E: + BG3VOFS = value & 511; + UPDATE_REG(0x1E, BG3VOFS); + break; + case 0x20: + BG2PA = value; + UPDATE_REG(0x20, BG2PA); + break; + case 0x22: + BG2PB = value; + UPDATE_REG(0x22, BG2PB); + break; + case 0x24: + BG2PC = value; + UPDATE_REG(0x24, BG2PC); + break; + case 0x26: + BG2PD = value; + UPDATE_REG(0x26, BG2PD); + break; + case 0x28: + BG2X_L = value; + UPDATE_REG(0x28, BG2X_L); + gfxBG2Changed |= 1; + break; + case 0x2A: + BG2X_H = (value & 0xFFF); + UPDATE_REG(0x2A, BG2X_H); + gfxBG2Changed |= 1; + break; + case 0x2C: + BG2Y_L = value; + UPDATE_REG(0x2C, BG2Y_L); + gfxBG2Changed |= 2; + break; + case 0x2E: + BG2Y_H = value & 0xFFF; + UPDATE_REG(0x2E, BG2Y_H); + gfxBG2Changed |= 2; + break; + case 0x30: + BG3PA = value; + UPDATE_REG(0x30, BG3PA); + break; + case 0x32: + BG3PB = value; + UPDATE_REG(0x32, BG3PB); + break; + case 0x34: + BG3PC = value; + UPDATE_REG(0x34, BG3PC); + break; + case 0x36: + BG3PD = value; + UPDATE_REG(0x36, BG3PD); + break; + case 0x38: + BG3X_L = value; + UPDATE_REG(0x38, BG3X_L); + gfxBG3Changed |= 1; + break; + case 0x3A: + BG3X_H = value & 0xFFF; + UPDATE_REG(0x3A, BG3X_H); + gfxBG3Changed |= 1; + break; + case 0x3C: + BG3Y_L = value; + UPDATE_REG(0x3C, BG3Y_L); + gfxBG3Changed |= 2; + break; + case 0x3E: + BG3Y_H = value & 0xFFF; + UPDATE_REG(0x3E, BG3Y_H); + gfxBG3Changed |= 2; + break; + case 0x40: + WIN0H = value; + UPDATE_REG(0x40, WIN0H); + CPUUpdateWindow0(); + break; + case 0x42: + WIN1H = value; + UPDATE_REG(0x42, WIN1H); + CPUUpdateWindow1(); + break; + case 0x44: + WIN0V = value; + UPDATE_REG(0x44, WIN0V); + break; + case 0x46: + WIN1V = value; + UPDATE_REG(0x46, WIN1V); + break; + case 0x48: + WININ = value & 0x3F3F; + UPDATE_REG(0x48, WININ); + break; + case 0x4A: + WINOUT = value & 0x3F3F; + UPDATE_REG(0x4A, WINOUT); + break; + case 0x4C: + MOSAIC = value; + UPDATE_REG(0x4C, MOSAIC); + break; + case 0x50: + BLDMOD = value & 0x3FFF; + UPDATE_REG(0x50, BLDMOD); + fxOn = ((BLDMOD>>6)&3) != 0; + CPUUpdateRender(); + break; + case 0x52: + COLEV = value & 0x1F1F; + UPDATE_REG(0x52, COLEV); + break; + case 0x54: + COLY = value & 0x1F; + UPDATE_REG(0x54, COLY); + break; + case 0x60: + case 0x62: + case 0x64: + case 0x68: + case 0x6c: + case 0x70: + case 0x72: + case 0x74: + case 0x78: + case 0x7c: + case 0x80: + case 0x84: + soundEvent(address&0xFF, (u8)(value & 0xFF)); + soundEvent((address&0xFF)+1, (u8)(value>>8)); + break; + case 0x82: + case 0x88: + case 0xa0: + case 0xa2: + case 0xa4: + case 0xa6: + case 0x90: + case 0x92: + case 0x94: + case 0x96: + case 0x98: + case 0x9a: + case 0x9c: + case 0x9e: + soundEvent(address&0xFF, value); + break; + case 0xB0: + DM0SAD_L = value; + UPDATE_REG(0xB0, DM0SAD_L); + break; + case 0xB2: + DM0SAD_H = value & 0x07FF; + UPDATE_REG(0xB2, DM0SAD_H); + break; + case 0xB4: + DM0DAD_L = value; + UPDATE_REG(0xB4, DM0DAD_L); + break; + case 0xB6: + DM0DAD_H = value & 0x07FF; + UPDATE_REG(0xB6, DM0DAD_H); + break; + case 0xB8: + DM0CNT_L = value & 0x3FFF; + UPDATE_REG(0xB8, 0); + break; + case 0xBA: + { + bool start = ((DM0CNT_H ^ value) & 0x8000) ? true : false; + value &= 0xF7E0; + + DM0CNT_H = value; + UPDATE_REG(0xBA, DM0CNT_H); + + if(start && (value & 0x8000)) { + dma0Source = DM0SAD_L | (DM0SAD_H << 16); + dma0Dest = DM0DAD_L | (DM0DAD_H << 16); + CPUCheckDMA(0, 1); + } + } + break; + case 0xBC: + DM1SAD_L = value; + UPDATE_REG(0xBC, DM1SAD_L); + break; + case 0xBE: + DM1SAD_H = value & 0x0FFF; + UPDATE_REG(0xBE, DM1SAD_H); + break; + case 0xC0: + DM1DAD_L = value; + UPDATE_REG(0xC0, DM1DAD_L); + break; + case 0xC2: + DM1DAD_H = value & 0x07FF; + UPDATE_REG(0xC2, DM1DAD_H); + break; + case 0xC4: + DM1CNT_L = value & 0x3FFF; + UPDATE_REG(0xC4, 0); + break; + case 0xC6: + { + bool start = ((DM1CNT_H ^ value) & 0x8000) ? true : false; + value &= 0xF7E0; + + DM1CNT_H = value; + UPDATE_REG(0xC6, DM1CNT_H); + + if(start && (value & 0x8000)) { + dma1Source = DM1SAD_L | (DM1SAD_H << 16); + dma1Dest = DM1DAD_L | (DM1DAD_H << 16); + CPUCheckDMA(0, 2); + } + } + break; + case 0xC8: + DM2SAD_L = value; + UPDATE_REG(0xC8, DM2SAD_L); + break; + case 0xCA: + DM2SAD_H = value & 0x0FFF; + UPDATE_REG(0xCA, DM2SAD_H); + break; + case 0xCC: + DM2DAD_L = value; + UPDATE_REG(0xCC, DM2DAD_L); + break; + case 0xCE: + DM2DAD_H = value & 0x07FF; + UPDATE_REG(0xCE, DM2DAD_H); + break; + case 0xD0: + DM2CNT_L = value & 0x3FFF; + UPDATE_REG(0xD0, 0); + break; + case 0xD2: + { + bool start = ((DM2CNT_H ^ value) & 0x8000) ? true : false; + + value &= 0xF7E0; + + DM2CNT_H = value; + UPDATE_REG(0xD2, DM2CNT_H); + + if(start && (value & 0x8000)) { + dma2Source = DM2SAD_L | (DM2SAD_H << 16); + dma2Dest = DM2DAD_L | (DM2DAD_H << 16); + + CPUCheckDMA(0, 4); + } + } + break; + case 0xD4: + DM3SAD_L = value; + UPDATE_REG(0xD4, DM3SAD_L); + break; + case 0xD6: + DM3SAD_H = value & 0x0FFF; + UPDATE_REG(0xD6, DM3SAD_H); + break; + case 0xD8: + DM3DAD_L = value; + UPDATE_REG(0xD8, DM3DAD_L); + break; + case 0xDA: + DM3DAD_H = value & 0x0FFF; + UPDATE_REG(0xDA, DM3DAD_H); + break; + case 0xDC: + DM3CNT_L = value; + UPDATE_REG(0xDC, 0); + break; + case 0xDE: + { + bool start = ((DM3CNT_H ^ value) & 0x8000) ? true : false; + + value &= 0xFFE0; + + DM3CNT_H = value; + UPDATE_REG(0xDE, DM3CNT_H); + + if(start && (value & 0x8000)) { + dma3Source = DM3SAD_L | (DM3SAD_H << 16); + dma3Dest = DM3DAD_L | (DM3DAD_H << 16); + CPUCheckDMA(0,8); + } + } + break; + case 0x100: + timer0Reload = value; +// interp_rate(); + break; + case 0x102: + timer0Value = value; + timerOnOffDelay|=1; + cpuNextEvent = cpuTotalTicks; + break; + case 0x104: + timer1Reload = value; +// interp_rate(); + break; + case 0x106: + timer1Value = value; + timerOnOffDelay|=2; + cpuNextEvent = cpuTotalTicks; + break; + case 0x108: + timer2Reload = value; + break; + case 0x10A: + timer2Value = value; + timerOnOffDelay|=4; + cpuNextEvent = cpuTotalTicks; + break; + case 0x10C: + timer3Reload = value; + break; + case 0x10E: + timer3Value = value; + timerOnOffDelay|=8; + cpuNextEvent = cpuTotalTicks; + break; + case 0x128: + #ifdef LINK_EMULATION + if (linkenable) + { + StartLink(value); + } + else +#endif + { + if(value & 0x80) { + value &= 0xff7f; + if(value & 1 && (value & 0x4000)) { + UPDATE_REG(0x12a, 0xFF); + IF |= 0x80; + UPDATE_REG(0x202, IF); + value &= 0x7f7f; + } + } + UPDATE_REG(0x128, value); + } + break; + case 0x12a: + #ifdef LINK_EMULATION + if(linkenable && lspeed) + LinkSSend(value); + #endif + { + UPDATE_REG(0x134, value); + } + break; + case 0x130: + P1 |= (value & 0x3FF); + UPDATE_REG(0x130, P1); + break; + case 0x132: + UPDATE_REG(0x132, value & 0xC3FF); + break; + case 0x134: +#ifdef LINK_EMULATION + if (linkenable) + StartGPLink(value); + else +#endif + UPDATE_REG(0x134, value); + + break; + case 0x140: +#ifdef LINK_EMULATION + if (linkenable) + StartJOYLink(value); + else +#endif + UPDATE_REG(0x140, value); + + break; + case 0x200: + IE = value & 0x3FFF; + UPDATE_REG(0x200, IE); + if ((IME & 1) && (IF & IE) && armIrqEnable) + cpuNextEvent = cpuTotalTicks; + break; + case 0x202: + IF ^= (value & IF); + UPDATE_REG(0x202, IF); + break; + case 0x204: + { + memoryWait[0x0e] = memoryWaitSeq[0x0e] = gamepakRamWaitState[value & 3]; + + if(!speedHack) { + memoryWait[0x08] = memoryWait[0x09] = gamepakWaitState[(value >> 2) & 3]; + memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = + gamepakWaitState0[(value >> 4) & 1]; + + memoryWait[0x0a] = memoryWait[0x0b] = gamepakWaitState[(value >> 5) & 3]; + memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = + gamepakWaitState1[(value >> 7) & 1]; + + memoryWait[0x0c] = memoryWait[0x0d] = gamepakWaitState[(value >> 8) & 3]; + memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = + gamepakWaitState2[(value >> 10) & 1]; + } else { + memoryWait[0x08] = memoryWait[0x09] = 3; + memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = 1; + + memoryWait[0x0a] = memoryWait[0x0b] = 3; + memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = 1; + + memoryWait[0x0c] = memoryWait[0x0d] = 3; + memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = 1; + } + + for(int i = 8; i < 15; i++) { + memoryWait32[i] = memoryWait[i] + memoryWaitSeq[i] + 1; + memoryWaitSeq32[i] = memoryWaitSeq[i]*2 + 1; + } + + if((value & 0x4000) == 0x4000) { + busPrefetchEnable = true; + busPrefetch = false; + busPrefetchCount = 0; + } else { + busPrefetchEnable = false; + busPrefetch = false; + busPrefetchCount = 0; + } + UPDATE_REG(0x204, value & 0x7FFF); + + } + break; + case 0x208: + IME = value & 1; + UPDATE_REG(0x208, IME); + if ((IME & 1) && (IF & IE) && armIrqEnable) + cpuNextEvent = cpuTotalTicks; + break; + case 0x300: + if(value != 0) + value &= 0xFFFE; + UPDATE_REG(0x300, value); + break; + default: + UPDATE_REG(address&0x3FE, value); + break; + } +} + +void applyTimer () +{ + if (timerOnOffDelay & 1) + { + timer0ClockReload = TIMER_TICKS[timer0Value & 3]; + if(!timer0On && (timer0Value & 0x80)) { + // reload the counter + TM0D = timer0Reload; + timer0Ticks = (0x10000 - TM0D) << timer0ClockReload; + UPDATE_REG(0x100, TM0D); + } + timer0On = timer0Value & 0x80 ? true : false; + TM0CNT = timer0Value & 0xC7; +// interp_rate(); + UPDATE_REG(0x102, TM0CNT); + // CPUUpdateTicks(); + } + if (timerOnOffDelay & 2) + { + timer1ClockReload = TIMER_TICKS[timer1Value & 3]; + if(!timer1On && (timer1Value & 0x80)) { + // reload the counter + TM1D = timer1Reload; + timer1Ticks = (0x10000 - TM1D) << timer1ClockReload; + UPDATE_REG(0x104, TM1D); + } + timer1On = timer1Value & 0x80 ? true : false; + TM1CNT = timer1Value & 0xC7; +// interp_rate(); + UPDATE_REG(0x106, TM1CNT); + } + if (timerOnOffDelay & 4) + { + timer2ClockReload = TIMER_TICKS[timer2Value & 3]; + if(!timer2On && (timer2Value & 0x80)) { + // reload the counter + TM2D = timer2Reload; + timer2Ticks = (0x10000 - TM2D) << timer2ClockReload; + UPDATE_REG(0x108, TM2D); + } + timer2On = timer2Value & 0x80 ? true : false; + TM2CNT = timer2Value & 0xC7; + UPDATE_REG(0x10A, TM2CNT); + } + if (timerOnOffDelay & 8) + { + timer3ClockReload = TIMER_TICKS[timer3Value & 3]; + if(!timer3On && (timer3Value & 0x80)) { + // reload the counter + TM3D = timer3Reload; + timer3Ticks = (0x10000 - TM3D) << timer3ClockReload; + UPDATE_REG(0x10C, TM3D); + } + timer3On = timer3Value & 0x80 ? true : false; + TM3CNT = timer3Value & 0xC7; + UPDATE_REG(0x10E, TM3CNT); + } + cpuNextEvent = CPUUpdateTicks(); + timerOnOffDelay = 0; +} + +u8 cpuBitsSet[256]; +u8 cpuLowestBitSet[256]; + +void CPUInit(const char *biosFileName, bool useBiosFile) +{ +#ifdef WORDS_BIGENDIAN + if(!cpuBiosSwapped) { + for(unsigned int i = 0; i < sizeof(myROM)/4; i++) { + WRITE32LE(&myROM[i], myROM[i]); + } + cpuBiosSwapped = true; + } +#endif + gbaSaveType = 0; + eepromInUse = 0; + saveType = 0; + useBios = false; + + if(useBiosFile) { + int size = 0x4000; + if(utilLoad(biosFileName, + CPUIsGBABios, + bios, + size)) { + if(size == 0x4000) + useBios = true; + else + systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BIOS file size")); + } + } + + if(!useBios) { + memcpy(bios, myROM, sizeof(myROM)); + } + + int i = 0; + + biosProtected[0] = 0x00; + biosProtected[1] = 0xf0; + biosProtected[2] = 0x29; + biosProtected[3] = 0xe1; + + for(i = 0; i < 256; i++) { + int count = 0; + int j; + for(j = 0; j < 8; j++) + if(i & (1 << j)) + count++; + cpuBitsSet[i] = count; + + for(j = 0; j < 8; j++) + if(i & (1 << j)) + break; + cpuLowestBitSet[i] = j; + } + + for(i = 0; i < 0x400; i++) + ioReadable[i] = true; + for(i = 0x10; i < 0x48; i++) + ioReadable[i] = false; + for(i = 0x4c; i < 0x50; i++) + ioReadable[i] = false; + for(i = 0x54; i < 0x60; i++) + ioReadable[i] = false; + for(i = 0x8c; i < 0x90; i++) + ioReadable[i] = false; + for(i = 0xa0; i < 0xb8; i++) + ioReadable[i] = false; + for(i = 0xbc; i < 0xc4; i++) + ioReadable[i] = false; + for(i = 0xc8; i < 0xd0; i++) + ioReadable[i] = false; + for(i = 0xd4; i < 0xdc; i++) + ioReadable[i] = false; + for(i = 0xe0; i < 0x100; i++) + ioReadable[i] = false; + for(i = 0x110; i < 0x120; i++) + ioReadable[i] = false; + for(i = 0x12c; i < 0x130; i++) + ioReadable[i] = false; + for(i = 0x138; i < 0x140; i++) + ioReadable[i] = false; + for(i = 0x144; i < 0x150; i++) + ioReadable[i] = false; + for(i = 0x15c; i < 0x200; i++) + ioReadable[i] = false; + for(i = 0x20c; i < 0x300; i++) + ioReadable[i] = false; + for(i = 0x304; i < 0x400; i++) + ioReadable[i] = false; + + if(romSize < 0x1fe2000) { + *((u16 *)&rom[0x1fe209c]) = 0xdffa; // SWI 0xFA + *((u16 *)&rom[0x1fe209e]) = 0x4770; // BX LR + } else { + agbPrintEnable(false); + } +} + +void CPUReset() +{ + if(gbaSaveType == 0) { + if(eepromInUse) + gbaSaveType = 3; + else + switch(saveType) { + case 1: + gbaSaveType = 1; + break; + case 2: + gbaSaveType = 2; + break; + } + } + rtcReset(); + // clean registers + memset(®[0], 0, sizeof(reg)); + // clean OAM + memset(oam, 0, 0x400); + // clean palette + memset(paletteRAM, 0, 0x400); + // clean picture + memset(pix, 0, 4*160*240); + // clean vram + memset(vram, 0, 0x20000); + // clean io memory + memset(ioMem, 0, 0x400); + + DISPCNT = 0x0080; + DISPSTAT = 0x0000; + VCOUNT = (useBios && !skipBios) ? 0 :0x007E; + BG0CNT = 0x0000; + BG1CNT = 0x0000; + BG2CNT = 0x0000; + BG3CNT = 0x0000; + BG0HOFS = 0x0000; + BG0VOFS = 0x0000; + BG1HOFS = 0x0000; + BG1VOFS = 0x0000; + BG2HOFS = 0x0000; + BG2VOFS = 0x0000; + BG3HOFS = 0x0000; + BG3VOFS = 0x0000; + BG2PA = 0x0100; + BG2PB = 0x0000; + BG2PC = 0x0000; + BG2PD = 0x0100; + BG2X_L = 0x0000; + BG2X_H = 0x0000; + BG2Y_L = 0x0000; + BG2Y_H = 0x0000; + BG3PA = 0x0100; + BG3PB = 0x0000; + BG3PC = 0x0000; + BG3PD = 0x0100; + BG3X_L = 0x0000; + BG3X_H = 0x0000; + BG3Y_L = 0x0000; + BG3Y_H = 0x0000; + WIN0H = 0x0000; + WIN1H = 0x0000; + WIN0V = 0x0000; + WIN1V = 0x0000; + WININ = 0x0000; + WINOUT = 0x0000; + MOSAIC = 0x0000; + BLDMOD = 0x0000; + COLEV = 0x0000; + COLY = 0x0000; + DM0SAD_L = 0x0000; + DM0SAD_H = 0x0000; + DM0DAD_L = 0x0000; + DM0DAD_H = 0x0000; + DM0CNT_L = 0x0000; + DM0CNT_H = 0x0000; + DM1SAD_L = 0x0000; + DM1SAD_H = 0x0000; + DM1DAD_L = 0x0000; + DM1DAD_H = 0x0000; + DM1CNT_L = 0x0000; + DM1CNT_H = 0x0000; + DM2SAD_L = 0x0000; + DM2SAD_H = 0x0000; + DM2DAD_L = 0x0000; + DM2DAD_H = 0x0000; + DM2CNT_L = 0x0000; + DM2CNT_H = 0x0000; + DM3SAD_L = 0x0000; + DM3SAD_H = 0x0000; + DM3DAD_L = 0x0000; + DM3DAD_H = 0x0000; + DM3CNT_L = 0x0000; + DM3CNT_H = 0x0000; + TM0D = 0x0000; + TM0CNT = 0x0000; + TM1D = 0x0000; + TM1CNT = 0x0000; + TM2D = 0x0000; + TM2CNT = 0x0000; + TM3D = 0x0000; + TM3CNT = 0x0000; + P1 = 0x03FF; + IE = 0x0000; + IF = 0x0000; + IME = 0x0000; + + armMode = 0x1F; + + if(cpuIsMultiBoot) { + reg[13].I = 0x03007F00; + reg[15].I = 0x02000000; + reg[16].I = 0x00000000; + reg[R13_IRQ].I = 0x03007FA0; + reg[R13_SVC].I = 0x03007FE0; + armIrqEnable = true; + } else { + if(useBios && !skipBios) { + reg[15].I = 0x00000000; + armMode = 0x13; + armIrqEnable = false; + } else { + reg[13].I = 0x03007F00; + reg[15].I = 0x08000000; + reg[16].I = 0x00000000; + reg[R13_IRQ].I = 0x03007FA0; + reg[R13_SVC].I = 0x03007FE0; + armIrqEnable = true; + } + } + armState = true; + C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false; + UPDATE_REG(0x00, DISPCNT); + UPDATE_REG(0x06, VCOUNT); + UPDATE_REG(0x20, BG2PA); + UPDATE_REG(0x26, BG2PD); + UPDATE_REG(0x30, BG3PA); + UPDATE_REG(0x36, BG3PD); + UPDATE_REG(0x130, P1); + UPDATE_REG(0x88, 0x200); + + // disable FIQ + reg[16].I |= 0x40; + + CPUUpdateCPSR(); + + armNextPC = reg[15].I; + reg[15].I += 4; + + // reset internal state + holdState = false; + holdType = 0; + + biosProtected[0] = 0x00; + biosProtected[1] = 0xf0; + biosProtected[2] = 0x29; + biosProtected[3] = 0xe1; + + lcdTicks = (useBios && !skipBios) ? 1008 : 208; + timer0On = false; + timer0Ticks = 0; + timer0Reload = 0; + timer0ClockReload = 0; + timer1On = false; + timer1Ticks = 0; + timer1Reload = 0; + timer1ClockReload = 0; + timer2On = false; + timer2Ticks = 0; + timer2Reload = 0; + timer2ClockReload = 0; + timer3On = false; + timer3Ticks = 0; + timer3Reload = 0; + timer3ClockReload = 0; + dma0Source = 0; + dma0Dest = 0; + dma1Source = 0; + dma1Dest = 0; + dma2Source = 0; + dma2Dest = 0; + dma3Source = 0; + dma3Dest = 0; + cpuSaveGameFunc = flashSaveDecide; + renderLine = mode0RenderLine; + fxOn = false; + windowOn = false; + frameCount = 0; + saveType = 0; + layerEnable = DISPCNT & layerSettings; + + CPUUpdateRenderBuffers(true); + + for(int i = 0; i < 256; i++) { + map[i].address = (u8 *)&dummyAddress; + map[i].mask = 0; + } + + map[0].address = bios; + map[0].mask = 0x3FFF; + map[2].address = workRAM; + map[2].mask = 0x3FFFF; + map[3].address = internalRAM; + map[3].mask = 0x7FFF; + map[4].address = ioMem; + map[4].mask = 0x3FF; + map[5].address = paletteRAM; + map[5].mask = 0x3FF; + map[6].address = vram; + map[6].mask = 0x1FFFF; + map[7].address = oam; + map[7].mask = 0x3FF; + map[8].address = rom; + map[8].mask = 0x1FFFFFF; + map[9].address = rom; + map[9].mask = 0x1FFFFFF; + map[10].address = rom; + map[10].mask = 0x1FFFFFF; + map[12].address = rom; + map[12].mask = 0x1FFFFFF; + map[14].address = flashSaveMemory; + map[14].mask = 0xFFFF; + + eepromReset(); + flashReset(); + + soundReset(); + + CPUUpdateWindow0(); + CPUUpdateWindow1(); + + // make sure registers are correctly initialized if not using BIOS + if(!useBios) { + if(cpuIsMultiBoot) + BIOS_RegisterRamReset(0xfe); + else + BIOS_RegisterRamReset(0xff); + } else { + if(cpuIsMultiBoot) + BIOS_RegisterRamReset(0xfe); + } + + switch(cpuSaveType) { + case 0: // automatic + cpuSramEnabled = true; + cpuFlashEnabled = true; + cpuEEPROMEnabled = true; + cpuEEPROMSensorEnabled = false; + saveType = gbaSaveType = 0; + break; + case 1: // EEPROM + cpuSramEnabled = false; + cpuFlashEnabled = false; + cpuEEPROMEnabled = true; + cpuEEPROMSensorEnabled = false; + saveType = gbaSaveType = 3; + // EEPROM usage is automatically detected + break; + case 2: // SRAM + cpuSramEnabled = true; + cpuFlashEnabled = false; + cpuEEPROMEnabled = false; + cpuEEPROMSensorEnabled = false; + cpuSaveGameFunc = sramDelayedWrite; // to insure we detect the write + saveType = gbaSaveType = 1; + break; + case 3: // FLASH + cpuSramEnabled = false; + cpuFlashEnabled = true; + cpuEEPROMEnabled = false; + cpuEEPROMSensorEnabled = false; + cpuSaveGameFunc = flashDelayedWrite; // to insure we detect the write + saveType = gbaSaveType = 2; + break; + case 4: // EEPROM+Sensor + cpuSramEnabled = false; + cpuFlashEnabled = false; + cpuEEPROMEnabled = true; + cpuEEPROMSensorEnabled = true; + // EEPROM usage is automatically detected + saveType = gbaSaveType = 3; + break; + case 5: // NONE + cpuSramEnabled = false; + cpuFlashEnabled = false; + cpuEEPROMEnabled = false; + cpuEEPROMSensorEnabled = false; + // no save at all + saveType = gbaSaveType = 5; + break; + } + + ARM_PREFETCH; + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + cpuDmaHack = false; + + lastTime = systemGetClock(); + + SWITicks = 0; +} + +void CPUInterrupt() +{ + u32 PC = reg[15].I; + bool savedState = armState; + CPUSwitchMode(0x12, true, false); + reg[14].I = PC; + if(!savedState) + reg[14].I += 2; + reg[15].I = 0x18; + armState = true; + armIrqEnable = false; + + armNextPC = reg[15].I; + reg[15].I += 4; + ARM_PREFETCH; + + // if(!holdState) + biosProtected[0] = 0x02; + biosProtected[1] = 0xc0; + biosProtected[2] = 0x5e; + biosProtected[3] = 0xe5; +} + +#ifdef SDL +void log(const char *defaultMsg, ...) +{ + char buffer[2048]; + va_list valist; + + va_start(valist, defaultMsg); + vsprintf(buffer, defaultMsg, valist); + + if(out == NULL) { + out = fopen("trace.log","w"); + } + + fputs(buffer, out); + + va_end(valist); +} +#else +extern void winlog(const char *, ...); +#endif + +void CPULoop(int ticks) +{ + int clockTicks; + int timerOverflow = 0; + // variable used by the CPU core + cpuTotalTicks = 0; +#ifdef LINK_EMULATION + if(linkenable) + cpuNextEvent = 1; +#endif + cpuBreakLoop = false; + cpuNextEvent = CPUUpdateTicks(); + if(cpuNextEvent > ticks) + cpuNextEvent = ticks; + + + for(;;) { +#ifndef FINAL_VERSION + if(systemDebug) { + if(systemDebug >= 10 && !holdState) { + CPUUpdateCPSR(); +#ifdef BKPT_SUPPORT + if (debugger_last) + { + sprintf(buffer, "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n", + oldreg[0], oldreg[1], oldreg[2], oldreg[3], oldreg[4], oldreg[5], + oldreg[6], oldreg[7], oldreg[8], oldreg[9], oldreg[10], oldreg[11], + oldreg[12], oldreg[13], oldreg[14], oldreg[15], oldreg[16], + oldreg[17]); + } +#endif + sprintf(buffer, "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n", + reg[0].I, reg[1].I, reg[2].I, reg[3].I, reg[4].I, reg[5].I, + reg[6].I, reg[7].I, reg[8].I, reg[9].I, reg[10].I, reg[11].I, + reg[12].I, reg[13].I, reg[14].I, reg[15].I, reg[16].I, + reg[17].I); +#ifdef SDL + log(buffer); +#else + winlog(buffer); +#endif + } else if(!holdState) { + sprintf(buffer, "PC=%08x\n", armNextPC); +#ifdef SDL + log(buffer); +#else + winlog(buffer); +#endif + } + } +#endif /* FINAL_VERSION */ + + if(!holdState && !SWITicks) { + if(armState) { + if (!armExecute()) + return; + } else { + if (!thumbExecute()) + return; + } + clockTicks = 0; + } else + clockTicks = CPUUpdateTicks(); + + cpuTotalTicks += clockTicks; + + + if(cpuTotalTicks >= cpuNextEvent) { + int remainingTicks = cpuTotalTicks - cpuNextEvent; + + if (SWITicks) + { + SWITicks-=clockTicks; + if (SWITicks<0) + SWITicks = 0; + } + + clockTicks = cpuNextEvent; + cpuTotalTicks = 0; + cpuDmaHack = false; + + updateLoop: + + if (IRQTicks) + { + IRQTicks -= clockTicks; + if (IRQTicks<0) + IRQTicks = 0; + } + + lcdTicks -= clockTicks; + + + if(lcdTicks <= 0) { + if(DISPSTAT & 1) { // V-BLANK + // if in V-Blank mode, keep computing... + if(DISPSTAT & 2) { + lcdTicks += 1008; + VCOUNT++; + UPDATE_REG(0x06, VCOUNT); + DISPSTAT &= 0xFFFD; + UPDATE_REG(0x04, DISPSTAT); + CPUCompareVCOUNT(); + } else { + lcdTicks += 224; + DISPSTAT |= 2; + UPDATE_REG(0x04, DISPSTAT); + if(DISPSTAT & 16) { + IF |= 2; + UPDATE_REG(0x202, IF); + } + } + + if(VCOUNT >= 228) { //Reaching last line + DISPSTAT &= 0xFFFC; + UPDATE_REG(0x04, DISPSTAT); + VCOUNT = 0; + UPDATE_REG(0x06, VCOUNT); + CPUCompareVCOUNT(); + } + } else { + int framesToSkip = systemFrameSkip; + if(speedup) + framesToSkip = 9; // try 6 FPS during speedup + + if(DISPSTAT & 2) { + // if in H-Blank, leave it and move to drawing mode + VCOUNT++; + UPDATE_REG(0x06, VCOUNT); + + lcdTicks += 1008; + DISPSTAT &= 0xFFFD; + if(VCOUNT == 160) { + count++; + systemFrame(); + + if((count % 10) == 0) { + system10Frames(60); + } + if(count == 60) { + u32 time = systemGetClock(); + if(time != lastTime) { + u32 t = 100000/(time - lastTime); + systemShowSpeed(t); + } else + systemShowSpeed(0); + lastTime = time; + count = 0; + } + u32 joy = 0; + // update joystick information + if(systemReadJoypads()) + // read default joystick + joy = systemReadJoypad(-1); + P1 = 0x03FF ^ (joy & 0x3FF); + if(cpuEEPROMSensorEnabled) + systemUpdateMotionSensor(); + UPDATE_REG(0x130, P1); + u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132])); + // this seems wrong, but there are cases where the game + // can enter the stop state without requesting an IRQ from + // the joypad. + if((P1CNT & 0x4000) || stopState) { + u16 p1 = (0x3FF ^ P1) & 0x3FF; + if(P1CNT & 0x8000) { + if(p1 == (P1CNT & 0x3FF)) { + IF |= 0x1000; + UPDATE_REG(0x202, IF); + } + } else { + if(p1 & P1CNT) { + IF |= 0x1000; + UPDATE_REG(0x202, IF); + } + } + } + + u32 ext = (joy >> 10); + // If no (m) code is enabled, apply the cheats at each LCDline + if((cheatsEnabled) && (mastercode==0)) + remainingTicks += cheatsCheckKeys(P1^0x3FF, ext); + speedup = (ext & 1) ? true : false; + capture = (ext & 2) ? true : false; + + if(capture && !capturePrevious) { + captureNumber++; + systemScreenCapture(captureNumber); + } + capturePrevious = capture; + + DISPSTAT |= 1; + DISPSTAT &= 0xFFFD; + UPDATE_REG(0x04, DISPSTAT); + if(DISPSTAT & 0x0008) { + IF |= 1; + UPDATE_REG(0x202, IF); + } + CPUCheckDMA(1, 0x0f); + if(frameCount >= framesToSkip) { + systemDrawScreen(); + frameCount = 0; + } else + frameCount++; + if(systemPauseOnFrame()) + ticks = 0; + } + + UPDATE_REG(0x04, DISPSTAT); + CPUCompareVCOUNT(); + + } else { + if(frameCount >= framesToSkip) + { + (*renderLine)(); + switch(systemColorDepth) { + case 16: + { + u16 *dest = (u16 *)pix + 242 * (VCOUNT+1); + for(int x = -1; x < 240;) { + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + *dest++ = systemColorMap16[lineMix[++x]&0xFFFF]; + } + // for filters that read past the screen + *dest = 0; + } + break; + case 24: + { + u8 *dest = (u8 *)pix + 240 * VCOUNT * 3; + for(int x = -1; x < 240;) { + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + dest += 3; + *((u32 *)dest) = systemColorMap32[lineMix[++x] & 0xFFFF]; + } + } + break; + case 32: + { + u32 *dest = (u32 *)pix + 241 * (VCOUNT+1); + for(int x = -1; x < 240; ) { + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + *dest++ = systemColorMap32[lineMix[++x] & 0xFFFF]; + *dest = systemColorMap32[lineMix[++x] & 0xFFFF]; + } + } + break; + } + } + // entering H-Blank + DISPSTAT |= 2; + UPDATE_REG(0x04, DISPSTAT); + lcdTicks += 224; + CPUCheckDMA(2, 0x0f); + if(DISPSTAT & 16) { + IF |= 2; + UPDATE_REG(0x202, IF); + } + } + } + } + + // we shouldn't be doing sound in stop state, but we loose synchronization + // if sound is disabled, so in stop state, soundTick will just produce + // mute sound + soundTicks -= clockTicks; + if(soundTicks <= 0) { + soundTick(); // psoundTickfn(); + soundTicks += SOUND_CLOCK_TICKS; + } + + if(!stopState) { + if(timer0On) { + timer0Ticks -= clockTicks; + if(timer0Ticks <= 0) { + timer0Ticks += (0x10000 - timer0Reload) << timer0ClockReload; + timerOverflow |= 1; + soundTimerOverflow(0); + if(TM0CNT & 0x40) { + IF |= 0x08; + UPDATE_REG(0x202, IF); + } + } + TM0D = 0xFFFF - (timer0Ticks >> timer0ClockReload); + UPDATE_REG(0x100, TM0D); + } + + if(timer1On) { + if(TM1CNT & 4) { + if(timerOverflow & 1) { + TM1D++; + if(TM1D == 0) { + TM1D += timer1Reload; + timerOverflow |= 2; + soundTimerOverflow(1); + if(TM1CNT & 0x40) { + IF |= 0x10; + UPDATE_REG(0x202, IF); + } + } + UPDATE_REG(0x104, TM1D); + } + } else { + timer1Ticks -= clockTicks; + if(timer1Ticks <= 0) { + timer1Ticks += (0x10000 - timer1Reload) << timer1ClockReload; + timerOverflow |= 2; + soundTimerOverflow(1); + if(TM1CNT & 0x40) { + IF |= 0x10; + UPDATE_REG(0x202, IF); + } + } + TM1D = 0xFFFF - (timer1Ticks >> timer1ClockReload); + UPDATE_REG(0x104, TM1D); + } + } + + if(timer2On) { + if(TM2CNT & 4) { + if(timerOverflow & 2) { + TM2D++; + if(TM2D == 0) { + TM2D += timer2Reload; + timerOverflow |= 4; + if(TM2CNT & 0x40) { + IF |= 0x20; + UPDATE_REG(0x202, IF); + } + } + UPDATE_REG(0x108, TM2D); + } + } else { + timer2Ticks -= clockTicks; + if(timer2Ticks <= 0) { + timer2Ticks += (0x10000 - timer2Reload) << timer2ClockReload; + timerOverflow |= 4; + if(TM2CNT & 0x40) { + IF |= 0x20; + UPDATE_REG(0x202, IF); + } + } + TM2D = 0xFFFF - (timer2Ticks >> timer2ClockReload); + UPDATE_REG(0x108, TM2D); + } + } + + if(timer3On) { + if(TM3CNT & 4) { + if(timerOverflow & 4) { + TM3D++; + if(TM3D == 0) { + TM3D += timer3Reload; + if(TM3CNT & 0x40) { + IF |= 0x40; + UPDATE_REG(0x202, IF); + } + } + UPDATE_REG(0x10C, TM3D); + } + } else { + timer3Ticks -= clockTicks; + if(timer3Ticks <= 0) { + timer3Ticks += (0x10000 - timer3Reload) << timer3ClockReload; + if(TM3CNT & 0x40) { + IF |= 0x40; + UPDATE_REG(0x202, IF); + } + } + TM3D = 0xFFFF - (timer3Ticks >> timer3ClockReload); + UPDATE_REG(0x10C, TM3D); + } + } + } + + timerOverflow = 0; + + + +#ifdef PROFILING + profilingTicks -= clockTicks; + if(profilingTicks <= 0) { + profilingTicks += profilingTicksReload; + if(profilSegment) { + profile_segment *seg = profilSegment; + do { + u16 *b = (u16 *)seg->sbuf; + int pc = ((reg[15].I - seg->s_lowpc) * seg->s_scale)/0x10000; + if(pc >= 0 && pc < seg->ssiz) { + b[pc]++; + break; + } + + seg = seg->next; + } while(seg); + } + } +#endif + + ticks -= clockTicks; +#ifdef LINK_EMULATION + if (linkenable) + LinkUpdate(clockTicks); +#endif + cpuNextEvent = CPUUpdateTicks(); + + if(cpuDmaTicksToUpdate > 0) { + if(cpuDmaTicksToUpdate > cpuNextEvent) + clockTicks = cpuNextEvent; + else + clockTicks = cpuDmaTicksToUpdate; + cpuDmaTicksToUpdate -= clockTicks; + if(cpuDmaTicksToUpdate < 0) + cpuDmaTicksToUpdate = 0; + cpuDmaHack = true; + goto updateLoop; + } +#ifdef LINK_EMULATION + if(linkenable) + cpuNextEvent = 1; +#endif + if(IF && (IME & 1) && armIrqEnable) { + int res = IF & IE; + if(stopState) + res &= 0x3080; + if(res) { + if (intState) + { + if (!IRQTicks) + { + CPUInterrupt(); + intState = false; + holdState = false; + stopState = false; + holdType = 0; + } + } + else + { + if (!holdState) + { + intState = true; + IRQTicks=7; + if (cpuNextEvent> IRQTicks) + cpuNextEvent = IRQTicks; + } + else + { + CPUInterrupt(); + holdState = false; + stopState = false; + holdType = 0; + } + } + + // Stops the SWI Ticks emulation if an IRQ is executed + //(to avoid problems with nested IRQ/SWI) + if (SWITicks) + SWITicks = 0; + } + } + + if(remainingTicks > 0) { + if(remainingTicks > cpuNextEvent) + clockTicks = cpuNextEvent; + else + clockTicks = remainingTicks; + remainingTicks -= clockTicks; + if(remainingTicks < 0) + remainingTicks = 0; + goto updateLoop; + } + + if (timerOnOffDelay) + applyTimer(); + + if(cpuNextEvent > ticks) + cpuNextEvent = ticks; + + if(ticks <= 0 || cpuBreakLoop) + break; + + } + } +} + + + +struct EmulatedSystem GBASystem = { + // emuMain + CPULoop, + // emuReset + CPUReset, + // emuCleanUp + CPUCleanUp, + // emuReadBattery + CPUReadBatteryFile, + // emuWriteBattery + CPUWriteBatteryFile, + // emuReadState + CPUReadState, + // emuWriteState + CPUWriteState, + // emuReadMemState + CPUReadMemState, + // emuWriteMemState + CPUWriteMemState, + // emuWritePNG + CPUWritePNGFile, + // emuWriteBMP + CPUWriteBMPFile, + // emuUpdateCPSR + CPUUpdateCPSR, + // emuHasDebugger + true, + // emuCount +#ifdef FINAL_VERSION + 250000 +#else + 5000 +#endif +}; diff --git a/source/vba/GBA.h b/source/vba/agb/GBA.h similarity index 72% rename from source/vba/GBA.h rename to source/vba/agb/GBA.h index 46169e6..a1c04a0 100644 --- a/source/vba/GBA.h +++ b/source/vba/agb/GBA.h @@ -1,153 +1,160 @@ -// -*- 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_GBA_H -#define VBA_GBA_H - -#include "System.h" - -#define SAVE_GAME_VERSION_1 1 -#define SAVE_GAME_VERSION_2 2 -#define SAVE_GAME_VERSION_3 3 -#define SAVE_GAME_VERSION_4 4 -#define SAVE_GAME_VERSION_5 5 -#define SAVE_GAME_VERSION_6 6 -#define SAVE_GAME_VERSION_7 7 -#define SAVE_GAME_VERSION_8 8 -#define SAVE_GAME_VERSION SAVE_GAME_VERSION_8 - -typedef struct - { - u8 *address; - u32 mask; - } -memoryMap; - -typedef union { - struct - { -#ifdef WORDS_BIGENDIAN - u8 B3; - u8 B2; - u8 B1; - u8 B0; -#else - u8 B0; - u8 B1; - u8 B2; - u8 B3; -#endif - } - B; - struct - { -#ifdef WORDS_BIGENDIAN - u16 W1; - u16 W0; -#else - u16 W0; - u16 W1; -#endif - } - W; -#ifdef WORDS_BIGENDIAN - volatile u32 I; -#else - u32 I; -#endif - } reg_pair; - -#ifndef NO_GBA_MAP -extern memoryMap map[256]; -#endif - -extern reg_pair reg[45]; -extern u8 biosProtected[4]; - -extern bool N_FLAG; -extern bool Z_FLAG; -extern bool C_FLAG; -extern bool V_FLAG; -extern bool armIrqEnable; -extern bool armState; -extern int armMode; -extern void (*cpuSaveGameFunc)(u32,u8); - -extern bool freezeWorkRAM[0x40000]; -extern bool freezeInternalRAM[0x8000]; -extern bool CPUReadGSASnapshot(const char *); -extern bool CPUWriteGSASnapshot(const char *, const char *, const char *, const char *); -extern bool CPUWriteBatteryFile(const char *); -extern bool CPUReadBatteryFile(const char *); -extern bool CPUExportEepromFile(const char *); -extern bool CPUImportEepromFile(const char *); -extern bool CPUWritePNGFile(const char *); -extern bool CPUWriteBMPFile(const char *); -extern void CPUCleanUp(); -extern void CPUUpdateRender(); -extern bool CPUReadMemState(char *, int); -extern bool CPUReadState(const char *); -extern bool CPUWriteMemState(char *, int); -extern bool CPUWriteState(const char *); -extern int CPULoadRom(const char *); -extern void CPUUpdateRegister(u32, u16); -extern void CPUWriteHalfWord(u32, u16); -extern void CPUWriteByte(u32, u8); -extern void CPUInit(const char *,bool); -extern void CPUReset(); -extern void CPULoop(int); -extern void CPUCheckDMA(int,int); -extern bool CPUIsGBAImage(const char *); -extern bool CPUIsZipFile(const char *); -#ifdef PROFILING -extern void cpuProfil(char *buffer, int, u32, int); -extern void cpuEnableProfiling(int hz); -#endif - -extern struct EmulatedSystem GBASystem; - -#define R13_IRQ 18 -#define R14_IRQ 19 -#define SPSR_IRQ 20 -#define R13_USR 26 -#define R14_USR 27 -#define R13_SVC 28 -#define R14_SVC 29 -#define SPSR_SVC 30 -#define R13_ABT 31 -#define R14_ABT 32 -#define SPSR_ABT 33 -#define R13_UND 34 -#define R14_UND 35 -#define SPSR_UND 36 -#define R8_FIQ 37 -#define R9_FIQ 38 -#define R10_FIQ 39 -#define R11_FIQ 40 -#define R12_FIQ 41 -#define R13_FIQ 42 -#define R14_FIQ 43 -#define SPSR_FIQ 44 - -#include "Cheats.h" -#include "Globals.h" -#include "EEprom.h" -#include "Flash.h" - -#endif //VBA_GBA_H +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 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_GBA_H +#define VBA_GBA_H + +#include "../System.h" + +#define SAVE_GAME_VERSION_1 1 +#define SAVE_GAME_VERSION_2 2 +#define SAVE_GAME_VERSION_3 3 +#define SAVE_GAME_VERSION_4 4 +#define SAVE_GAME_VERSION_5 5 +#define SAVE_GAME_VERSION_6 6 +#define SAVE_GAME_VERSION_7 7 +#define SAVE_GAME_VERSION_8 8 +#define SAVE_GAME_VERSION_9 9 +#define SAVE_GAME_VERSION_10 10 +#define SAVE_GAME_VERSION SAVE_GAME_VERSION_10 + +typedef struct { + u8 *address; + u32 mask; +} memoryMap; + +typedef union { + struct { +#ifdef WORDS_BIGENDIAN + u8 B3; + u8 B2; + u8 B1; + u8 B0; +#else + u8 B0; + u8 B1; + u8 B2; + u8 B3; +#endif + } B; + struct { +#ifdef WORDS_BIGENDIAN + u16 W1; + u16 W0; +#else + u16 W0; + u16 W1; +#endif + } W; +#ifdef WORDS_BIGENDIAN + volatile u32 I; +#else + u32 I; +#endif +} reg_pair; + +#ifndef NO_GBA_MAP +extern memoryMap map[256]; +#endif + +extern reg_pair reg[45]; +extern u8 biosProtected[4]; + +extern bool N_FLAG; +extern bool Z_FLAG; +extern bool C_FLAG; +extern bool V_FLAG; +extern bool armIrqEnable; +extern bool armState; +extern int armMode; +extern void (*cpuSaveGameFunc)(u32,u8); + +#ifdef BKPT_SUPPORT +extern u8 freezeWorkRAM[0x40000]; +extern u8 freezeInternalRAM[0x8000]; +extern u8 freezeVRAM[0x18000]; +extern u8 freezeOAM[0x400]; +extern u8 freezePRAM[0x400]; +extern bool debugger_last; +extern int oldreg[17]; +extern char oldbuffer[10]; +#endif + +extern bool CPUReadGSASnapshot(const char *); +extern bool CPUWriteGSASnapshot(const char *, const char *, const char *, const char *); +extern bool CPUWriteBatteryFile(const char *); +extern bool CPUReadBatteryFile(const char *); +extern bool CPUExportEepromFile(const char *); +extern bool CPUImportEepromFile(const char *); +extern bool CPUWritePNGFile(const char *); +extern bool CPUWriteBMPFile(const char *); +extern void CPUCleanUp(); +extern void CPUUpdateRender(); +extern void CPUUpdateRenderBuffers(bool); +extern bool CPUReadMemState(char *, int); +extern bool CPUReadState(const char *); +extern bool CPUWriteMemState(char *, int); +extern bool CPUWriteState(const char *); +extern int CPULoadRom(const char *); +extern void doMirroring(bool); +extern void CPUUpdateRegister(u32, u16); +extern void applyTimer (); +extern void CPUInit(const char *,bool); +extern void CPUReset(); +extern void CPULoop(int); +extern void CPUCheckDMA(int,int); +extern bool CPUIsGBAImage(const char *); +extern bool CPUIsZipFile(const char *); +#ifdef PROFILING +#include "prof/prof.h" +extern void cpuProfil(profile_segment *seg); +extern void cpuEnableProfiling(int hz); +#endif + +extern struct EmulatedSystem GBASystem; + +#define R13_IRQ 18 +#define R14_IRQ 19 +#define SPSR_IRQ 20 +#define R13_USR 26 +#define R14_USR 27 +#define R13_SVC 28 +#define R14_SVC 29 +#define SPSR_SVC 30 +#define R13_ABT 31 +#define R14_ABT 32 +#define SPSR_ABT 33 +#define R13_UND 34 +#define R14_UND 35 +#define SPSR_UND 36 +#define R8_FIQ 37 +#define R9_FIQ 38 +#define R10_FIQ 39 +#define R11_FIQ 40 +#define R12_FIQ 41 +#define R13_FIQ 42 +#define R14_FIQ 43 +#define SPSR_FIQ 44 + +#include "../Cheats.h" +#include "../Globals.h" +#include "../EEprom.h" +#include "../Flash.h" + +#endif //VBA_GBA_H diff --git a/source/vba/Gfx.cpp b/source/vba/agb/GBAGfx.cpp similarity index 85% rename from source/vba/Gfx.cpp rename to source/vba/agb/GBAGfx.cpp index c4ba850..24c73f6 100644 --- a/source/vba/Gfx.cpp +++ b/source/vba/agb/GBAGfx.cpp @@ -1,47 +1,47 @@ -// 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. - -#include "System.h" - -int coeff[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; - - -u32 line0[240]; -u32 line1[240]; -u32 line2[240]; -u32 line3[240]; -u32 lineOBJ[240]; -u32 lineOBJWin[240]; -u32 lineMix[240]; -bool gfxInWin0[240]; -bool gfxInWin1[240]; - -int gfxBG2Changed = 0; -int gfxBG3Changed = 0; - -int gfxBG2X = 0; -int gfxBG2Y = 0; -int gfxBG2LastX = 0; -int gfxBG2LastY = 0; -int gfxBG3X = 0; -int gfxBG3Y = 0; -int gfxBG3LastX = 0; -int gfxBG3LastY = 0; -int gfxLastVCOUNT = 0; +// 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. + +#include "../System.h" + +int coeff[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; + +u32 line0[240]; +u32 line1[240]; +u32 line2[240]; +u32 line3[240]; +u32 lineOBJ[240]; +u32 lineOBJWin[240]; +u32 lineMix[240]; +bool gfxInWin0[240]; +bool gfxInWin1[240]; +int lineOBJpixleft[128]; + +int gfxBG2Changed = 0; +int gfxBG3Changed = 0; + +int gfxBG2X = 0; +int gfxBG2Y = 0; +int gfxBG2LastX = 0; +int gfxBG2LastY = 0; +int gfxBG3X = 0; +int gfxBG3Y = 0; +int gfxBG3LastX = 0; +int gfxBG3LastY = 0; +int gfxLastVCOUNT = 0; diff --git a/source/vba/agb/GBAGfx.h b/source/vba/agb/GBAGfx.h new file mode 100644 index 0000000..73f1dd4 --- /dev/null +++ b/source/vba/agb/GBAGfx.h @@ -0,0 +1,1601 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 Forgotten and the VBA development team +// Copyright (C) 2008 VBA-M 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_GFX_H +#define VBA_GFX_H + +#include "GBA.h" +#include "../Globals.h" + +#include "../Port.h" + +//#define SPRITE_DEBUG + +static void gfxDrawTextScreen(u16, u16, u16, u32 *); +static void gfxDrawRotScreen(u16, + u16, u16, + u16, u16, + u16, u16, + u16, u16, + int&, int&, + int, + u32*); +static void gfxDrawRotScreen16Bit(u16, + u16, u16, + u16, u16, + u16, u16, + u16, u16, + int&, int&, + int, + u32*); +static void gfxDrawRotScreen256(u16, + u16, u16, + u16, u16, + u16, u16, + u16, u16, + int&, int&, + int, + u32*); +static void gfxDrawRotScreen16Bit160(u16, + u16, u16, + u16, u16, + u16, u16, + u16, u16, + int&, int&, + int, + u32*); +static void gfxDrawSprites(u32 *); +static void gfxIncreaseBrightness(u32 *line, int coeff); +static void gfxDecreaseBrightness(u32 *line, int coeff); +static void gfxAlphaBlend(u32 *ta, u32 *tb, int ca, int cb); + +void mode0RenderLine(); +void mode0RenderLineNoWindow(); +void mode0RenderLineAll(); + +void mode1RenderLine(); +void mode1RenderLineNoWindow(); +void mode1RenderLineAll(); + +void mode2RenderLine(); +void mode2RenderLineNoWindow(); +void mode2RenderLineAll(); + +void mode3RenderLine(); +void mode3RenderLineNoWindow(); +void mode3RenderLineAll(); + +void mode4RenderLine(); +void mode4RenderLineNoWindow(); +void mode4RenderLineAll(); + +void mode5RenderLine(); +void mode5RenderLineNoWindow(); +void mode5RenderLineAll(); + +extern int coeff[32]; +extern u32 line0[240]; +extern u32 line1[240]; +extern u32 line2[240]; +extern u32 line3[240]; +extern u32 lineOBJ[240]; +extern u32 lineOBJWin[240]; +extern u32 lineMix[240]; +extern bool gfxInWin0[240]; +extern bool gfxInWin1[240]; +extern int lineOBJpixleft[128]; + +extern int gfxBG2Changed; +extern int gfxBG3Changed; + +extern int gfxBG2X; +extern int gfxBG2Y; +extern int gfxBG2LastX; +extern int gfxBG2LastY; +extern int gfxBG3X; +extern int gfxBG3Y; +extern int gfxBG3LastX; +extern int gfxBG3LastY; +extern int gfxLastVCOUNT; + +static inline void gfxClearArray(u32 *array) +{ + for(int i = 0; i < 240; i++) { + *array++ = 0x80000000; + } +} + +static inline void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs, + u32 *line) +{ + u16 *palette = (u16 *)paletteRAM; + u8 *charBase = &vram[((control >> 2) & 0x03) * 0x4000]; + u16 *screenBase = (u16 *)&vram[((control >> 8) & 0x1f) * 0x800]; + u32 prio = ((control & 3)<<25) + 0x1000000; + int sizeX = 256; + int sizeY = 256; + switch((control >> 14) & 3) { + case 0: + break; + case 1: + sizeX = 512; + break; + case 2: + sizeY = 512; + break; + case 3: + sizeX = 512; + sizeY = 512; + break; + } + + int maskX = sizeX-1; + int maskY = sizeY-1; + + bool mosaicOn = (control & 0x40) ? true : false; + + int xxx = hofs & maskX; + int yyy = (vofs + VCOUNT) & maskY; + int mosaicX = (MOSAIC & 0x000F)+1; + int mosaicY = ((MOSAIC & 0x00F0)>>4)+1; + + if(mosaicOn) { + if((VCOUNT % mosaicY) != 0) { + mosaicY = VCOUNT - (VCOUNT % mosaicY); + yyy = (vofs + mosaicY) & maskY; + } + } + + if(yyy > 255 && sizeY > 256) { + yyy &= 255; + screenBase += 0x400; + if(sizeX > 256) + screenBase += 0x400; + } + + int yshift = ((yyy>>3)<<5); + if((control) & 0x80) { + u16 *screenSource = screenBase + 0x400 * (xxx>>8) + ((xxx & 255)>>3) + yshift; + for(int x = 0; x < 240; x++) { + u16 data = READ16LE(screenSource); + + int tile = data & 0x3FF; + int tileX = (xxx & 7); + int tileY = yyy & 7; + + if(tileX == 7) + screenSource++; + + if(data & 0x0400) + tileX = 7 - tileX; + if(data & 0x0800) + tileY = 7 - tileY; + + u8 color = charBase[tile * 64 + tileY * 8 + tileX]; + + line[x] = color ? (READ16LE(&palette[color]) | prio): 0x80000000; + + xxx++; + if(xxx == 256) { + if(sizeX > 256) + screenSource = screenBase + 0x400 + yshift; + else { + screenSource = screenBase + yshift; + xxx = 0; + } + } else if(xxx >= sizeX) { + xxx = 0; + screenSource = screenBase + yshift; + } + } + } else { + u16 *screenSource = screenBase + 0x400*(xxx>>8)+((xxx&255)>>3) + + yshift; + for(int x = 0; x < 240; x++) { + u16 data = READ16LE(screenSource); + + int tile = data & 0x3FF; + int tileX = (xxx & 7); + int tileY = yyy & 7; + + if(tileX == 7) + screenSource++; + + if(data & 0x0400) + tileX = 7 - tileX; + if(data & 0x0800) + tileY = 7 - tileY; + + u8 color = charBase[(tile<<5) + (tileY<<2) + (tileX>>1)]; + + if(tileX & 1) { + color = (color >> 4); + } else { + color &= 0x0F; + } + + int pal = (data>>8) & 0xF0; + line[x] = color ? (READ16LE(&palette[pal + color])|prio): 0x80000000; + + xxx++; + if(xxx == 256) { + if(sizeX > 256) + screenSource = screenBase + 0x400 + yshift; + else { + screenSource = screenBase + yshift; + xxx = 0; + } + } else if(xxx >= sizeX) { + xxx = 0; + screenSource = screenBase + yshift; + } + } + } + if(mosaicOn) { + if(mosaicX > 1) { + int m = 1; + for(int i = 0; i < 239; i++) { + line[i+1] = line[i]; + m++; + if(m == mosaicX) { + m = 1; + i++; + } + } + } + } +} + +static inline void gfxDrawRotScreen(u16 control, + u16 x_l, u16 x_h, + u16 y_l, u16 y_h, + u16 pa, u16 pb, + u16 pc, u16 pd, + int& currentX, int& currentY, + int changed, + u32 *line) +{ + u16 *palette = (u16 *)paletteRAM; + u8 *charBase = &vram[((control >> 2) & 0x03) * 0x4000]; + u8 *screenBase = (u8 *)&vram[((control >> 8) & 0x1f) * 0x800]; + int prio = ((control & 3) << 25) + 0x1000000; + + int sizeX = 128; + int sizeY = 128; + switch((control >> 14) & 3) { + case 0: + break; + case 1: + sizeX = sizeY = 256; + break; + case 2: + sizeX = sizeY = 512; + break; + case 3: + sizeX = sizeY = 1024; + break; + } + + int maskX = sizeX-1; + int maskY = sizeY-1; + + int yshift = ((control >> 14) & 3)+4; + + int dx = pa & 0x7FFF; + if(pa & 0x8000) + dx |= 0xFFFF8000; + int dmx = pb & 0x7FFF; + if(pb & 0x8000) + dmx |= 0xFFFF8000; + int dy = pc & 0x7FFF; + if(pc & 0x8000) + dy |= 0xFFFF8000; + int dmy = pd & 0x7FFF; + if(pd & 0x8000) + dmy |= 0xFFFF8000; + + if(VCOUNT == 0) + changed = 3; + + if(changed & 1) { + currentX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + currentX |= 0xF8000000; + } else { + currentX += dmx; + } + + if(changed & 2) { + currentY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + currentY |= 0xF8000000; + } else { + currentY += dmy; + } + + int realX = currentX; + int realY = currentY; + + if(control & 0x40) { + int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; + int y = (VCOUNT % mosaicY); + realX -= y*dmx; + realY -= y*dmy; + } + + if(control & 0x2000) { + for(int x = 0; x < 240; x++) { + int xxx = (realX >> 8) & maskX; + int yyy = (realY >> 8) & maskY; + + int tile = screenBase[(xxx>>3) + ((yyy>>3)<> 8); + int yyy = (realY >> 8); + + if(xxx < 0 || + yyy < 0 || + xxx >= sizeX || + yyy >= sizeY) { + line[x] = 0x80000000; + } else { + int tile = screenBase[(xxx>>3) + ((yyy>>3)< 1) { + int m = 1; + for(int i = 0; i < 239; i++) { + line[i+1] = line[i]; + m++; + if(m == mosaicX) { + m = 1; + i++; + } + } + } + } +} + +static inline void gfxDrawRotScreen16Bit(u16 control, + u16 x_l, u16 x_h, + u16 y_l, u16 y_h, + u16 pa, u16 pb, + u16 pc, u16 pd, + int& currentX, int& currentY, + int changed, + u32 *line) +{ + u16 *screenBase = (u16 *)&vram[0]; + int prio = ((control & 3) << 25) + 0x1000000; + int sizeX = 240; + int sizeY = 160; + + int startX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + startX |= 0xF8000000; + int startY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + startY |= 0xF8000000; + + int dx = pa & 0x7FFF; + if(pa & 0x8000) + dx |= 0xFFFF8000; + int dmx = pb & 0x7FFF; + if(pb & 0x8000) + dmx |= 0xFFFF8000; + int dy = pc & 0x7FFF; + if(pc & 0x8000) + dy |= 0xFFFF8000; + int dmy = pd & 0x7FFF; + if(pd & 0x8000) + dmy |= 0xFFFF8000; + + if(VCOUNT == 0) + changed = 3; + + if(changed & 1) { + currentX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + currentX |= 0xF8000000; + } else + currentX += dmx; + + if(changed & 2) { + currentY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + currentY |= 0xF8000000; + } else { + currentY += dmy; + } + + int realX = currentX; + int realY = currentY; + + if(control & 0x40) { + int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; + int y = (VCOUNT % mosaicY); + realX -= y*dmx; + realY -= y*dmy; + } + + int xxx = (realX >> 8); + int yyy = (realY >> 8); + + for(int x = 0; x < 240; x++) { + if(xxx < 0 || + yyy < 0 || + xxx >= sizeX || + yyy >= sizeY) { + line[x] = 0x80000000; + } else { + line[x] = (READ16LE(&screenBase[yyy * sizeX + xxx]) | prio); + } + realX += dx; + realY += dy; + + xxx = (realX >> 8); + yyy = (realY >> 8); + } + + if(control & 0x40) { + int mosaicX = (MOSAIC & 0xF) + 1; + if(mosaicX > 1) { + int m = 1; + for(int i = 0; i < 239; i++) { + line[i+1] = line[i]; + m++; + if(m == mosaicX) { + m = 1; + i++; + } + } + } + } +} + +static inline void gfxDrawRotScreen256(u16 control, + u16 x_l, u16 x_h, + u16 y_l, u16 y_h, + u16 pa, u16 pb, + u16 pc, u16 pd, + int ¤tX, int& currentY, + int changed, + u32 *line) +{ + u16 *palette = (u16 *)paletteRAM; + u8 *screenBase = (DISPCNT & 0x0010) ? &vram[0xA000] : &vram[0x0000]; + int prio = ((control & 3) << 25) + 0x1000000; + int sizeX = 240; + int sizeY = 160; + + int startX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + startX |= 0xF8000000; + int startY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + startY |= 0xF8000000; + + int dx = pa & 0x7FFF; + if(pa & 0x8000) + dx |= 0xFFFF8000; + int dmx = pb & 0x7FFF; + if(pb & 0x8000) + dmx |= 0xFFFF8000; + int dy = pc & 0x7FFF; + if(pc & 0x8000) + dy |= 0xFFFF8000; + int dmy = pd & 0x7FFF; + if(pd & 0x8000) + dmy |= 0xFFFF8000; + + if(VCOUNT == 0) + changed = 3; + + if(changed & 1) { + currentX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + currentX |= 0xF8000000; + } else { + currentX += dmx; + } + + if(changed & 2) { + currentY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + currentY |= 0xF8000000; + } else { + currentY += dmy; + } + + int realX = currentX; + int realY = currentY; + + if(control & 0x40) { + int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; + int y = VCOUNT - (VCOUNT % mosaicY); + realX = startX + y*dmx; + realY = startY + y*dmy; + } + + int xxx = (realX >> 8); + int yyy = (realY >> 8); + + for(int x = 0; x < 240; x++) { + if(xxx < 0 || + yyy < 0 || + xxx >= sizeX || + yyy >= sizeY) { + line[x] = 0x80000000; + } else { + u8 color = screenBase[yyy * 240 + xxx]; + + line[x] = color ? (READ16LE(&palette[color])|prio): 0x80000000; + } + realX += dx; + realY += dy; + + xxx = (realX >> 8); + yyy = (realY >> 8); + } + + if(control & 0x40) { + int mosaicX = (MOSAIC & 0xF) + 1; + if(mosaicX > 1) { + int m = 1; + for(int i = 0; i < 239; i++) { + line[i+1] = line[i]; + m++; + if(m == mosaicX) { + m = 1; + i++; + } + } + } + } +} + +static inline void gfxDrawRotScreen16Bit160(u16 control, + u16 x_l, u16 x_h, + u16 y_l, u16 y_h, + u16 pa, u16 pb, + u16 pc, u16 pd, + int& currentX, int& currentY, + int changed, + u32 *line) +{ + u16 *screenBase = (DISPCNT & 0x0010) ? (u16 *)&vram[0xa000] : + (u16 *)&vram[0]; + int prio = ((control & 3) << 25) + 0x1000000; + int sizeX = 160; + int sizeY = 128; + + int startX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + startX |= 0xF8000000; + int startY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + startY |= 0xF8000000; + + int dx = pa & 0x7FFF; + if(pa & 0x8000) + dx |= 0xFFFF8000; + int dmx = pb & 0x7FFF; + if(pb & 0x8000) + dmx |= 0xFFFF8000; + int dy = pc & 0x7FFF; + if(pc & 0x8000) + dy |= 0xFFFF8000; + int dmy = pd & 0x7FFF; + if(pd & 0x8000) + dmy |= 0xFFFF8000; + + if(VCOUNT == 0) + changed = 3; + + if(changed & 1) { + currentX = (x_l) | ((x_h & 0x07FF)<<16); + if(x_h & 0x0800) + currentX |= 0xF8000000; + } else { + currentX += dmx; + } + + if(changed & 2) { + currentY = (y_l) | ((y_h & 0x07FF)<<16); + if(y_h & 0x0800) + currentY |= 0xF8000000; + } else { + currentY += dmy; + } + + int realX = currentX; + int realY = currentY; + + if(control & 0x40) { + int mosaicY = ((MOSAIC & 0xF0)>>4) + 1; + int y = VCOUNT - (VCOUNT % mosaicY); + realX = startX + y*dmx; + realY = startY + y*dmy; + } + + int xxx = (realX >> 8); + int yyy = (realY >> 8); + + for(int x = 0; x < 240; x++) { + if(xxx < 0 || + yyy < 0 || + xxx >= sizeX || + yyy >= sizeY) { + line[x] = 0x80000000; + } else { + line[x] = (READ16LE(&screenBase[yyy * sizeX + xxx]) | prio); + } + realX += dx; + realY += dy; + + xxx = (realX >> 8); + yyy = (realY >> 8); + } + + if(control & 0x40) { + int mosaicX = (MOSAIC & 0xF) + 1; + if(mosaicX > 1) { + int m = 1; + for(int i = 0; i < 239; i++) { + line[i+1] = line[i]; + m++; + if(m == mosaicX) { + m = 1; + i++; + } + } + } + } +} + +static inline void gfxDrawSprites(u32 *lineOBJ) +{ + // lineOBJpix is used to keep track of the drawn OBJs + // and to stop drawing them if the 'maximum number of OBJ per line' + // has been reached. + int lineOBJpix = (DISPCNT & 0x20) ? 954 : 1226; + int m=0; + gfxClearArray(lineOBJ); + if(layerEnable & 0x1000) { + u16 *sprites = (u16 *)oam; + u16 *spritePalette = &((u16 *)paletteRAM)[256]; + int mosaicY = ((MOSAIC & 0xF000)>>12) + 1; + int mosaicX = ((MOSAIC & 0xF00)>>8) + 1; + for(int x = 0; x < 128 ; x++) { + u16 a0 = READ16LE(sprites++); + u16 a1 = READ16LE(sprites++); + u16 a2 = READ16LE(sprites++); + sprites++; + + lineOBJpixleft[x]=lineOBJpix; + + lineOBJpix-=2; + if (lineOBJpix<=0) + continue; + + if ((a0 & 0x0c00) == 0x0c00) + a0 &=0xF3FF; + + if ((a0>>14) == 3) + { + a0 &= 0x3FFF; + a1 &= 0x3FFF; + } + + int sizeX = 8<<(a1>>14); + int sizeY = sizeX; + + if ((a0>>14) & 1) + { + if (sizeX<32) + sizeX<<=1; + if (sizeY>8) + sizeY>>=1; + } + else if ((a0>>14) & 2) + { + if (sizeX>8) + sizeX>>=1; + if (sizeY<32) + sizeY<<=1; + } + +#ifdef SPRITE_DEBUG + int maskX = sizeX-1; + int maskY = sizeY-1; +#endif + + int sy = (a0 & 255); + int sx = (a1 & 0x1FF); + + // computes ticks used by OBJ-WIN if OBJWIN is enabled + if (((a0 & 0x0c00) == 0x0800) && (layerEnable & 0x8000)) + { + if ((a0 & 0x0300) == 0x0300) + { + sizeX<<=1; + sizeY<<=1; + } + if((sy+sizeY) > 256) + sy -= 256; + if ((sx+sizeX)> 512) + sx-=512; + if (sx<0) + { + sizeX+=sx; + sx = 0; + } + else if ((sx+sizeX)>240) + sizeX=240-sx; + if ((VCOUNT>=sy) && (VCOUNT 256) + sy -= 256; + int t = VCOUNT - sy; + if((t >= 0) && (t < fieldY)) { + int startpix = 0; + if ((sx+fieldX)> 512) + { + startpix=512-sx; + } + if (lineOBJpix>0) + if((sx < 240) || startpix) { + lineOBJpix-=8; + // int t2 = t - (fieldY >> 1); + int rot = (a1 >> 9) & 0x1F; + u16 *OAM = (u16 *)oam; + int dx = READ16LE(&OAM[3 + (rot << 4)]); + if(dx & 0x8000) + dx |= 0xFFFF8000; + int dmx = READ16LE(&OAM[7 + (rot << 4)]); + if(dmx & 0x8000) + dmx |= 0xFFFF8000; + int dy = READ16LE(&OAM[11 + (rot << 4)]); + if(dy & 0x8000) + dy |= 0xFFFF8000; + int dmy = READ16LE(&OAM[15 + (rot << 4)]); + if(dmy & 0x8000) + dmy |= 0xFFFF8000; + + if(a0 & 0x1000) { + t -= (t % mosaicY); + } + + int realX = ((sizeX) << 7) - (fieldX >> 1)*dx - (fieldY>>1)*dmx + + t * dmx; + int realY = ((sizeY) << 7) - (fieldX >> 1)*dy - (fieldY>>1)*dmy + + t * dmy; + + u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); + + if(a0 & 0x2000) { + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + int inc = 32; + if(DISPCNT & 0x40) + inc = sizeX >> 2; + else + c &= 0x3FE; + for(int x = 0; x < fieldX; x++) { + if (x >= startpix) + lineOBJpix-=2; + if (lineOBJpix<0) + continue; + int xxx = realX >> 8; + int yyy = realY >> 8; + + if(xxx < 0 || xxx >= sizeX || + yyy < 0 || yyy >= sizeY || + sx >= 240); + else { + u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) + + ((yyy & 7)<<3) + ((xxx >> 3)<<6) + + (xxx & 7))&0x7FFF)]; + if ((color==0) && (((prio >> 25)&3) < + ((lineOBJ[sx]>>25)&3))) { + lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { + lineOBJ[sx] = READ16LE(&spritePalette[color]) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } + + if (a0 & 0x1000) { + m++; + if (m==mosaicX) + m=0; + } +#ifdef SPRITE_DEBUG + if(t == 0 || t == maskY || x == 0 || x == maskX) + lineOBJ[sx] = 0x001F; +#endif + } + sx = (sx+1)&511; + realX += dx; + realY += dy; + } + } else { + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + + int inc = 32; + if(DISPCNT & 0x40) + inc = sizeX >> 3; + int palette = (a2 >> 8) & 0xF0; + for(int x = 0; x < fieldX; x++) { + if (x >= startpix) + lineOBJpix-=2; + if (lineOBJpix<0) + continue; + int xxx = realX >> 8; + int yyy = realY >> 8; + if(xxx < 0 || xxx >= sizeX || + yyy < 0 || yyy >= sizeY || + sx >= 240); + else { + u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) + + ((yyy & 7)<<2) + ((xxx >> 3)<<5) + + ((xxx & 7)>>1))&0x7FFF)]; + if(xxx & 1) + color >>= 4; + else + color &= 0x0F; + + if ((color==0) && (((prio >> 25)&3) < + ((lineOBJ[sx]>>25)&3))) { + lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { + lineOBJ[sx] = READ16LE(&spritePalette[palette+color]) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } + } + if((a0 & 0x1000) && m) { + m++; + if (m==mosaicX) + m=0; + } + +#ifdef SPRITE_DEBUG + if(t == 0 || t == maskY || x == 0 || x == maskX) + lineOBJ[sx] = 0x001F; +#endif + sx = (sx+1)&511; + realX += dx; + realY += dy; + + } + } + } + } + } else { + if(sy+sizeY > 256) + sy -= 256; + int t = VCOUNT - sy; + if((t >= 0) && (t < sizeY)) { + int startpix = 0; + if ((sx+sizeX)> 512) + { + startpix=512-sx; + } + if((sx < 240) || startpix) { + lineOBJpix+=2; + if(a0 & 0x2000) { + if(a1 & 0x2000) + t = sizeY - t - 1; + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + + int inc = 32; + if(DISPCNT & 0x40) { + inc = sizeX >> 2; + } else { + c &= 0x3FE; + } + int xxx = 0; + if(a1 & 0x1000) + xxx = sizeX-1; + + if(a0 & 0x1000) { + t -= (t % mosaicY); + } + + int address = 0x10000 + ((((c+ (t>>3) * inc) << 5) + + ((t & 7) << 3) + ((xxx>>3)<<6) + (xxx & 7)) & 0x7FFF); + + if(a1 & 0x1000) + xxx = 7; + u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); + + for(int xx = 0; xx < sizeX; xx++) { + if (xx >= startpix) + lineOBJpix--; + if (lineOBJpix<0) + continue; + if(sx < 240) { + u8 color = vram[address]; + if ((color==0) && (((prio >> 25)&3) < + ((lineOBJ[sx]>>25)&3))) { + lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { + lineOBJ[sx] = READ16LE(&spritePalette[color]) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } + + if (a0 & 0x1000) { + m++; + if (m==mosaicX) + m=0; + } + +#ifdef SPRITE_DEBUG + if(t == 0 || t == maskY || xx == 0 || xx == maskX) + lineOBJ[sx] = 0x001F; +#endif + } + + sx = (sx+1) & 511; + if(a1 & 0x1000) { + xxx--; + address--; + if(xxx == -1) { + address -= 56; + xxx = 7; + } + if(address < 0x10000) + address += 0x8000; + } else { + xxx++; + address++; + if(xxx == 8) { + address += 56; + xxx = 0; + } + if(address > 0x17fff) + address -= 0x8000; + } + } + } else { + if(a1 & 0x2000) + t = sizeY - t - 1; + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + + int inc = 32; + if(DISPCNT & 0x40) { + inc = sizeX >> 3; + } + int xxx = 0; + if(a1 & 0x1000) + xxx = sizeX - 1; + + if(a0 & 0x1000) { + t -= (t % mosaicY); + } + + int address = 0x10000 + ((((c + (t>>3) * inc)<<5) + + ((t & 7)<<2) + ((xxx>>3)<<5) + ((xxx & 7) >> 1))&0x7FFF); + u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); + int palette = (a2 >> 8) & 0xF0; + if(a1 & 0x1000) { + xxx = 7; + for(int xx = sizeX - 1; xx >= 0; xx--) { + if (xx >= startpix) + lineOBJpix--; + if (lineOBJpix<0) + continue; + if(sx < 240) { + u8 color = vram[address]; + if(xx & 1) { + color = (color >> 4); + } else + color &= 0x0F; + + if ((color==0) && (((prio >> 25)&3) < + ((lineOBJ[sx]>>25)&3))) { + lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { + lineOBJ[sx] = READ16LE(&spritePalette[palette + color]) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } + } + if (a0 & 0x1000) { + m++; + if (m==mosaicX) + m=0; + } +#ifdef SPRITE_DEBUG + if(t == 0 || t == maskY || xx == 0 || xx == maskX) + lineOBJ[sx] = 0x001F; +#endif + sx = (sx+1) & 511; + xxx--; + if(!(xx & 1)) + address--; + if(xxx == -1) { + xxx = 7; + address -= 28; + } + if(address < 0x10000) + address += 0x8000; + } + } else { + for(int xx = 0; xx < sizeX; xx++) { + if (xx >= startpix) + lineOBJpix--; + if (lineOBJpix<0) + continue; + if(sx < 240) { + u8 color = vram[address]; + if(xx & 1) { + color = (color >> 4); + } else + color &= 0x0F; + + if ((color==0) && (((prio >> 25)&3) < + ((lineOBJ[sx]>>25)&3))) { + lineOBJ[sx] = (lineOBJ[sx] & 0xF9FFFFFF) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + } else if((color) && (prio < (lineOBJ[sx]&0xFF000000))) { + lineOBJ[sx] = READ16LE(&spritePalette[palette + color]) | prio; + if((a0 & 0x1000) && m) + lineOBJ[sx]=(lineOBJ[sx-1] & 0xF9FFFFFF) | prio; + + } + } + if (a0 & 0x1000) { + m++; + if (m==mosaicX) + m=0; + } +#ifdef SPRITE_DEBUG + if(t == 0 || t == maskY || xx == 0 || xx == maskX) + lineOBJ[sx] = 0x001F; +#endif + sx = (sx+1) & 511; + xxx++; + if(xx & 1) + address++; + if(xxx == 8) { + address += 28; + xxx = 0; + } + if(address > 0x17fff) + address -= 0x8000; + } + } + } + } + } + } + } + } +} + +static inline void gfxDrawOBJWin(u32 *lineOBJWin) +{ + gfxClearArray(lineOBJWin); + if((layerEnable & 0x9000) == 0x9000) { + u16 *sprites = (u16 *)oam; + // u16 *spritePalette = &((u16 *)paletteRAM)[256]; + for(int x = 0; x < 128 ; x++) { + int lineOBJpix = lineOBJpixleft[x]; + u16 a0 = READ16LE(sprites++); + u16 a1 = READ16LE(sprites++); + u16 a2 = READ16LE(sprites++); + sprites++; + + if (lineOBJpix<=0) + continue; + + // ignores non OBJ-WIN and disabled OBJ-WIN + if(((a0 & 0x0c00) != 0x0800) || ((a0 & 0x0300) == 0x0200)) + continue; + + if ((a0 & 0x0c00) == 0x0c00) + a0 &=0xF3FF; + + if ((a0>>14) == 3) + { + a0 &= 0x3FFF; + a1 &= 0x3FFF; + } + + int sizeX = 8<<(a1>>14); + int sizeY = sizeX; + + if ((a0>>14) & 1) + { + if (sizeX<32) + sizeX<<=1; + if (sizeY>8) + sizeY>>=1; + } + else if ((a0>>14) & 2) + { + if (sizeX>8) + sizeX>>=1; + if (sizeY<32) + sizeY<<=1; + } + + int sy = (a0 & 255); + + if(a0 & 0x0100) { + int fieldX = sizeX; + int fieldY = sizeY; + if(a0 & 0x0200) { + fieldX <<= 1; + fieldY <<= 1; + } + if((sy+fieldY) > 256) + sy -= 256; + int t = VCOUNT - sy; + if((t >= 0) && (t < fieldY)) { + int sx = (a1 & 0x1FF); + int startpix = 0; + if ((sx+fieldX)> 512) + { + startpix=512-sx; + } + if((sx < 240) || startpix) { + lineOBJpix-=8; + // int t2 = t - (fieldY >> 1); + int rot = (a1 >> 9) & 0x1F; + u16 *OAM = (u16 *)oam; + int dx = READ16LE(&OAM[3 + (rot << 4)]); + if(dx & 0x8000) + dx |= 0xFFFF8000; + int dmx = READ16LE(&OAM[7 + (rot << 4)]); + if(dmx & 0x8000) + dmx |= 0xFFFF8000; + int dy = READ16LE(&OAM[11 + (rot << 4)]); + if(dy & 0x8000) + dy |= 0xFFFF8000; + int dmy = READ16LE(&OAM[15 + (rot << 4)]); + if(dmy & 0x8000) + dmy |= 0xFFFF8000; + + int realX = ((sizeX) << 7) - (fieldX >> 1)*dx - (fieldY>>1)*dmx + + t * dmx; + int realY = ((sizeY) << 7) - (fieldX >> 1)*dy - (fieldY>>1)*dmy + + t * dmy; + + // u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); + + if(a0 & 0x2000) { + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + int inc = 32; + if(DISPCNT & 0x40) + inc = sizeX >> 2; + else + c &= 0x3FE; + for(int x = 0; x < fieldX; x++) { + if (x >= startpix) + lineOBJpix-=2; + if (lineOBJpix<0) + continue; + int xxx = realX >> 8; + int yyy = realY >> 8; + + if(xxx < 0 || xxx >= sizeX || + yyy < 0 || yyy >= sizeY || + sx >= 240) { + } else { + u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) + + ((yyy & 7)<<3) + ((xxx >> 3)<<6) + + (xxx & 7))&0x7fff)]; + if(color) { + lineOBJWin[sx] = 1; + } + } + sx = (sx+1)&511; + realX += dx; + realY += dy; + } + } else { + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + + int inc = 32; + if(DISPCNT & 0x40) + inc = sizeX >> 3; + // int palette = (a2 >> 8) & 0xF0; + for(int x = 0; x < fieldX; x++) { + if (x >= startpix) + lineOBJpix-=2; + if (lineOBJpix<0) + continue; + int xxx = realX >> 8; + int yyy = realY >> 8; + + // if(x == 0 || x == (sizeX-1) || + // t == 0 || t == (sizeY-1)) { + // lineOBJ[sx] = 0x001F | prio; + // } else { + if(xxx < 0 || xxx >= sizeX || + yyy < 0 || yyy >= sizeY || + sx >= 240) { + } else { + u32 color = vram[0x10000 + ((((c + (yyy>>3) * inc)<<5) + + ((yyy & 7)<<2) + ((xxx >> 3)<<5) + + ((xxx & 7)>>1))&0x7fff)]; + if(xxx & 1) + color >>= 4; + else + color &= 0x0F; + + if(color) { + lineOBJWin[sx] = 1; + } + } + // } + sx = (sx+1)&511; + realX += dx; + realY += dy; + } + } + } + } + } else { + if((sy+sizeY) > 256) + sy -= 256; + int t = VCOUNT - sy; + if((t >= 0) && (t < sizeY)) { + int sx = (a1 & 0x1FF); + int startpix = 0; + if ((sx+sizeX)> 512) + { + startpix=512-sx; + } + if((sx < 240) || startpix) { + lineOBJpix+=2; + if(a0 & 0x2000) { + if(a1 & 0x2000) + t = sizeY - t - 1; + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + + int inc = 32; + if(DISPCNT & 0x40) { + inc = sizeX >> 2; + } else { + c &= 0x3FE; + } + int xxx = 0; + if(a1 & 0x1000) + xxx = sizeX-1; + int address = 0x10000 + ((((c+ (t>>3) * inc) << 5) + + ((t & 7) << 3) + ((xxx>>3)<<6) + (xxx & 7))&0x7fff); + if(a1 & 0x1000) + xxx = 7; + // u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); + for(int xx = 0; xx < sizeX; xx++) { + if (xx >= startpix) + lineOBJpix--; + if (lineOBJpix<0) + continue; + if(sx < 240) { + u8 color = vram[address]; + if(color) { + lineOBJWin[sx] = 1; + } + } + + sx = (sx+1) & 511; + if(a1 & 0x1000) { + xxx--; + address--; + if(xxx == -1) { + address -= 56; + xxx = 7; + } + if(address < 0x10000) + address += 0x8000; + } else { + xxx++; + address++; + if(xxx == 8) { + address += 56; + xxx = 0; + } + if(address > 0x17fff) + address -= 0x8000; + } + } + } else { + if(a1 & 0x2000) + t = sizeY - t - 1; + int c = (a2 & 0x3FF); + if((DISPCNT & 7) > 2 && (c < 512)) + continue; + + int inc = 32; + if(DISPCNT & 0x40) { + inc = sizeX >> 3; + } + int xxx = 0; + if(a1 & 0x1000) + xxx = sizeX - 1; + int address = 0x10000 + ((((c + (t>>3) * inc)<<5) + + ((t & 7)<<2) + ((xxx>>3)<<5) + ((xxx & 7) >> 1))&0x7fff); + // u32 prio = (((a2 >> 10) & 3) << 25) | ((a0 & 0x0c00)<<6); + // int palette = (a2 >> 8) & 0xF0; + if(a1 & 0x1000) { + xxx = 7; + for(int xx = sizeX - 1; xx >= 0; xx--) { + if (xx >= startpix) + lineOBJpix--; + if (lineOBJpix<0) + continue; + if(sx < 240) { + u8 color = vram[address]; + if(xx & 1) { + color = (color >> 4); + } else + color &= 0x0F; + + if(color) { + lineOBJWin[sx] = 1; + } + } + sx = (sx+1) & 511; + xxx--; + if(!(xx & 1)) + address--; + if(xxx == -1) { + xxx = 7; + address -= 28; + } + if(address < 0x10000) + address += 0x8000; + } + } else { + for(int xx = 0; xx < sizeX; xx++) { + if (xx >= startpix) + lineOBJpix--; + if (lineOBJpix<0) + continue; + if(sx < 240) { + u8 color = vram[address]; + if(xx & 1) { + color = (color >> 4); + } else + color &= 0x0F; + + if(color) { + lineOBJWin[sx] = 1; + } + } + sx = (sx+1) & 511; + xxx++; + if(xx & 1) + address++; + if(xxx == 8) { + address += 28; + xxx = 0; + } + if(address > 0x17fff) + address -= 0x8000; + } + } + } + } + } + } + } + } +} + +static inline u32 gfxIncreaseBrightness(u32 color, int coeff) +{ + color &= 0xffff; + color = ((color << 16) | color) & 0x3E07C1F; + + color = color + (((0x3E07C1F - color) * coeff) >> 4); + color &= 0x3E07C1F; + + return (color >> 16) | color; +} + +static inline void gfxIncreaseBrightness(u32 *line, int coeff) +{ + for(int x = 0; x < 240; x++) { + u32 color = *line; + int r = (color & 0x1F); + int g = ((color >> 5) & 0x1F); + int b = ((color >> 10) & 0x1F); + + r = r + (((31 - r) * coeff) >> 4); + g = g + (((31 - g) * coeff) >> 4); + b = b + (((31 - b) * coeff) >> 4); + if(r > 31) + r = 31; + if(g > 31) + g = 31; + if(b > 31) + b = 31; + *line++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; + } +} + +static inline u32 gfxDecreaseBrightness(u32 color, int coeff) +{ + color &= 0xffff; + color = ((color << 16) | color) & 0x3E07C1F; + + color = color - (((color * coeff) >> 4) & 0x3E07C1F); + + return (color >> 16) | color; +} + +static inline void gfxDecreaseBrightness(u32 *line, int coeff) +{ + for(int x = 0; x < 240; x++) { + u32 color = *line; + int r = (color & 0x1F); + int g = ((color >> 5) & 0x1F); + int b = ((color >> 10) & 0x1F); + + r = r - ((r * coeff) >> 4); + g = g - ((g * coeff) >> 4); + b = b - ((b * coeff) >> 4); + if(r < 0) + r = 0; + if(g < 0) + g = 0; + if(b < 0) + b = 0; + *line++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; + } +} + +static inline u32 gfxAlphaBlend(u32 color, u32 color2, int ca, int cb) +{ + if(color < 0x80000000) { + color&=0xffff; + color2&=0xffff; + + color = ((color << 16) | color) & 0x03E07C1F; + color2 = ((color2 << 16) | color2) & 0x03E07C1F; + color = ((color * ca) + (color2 * cb)) >> 4; + + if ((ca + cb)>16) + { + if (color & 0x20) + color |= 0x1f; + if (color & 0x8000) + color |= 0x7C00; + if (color & 0x4000000) + color |= 0x03E00000; + } + + color &= 0x03E07C1F; + color = (color >> 16) | color; + } + return color; +} + +static inline void gfxAlphaBlend(u32 *ta, u32 *tb, int ca, int cb) +{ + for(int x = 0; x < 240; x++) { + u32 color = *ta; + if(color < 0x80000000) { + int r = (color & 0x1F); + int g = ((color >> 5) & 0x1F); + int b = ((color >> 10) & 0x1F); + u32 color2 = (*tb++); + int r0 = (color2 & 0x1F); + int g0 = ((color2 >> 5) & 0x1F); + int b0 = ((color2 >> 10) & 0x1F); + + r = ((r * ca) + (r0 * cb)) >> 4; + g = ((g * ca) + (g0 * cb)) >> 4; + b = ((b * ca) + (b0 * cb)) >> 4; + + if(r > 31) + r = 31; + if(g > 31) + g = 31; + if(b > 31) + b = 31; + + *ta++ = (color & 0xFFFF0000) | (b << 10) | (g << 5) | r; + } else { + ta++; + tb++; + } + } +} + +#endif // VBA_GFX_H diff --git a/source/vba/agb/GBAcpu.h b/source/vba/agb/GBAcpu.h new file mode 100644 index 0000000..c617b14 --- /dev/null +++ b/source/vba/agb/GBAcpu.h @@ -0,0 +1,302 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 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_GBAcpu_H +#define VBA_GBAcpu_H + +extern int armExecute(); +extern int thumbExecute(); + +#ifdef __GNUC__ +# define INSN_REGPARM __attribute__((regparm(1))) +# define LIKELY(x) __builtin_expect(!!(x),1) +# define UNLIKELY(x) __builtin_expect(!!(x),0) +#else +# define INSN_REGPARM /*nothing*/ +# define LIKELY(x) (x) +# define UNLIKELY(x) (x) +#endif + +#define UPDATE_REG(address, value)\ + {\ + WRITE16LE(((u16 *)&ioMem[address]),value);\ + }\ + +#define ARM_PREFETCH \ + {\ + cpuPrefetch[0] = CPUReadMemoryQuick(armNextPC);\ + cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);\ + } + +#define THUMB_PREFETCH \ + {\ + cpuPrefetch[0] = CPUReadHalfWordQuick(armNextPC);\ + cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);\ + } + +#define ARM_PREFETCH_NEXT \ + cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4); + +#define THUMB_PREFETCH_NEXT\ + cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2); + + +extern int SWITicks; +extern u32 mastercode; +extern bool busPrefetch; +extern bool busPrefetchEnable; +extern u32 busPrefetchCount; +extern int cpuNextEvent; +extern bool holdState; +extern u32 cpuPrefetch[2]; +extern int cpuTotalTicks; +extern u8 memoryWait[16]; +extern u8 memoryWait32[16]; +extern u8 memoryWaitSeq[16]; +extern u8 memoryWaitSeq32[16]; +extern u8 cpuBitsSet[256]; +extern u8 cpuLowestBitSet[256]; +extern void CPUSwitchMode(int mode, bool saveState, bool breakLoop); +extern void CPUSwitchMode(int mode, bool saveState); +extern void CPUUpdateCPSR(); +extern void CPUUpdateFlags(bool breakLoop); +extern void CPUUpdateFlags(); +extern void CPUUndefinedException(); +extern void CPUSoftwareInterrupt(); +extern void CPUSoftwareInterrupt(int comment); + + +// Waitstates when accessing data +inline int dataTicksAccess16(u32 address) // DATA 8/16bits NON SEQ +{ + int addr = (address>>24)&15; + int value = memoryWait[addr]; + + if ((addr>=0x08) || (addr < 0x02)) + { + busPrefetchCount=0; + busPrefetch=false; + } + else if (busPrefetch) + { + int waitState = value; + if (!waitState) + waitState = 1; + busPrefetchCount = ((busPrefetchCount+1)<>24)&15; + int value = memoryWait32[addr]; + + if ((addr>=0x08) || (addr < 0x02)) + { + busPrefetchCount=0; + busPrefetch=false; + } + else if (busPrefetch) + { + int waitState = value; + if (!waitState) + waitState = 1; + busPrefetchCount = ((busPrefetchCount+1)<>24)&15; + int value = memoryWaitSeq[addr]; + + if ((addr>=0x08) || (addr < 0x02)) + { + busPrefetchCount=0; + busPrefetch=false; + } + else if (busPrefetch) + { + int waitState = value; + if (!waitState) + waitState = 1; + busPrefetchCount = ((busPrefetchCount+1)<>24)&15; + int value = memoryWaitSeq32[addr]; + + if ((addr>=0x08) || (addr < 0x02)) + { + busPrefetchCount=0; + busPrefetch=false; + } + else if (busPrefetch) + { + int waitState = value; + if (!waitState) + waitState = 1; + busPrefetchCount = ((busPrefetchCount+1)<>24)&15; + + if ((addr>=0x08) && (addr<=0x0D)) + { + if (busPrefetchCount&0x1) + { + if (busPrefetchCount&0x2) + { + busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00); + return 0; + } + busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00); + return memoryWaitSeq[addr]-1; + } + else + { + busPrefetchCount=0; + return memoryWait[addr]; + } + } + else + { + busPrefetchCount = 0; + return memoryWait[addr]; + } +} + +inline int codeTicksAccess32(u32 address) // ARM NON SEQ +{ + int addr = (address>>24)&15; + + if ((addr>=0x08) && (addr<=0x0D)) + { + if (busPrefetchCount&0x1) + { + if (busPrefetchCount&0x2) + { + busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00); + return 0; + } + busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00); + return memoryWaitSeq[addr] - 1; + } + else + { + busPrefetchCount = 0; + return memoryWait32[addr]; + } + } + else + { + busPrefetchCount = 0; + return memoryWait32[addr]; + } +} + +inline int codeTicksAccessSeq16(u32 address) // THUMB SEQ +{ + int addr = (address>>24)&15; + + if ((addr>=0x08) && (addr<=0x0D)) + { + if (busPrefetchCount&0x1) + { + busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00); + return 0; + } + else + if (busPrefetchCount>0xFF) + { + busPrefetchCount=0; + return memoryWait[addr]; + } + else + return memoryWaitSeq[addr]; + } + else + { + busPrefetchCount = 0; + return memoryWaitSeq[addr]; + } +} + +inline int codeTicksAccessSeq32(u32 address) // ARM SEQ +{ + int addr = (address>>24)&15; + + if ((addr>=0x08) && (addr<=0x0D)) + { + if (busPrefetchCount&0x1) + { + if (busPrefetchCount&0x2) + { + busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00); + return 0; + } + busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00); + return memoryWaitSeq[addr]; + } + else + if (busPrefetchCount>0xFF) + { + busPrefetchCount=0; + return memoryWait32[addr]; + } + else + return memoryWaitSeq32[addr]; + } + else + { + return memoryWaitSeq32[addr]; + } +} + + +// Emulates the Cheat System (m) code +inline void cpuMasterCodeCheck() +{ + if((mastercode) && (mastercode == armNextPC)) + { + u32 joy = 0; + if(systemReadJoypads()) + joy = systemReadJoypad(-1); + u32 ext = (joy >> 10); + cpuTotalTicks += cheatsCheckKeys(P1^0x3FF, ext); + } +} + +#endif //VBA_GBAcpu_H diff --git a/source/vba/agb/GBAinline.h b/source/vba/agb/GBAinline.h new file mode 100644 index 0000000..f804211 --- /dev/null +++ b/source/vba/agb/GBAinline.h @@ -0,0 +1,738 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005 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 "../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 0x301: + if(b == 0x80) + stopState = true; + holdState = 1; + holdType = -1; + cpuNextEvent = cpuTotalTicks; + break; + 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; + default: + if(address & 1) + CPUUpdateRegister(address & 0x3fe, + ((READ16LE(((u16 *)&ioMem[address & 0x3fe]))) + & 0x00FF) | + b<<8); + else + CPUUpdateRegister(address & 0x3fe, + ((READ16LE(((u16 *)&ioMem[address & 0x3fe])) & 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 //VBA_GBAinline_H diff --git a/source/vba/agbprint.cpp b/source/vba/agb/agbprint.cpp similarity index 61% rename from source/vba/agbprint.cpp rename to source/vba/agb/agbprint.cpp index f1db198..7104318 100644 --- a/source/vba/agbprint.cpp +++ b/source/vba/agb/agbprint.cpp @@ -1,106 +1,98 @@ -// 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. - -#include -#include - -#include "GBA.h" -#include "Globals.h" -#include "Port.h" - -#define debuggerWriteHalfWord(addr, value) \ - WRITE16LE((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask], (value)) - -#define debuggerReadHalfWord(addr) \ - READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) - -static bool agbPrintEnabled = false; -static bool agbPrintProtect = false; - -bool agbPrintWrite(u32 address, u16 value) -{ - if(agbPrintEnabled) - { - if(address == 0x9fe2ffe) - { // protect - agbPrintProtect = (value != 0); - debuggerWriteHalfWord(address, value); - return true; - } - else - { - if(agbPrintProtect && - ((address >= 0x9fe20f8 && address <= 0x9fe20ff) // control structure - || (address >= 0x8fd0000 && address <= 0x8fdffff) - || (address >= 0x9fd0000 && address <= 0x9fdffff))) - { - debuggerWriteHalfWord(address, value); - return true; - } - } - } - return false; -} - -void agbPrintReset() -{ - agbPrintProtect = false; -} - -void agbPrintEnable(bool enable) -{ - agbPrintEnabled = enable; -} - -bool agbPrintIsEnabled() -{ - return agbPrintEnabled; -} - -extern void (*dbgOutput)(char *, u32); - -void agbPrintFlush() -{ - u16 get = debuggerReadHalfWord(0x9fe20fc); - u16 put = debuggerReadHalfWord(0x9fe20fe); - - u32 address = (debuggerReadHalfWord(0x9fe20fa) << 16); - if(address != 0xfd0000 && address != 0x1fd0000) - { - dbgOutput("Did you forget to call AGBPrintInit?\n", 0); - // get rid of the text otherwise we will continue to be called - debuggerWriteHalfWord(0x9fe20fc, put); - return; - } - - u8 *data = &rom[address]; - - while(get != put) - { - char c = data[get++]; - char s[2]; - s[0] = c; - s[1] = 0; - - if(systemVerbose & VERBOSE_AGBPRINT) - dbgOutput(s, 0); - if(c == '\n') - break; - } - debuggerWriteHalfWord(0x9fe20fc, get); -} +// 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. + +#include +#include + +#include "GBA.h" +#include "Globals.h" +#include "Port.h" +#include "System.h" + +#define debuggerWriteHalfWord(addr, value) \ + WRITE16LE((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask], (value)) + +#define debuggerReadHalfWord(addr) \ + READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) + +static bool agbPrintEnabled = false; +static bool agbPrintProtect = false; + +bool agbPrintWrite(u32 address, u16 value) +{ + if(agbPrintEnabled) { + if(address == 0x9fe2ffe) { // protect + agbPrintProtect = (value != 0); + debuggerWriteHalfWord(address, value); + return true; + } else { + if(agbPrintProtect && + ((address >= 0x9fe20f8 && address <= 0x9fe20ff) // control structure + || (address >= 0x8fd0000 && address <= 0x8fdffff) + || (address >= 0x9fd0000 && address <= 0x9fdffff))) { + debuggerWriteHalfWord(address, value); + return true; + } + } + } + return false; +} + +void agbPrintReset() +{ + agbPrintProtect = false; +} + +void agbPrintEnable(bool enable) +{ + agbPrintEnabled = enable; +} + +bool agbPrintIsEnabled() +{ + return agbPrintEnabled; +} + +void agbPrintFlush() +{ + u16 get = debuggerReadHalfWord(0x9fe20fc); + u16 put = debuggerReadHalfWord(0x9fe20fe); + + u32 address = (debuggerReadHalfWord(0x9fe20fa) << 16); + if(address != 0xfd0000 && address != 0x1fd0000) { + dbgOutput("Did you forget to call AGBPrintInit?\n", 0); + // get rid of the text otherwise we will continue to be called + debuggerWriteHalfWord(0x9fe20fc, put); + return; + } + + u8 *data = &rom[address]; + + while(get != put) { + char c = data[get++]; + char s[2]; + s[0] = c; + s[1] = 0; + + if(systemVerbose & VERBOSE_AGBPRINT) + dbgOutput(s, 0); + if(c == '\n') + break; + } + debuggerWriteHalfWord(0x9fe20fc, get); +} diff --git a/source/vba/agbprint.h b/source/vba/agb/agbprint.h similarity index 97% rename from source/vba/agbprint.h rename to source/vba/agb/agbprint.h index d7742de..7f63fa6 100644 --- a/source/vba/agbprint.h +++ b/source/vba/agb/agbprint.h @@ -1,27 +1,27 @@ -// -*- 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_AGBPRINT_H -#define VBA_AGBPRINT_H -extern void agbPrintEnable(bool); -extern bool agbPrintIsEnabled(); -extern void agbPrintReset(); -extern bool agbPrintWrite(u32, u16); -extern void agbPrintFlush(); -#endif +// -*- 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_AGBPRINT_H +#define VBA_AGBPRINT_H +extern void agbPrintEnable(bool); +extern bool agbPrintIsEnabled(); +extern void agbPrintReset(); +extern bool agbPrintWrite(u32, u16); +extern void agbPrintFlush(); +#endif diff --git a/source/vba/arm-new.h b/source/vba/arm-new.h deleted file mode 100644 index c8e769b..0000000 --- a/source/vba/arm-new.h +++ /dev/null @@ -1,7472 +0,0 @@ -// -*- 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. - -#ifdef BKPT_SUPPORT -#define CONSOLE_OUTPUT(a,b) \ - extern void (*dbgOutput)(char *, u32);\ - if((opcode == 0xe0000000) && (reg[0].I == 0xC0DED00D)) {\ - dbgOutput((a), (b));\ - } -#else -#define CONSOLE_OUTPUT(a,b) -#endif - -#define OP_AND \ - reg[dest].I = reg[(opcode>>16)&15].I & value;\ - CONSOLE_OUTPUT(NULL,reg[2].I); - -#define OP_ANDS \ - reg[dest].I = reg[(opcode>>16)&15].I & value;\ - \ - N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\ - Z_FLAG = (reg[dest].I) ? false : true;\ - C_FLAG = C_OUT; - -#define OP_EOR \ - reg[dest].I = reg[(opcode>>16)&15].I ^ value; - -#define OP_EORS \ - reg[dest].I = reg[(opcode>>16)&15].I ^ value;\ - \ - N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\ - Z_FLAG = (reg[dest].I) ? false : true;\ - C_FLAG = C_OUT; -#ifdef C_CORE -#define NEG(i) ((i) >> 31) -#define POS(i) ((~(i)) >> 31) -#define ADDCARRY(a, b, c) \ - C_FLAG = ((NEG(a) & NEG(b)) |\ - (NEG(a) & POS(c)) |\ - (NEG(b) & POS(c))) ? true : false; -#define ADDOVERFLOW(a, b, c) \ - V_FLAG = ((NEG(a) & NEG(b) & POS(c)) |\ - (POS(a) & POS(b) & NEG(c))) ? true : false; -#define SUBCARRY(a, b, c) \ - C_FLAG = ((NEG(a) & POS(b)) |\ - (NEG(a) & POS(c)) |\ - (POS(b) & POS(c))) ? true : false; -#define SUBOVERFLOW(a, b, c)\ - V_FLAG = ((NEG(a) & POS(b) & POS(c)) |\ - (POS(a) & NEG(b) & NEG(c))) ? true : false; -#define OP_SUB \ - {\ - reg[dest].I = reg[base].I - value;\ - } -#define OP_SUBS \ - {\ - u32 lhs = reg[base].I;\ - u32 rhs = value;\ - u32 res = lhs - rhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#define OP_RSB \ - {\ - reg[dest].I = value - reg[base].I;\ - } -#define OP_RSBS \ - {\ - u32 lhs = reg[base].I;\ - u32 rhs = value;\ - u32 res = rhs - lhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(rhs, lhs, res);\ - SUBOVERFLOW(rhs, lhs, res);\ - } -#define OP_ADD \ - {\ - reg[dest].I = reg[base].I + value;\ - } -#define OP_ADDS \ - {\ - u32 lhs = reg[base].I;\ - u32 rhs = value;\ - u32 res = lhs + rhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } -#define OP_ADC \ - {\ - reg[dest].I = reg[base].I + value + (u32)C_FLAG;\ - } -#define OP_ADCS \ - {\ - u32 lhs = reg[base].I;\ - u32 rhs = value;\ - u32 res = lhs + rhs + (u32)C_FLAG;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } -#define OP_SBC \ - {\ - reg[dest].I = reg[base].I - value - !((u32)C_FLAG);\ - } -#define OP_SBCS \ - {\ - u32 lhs = reg[base].I;\ - u32 rhs = value;\ - u32 res = lhs - rhs - !((u32)C_FLAG);\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#define OP_RSC \ - {\ - reg[dest].I = value - reg[base].I - !((u32)C_FLAG);\ - } -#define OP_RSCS \ - {\ - u32 lhs = reg[base].I;\ - u32 rhs = value;\ - u32 res = rhs - lhs - !((u32)C_FLAG);\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(rhs, lhs, res);\ - SUBOVERFLOW(rhs, lhs, res);\ - } -#define OP_CMP \ - {\ - u32 lhs = reg[base].I;\ - u32 rhs = value;\ - u32 res = lhs - rhs;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#define OP_CMN \ - {\ - u32 lhs = reg[base].I;\ - u32 rhs = value;\ - u32 res = lhs + rhs;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } - -#define LOGICAL_LSL_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - C_OUT = (v >> (32 - shift)) & 1 ? true : false;\ - value = v << shift;\ - } -#define LOGICAL_LSR_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - C_OUT = (v >> (shift - 1)) & 1 ? true : false;\ - value = v >> shift;\ - } -#define LOGICAL_ASR_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - C_OUT = ((s32)v >> (int)(shift - 1)) & 1 ? true : false;\ - value = (s32)v >> (int)shift;\ - } -#define LOGICAL_ROR_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - C_OUT = (v >> (shift - 1)) & 1 ? true : false;\ - value = ((v << (32 - shift)) |\ - (v >> shift));\ - } -#define LOGICAL_RRX_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - shift = (int)C_FLAG;\ - C_OUT = (v & 1) ? true : false;\ - value = ((v >> 1) |\ - (shift << 31));\ - } -#define LOGICAL_ROR_IMM \ - {\ - u32 v = opcode & 0xff;\ - C_OUT = (v >> (shift - 1)) & 1 ? true : false;\ - value = ((v << (32 - shift)) |\ - (v >> shift));\ - } -#define ARITHMETIC_LSL_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - value = v << shift;\ - } -#define ARITHMETIC_LSR_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - value = v >> shift;\ - } -#define ARITHMETIC_ASR_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - value = (s32)v >> (int)shift;\ - } -#define ARITHMETIC_ROR_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - value = ((v << (32 - shift)) |\ - (v >> shift));\ - } -#define ARITHMETIC_RRX_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - shift = (int)C_FLAG;\ - value = ((v >> 1) |\ - (shift << 31));\ - } -#define ARITHMETIC_ROR_IMM \ - {\ - u32 v = opcode & 0xff;\ - value = ((v << (32 - shift)) |\ - (v >> shift));\ - } -#define ROR_IMM_MSR \ - {\ - u32 v = opcode & 0xff;\ - value = ((v << (32 - shift)) |\ - (v >> shift));\ - } -#define ROR_VALUE \ - {\ - value = ((value << (32 - shift)) |\ - (value >> shift));\ - } -#define RCR_VALUE \ - {\ - shift = (int)C_FLAG;\ - value = ((value >> 1) |\ - (shift << 31));\ - } -#else -#ifdef __GNUC__ -#ifdef __POWERPC__ -#define OP_SUB \ - {\ - reg[dest].I = reg[base].I - value;\ - } -#define OP_SUBS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } -#define OP_RSB \ - {\ - reg[dest].I = value - reg[base].I;\ - } -#define OP_RSBS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subfco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } -#define OP_ADD \ - {\ - reg[dest].I = reg[base].I + value;\ - } - -#define OP_ADDS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("addco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } -#define OP_ADC \ - {\ - reg[dest].I = reg[base].I + value + (u32)C_FLAG;\ - } -#define OP_ADCS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("mtspr xer, %4\n" \ - "addeo. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value), \ - "r" (C_FLAG << 29) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } -#define OP_SBC \ - {\ - reg[dest].I = reg[base].I - value - (C_FLAG^1);\ - } -#define OP_SBCS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("mtspr xer, %4\n" \ - "subfeo. %0, %3, %2\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value), \ - "r" (C_FLAG << 29) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } -#define OP_RSC \ - {\ - reg[dest].I = value - reg[base].I - (C_FLAG^1);\ - } -#define OP_RSCS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("mtspr xer, %4\n" \ - "subfeo. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value), \ - "r" (C_FLAG << 29) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } -#define OP_CMP \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value) \ - ); \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } -#define OP_CMN \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("addco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[base].I), \ - "r" (value) \ - ); \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - -#define LOGICAL_LSL_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - C_OUT = (v >> (32 - shift)) & 1 ? true : false;\ - value = v << shift;\ - } -#define LOGICAL_LSR_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - C_OUT = (v >> (shift - 1)) & 1 ? true : false;\ - value = v >> shift;\ - } -#define LOGICAL_ASR_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - C_OUT = ((s32)v >> (int)(shift - 1)) & 1 ? true : false;\ - value = (s32)v >> (int)shift;\ - } -#define LOGICAL_ROR_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - C_OUT = (v >> (shift - 1)) & 1 ? true : false;\ - value = ((v << (32 - shift)) |\ - (v >> shift));\ - } -#define LOGICAL_RRX_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - shift = (int)C_FLAG;\ - C_OUT = (v & 1) ? true : false;\ - value = ((v >> 1) |\ - (shift << 31));\ - } -#define LOGICAL_ROR_IMM \ - {\ - u32 v = opcode & 0xff;\ - C_OUT = (v >> (shift - 1)) & 1 ? true : false;\ - value = ((v << (32 - shift)) |\ - (v >> shift));\ - } -#define ARITHMETIC_LSL_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - value = v << shift;\ - } -#define ARITHMETIC_LSR_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - value = v >> shift;\ - } -#define ARITHMETIC_ASR_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - value = (s32)v >> (int)shift;\ - } -#define ARITHMETIC_ROR_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - value = ((v << (32 - shift)) |\ - (v >> shift));\ - } -#define ARITHMETIC_RRX_REG \ - {\ - u32 v = reg[opcode & 0x0f].I;\ - shift = (int)C_FLAG;\ - value = ((v >> 1) |\ - (shift << 31));\ - } -#define ARITHMETIC_ROR_IMM \ - {\ - u32 v = opcode & 0xff;\ - value = ((v << (32 - shift)) |\ - (v >> shift));\ - } -#define ROR_IMM_MSR \ - {\ - u32 v = opcode & 0xff;\ - value = ((v << (32 - shift)) |\ - (v >> shift));\ - } -#define ROR_VALUE \ - {\ - value = ((value << (32 - shift)) |\ - (value >> shift));\ - } -#define RCR_VALUE \ - {\ - shift = (int)C_FLAG;\ - value = ((value >> 1) |\ - (shift << 31));\ - } -#else -#define OP_SUB \ - asm ("sub %1, %%ebx;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[base].I)); - -#define OP_SUBS \ - asm ("sub %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setncb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[base].I)); - -#define OP_RSB \ - asm ("sub %1, %%ebx;"\ - : "=b" (reg[dest].I)\ - : "r" (reg[base].I), "b" (value)); - -#define OP_RSBS \ - asm ("sub %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setncb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (reg[base].I), "b" (value)); - -#define OP_ADD \ - asm ("add %1, %%ebx;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[base].I)); - -#define OP_ADDS \ - asm ("add %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setcb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[base].I)); - -#define OP_ADC \ - asm ("bt $0, C_FLAG;"\ - "adc %1, %%ebx;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[base].I)); - -#define OP_ADCS \ - asm ("bt $0, C_FLAG;"\ - "adc %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setcb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[base].I)); - -#define OP_SBC \ - asm ("bt $0, C_FLAG;"\ - "cmc;"\ - "sbb %1, %%ebx;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[base].I)); - -#define OP_SBCS \ - asm ("bt $0, C_FLAG;"\ - "cmc;"\ - "sbb %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setncb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[base].I)); -#define OP_RSC \ - asm ("bt $0, C_FLAG;"\ - "cmc;"\ - "sbb %1, %%ebx;"\ - : "=b" (reg[dest].I)\ - : "r" (reg[base].I), "b" (value)); - -#define OP_RSCS \ - asm ("bt $0, C_FLAG;"\ - "cmc;"\ - "sbb %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setncb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (reg[base].I), "b" (value)); -#define OP_CMP \ - asm ("sub %0, %1;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setncb C_FLAG;"\ - "setob V_FLAG;"\ - :\ - : "r" (value), "r" (reg[base].I)); - -#define OP_CMN \ - asm ("add %0, %1;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setcb C_FLAG;"\ - "setob V_FLAG;"\ - : \ - : "r" (value), "r" (reg[base].I)); -#define LOGICAL_LSL_REG \ - asm("shl %%cl, %%eax;"\ - "setcb %%cl;"\ - : "=a" (value), "=c" (C_OUT)\ - : "a" (reg[opcode & 0x0f].I), "c" (shift)); - -#define LOGICAL_LSR_REG \ - asm("shr %%cl, %%eax;"\ - "setcb %%cl;"\ - : "=a" (value), "=c" (C_OUT)\ - : "a" (reg[opcode & 0x0f].I), "c" (shift)); - -#define LOGICAL_ASR_REG \ - asm("sar %%cl, %%eax;"\ - "setcb %%cl;"\ - : "=a" (value), "=c" (C_OUT)\ - : "a" (reg[opcode & 0x0f].I), "c" (shift)); - -#define LOGICAL_ROR_REG \ - asm("ror %%cl, %%eax;"\ - "setcb %%cl;"\ - : "=a" (value), "=c" (C_OUT)\ - : "a" (reg[opcode & 0x0f].I), "c" (shift)); - -#define LOGICAL_RRX_REG \ - asm("bt $0, C_FLAG;"\ - "rcr $1, %%eax;"\ - "setcb %%cl;"\ - : "=a" (value), "=c" (C_OUT)\ - : "a" (reg[opcode & 0x0f].I)); - -#define LOGICAL_ROR_IMM \ - asm("ror %%cl, %%eax;"\ - "setcb %%cl;"\ - : "=a" (value), "=c" (C_OUT)\ - : "a" (opcode & 0xff), "c" (shift)); -#define ARITHMETIC_LSL_REG \ - asm("\ - shl %%cl, %%eax;"\ - : "=a" (value)\ - : "a" (reg[opcode & 0x0f].I), "c" (shift)); - -#define ARITHMETIC_LSR_REG \ - asm("\ - shr %%cl, %%eax;"\ - : "=a" (value)\ - : "a" (reg[opcode & 0x0f].I), "c" (shift)); - -#define ARITHMETIC_ASR_REG \ - asm("\ - sar %%cl, %%eax;"\ - : "=a" (value)\ - : "a" (reg[opcode & 0x0f].I), "c" (shift)); - -#define ARITHMETIC_ROR_REG \ - asm("\ - ror %%cl, %%eax;"\ - : "=a" (value)\ - : "a" (reg[opcode & 0x0f].I), "c" (shift)); - -#define ARITHMETIC_RRX_REG \ - asm("\ - bt $0, C_FLAG;\ - rcr $1, %%eax;"\ - : "=a" (value)\ - : "a" (reg[opcode & 0x0f].I)); - -#define ARITHMETIC_ROR_IMM \ - asm("\ - ror %%cl, %%eax;"\ - : "=a" (value)\ - : "a" (opcode & 0xff), "c" (shift)); -#define ROR_IMM_MSR \ - asm ("ror %%cl, %%eax;"\ - : "=a" (value)\ - : "a" (opcode & 0xFF), "c" (shift)); -#define ROR_VALUE \ - asm("ror %%cl, %0"\ - : "=r" (value)\ - : "r" (value), "c" (shift)); -#define RCR_VALUE \ - asm("bt $0, C_FLAG;"\ - "rcr $1, %0"\ - : "=r" (value)\ - : "r" (value)); -#endif -#else -#define OP_SUB \ - {\ - __asm mov ebx, base\ - __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ - __asm sub ebx, value\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - } - -#define OP_SUBS \ - {\ - __asm mov ebx, base\ - __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ - __asm sub ebx, value\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - -#define OP_RSB \ - {\ - __asm mov ebx, base\ - __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ - __asm mov eax, value\ - __asm sub eax, ebx\ - __asm mov ebx, dest\ - __asm mov dword ptr [OFFSET reg+4*ebx], eax\ - } - -#define OP_RSBS \ - {\ - __asm mov ebx, base\ - __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ - __asm mov eax, value\ - __asm sub eax, ebx\ - __asm mov ebx, dest\ - __asm mov dword ptr [OFFSET reg+4*ebx], eax\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - -#define OP_ADD \ - {\ - __asm mov ebx, base\ - __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ - __asm add ebx, value\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - } - -#define OP_ADDS \ - {\ - __asm mov ebx, base\ - __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ - __asm add ebx, value\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - -#define OP_ADC \ - {\ - __asm mov ebx, base\ - __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ - __asm bt word ptr C_FLAG, 0\ - __asm adc ebx, value\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - } - -#define OP_ADCS \ - {\ - __asm mov ebx, base\ - __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ - __asm bt word ptr C_FLAG, 0\ - __asm adc ebx, value\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - -#define OP_SBC \ - {\ - __asm mov ebx, base\ - __asm mov ebx, dword ptr [OFFSET reg + 4*ebx]\ - __asm mov eax, value\ - __asm bt word ptr C_FLAG, 0\ - __asm cmc\ - __asm sbb ebx, eax\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg + 4*eax], ebx\ - } - -#define OP_SBCS \ - {\ - __asm mov ebx, base\ - __asm mov ebx, dword ptr [OFFSET reg + 4*ebx]\ - __asm mov eax, value\ - __asm bt word ptr C_FLAG, 0\ - __asm cmc\ - __asm sbb ebx, eax\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg + 4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define OP_RSC \ - {\ - __asm mov ebx, value\ - __asm mov eax, base\ - __asm mov eax, dword ptr[OFFSET reg + 4*eax]\ - __asm bt word ptr C_FLAG, 0\ - __asm cmc\ - __asm sbb ebx, eax\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg + 4*eax], ebx\ - } - -#define OP_RSCS \ - {\ - __asm mov ebx, value\ - __asm mov eax, base\ - __asm mov eax, dword ptr[OFFSET reg + 4*eax]\ - __asm bt word ptr C_FLAG, 0\ - __asm cmc\ - __asm sbb ebx, eax\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg + 4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define OP_CMP \ - {\ - __asm mov eax, base\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm sub ebx, value\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } - -#define OP_CMN \ - {\ - __asm mov eax, base\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm add ebx, value\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define LOGICAL_LSL_REG \ - __asm mov eax, opcode\ - __asm and eax, 0x0f\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr shift\ - __asm shl eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_OUT - -#define LOGICAL_LSR_REG \ - __asm mov eax, opcode\ - __asm and eax, 0x0f\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr shift\ - __asm shr eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_OUT - -#define LOGICAL_ASR_REG \ - __asm mov eax, opcode\ - __asm and eax, 0x0f\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr shift\ - __asm sar eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_OUT - -#define LOGICAL_ROR_REG \ - __asm mov eax, opcode\ - __asm and eax, 0x0F\ - __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ - __asm mov cl, byte ptr shift\ - __asm ror eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_OUT - -#define LOGICAL_RRX_REG \ - __asm mov eax, opcode\ - __asm and eax, 0x0F\ - __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ - __asm bt word ptr C_OUT, 0\ - __asm rcr eax, 1\ - __asm mov value, eax\ - __asm setc byte ptr C_OUT - -#define LOGICAL_ROR_IMM \ - __asm mov eax, opcode\ - __asm and eax, 0xff\ - __asm mov cl, byte ptr shift\ - __asm ror eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_OUT -#define ARITHMETIC_LSL_REG \ - __asm mov eax, opcode\ - __asm and eax, 0x0f\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr shift\ - __asm shl eax, cl\ - __asm mov value, eax - -#define ARITHMETIC_LSR_REG \ - __asm mov eax, opcode\ - __asm and eax, 0x0f\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr shift\ - __asm shr eax, cl\ - __asm mov value, eax - -#define ARITHMETIC_ASR_REG \ - __asm mov eax, opcode\ - __asm and eax, 0x0f\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr shift\ - __asm sar eax, cl\ - __asm mov value, eax - -#define ARITHMETIC_ROR_REG \ - __asm mov eax, opcode\ - __asm and eax, 0x0F\ - __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ - __asm mov cl, byte ptr shift\ - __asm ror eax, cl\ - __asm mov value, eax - -#define ARITHMETIC_RRX_REG \ - __asm mov eax, opcode\ - __asm and eax, 0x0F\ - __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ - __asm bt word ptr C_FLAG, 0\ - __asm rcr eax, 1\ - __asm mov value, eax - -#define ARITHMETIC_ROR_IMM \ - __asm mov eax, opcode\ - __asm and eax, 0xff\ - __asm mov cl, byte ptr shift\ - __asm ror eax, cl\ - __asm mov value, eax -#define ROR_IMM_MSR \ - {\ - __asm mov eax, opcode\ - __asm and eax, 0xff\ - __asm mov cl, byte ptr shift\ - __asm ror eax, CL\ - __asm mov value, eax\ - } -#define ROR_VALUE \ - {\ - __asm mov cl, byte ptr shift\ - __asm ror dword ptr value, cl\ - } -#define RCR_VALUE \ - {\ - __asm mov cl, byte ptr shift\ - __asm bt word ptr C_FLAG, 0\ - __asm rcr dword ptr value, 1\ - } -#endif -#endif - -#define OP_TST \ - u32 res = reg[base].I & value;\ - N_FLAG = (res & 0x80000000) ? true : false;\ - Z_FLAG = (res) ? false : true;\ - C_FLAG = C_OUT; - -#define OP_TEQ \ - u32 res = reg[base].I ^ value;\ - N_FLAG = (res & 0x80000000) ? true : false;\ - Z_FLAG = (res) ? false : true;\ - C_FLAG = C_OUT; - -#define OP_ORR \ - reg[dest].I = reg[base].I | value; - -#define OP_ORRS \ - reg[dest].I = reg[base].I | value;\ - N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\ - Z_FLAG = (reg[dest].I) ? false : true;\ - C_FLAG = C_OUT; - -#define OP_MOV \ - reg[dest].I = value; - -#define OP_MOVS \ - reg[dest].I = value;\ - N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\ - Z_FLAG = (reg[dest].I) ? false : true;\ - C_FLAG = C_OUT; - -#define OP_BIC \ - reg[dest].I = reg[base].I & (~value); - -#define OP_BICS \ - reg[dest].I = reg[base].I & (~value);\ - N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\ - Z_FLAG = (reg[dest].I) ? false : true;\ - C_FLAG = C_OUT; - -#define OP_MVN \ - reg[dest].I = ~value; - -#define OP_MVNS \ - reg[dest].I = ~value; \ - N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\ - Z_FLAG = (reg[dest].I) ? false : true;\ - C_FLAG = C_OUT; - -#define CASE_16(BASE) \ - case BASE:\ - case BASE+1:\ - case BASE+2:\ - case BASE+3:\ - case BASE+4:\ - case BASE+5:\ - case BASE+6:\ - case BASE+7:\ - case BASE+8:\ - case BASE+9:\ - case BASE+10:\ - case BASE+11:\ - case BASE+12:\ - case BASE+13:\ - case BASE+14:\ - case BASE+15: - -#define CASE_256(BASE) \ - CASE_16(BASE)\ - CASE_16(BASE+0x10)\ - CASE_16(BASE+0x20)\ - CASE_16(BASE+0x30)\ - CASE_16(BASE+0x40)\ - CASE_16(BASE+0x50)\ - CASE_16(BASE+0x60)\ - CASE_16(BASE+0x70)\ - CASE_16(BASE+0x80)\ - CASE_16(BASE+0x90)\ - CASE_16(BASE+0xa0)\ - CASE_16(BASE+0xb0)\ - CASE_16(BASE+0xc0)\ - CASE_16(BASE+0xd0)\ - CASE_16(BASE+0xe0)\ - CASE_16(BASE+0xf0) - -#define LOGICAL_DATA_OPCODE(OPCODE, OPCODE2, BASE) \ - case BASE: \ - case BASE+8:\ - {\ - /* OP Rd,Rb,Rm LSL # */ \ - int base = (opcode >> 16) & 0x0F;\ - int shift = (opcode >> 7) & 0x1F;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - \ - if(shift) {\ - LOGICAL_LSL_REG\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+2:\ - case BASE+10:\ - {\ - /* OP Rd,Rb,Rm LSR # */ \ - int base = (opcode >> 16) & 0x0F;\ - int shift = (opcode >> 7) & 0x1F;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - LOGICAL_LSR_REG\ - } else {\ - value = 0;\ - C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false;\ - }\ - \ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+4:\ - case BASE+12:\ - {\ - /* OP Rd,Rb,Rm ASR # */\ - int base = (opcode >> 16) & 0x0F;\ - int shift = (opcode >> 7) & 0x1F;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - LOGICAL_ASR_REG\ - } else {\ - if(reg[opcode & 0x0F].I & 0x80000000){\ - value = 0xFFFFFFFF;\ - C_OUT = true;\ - } else {\ - value = 0;\ - C_OUT = false;\ - } \ - }\ - \ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+6:\ - case BASE+14:\ - {\ - /* OP Rd,Rb,Rm ROR # */\ - int base = (opcode >> 16) & 0x0F;\ - int shift = (opcode >> 7) & 0x1F;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - LOGICAL_ROR_REG\ - } else {\ - LOGICAL_RRX_REG\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+1:\ - {\ - /* OP Rd,Rb,Rm LSL Rs */\ - clockTicks++;\ - int base = (opcode >> 16) & 0x0F;\ - int shift = reg[(opcode >> 8)&15].B.B0;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - if(shift == 32) {\ - value = 0;\ - C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false);\ - } else if(shift < 32) {\ - LOGICAL_LSL_REG\ - } else {\ - value = 0;\ - C_OUT = false;\ - }\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+3:\ - {\ - /* OP Rd,Rb,Rm LSR Rs */ \ - clockTicks++;\ - int base = (opcode >> 16) & 0x0F;\ - int shift = reg[(opcode >> 8)&15].B.B0;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - if(shift == 32) {\ - value = 0;\ - C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false);\ - } else if(shift < 32) {\ - LOGICAL_LSR_REG\ - } else {\ - value = 0;\ - C_OUT = false;\ - }\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+5:\ - {\ - /* OP Rd,Rb,Rm ASR Rs */ \ - clockTicks++;\ - int base = (opcode >> 16) & 0x0F;\ - int shift = reg[(opcode >> 8)&15].B.B0;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift < 32) {\ - if(shift) {\ - LOGICAL_ASR_REG\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - } else {\ - if(reg[opcode & 0x0F].I & 0x80000000){\ - value = 0xFFFFFFFF;\ - C_OUT = true;\ - } else {\ - value = 0;\ - C_OUT = false;\ - }\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+7:\ - {\ - /* OP Rd,Rb,Rm ROR Rs */\ - clockTicks++;\ - int base = (opcode >> 16) & 0x0F;\ - int shift = reg[(opcode >> 8)&15].B.B0;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - shift &= 0x1f;\ - if(shift) {\ - LOGICAL_ROR_REG\ - } else {\ - value = reg[opcode & 0x0F].I;\ - C_OUT = (value & 0x80000000 ? true : false);\ - }\ - } else {\ - value = reg[opcode & 0x0F].I;\ - C_OUT = (value & 0x80000000 ? true : false);\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+0x200:\ - case BASE+0x201:\ - case BASE+0x202:\ - case BASE+0x203:\ - case BASE+0x204:\ - case BASE+0x205:\ - case BASE+0x206:\ - case BASE+0x207:\ - case BASE+0x208:\ - case BASE+0x209:\ - case BASE+0x20a:\ - case BASE+0x20b:\ - case BASE+0x20c:\ - case BASE+0x20d:\ - case BASE+0x20e:\ - case BASE+0x20f:\ - {\ - int shift = (opcode & 0xF00) >> 7;\ - int base = (opcode >> 16) & 0x0F;\ - int dest = (opcode >> 12) & 0x0F;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - LOGICAL_ROR_IMM\ - } else {\ - value = opcode & 0xff;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break; - -#define LOGICAL_DATA_OPCODE_WITHOUT_base(OPCODE, OPCODE2, BASE) \ - case BASE: \ - case BASE+8:\ - {\ - /* OP Rd,Rb,Rm LSL # */ \ - int shift = (opcode >> 7) & 0x1F;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - \ - if(shift) {\ - LOGICAL_LSL_REG\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+2:\ - case BASE+10:\ - {\ - /* OP Rd,Rb,Rm LSR # */ \ - int shift = (opcode >> 7) & 0x1F;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - LOGICAL_LSR_REG\ - } else {\ - value = 0;\ - C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false;\ - }\ - \ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+4:\ - case BASE+12:\ - {\ - /* OP Rd,Rb,Rm ASR # */\ - int shift = (opcode >> 7) & 0x1F;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - LOGICAL_ASR_REG\ - } else {\ - if(reg[opcode & 0x0F].I & 0x80000000){\ - value = 0xFFFFFFFF;\ - C_OUT = true;\ - } else {\ - value = 0;\ - C_OUT = false;\ - } \ - }\ - \ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+6:\ - case BASE+14:\ - {\ - /* OP Rd,Rb,Rm ROR # */\ - int shift = (opcode >> 7) & 0x1F;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - LOGICAL_ROR_REG\ - } else {\ - LOGICAL_RRX_REG\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+1:\ - {\ - /* OP Rd,Rb,Rm LSL Rs */\ - clockTicks++;\ - int shift = reg[(opcode >> 8)&15].B.B0;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - if(shift == 32) {\ - value = 0;\ - C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false);\ - } else if(shift < 32) {\ - LOGICAL_LSL_REG\ - } else {\ - value = 0;\ - C_OUT = false;\ - }\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+3:\ - {\ - /* OP Rd,Rb,Rm LSR Rs */ \ - clockTicks++;\ - int shift = reg[(opcode >> 8)&15].B.B0;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - if(shift == 32) {\ - value = 0;\ - C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false);\ - } else if(shift < 32) {\ - LOGICAL_LSR_REG\ - } else {\ - value = 0;\ - C_OUT = false;\ - }\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+5:\ - {\ - /* OP Rd,Rb,Rm ASR Rs */ \ - clockTicks++;\ - int shift = reg[(opcode >> 8)&15].B.B0;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift < 32) {\ - if(shift) {\ - LOGICAL_ASR_REG\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - } else {\ - if(reg[opcode & 0x0F].I & 0x80000000){\ - value = 0xFFFFFFFF;\ - C_OUT = true;\ - } else {\ - value = 0;\ - C_OUT = false;\ - }\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+7:\ - {\ - /* OP Rd,Rb,Rm ROR Rs */\ - clockTicks++;\ - int shift = reg[(opcode >> 8)&15].B.B0;\ - int dest = (opcode>>12) & 15;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - shift &= 0x1f;\ - if(shift) {\ - LOGICAL_ROR_REG\ - } else {\ - value = reg[opcode & 0x0F].I;\ - C_OUT = (value & 0x80000000 ? true : false);\ - }\ - } else {\ - value = reg[opcode & 0x0F].I;\ - C_OUT = (value & 0x80000000 ? true : false);\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+0x200:\ - case BASE+0x201:\ - case BASE+0x202:\ - case BASE+0x203:\ - case BASE+0x204:\ - case BASE+0x205:\ - case BASE+0x206:\ - case BASE+0x207:\ - case BASE+0x208:\ - case BASE+0x209:\ - case BASE+0x20a:\ - case BASE+0x20b:\ - case BASE+0x20c:\ - case BASE+0x20d:\ - case BASE+0x20e:\ - case BASE+0x20f:\ - {\ - int shift = (opcode & 0xF00) >> 7;\ - int dest = (opcode >> 12) & 0x0F;\ - bool C_OUT = C_FLAG;\ - u32 value;\ - if(shift) {\ - LOGICAL_ROR_IMM\ - } else {\ - value = opcode & 0xff;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break; - -#define ARITHMETIC_DATA_OPCODE(OPCODE, OPCODE2, BASE) \ - case BASE:\ - case BASE+8:\ - {\ - /* OP Rd,Rb,Rm LSL # */\ - int base = (opcode >> 16) & 0x0F;\ - int shift = (opcode >> 7) & 0x1F;\ - int dest = (opcode>>12) & 15;\ - u32 value;\ - if(shift) {\ - ARITHMETIC_LSL_REG\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+2:\ - case BASE+10:\ - {\ - /* OP Rd,Rb,Rm LSR # */\ - int base = (opcode >> 16) & 0x0F;\ - int shift = (opcode >> 7) & 0x1F;\ - int dest = (opcode>>12) & 15;\ - u32 value;\ - if(shift) {\ - ARITHMETIC_LSR_REG\ - } else {\ - value = 0;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+4:\ - case BASE+12:\ - {\ - /* OP Rd,Rb,Rm ASR # */\ - int base = (opcode >> 16) & 0x0F;\ - int shift = (opcode >> 7) & 0x1F;\ - int dest = (opcode>>12) & 15;\ - u32 value;\ - if(shift) {\ - ARITHMETIC_ASR_REG\ - } else {\ - if(reg[opcode & 0x0F].I & 0x80000000){\ - value = 0xFFFFFFFF;\ - } else value = 0;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+6:\ - case BASE+14:\ - {\ - /* OP Rd,Rb,Rm ROR # */\ - int base = (opcode >> 16) & 0x0F;\ - int shift = (opcode >> 7) & 0x1F;\ - int dest = (opcode>>12) & 15;\ - u32 value;\ - if(shift) {\ - ARITHMETIC_ROR_REG\ - } else {\ - ARITHMETIC_RRX_REG\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+1:\ - {\ - /* OP Rd,Rb,Rm LSL Rs */\ - clockTicks++;\ - int base = (opcode >> 16) & 0x0F;\ - int shift = reg[(opcode >> 8)&15].B.B0;\ - int dest = (opcode>>12) & 15;\ - u32 value;\ - if(shift) {\ - if(shift == 32) {\ - value = 0;\ - } else if(shift < 32) {\ - ARITHMETIC_LSL_REG\ - } else value = 0;\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+3:\ - {\ - /* OP Rd,Rb,Rm LSR Rs */\ - clockTicks++;\ - int base = (opcode >> 16) & 0x0F;\ - int shift = reg[(opcode >> 8)&15].B.B0;\ - int dest = (opcode>>12) & 15;\ - u32 value;\ - if(shift) {\ - if(shift == 32) {\ - value = 0;\ - } else if(shift < 32) {\ - ARITHMETIC_LSR_REG\ - } else value = 0;\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+5:\ - {\ - /* OP Rd,Rb,Rm ASR Rs */\ - clockTicks++;\ - int base = (opcode >> 16) & 0x0F;\ - int shift = reg[(opcode >> 8)&15].B.B0;\ - int dest = (opcode>>12) & 15;\ - u32 value;\ - if(shift < 32) {\ - if(shift) {\ - ARITHMETIC_ASR_REG\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - } else {\ - if(reg[opcode & 0x0F].I & 0x80000000){\ - value = 0xFFFFFFFF;\ - } else value = 0;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+7:\ - {\ - /* OP Rd,Rb,Rm ROR Rs */\ - clockTicks++;\ - int base = (opcode >> 16) & 0x0F;\ - int shift = reg[(opcode >> 8)&15].B.B0;\ - int dest = (opcode>>12) & 15;\ - u32 value;\ - if(shift) {\ - shift &= 0x1f;\ - if(shift) {\ - ARITHMETIC_ROR_REG\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - } else {\ - value = reg[opcode & 0x0F].I;\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break;\ - case BASE+0x200:\ - case BASE+0x201:\ - case BASE+0x202:\ - case BASE+0x203:\ - case BASE+0x204:\ - case BASE+0x205:\ - case BASE+0x206:\ - case BASE+0x207:\ - case BASE+0x208:\ - case BASE+0x209:\ - case BASE+0x20a:\ - case BASE+0x20b:\ - case BASE+0x20c:\ - case BASE+0x20d:\ - case BASE+0x20e:\ - case BASE+0x20f:\ - {\ - int shift = (opcode & 0xF00) >> 7;\ - int base = (opcode >> 16) & 0x0F;\ - int dest = (opcode >> 12) & 0x0F;\ - u32 value;\ - {\ - ARITHMETIC_ROR_IMM\ - }\ - if(dest == 15) {\ - OPCODE2\ - /* todo */\ - if(opcode & 0x00100000) {\ - clockTicks++;\ - CPUSwitchMode(reg[17].I & 0x1f, false);\ - }\ - if(armState) {\ - reg[15].I &= 0xFFFFFFFC;\ - armNextPC = reg[15].I;\ - reg[15].I += 4;\ - } else {\ - reg[15].I &= 0xFFFFFFFE;\ - armNextPC = reg[15].I;\ - reg[15].I += 2;\ - }\ - } else {\ - OPCODE \ - }\ - }\ - break; - -u32 opcode = CPUReadMemoryQuick(armNextPC); - -clockTicks = memoryWaitFetch32[(armNextPC >> 24) & 15]; - -#ifndef FINAL_VERSION -if(armNextPC == stop) - { - armNextPC++; - } -#endif - -armNextPC = reg[15].I; -reg[15].I += 4; -int cond = opcode >> 28; -// suggested optimization for frequent cases -bool cond_res; -if(cond == 0x0e) - { - cond_res = true; - } -else - { - switch(cond) - { - case 0x00: // EQ - cond_res = Z_FLAG; - break; - case 0x01: // NE - cond_res = !Z_FLAG; - break; - case 0x02: // CS - cond_res = C_FLAG; - break; - case 0x03: // CC - cond_res = !C_FLAG; - break; - case 0x04: // MI - cond_res = N_FLAG; - break; - case 0x05: // PL - cond_res = !N_FLAG; - break; - case 0x06: // VS - cond_res = V_FLAG; - break; - case 0x07: // VC - cond_res = !V_FLAG; - break; - case 0x08: // HI - cond_res = C_FLAG && !Z_FLAG; - break; - case 0x09: // LS - cond_res = !C_FLAG || Z_FLAG; - break; - case 0x0A: // GE - cond_res = N_FLAG == V_FLAG; - break; - case 0x0B: // LT - cond_res = N_FLAG != V_FLAG; - break; - case 0x0C: // GT - cond_res = !Z_FLAG &&(N_FLAG == V_FLAG); - break; - case 0x0D: // LE - cond_res = Z_FLAG || (N_FLAG != V_FLAG); - break; - case 0x0E: - cond_res = true; - break; - case 0x0F: - default: - // ??? - cond_res = false; - break; - } - } - -if(cond_res) - { - switch(((opcode>>16)&0xFF0) | ((opcode>>4)&0x0F)) - { - LOGICAL_DATA_OPCODE_WITHOUT_base(OP_AND, OP_AND, 0x000); - LOGICAL_DATA_OPCODE_WITHOUT_base(OP_ANDS, OP_AND, 0x010); - case 0x009: - { - // MUL Rd, Rm, Rs - int dest = (opcode >> 16) & 0x0F; - int mult = (opcode & 0x0F); - u32 rs = reg[(opcode >> 8) & 0x0F].I; - reg[dest].I = reg[mult].I * rs; - if(((s32)rs)<0) - rs = ~rs; - if((rs & 0xFFFFFF00) == 0) - clockTicks += 2; - else if ((rs & 0xFFFF0000) == 0) - clockTicks += 3; - else if ((rs & 0xFF000000) == 0) - clockTicks += 4; - else - clockTicks += 5; - } - break; - case 0x019: - { - // MULS Rd, Rm, Rs - int dest = (opcode >> 16) & 0x0F; - int mult = (opcode & 0x0F); - u32 rs = reg[(opcode >> 8) & 0x0F].I; - reg[dest].I = reg[mult].I * rs; - N_FLAG = (reg[dest].I & 0x80000000) ? true : false; - Z_FLAG = (reg[dest].I) ? false : true; - if(((s32)rs)<0) - rs = ~rs; - if((rs & 0xFFFFFF00) == 0) - clockTicks += 2; - else if ((rs & 0xFFFF0000) == 0) - clockTicks += 3; - else if ((rs & 0xFF000000) == 0) - clockTicks += 4; - else - clockTicks += 5; - } - break; - case 0x00b: - case 0x02b: - { - // STRH Rd, [Rn], -Rm - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = reg[opcode & 0x0F].I; - clockTicks += 4 + CPUUpdateTicksAccess16(address); - CPUWriteHalfWord(address, reg[dest].W.W0); - address -= offset; - reg[base].I = address; - } - break; - case 0x04b: - case 0x06b: - { - // STRH Rd, [Rn], #-offset - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0); - clockTicks += 4 + CPUUpdateTicksAccess16(address); - CPUWriteHalfWord(address, reg[dest].W.W0); - address -= offset; - reg[base].I = address; - } - break; - case 0x08b: - case 0x0ab: - { - // STRH Rd, [Rn], Rm - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = reg[opcode & 0x0F].I; - clockTicks += 4 + CPUUpdateTicksAccess16(address); - CPUWriteHalfWord(address, reg[dest].W.W0); - address += offset; - reg[base].I = address; - } - break; - case 0x0cb: - case 0x0eb: - { - // STRH Rd, [Rn], #offset - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0); - clockTicks += 4 + CPUUpdateTicksAccess16(address); - CPUWriteHalfWord(address, reg[dest].W.W0); - address += offset; - reg[base].I = address; - } - break; - case 0x10b: - { - // STRH Rd, [Rn, -Rm] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - reg[opcode & 0x0F].I; - clockTicks += 4 + CPUUpdateTicksAccess16(address); - CPUWriteHalfWord(address, reg[dest].W.W0); - } - break; - case 0x12b: - { - // STRH Rd, [Rn, -Rm]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - reg[opcode & 0x0F].I; - clockTicks += 4 + CPUUpdateTicksAccess16(address); - CPUWriteHalfWord(address, reg[dest].W.W0); - reg[base].I = address; - } - break; - case 0x14b: - { - // STRH Rd, [Rn, -#offset] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 4 + CPUUpdateTicksAccess16(address); - CPUWriteHalfWord(address, reg[dest].W.W0); - } - break; - case 0x16b: - { - // STRH Rd, [Rn, -#offset]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 4 + CPUUpdateTicksAccess16(address); - CPUWriteHalfWord(address, reg[dest].W.W0); - reg[base].I = address; - } - break; - case 0x18b: - { - // STRH Rd, [Rn, Rm] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + reg[opcode & 0x0F].I; - clockTicks += 4 + CPUUpdateTicksAccess16(address); - CPUWriteHalfWord(address, reg[dest].W.W0); - } - break; - case 0x1ab: - { - // STRH Rd, [Rn, Rm]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + reg[opcode & 0x0F].I; - clockTicks += 4 + CPUUpdateTicksAccess16(address); - CPUWriteHalfWord(address, reg[dest].W.W0); - reg[base].I = address; - } - break; - case 0x1cb: - { - // STRH Rd, [Rn, #offset] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 4 + CPUUpdateTicksAccess16(address); - CPUWriteHalfWord(address, reg[dest].W.W0); - } - break; - case 0x1eb: - { - // STRH Rd, [Rn, #offset]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 4 + CPUUpdateTicksAccess16(address); - CPUWriteHalfWord(address, reg[dest].W.W0); - reg[base].I = address; - } - break; - case 0x01b: - case 0x03b: - { - // LDRH Rd, [Rn], -Rm - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = CPUReadHalfWord(address); - if(dest != base) - { - address -= offset; - reg[base].I = address; - } - } - break; - case 0x05b: - case 0x07b: - { - // LDRH Rd, [Rn], #-offset - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = CPUReadHalfWord(address); - if(dest != base) - { - address -= offset; - reg[base].I = address; - } - } - break; - case 0x09b: - case 0x0bb: - { - // LDRH Rd, [Rn], Rm - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = CPUReadHalfWord(address); - if(dest != base) - { - address += offset; - reg[base].I = address; - } - } - break; - case 0x0db: - case 0x0fb: - { - // LDRH Rd, [Rn], #offset - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = CPUReadHalfWord(address); - if(dest != base) - { - address += offset; - reg[base].I = address; - } - } - break; - case 0x11b: - { - // LDRH Rd, [Rn, -Rm] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = CPUReadHalfWord(address); - } - break; - case 0x13b: - { - // LDRH Rd, [Rn, -Rm]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = CPUReadHalfWord(address); - if(dest != base) - reg[base].I = address; - } - break; - case 0x15b: - { - // LDRH Rd, [Rn, -#offset] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = CPUReadHalfWord(address); - } - break; - case 0x17b: - { - // LDRH Rd, [Rn, -#offset]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = CPUReadHalfWord(address); - if(dest != base) - reg[base].I = address; - } - break; - case 0x19b: - { - // LDRH Rd, [Rn, Rm] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = CPUReadHalfWord(address); - } - break; - case 0x1bb: - { - // LDRH Rd, [Rn, Rm]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = CPUReadHalfWord(address); - if(dest != base) - reg[base].I = address; - } - break; - case 0x1db: - { - // LDRH Rd, [Rn, #offset] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = CPUReadHalfWord(address); - } - break; - case 0x1fb: - { - // LDRH Rd, [Rn, #offset]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = CPUReadHalfWord(address); - if(dest != base) - reg[base].I = address; - } - break; - case 0x01d: - case 0x03d: - { - // LDRSB Rd, [Rn], -Rm - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s8)CPUReadByte(address); - if(dest != base) - { - address -= offset; - reg[base].I = address; - } - } - break; - case 0x05d: - case 0x07d: - { - // LDRSB Rd, [Rn], #-offset - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s8)CPUReadByte(address); - if(dest != base) - { - address -= offset; - reg[base].I = address; - } - } - break; - case 0x09d: - case 0x0bd: - { - // LDRSB Rd, [Rn], Rm - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s8)CPUReadByte(address); - if(dest != base) - { - address += offset; - reg[base].I = address; - } - } - break; - case 0x0dd: - case 0x0fd: - { - // LDRSB Rd, [Rn], #offset - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s8)CPUReadByte(address); - if(dest != base) - { - address += offset; - reg[base].I = address; - } - } - break; - case 0x11d: - { - // LDRSB Rd, [Rn, -Rm] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s8)CPUReadByte(address); - } - break; - case 0x13d: - { - // LDRSB Rd, [Rn, -Rm]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s8)CPUReadByte(address); - if(dest != base) - reg[base].I = address; - } - break; - case 0x15d: - { - // LDRSB Rd, [Rn, -#offset] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s8)CPUReadByte(address); - } - break; - case 0x17d: - { - // LDRSB Rd, [Rn, -#offset]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s8)CPUReadByte(address); - if(dest != base) - reg[base].I = address; - } - break; - case 0x19d: - { - // LDRSB Rd, [Rn, Rm] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s8)CPUReadByte(address); - } - break; - case 0x1bd: - { - // LDRSB Rd, [Rn, Rm]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s8)CPUReadByte(address); - if(dest != base) - reg[base].I = address; - } - break; - case 0x1dd: - { - // LDRSB Rd, [Rn, #offset] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s8)CPUReadByte(address); - } - break; - case 0x1fd: - { - // LDRSB Rd, [Rn, #offset]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s8)CPUReadByte(address); - if(dest != base) - reg[base].I = address; - } - break; - case 0x01f: - case 0x03f: - { - // LDRSH Rd, [Rn], -Rm - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s16)CPUReadHalfWordSigned(address); - if(dest != base) - { - address -= offset; - reg[base].I = address; - } - } - break; - case 0x05f: - case 0x07f: - { - // LDRSH Rd, [Rn], #-offset - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s16)CPUReadHalfWordSigned(address); - if(dest != base) - { - address -= offset; - reg[base].I = address; - } - } - break; - case 0x09f: - case 0x0bf: - { - // LDRSH Rd, [Rn], Rm - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s16)CPUReadHalfWordSigned(address); - if(dest != base) - { - address += offset; - reg[base].I = address; - } - } - break; - case 0x0df: - case 0x0ff: - { - // LDRSH Rd, [Rn], #offset - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I; - int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s16)CPUReadHalfWordSigned(address); - if(dest != base) - { - address += offset; - reg[base].I = address; - } - } - break; - case 0x11f: - { - // LDRSH Rd, [Rn, -Rm] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s16)CPUReadHalfWordSigned(address); - } - break; - case 0x13f: - { - // LDRSH Rd, [Rn, -Rm]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s16)CPUReadHalfWordSigned(address); - if(dest != base) - reg[base].I = address; - } - break; - case 0x15f: - { - // LDRSH Rd, [Rn, -#offset] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s16)CPUReadHalfWordSigned(address); - } - break; - case 0x17f: - { - // LDRSH Rd, [Rn, -#offset]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s16)CPUReadHalfWordSigned(address); - if(dest != base) - reg[base].I = address; - } - break; - case 0x19f: - { - // LDRSH Rd, [Rn, Rm] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s16)CPUReadHalfWordSigned(address); - } - break; - case 0x1bf: - { - // LDRSH Rd, [Rn, Rm]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + reg[opcode & 0x0F].I; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s16)CPUReadHalfWordSigned(address); - if(dest != base) - reg[base].I = address; - } - break; - case 0x1df: - { - // LDRSH Rd, [Rn, #offset] - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s16)CPUReadHalfWordSigned(address); - } - break; - case 0x1ff: - { - // LDRSH Rd, [Rn, #offset]! - int base = (opcode >> 16) & 0x0F; - int dest = (opcode >> 12) & 0x0F; - u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0)); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - reg[dest].I = (s16)CPUReadHalfWordSigned(address); - if(dest != base) - reg[base].I = address; - } - break; - LOGICAL_DATA_OPCODE_WITHOUT_base(OP_EOR, OP_EOR, 0x020); - LOGICAL_DATA_OPCODE_WITHOUT_base(OP_EORS, OP_EOR, 0x030); - case 0x029: - { - // MLA Rd, Rm, Rs, Rn - int dest = (opcode >> 16) & 0x0F; - int mult = (opcode & 0x0F); - u32 rs = reg[(opcode >> 8) & 0x0F].I; - reg[dest].I = reg[mult].I * rs + reg[(opcode>>12)&0x0f].I; - if(((s32)rs)<0) - rs = ~rs; - if((rs & 0xFFFFFF00) == 0) - clockTicks += 3; - else if ((rs & 0xFFFF0000) == 0) - clockTicks += 4; - else if ((rs & 0xFF000000) == 0) - clockTicks += 5; - else - clockTicks += 6; - } - break; - case 0x039: - { - // MLAS Rd, Rm, Rs, Rn - int dest = (opcode >> 16) & 0x0F; - int mult = (opcode & 0x0F); - u32 rs = reg[(opcode >> 8) & 0x0F].I; - reg[dest].I = reg[mult].I * rs + reg[(opcode>>12)&0x0f].I; - N_FLAG = (reg[dest].I & 0x80000000) ? true : false; - Z_FLAG = (reg[dest].I) ? false : true; - if(((s32)rs)<0) - rs = ~rs; - if((rs & 0xFFFFFF00) == 0) - clockTicks += 3; - else if ((rs & 0xFFFF0000) == 0) - clockTicks += 4; - else if ((rs & 0xFF000000) == 0) - clockTicks += 5; - else - clockTicks += 6; - } - break; - ARITHMETIC_DATA_OPCODE(OP_SUB, OP_SUB, 0x040); - ARITHMETIC_DATA_OPCODE(OP_SUBS, OP_SUB, 0x050); - ARITHMETIC_DATA_OPCODE(OP_RSB, OP_RSB, 0x060); - ARITHMETIC_DATA_OPCODE(OP_RSBS, OP_RSB, 0x070); - ARITHMETIC_DATA_OPCODE(OP_ADD, OP_ADD, 0x080); - ARITHMETIC_DATA_OPCODE(OP_ADDS, OP_ADD, 0x090); - case 0x089: - { - // UMULL RdLo, RdHi, Rn, Rs - u32 umult = reg[(opcode & 0x0F)].I; - u32 usource = reg[(opcode >> 8) & 0x0F].I; - int destLo = (opcode >> 12) & 0x0F; - int destHi = (opcode >> 16) & 0x0F; - u64 uTemp = ((u64)umult)*((u64)usource); - reg[destLo].I = (u32)uTemp; - reg[destHi].I = (u32)(uTemp >> 32); - if ((usource & 0xFFFFFF00) == 0) - clockTicks += 2; - else if ((usource & 0xFFFF0000) == 0) - clockTicks += 3; - else if ((usource & 0xFF000000) == 0) - clockTicks += 4; - else - clockTicks += 5; - } - break; - case 0x099: - { - // UMULLS RdLo, RdHi, Rn, Rs - u32 umult = reg[(opcode & 0x0F)].I; - u32 usource = reg[(opcode >> 8) & 0x0F].I; - int destLo = (opcode >> 12) & 0x0F; - int destHi = (opcode >> 16) & 0x0F; - u64 uTemp = ((u64)umult)*((u64)usource); - reg[destLo].I = (u32)uTemp; - reg[destHi].I = (u32)(uTemp >> 32); - Z_FLAG = (uTemp) ? false : true; - N_FLAG = (reg[destHi].I & 0x80000000) ? true : false; - if ((usource & 0xFFFFFF00) == 0) - clockTicks += 2; - else if ((usource & 0xFFFF0000) == 0) - clockTicks += 3; - else if ((usource & 0xFF000000) == 0) - clockTicks += 4; - else - clockTicks += 5; - } - break; - ARITHMETIC_DATA_OPCODE(OP_ADC, OP_ADC, 0x0a0); - ARITHMETIC_DATA_OPCODE(OP_ADCS, OP_ADC, 0x0b0); - case 0x0a9: - { - // UMLAL RdLo, RdHi, Rn, Rs - u32 umult = reg[(opcode & 0x0F)].I; - u32 usource = reg[(opcode >> 8) & 0x0F].I; - int destLo = (opcode >> 12) & 0x0F; - int destHi = (opcode >> 16) & 0x0F; - u64 uTemp = (u64)reg[destHi].I; - uTemp <<= 32; - uTemp |= (u64)reg[destLo].I; - uTemp += ((u64)umult)*((u64)usource); - reg[destLo].I = (u32)uTemp; - reg[destHi].I = (u32)(uTemp >> 32); - if ((usource & 0xFFFFFF00) == 0) - clockTicks += 3; - else if ((usource & 0xFFFF0000) == 0) - clockTicks += 4; - else if ((usource & 0xFF000000) == 0) - clockTicks += 5; - else - clockTicks += 6; - } - break; - case 0x0b9: - { - // UMLALS RdLo, RdHi, Rn, Rs - u32 umult = reg[(opcode & 0x0F)].I; - u32 usource = reg[(opcode >> 8) & 0x0F].I; - int destLo = (opcode >> 12) & 0x0F; - int destHi = (opcode >> 16) & 0x0F; - u64 uTemp = (u64)reg[destHi].I; - uTemp <<= 32; - uTemp |= (u64)reg[destLo].I; - uTemp += ((u64)umult)*((u64)usource); - reg[destLo].I = (u32)uTemp; - reg[destHi].I = (u32)(uTemp >> 32); - Z_FLAG = (uTemp) ? false : true; - N_FLAG = (reg[destHi].I & 0x80000000) ? true : false; - if ((usource & 0xFFFFFF00) == 0) - clockTicks += 3; - else if ((usource & 0xFFFF0000) == 0) - clockTicks += 4; - else if ((usource & 0xFF000000) == 0) - clockTicks += 5; - else - clockTicks += 6; - } - break; - ARITHMETIC_DATA_OPCODE(OP_SBC, OP_SBC, 0x0c0); - ARITHMETIC_DATA_OPCODE(OP_SBCS, OP_SBC, 0x0d0); - case 0x0c9: - { - // SMULL RdLo, RdHi, Rm, Rs - int destLo = (opcode >> 12) & 0x0F; - int destHi = (opcode >> 16) & 0x0F; - u32 rs = reg[(opcode >> 8) & 0x0F].I; - s64 m = (s32)reg[(opcode & 0x0F)].I; - s64 s = (s32)rs; - s64 sTemp = m*s; - reg[destLo].I = (u32)sTemp; - reg[destHi].I = (u32)(sTemp >> 32); - if(((s32)rs) < 0) - rs = ~rs; - if((rs & 0xFFFFFF00) == 0) - clockTicks += 2; - else if((rs & 0xFFFF0000) == 0) - clockTicks += 3; - else if((rs & 0xFF000000) == 0) - clockTicks += 4; - else - clockTicks += 5; - } - break; - case 0x0d9: - { - // SMULLS RdLo, RdHi, Rm, Rs - int destLo = (opcode >> 12) & 0x0F; - int destHi = (opcode >> 16) & 0x0F; - u32 rs = reg[(opcode >> 8) & 0x0F].I; - s64 m = (s32)reg[(opcode & 0x0F)].I; - s64 s = (s32)rs; - s64 sTemp = m*s; - reg[destLo].I = (u32)sTemp; - reg[destHi].I = (u32)(sTemp >> 32); - Z_FLAG = (sTemp) ? false : true; - N_FLAG = (sTemp < 0) ? true : false; - if(((s32)rs) < 0) - rs = ~rs; - if((rs & 0xFFFFFF00) == 0) - clockTicks += 2; - else if((rs & 0xFFFF0000) == 0) - clockTicks += 3; - else if((rs & 0xFF000000) == 0) - clockTicks += 4; - else - clockTicks += 5; - } - break; - ARITHMETIC_DATA_OPCODE(OP_RSC, OP_RSC, 0x0e0); - ARITHMETIC_DATA_OPCODE(OP_RSCS, OP_RSC, 0x0f0); - case 0x0e9: - { - // SMLAL RdLo, RdHi, Rm, Rs - int destLo = (opcode >> 12) & 0x0F; - int destHi = (opcode >> 16) & 0x0F; - u32 rs = reg[(opcode >> 8) & 0x0F].I; - s64 m = (s32)reg[(opcode & 0x0F)].I; - s64 s = (s32)rs; - s64 sTemp = (u64)reg[destHi].I; - sTemp <<= 32; - sTemp |= (u64)reg[destLo].I; - sTemp += m*s; - reg[destLo].I = (u32)sTemp; - reg[destHi].I = (u32)(sTemp >> 32); - if(((s32)rs) < 0) - rs = ~rs; - if((rs & 0xFFFFFF00) == 0) - clockTicks += 3; - else if((rs & 0xFFFF0000) == 0) - clockTicks += 4; - else if((rs & 0xFF000000) == 0) - clockTicks += 5; - else - clockTicks += 6; - } - break; - case 0x0f9: - { - // SMLALS RdLo, RdHi, Rm, Rs - int destLo = (opcode >> 12) & 0x0F; - int destHi = (opcode >> 16) & 0x0F; - u32 rs = reg[(opcode >> 8) & 0x0F].I; - s64 m = (s32)reg[(opcode & 0x0F)].I; - s64 s = (s32)rs; - s64 sTemp = (u64)reg[destHi].I; - sTemp <<= 32; - sTemp |= (u64)reg[destLo].I; - sTemp += m*s; - reg[destLo].I = (u32)sTemp; - reg[destHi].I = (u32)(sTemp >> 32); - Z_FLAG = (sTemp) ? false : true; - N_FLAG = (sTemp < 0) ? true : false; - if(((s32)rs) < 0) - rs = ~rs; - if((rs & 0xFFFFFF00) == 0) - clockTicks += 3; - else if((rs & 0xFFFF0000) == 0) - clockTicks += 4; - else if((rs & 0xFF000000) == 0) - clockTicks += 5; - else - clockTicks += 6; - } - break; - LOGICAL_DATA_OPCODE(OP_TST, OP_TST, 0x110); - case 0x100: - // MRS Rd, CPSR - // TODO: check if right instruction.... - CPUUpdateCPSR(); - reg[(opcode >> 12) & 0x0F].I = reg[16].I; - break; - case 0x109: - { - // SWP Rd, Rm, [Rn] - u32 address = reg[(opcode >> 16) & 15].I; - u32 temp = CPUReadMemory(address); - CPUWriteMemory(address, reg[opcode&15].I); - reg[(opcode >> 12) & 15].I = temp; - } - break; - LOGICAL_DATA_OPCODE(OP_TEQ, OP_TEQ, 0x130); - case 0x120: - { - // MSR CPSR_fields, Rm - CPUUpdateCPSR(); - u32 value = reg[opcode & 15].I; - u32 newValue = reg[16].I; - if(armMode > 0x10) - { - if(opcode & 0x00010000) - newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF); - if(opcode & 0x00020000) - newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00); - if(opcode & 0x00040000) - newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000); - } - if(opcode & 0x00080000) - newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000); - newValue |= 0x10; - CPUSwitchMode(newValue & 0x1f, false); - reg[16].I = newValue; - CPUUpdateFlags(); - } - break; - case 0x121: - { - // BX Rm - // TODO: check if right instruction... - clockTicks += 3; - int base = opcode & 0x0F; - armState = reg[base].I & 1 ? false : true; - if(armState) - { - reg[15].I = reg[base].I & 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - else - { - reg[15].I = reg[base].I & 0xFFFFFFFE; - armNextPC = reg[15].I; - reg[15].I += 2; - } - } - break; - ARITHMETIC_DATA_OPCODE(OP_CMP, OP_CMP, 0x150); - case 0x140: - // MRS Rd, SPSR - // TODO: check if right instruction... - reg[(opcode >> 12) & 0x0F].I = reg[17].I; - break; - case 0x149: - { - // SWPB Rd, Rm, [Rn] - u32 address = reg[(opcode >> 16) & 15].I; - u32 temp = CPUReadByte(address); - CPUWriteByte(address, reg[opcode&15].B.B0); - reg[(opcode>>12)&15].I = temp; - } - break; - ARITHMETIC_DATA_OPCODE(OP_CMN, OP_CMN, 0x170); - case 0x160: - { - // MSR SPSR_fields, Rm - u32 value = reg[opcode & 15].I; - if(armMode > 0x10 && armMode < 0x1f) - { - if(opcode & 0x00010000) - reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF); - if(opcode & 0x00020000) - reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00); - if(opcode & 0x00040000) - reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000); - if(opcode & 0x00080000) - reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000); - } - } - break; - LOGICAL_DATA_OPCODE (OP_ORR, OP_ORR, 0x180); - LOGICAL_DATA_OPCODE (OP_ORRS, OP_ORR, 0x190); - LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MOV, OP_MOV, 0x1a0); - LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MOVS, OP_MOV, 0x1b0); - LOGICAL_DATA_OPCODE (OP_BIC, OP_BIC, 0x1c0); - LOGICAL_DATA_OPCODE (OP_BICS, OP_BIC, 0x1d0); - LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MVN, OP_MVN, 0x1e0); - LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MVNS, OP_MVN, 0x1f0); -#ifdef BKPT_SUPPORT - case 0x127: - case 0x7ff: // for GDB support - extern void (*dbgSignal)(int,int); - reg[15].I -= 4; - armNextPC -= 4; - dbgSignal(5, (opcode & 0x0f)|((opcode>>4) & 0xfff0)); - return; -#endif - case 0x320: - case 0x321: - case 0x322: - case 0x323: - case 0x324: - case 0x325: - case 0x326: - case 0x327: - case 0x328: - case 0x329: - case 0x32a: - case 0x32b: - case 0x32c: - case 0x32d: - case 0x32e: - case 0x32f: - { - // MSR CPSR_fields, # - CPUUpdateCPSR(); - u32 value = opcode & 0xFF; - int shift = (opcode & 0xF00) >> 7; - if(shift) - { - ROR_IMM_MSR; - } - u32 newValue = reg[16].I; - if(armMode > 0x10) - { - if(opcode & 0x00010000) - newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF); - if(opcode & 0x00020000) - newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00); - if(opcode & 0x00040000) - newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000); - } - if(opcode & 0x00080000) - newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000); - - newValue |= 0x10; - - CPUSwitchMode(newValue & 0x1f, false); - reg[16].I = newValue; - CPUUpdateFlags(); - } - break; - case 0x360: - case 0x361: - case 0x362: - case 0x363: - case 0x364: - case 0x365: - case 0x366: - case 0x367: - case 0x368: - case 0x369: - case 0x36a: - case 0x36b: - case 0x36c: - case 0x36d: - case 0x36e: - case 0x36f: - { - // MSR SPSR_fields, # - if(armMode > 0x10 && armMode < 0x1f) - { - u32 value = opcode & 0xFF; - int shift = (opcode & 0xF00) >> 7; - if(shift) - { - ROR_IMM_MSR; - } - if(opcode & 0x00010000) - reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF); - if(opcode & 0x00020000) - reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00); - if(opcode & 0x00040000) - reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000); - if(opcode & 0x00080000) - reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000); - } - } - break; - CASE_16(0x400) - // T versions shouldn't be different on GBA - CASE_16(0x420) - { - // STR Rd, [Rn], -# - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteMemory(address, reg[dest].I); - reg[base].I = address - offset; - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - CASE_16(0x480) - // T versions shouldn't be different on GBA - CASE_16(0x4a0) - { - // STR Rd, [Rn], # - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteMemory(address, reg[dest].I); - reg[base].I = address + offset; - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - CASE_16(0x500) - { - // STR Rd, [Rn, -#] - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - CASE_16(0x520) - { - // STR Rd, [Rn, -#]! - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[base].I = address; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - CASE_16(0x580) - { - // STR Rd, [Rn, #] - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - CASE_16(0x5a0) - { - // STR Rd, [Rn, #]! - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[base].I = address; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - CASE_16(0x410) - { - // LDR Rd, [Rn], -# - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I -= offset; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - CASE_16(0x430) - { - // LDRT Rd, [Rn], -# - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I -= offset; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - } - break; - CASE_16(0x490) - { - // LDR Rd, [Rn], # - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I += offset; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - CASE_16(0x4b0) - { - // LDRT Rd, [Rn], # - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I += offset; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - } - break; - CASE_16(0x510) - { - // LDR Rd, [Rn, -#] - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadMemory(address); - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - CASE_16(0x530) - { - // LDR Rd, [Rn, -#]! - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - CASE_16(0x590) - { - // LDR Rd, [Rn, #] - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadMemory(address); - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - CASE_16(0x5b0) - { - // LDR Rd, [Rn, #]! - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - CASE_16(0x440) - // T versions shouldn't be different on GBA - CASE_16(0x460) - { - // STRB Rd, [Rn], -# - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteByte(address, reg[dest].B.B0); - reg[base].I = address - offset; - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - CASE_16(0x4c0) - // T versions shouldn't be different on GBA - CASE_16(0x4e0) - // STRB Rd, [Rn], # - { - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteByte(address, reg[dest].B.B0); - reg[base].I = address + offset; - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - CASE_16(0x540) - { - // STRB Rd, [Rn, -#] - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - CASE_16(0x560) - { - // STRB Rd, [Rn, -#]! - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[base].I = address; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - CASE_16(0x5c0) - { - // STRB Rd, [Rn, #] - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - CASE_16(0x5e0) - { - // STRB Rd, [Rn, #]! - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[base].I = address; - CPUWriteByte(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - CASE_16(0x450) - // T versions shouldn't be different - CASE_16(0x470) - { - // LDRB Rd, [Rn], -# - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I -= offset; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - CASE_16(0x4d0) - CASE_16(0x4f0) // T versions should not be different - { - // LDRB Rd, [Rn], # - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I += offset; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - CASE_16(0x550) - { - // LDRB Rd, [Rn, -#] - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadByte(address); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - CASE_16(0x570) - { - // LDRB Rd, [Rn, -#]! - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - CASE_16(0x5d0) - { - // LDRB Rd, [Rn, #] - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadByte(address); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - CASE_16(0x5f0) - { - // LDRB Rd, [Rn, #]! - int offset = opcode & 0xFFF; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x600: - case 0x608: - // T versions are the same - case 0x620: - case 0x628: - { - // STR Rd, [Rn], -Rm, LSL # - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteMemory(address, reg[dest].I); - reg[base].I = address - offset; - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x602: - case 0x60a: - // T versions are the same - case 0x622: - case 0x62a: - { - // STR Rd, [Rn], -Rm, LSR # - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteMemory(address, reg[dest].I); - reg[base].I = address - offset; - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x604: - case 0x60c: - // T versions are the same - case 0x624: - case 0x62c: - { - // STR Rd, [Rn], -Rm, ASR # - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteMemory(address, reg[dest].I); - reg[base].I = address - offset; - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x606: - case 0x60e: - // T versions are the same - case 0x626: - case 0x62e: - { - // STR Rd, [Rn], -Rm, ROR # - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteMemory(address, reg[dest].I); - reg[base].I = address - value; - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x680: - case 0x688: - // T versions are the same - case 0x6a0: - case 0x6a8: - { - // STR Rd, [Rn], Rm, LSL # - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteMemory(address, reg[dest].I); - reg[base].I = address + offset; - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x682: - case 0x68a: - // T versions are the same - case 0x6a2: - case 0x6aa: - { - // STR Rd, [Rn], Rm, LSR # - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteMemory(address, reg[dest].I); - reg[base].I = address + offset; - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x684: - case 0x68c: - // T versions are the same - case 0x6a4: - case 0x6ac: - { - // STR Rd, [Rn], Rm, ASR # - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteMemory(address, reg[dest].I); - reg[base].I = address + offset; - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x686: - case 0x68e: - // T versions are the same - case 0x6a6: - case 0x6ae: - { - // STR Rd, [Rn], Rm, ROR # - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteMemory(address, reg[dest].I); - reg[base].I = address + value; - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x700: - case 0x708: - { - // STR Rd, [Rn, -Rm, LSL #] - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x702: - case 0x70a: - { - // STR Rd, [Rn, -Rm, LSR #] - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x704: - case 0x70c: - { - // STR Rd, [Rn, -Rm, ASR #] - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x706: - case 0x70e: - { - // STR Rd, [Rn, -Rm, ROR #] - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - value; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x720: - case 0x728: - { - // STR Rd, [Rn, -Rm, LSL #]! - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[base].I = address; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x722: - case 0x72a: - { - // STR Rd, [Rn, -Rm, LSR #]! - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[base].I = address; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x724: - case 0x72c: - { - // STR Rd, [Rn, -Rm, ASR #]! - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[base].I = address; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x726: - case 0x72e: - { - // STR Rd, [Rn, -Rm, ROR #]! - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - value; - reg[base].I = address; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x780: - case 0x788: - { - // STR Rd, [Rn, Rm, LSL #] - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x782: - case 0x78a: - { - // STR Rd, [Rn, Rm, LSR #] - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x784: - case 0x78c: - { - // STR Rd, [Rn, Rm, ASR #] - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x786: - case 0x78e: - { - // STR Rd, [Rn, Rm, ROR #] - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + value; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x7a0: - case 0x7a8: - { - // STR Rd, [Rn, Rm, LSL #]! - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[base].I = address; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x7a2: - case 0x7aa: - { - // STR Rd, [Rn, Rm, LSR #]! - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[base].I = address; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x7a4: - case 0x7ac: - { - // STR Rd, [Rn, Rm, ASR #]! - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[base].I = address; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x7a6: - case 0x7ae: - { - // STR Rd, [Rn, Rm, ROR #]! - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + value; - reg[base].I = address; - CPUWriteMemory(address, reg[dest].I); - clockTicks += 2 + CPUUpdateTicksAccess32(address); - } - break; - case 0x610: - case 0x618: - // T versions are the same - case 0x630: - case 0x638: - { - // LDR Rd, [Rn], -Rm, LSL # - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address - offset; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x612: - case 0x61a: - // T versions are the same - case 0x632: - case 0x63a: - { - // LDR Rd, [Rn], -Rm, LSR # - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address - offset; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x614: - case 0x61c: - // T versions are the same - case 0x634: - case 0x63c: - { - // LDR Rd, [Rn], -Rm, ASR # - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address - offset; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x616: - case 0x61e: - // T versions are the same - case 0x636: - case 0x63e: - { - // LDR Rd, [Rn], -Rm, ROR # - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address - value; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x690: - case 0x698: - // T versions are the same - case 0x6b0: - case 0x6b8: - { - // LDR Rd, [Rn], Rm, LSL # - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address + offset; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x692: - case 0x69a: - // T versions are the same - case 0x6b2: - case 0x6ba: - { - // LDR Rd, [Rn], Rm, LSR # - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address + offset; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x694: - case 0x69c: - // T versions are the same - case 0x6b4: - case 0x6bc: - { - // LDR Rd, [Rn], Rm, ASR # - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address + offset; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x696: - case 0x69e: - // T versions are the same - case 0x6b6: - case 0x6be: - { - // LDR Rd, [Rn], Rm, ROR # - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address + value; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x710: - case 0x718: - { - // LDR Rd, [Rn, -Rm, LSL #] - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadMemory(address); - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x712: - case 0x71a: - { - // LDR Rd, [Rn, -Rm, LSR #] - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadMemory(address); - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x714: - case 0x71c: - { - // LDR Rd, [Rn, -Rm, ASR #] - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadMemory(address); - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x716: - case 0x71e: - { - // LDR Rd, [Rn, -Rm, ROR #] - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - value; - reg[dest].I = CPUReadMemory(address); - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x730: - case 0x738: - { - // LDR Rd, [Rn, -Rm, LSL #]! - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x732: - case 0x73a: - { - // LDR Rd, [Rn, -Rm, LSR #]! - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x734: - case 0x73c: - { - // LDR Rd, [Rn, -Rm, ASR #]! - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x736: - case 0x73e: - { - // LDR Rd, [Rn, -Rm, ROR #]! - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - value; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x790: - case 0x798: - { - // LDR Rd, [Rn, Rm, LSL #] - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadMemory(address); - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x792: - case 0x79a: - { - // LDR Rd, [Rn, Rm, LSR #] - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadMemory(address); - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x794: - case 0x79c: - { - // LDR Rd, [Rn, Rm, ASR #] - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadMemory(address); - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x796: - case 0x79e: - { - // LDR Rd, [Rn, Rm, ROR #] - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + value; - reg[dest].I = CPUReadMemory(address); - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x7b0: - case 0x7b8: - { - // LDR Rd, [Rn, Rm, LSL #]! - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x7b2: - case 0x7ba: - { - // LDR Rd, [Rn, Rm, LSR #]! - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x7b4: - case 0x7bc: - { - // LDR Rd, [Rn, Rm, ASR #]! - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x7b6: - case 0x7be: - { - // LDR Rd, [Rn, Rm, ROR #]! - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + value; - reg[dest].I = CPUReadMemory(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess32(address); - if(dest == 15) - { - clockTicks += 2; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - case 0x640: - case 0x648: - // T versions are the same - case 0x660: - case 0x668: - { - // STRB Rd, [Rn], -Rm, LSL # - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteByte(address, reg[dest].B.B0); - reg[base].I = address - offset; - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x642: - case 0x64a: - // T versions are the same - case 0x662: - case 0x66a: - { - // STRB Rd, [Rn], -Rm, LSR # - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteByte(address, reg[dest].B.B0); - reg[base].I = address - offset; - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x644: - case 0x64c: - // T versions are the same - case 0x664: - case 0x66c: - { - // STRB Rd, [Rn], -Rm, ASR # - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteByte(address, reg[dest].B.B0); - reg[base].I = address - offset; - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x646: - case 0x64e: - // T versions are the same - case 0x666: - case 0x66e: - { - // STRB Rd, [Rn], -Rm, ROR # - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteByte(address, reg[dest].B.B0); - reg[base].I = address - value; - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x6c0: - case 0x6c8: - // T versions are the same - case 0x6e0: - case 0x6e8: - { - // STRB Rd, [Rn], Rm, LSL # - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteByte(address, reg[dest].B.B0); - reg[base].I = address + offset; - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x6c2: - case 0x6ca: - // T versions are the same - case 0x6e2: - case 0x6ea: - { - // STRB Rd, [Rn], Rm, LSR # - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteByte(address, reg[dest].B.B0); - reg[base].I = address + offset; - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x6c4: - case 0x6cc: - // T versions are the same - case 0x6e4: - case 0x6ec: - { - // STR Rd, [Rn], Rm, ASR # - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteByte(address, reg[dest].B.B0); - reg[base].I = address + offset; - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x6c6: - case 0x6ce: - // T versions are the same - case 0x6e6: - case 0x6ee: - { - // STRB Rd, [Rn], Rm, ROR # - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - CPUWriteByte(address, reg[dest].B.B0); - reg[base].I = address + value; - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x740: - case 0x748: - { - // STRB Rd, [Rn, -Rm, LSL #] - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x742: - case 0x74a: - { - // STRB Rd, [Rn, -Rm, LSR #] - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x744: - case 0x74c: - { - // STRB Rd, [Rn, -Rm, ASR #] - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x746: - case 0x74e: - { - // STRB Rd, [Rn, -Rm, ROR #] - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - value; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x760: - case 0x768: - { - // STRB Rd, [Rn, -Rm, LSL #]! - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[base].I = address; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x762: - case 0x76a: - { - // STRB Rd, [Rn, -Rm, LSR #]! - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[base].I = address; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x764: - case 0x76c: - { - // STRB Rd, [Rn, -Rm, ASR #]! - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[base].I = address; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x766: - case 0x76e: - { - // STRB Rd, [Rn, -Rm, ROR #]! - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - value; - reg[base].I = address; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7c0: - case 0x7c8: - { - // STRB Rd, [Rn, Rm, LSL #] - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7c2: - case 0x7ca: - { - // STRB Rd, [Rn, Rm, LSR #] - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7c4: - case 0x7cc: - { - // STRB Rd, [Rn, Rm, ASR #] - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7c6: - case 0x7ce: - { - // STRB Rd, [Rn, Rm, ROR #] - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + value; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7e0: - case 0x7e8: - { - // STRB Rd, [Rn, Rm, LSL #]! - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[base].I = address; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7e2: - case 0x7ea: - { - // STRB Rd, [Rn, Rm, LSR #]! - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[base].I = address; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7e4: - case 0x7ec: - { - // STRB Rd, [Rn, Rm, ASR #]! - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[base].I = address; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7e6: - case 0x7ee: - { - // STRB Rd, [Rn, Rm, ROR #]! - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + value; - reg[base].I = address; - CPUWriteByte(address, reg[dest].B.B0); - clockTicks += 2 + CPUUpdateTicksAccess16(address); - } - break; - case 0x650: - case 0x658: - // T versions are the same - case 0x670: - case 0x678: - { - // LDRB Rd, [Rn], -Rm, LSL # - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address - offset; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x652: - case 0x65a: - // T versions are the same - case 0x672: - case 0x67a: - { - // LDRB Rd, [Rn], -Rm, LSR # - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address - offset; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x654: - case 0x65c: - // T versions are the same - case 0x674: - case 0x67c: - { - // LDRB Rd, [Rn], -Rm, ASR # - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address - offset; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x656: - case 0x65e: - // T versions are the same - case 0x676: - case 0x67e: - { - // LDRB Rd, [Rn], -Rm, ROR # - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address - value; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x6d0: - case 0x6d8: - // T versions are the same - case 0x6f0: - case 0x6f8: - { - // LDRB Rd, [Rn], Rm, LSL # - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address + offset; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x6d2: - case 0x6da: - // T versions are the same - case 0x6f2: - case 0x6fa: - { - // LDRB Rd, [Rn], Rm, LSR # - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address + offset; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x6d4: - case 0x6dc: - // T versions are the same - case 0x6f4: - case 0x6fc: - { - // LDRB Rd, [Rn], Rm, ASR # - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address + offset; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x6d6: - case 0x6de: - // T versions are the same - case 0x6f6: - case 0x6fe: - { - // LDRB Rd, [Rn], Rm, ROR # - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address + value; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x750: - case 0x758: - { - // LDRB Rd, [Rn, -Rm, LSL #] - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadByte(address); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x752: - case 0x75a: - { - // LDRB Rd, [Rn, -Rm, LSR #] - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadByte(address); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x754: - case 0x75c: - { - // LDRB Rd, [Rn, -Rm, ASR #] - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadByte(address); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x756: - case 0x75e: - { - // LDRB Rd, [Rn, -Rm, ROR #] - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - value; - reg[dest].I = CPUReadByte(address); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x770: - case 0x778: - { - // LDRB Rd, [Rn, -Rm, LSL #]! - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x772: - case 0x77a: - { - // LDRB Rd, [Rn, -Rm, LSR #]! - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x774: - case 0x77c: - { - // LDRB Rd, [Rn, -Rm, ASR #]! - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - offset; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x776: - case 0x77e: - { - // LDRB Rd, [Rn, -Rm, ROR #]! - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I - value; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7d0: - case 0x7d8: - { - // LDRB Rd, [Rn, Rm, LSL #] - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadByte(address); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7d2: - case 0x7da: - { - // LDRB Rd, [Rn, Rm, LSR #] - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadByte(address); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7d4: - case 0x7dc: - { - // LDRB Rd, [Rn, Rm, ASR #] - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadByte(address); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7d6: - case 0x7de: - { - // LDRB Rd, [Rn, Rm, ROR #] - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + value; - reg[dest].I = CPUReadByte(address); - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7f0: - case 0x7f8: - { - // LDRB Rd, [Rn, Rm, LSL #]! - int offset = reg[opcode & 15].I << ((opcode>>7)& 31); - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7f2: - case 0x7fa: - { - // LDRB Rd, [Rn, Rm, LSR #]! - int shift = (opcode >> 7) & 31; - int offset = shift ? reg[opcode & 15].I >> shift : 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7f4: - case 0x7fc: - { - // LDRB Rd, [Rn, Rm, ASR #]! - int shift = (opcode >> 7) & 31; - int offset; - if(shift) - offset = (int)((s32)reg[opcode & 15].I >> shift); - else if(reg[opcode & 15].I & 0x80000000) - offset = 0xFFFFFFFF; - else - offset = 0; - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + offset; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; - case 0x7f6: - case 0x7fe: - { - // LDRB Rd, [Rn, Rm, ROR #]! - int shift = (opcode >> 7) & 31; - u32 value = reg[opcode & 15].I; - if(shift) - { - ROR_VALUE; - } - else - { - RCR_VALUE; - } - int dest = (opcode >> 12) & 15; - int base = (opcode >> 16) & 15; - u32 address = reg[base].I + value; - reg[dest].I = CPUReadByte(address); - if(dest != base) - reg[base].I = address; - clockTicks += 3 + CPUUpdateTicksAccess16(address); - } - break; -#define STMW_REG(val,num) \ -if(opcode & (val)) {\ -CPUWriteMemory(address, reg[(num)].I);\ -if(!offset) {\ -reg[base].I = temp;\ -clockTicks += 1 + CPUUpdateTicksAccess32(address);\ -offset = 1;\ -} else {\ -clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);\ -}\ -address += 4;\ -} -#define STM_REG(val,num) \ -if(opcode & (val)) {\ -CPUWriteMemory(address, reg[(num)].I);\ -if(!offset) {\ -clockTicks += 1 + CPUUpdateTicksAccess32(address);\ -offset = 1;\ -} else {\ -clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);\ -}\ -address += 4;\ -} - - CASE_16(0x800) - // STMDA Rn, {Rlist} - { - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - STM_REG(1, 0); - STM_REG(2, 1); - STM_REG(4, 2); - STM_REG(8, 3); - STM_REG(16, 4); - STM_REG(32, 5); - STM_REG(64, 6); - STM_REG(128, 7); - STM_REG(256, 8); - STM_REG(512, 9); - STM_REG(1024, 10); - STM_REG(2048, 11); - STM_REG(4096, 12); - STM_REG(8192, 13); - STM_REG(16384, 14); - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - clockTicks += 1 + CPUUpdateTicksAccess32(address); - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - } - } - break; - CASE_16(0x820) - { - // STMDA Rn!, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp+4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - - STMW_REG(1, 0); - STMW_REG(2, 1); - STMW_REG(4, 2); - STMW_REG(8, 3); - STMW_REG(16, 4); - STMW_REG(32, 5); - STMW_REG(64, 6); - STMW_REG(128, 7); - STMW_REG(256, 8); - STMW_REG(512, 9); - STMW_REG(1024, 10); - STMW_REG(2048, 11); - STMW_REG(4096, 12); - STMW_REG(8192, 13); - STMW_REG(16384, 14); - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - clockTicks += 1 + CPUUpdateTicksAccess32(address); - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - reg[base].I = temp; - } - } - break; - CASE_16(0x840) - { - // STMDA Rn, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp+4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - - STM_REG(1, 0); - STM_REG(2, 1); - STM_REG(4, 2); - STM_REG(8, 3); - STM_REG(16, 4); - STM_REG(32, 5); - STM_REG(64, 6); - STM_REG(128, 7); - - if(armMode == 0x11) - { - STM_REG(256, R8_FIQ); - STM_REG(512, R9_FIQ); - STM_REG(1024, R10_FIQ); - STM_REG(2048, R11_FIQ); - STM_REG(4096, R12_FIQ); - } - else - { - STM_REG(256, 8); - STM_REG(512, 9); - STM_REG(1024, 10); - STM_REG(2048, 11); - STM_REG(4096, 12); - } - - if(armMode != 0x10 && armMode != 0x1f) - { - STM_REG(8192, R13_USR); - STM_REG(16384, R14_USR); - } - else - { - STM_REG(8192, 13); - STM_REG(16384, 14); - } - - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - clockTicks += 1 + CPUUpdateTicksAccess32(address); - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - } - } - break; - CASE_16(0x860) - { - // STMDA Rn!, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp+4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - - STMW_REG(1, 0); - STMW_REG(2, 1); - STMW_REG(4, 2); - STMW_REG(8, 3); - STMW_REG(16, 4); - STMW_REG(32, 5); - STMW_REG(64, 6); - STMW_REG(128, 7); - - if(armMode == 0x11) - { - STMW_REG(256, R8_FIQ); - STMW_REG(512, R9_FIQ); - STMW_REG(1024, R10_FIQ); - STMW_REG(2048, R11_FIQ); - STMW_REG(4096, R12_FIQ); - } - else - { - STMW_REG(256, 8); - STMW_REG(512, 9); - STMW_REG(1024, 10); - STMW_REG(2048, 11); - STMW_REG(4096, 12); - } - - if(armMode != 0x10 && armMode != 0x1f) - { - STMW_REG(8192, R13_USR); - STMW_REG(16384, R14_USR); - } - else - { - STMW_REG(8192, 13); - STMW_REG(16384, 14); - } - - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - clockTicks += 1 + CPUUpdateTicksAccess32(address); - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - reg[base].I = temp; - } - } - break; - - CASE_16(0x880) - { - // STMIA Rn, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 address = reg[base].I & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - STM_REG(1, 0); - STM_REG(2, 1); - STM_REG(4, 2); - STM_REG(8, 3); - STM_REG(16, 4); - STM_REG(32, 5); - STM_REG(64, 6); - STM_REG(128, 7); - STM_REG(256, 8); - STM_REG(512, 9); - STM_REG(1024, 10); - STM_REG(2048, 11); - STM_REG(4096, 12); - STM_REG(8192, 13); - STM_REG(16384, 14); - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - clockTicks += 1 + CPUUpdateTicksAccess32(address); - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - } - } - break; - CASE_16(0x8a0) - { - // STMIA Rn!, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 address = reg[base].I & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - u32 temp = reg[base].I + 4*(cpuBitsSet[opcode & 0xFF] + - cpuBitsSet[(opcode >> 8) & 255]); - STMW_REG(1, 0); - STMW_REG(2, 1); - STMW_REG(4, 2); - STMW_REG(8, 3); - STMW_REG(16, 4); - STMW_REG(32, 5); - STMW_REG(64, 6); - STMW_REG(128, 7); - STMW_REG(256, 8); - STMW_REG(512, 9); - STMW_REG(1024, 10); - STMW_REG(2048, 11); - STMW_REG(4096, 12); - STMW_REG(8192, 13); - STMW_REG(16384, 14); - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - { - reg[base].I = temp; - clockTicks += 1 + CPUUpdateTicksAccess32(address); - } - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - } - } - break; - CASE_16(0x8c0) - { - // STMIA Rn, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 address = reg[base].I & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - STM_REG(1, 0); - STM_REG(2, 1); - STM_REG(4, 2); - STM_REG(8, 3); - STM_REG(16, 4); - STM_REG(32, 5); - STM_REG(64, 6); - STM_REG(128, 7); - if(armMode == 0x11) - { - STM_REG(256, R8_FIQ); - STM_REG(512, R9_FIQ); - STM_REG(1024, R10_FIQ); - STM_REG(2048, R11_FIQ); - STM_REG(4096, R12_FIQ); - } - else - { - STM_REG(256, 8); - STM_REG(512, 9); - STM_REG(1024, 10); - STM_REG(2048, 11); - STM_REG(4096, 12); - } - if(armMode != 0x10 && armMode != 0x1f) - { - STM_REG(8192, R13_USR); - STM_REG(16384, R14_USR); - } - else - { - STM_REG(8192, 13); - STM_REG(16384, 14); - } - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - clockTicks += 1 + CPUUpdateTicksAccess32(address); - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - } - } - break; - CASE_16(0x8e0) - { - // STMIA Rn!, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 address = reg[base].I & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - u32 temp = reg[base].I + 4*(cpuBitsSet[opcode & 0xFF] + - cpuBitsSet[(opcode >> 8) & 255]); - STMW_REG(1, 0); - STMW_REG(2, 1); - STMW_REG(4, 2); - STMW_REG(8, 3); - STMW_REG(16, 4); - STMW_REG(32, 5); - STMW_REG(64, 6); - STMW_REG(128, 7); - if(armMode == 0x11) - { - STMW_REG(256, R8_FIQ); - STMW_REG(512, R9_FIQ); - STMW_REG(1024, R10_FIQ); - STMW_REG(2048, R11_FIQ); - STMW_REG(4096, R12_FIQ); - } - else - { - STMW_REG(256, 8); - STMW_REG(512, 9); - STMW_REG(1024, 10); - STMW_REG(2048, 11); - STMW_REG(4096, 12); - } - if(armMode != 0x10 && armMode != 0x1f) - { - STMW_REG(8192, R13_USR); - STMW_REG(16384, R14_USR); - } - else - { - STMW_REG(8192, 13); - STMW_REG(16384, 14); - } - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - { - reg[base].I = temp; - clockTicks += 1 + CPUUpdateTicksAccess32(address); - } - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - } - } - break; - - CASE_16(0x900) - { - // STMDB Rn, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - STM_REG(1, 0); - STM_REG(2, 1); - STM_REG(4, 2); - STM_REG(8, 3); - STM_REG(16, 4); - STM_REG(32, 5); - STM_REG(64, 6); - STM_REG(128, 7); - STM_REG(256, 8); - STM_REG(512, 9); - STM_REG(1024, 10); - STM_REG(2048, 11); - STM_REG(4096, 12); - STM_REG(8192, 13); - STM_REG(16384, 14); - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - clockTicks += 1 + CPUUpdateTicksAccess32(address); - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - } - } - break; - CASE_16(0x920) - { - // STMDB Rn!, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - - STMW_REG(1, 0); - STMW_REG(2, 1); - STMW_REG(4, 2); - STMW_REG(8, 3); - STMW_REG(16, 4); - STMW_REG(32, 5); - STMW_REG(64, 6); - STMW_REG(128, 7); - STMW_REG(256, 8); - STMW_REG(512, 9); - STMW_REG(1024, 10); - STMW_REG(2048, 11); - STMW_REG(4096, 12); - STMW_REG(8192, 13); - STMW_REG(16384, 14); - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - clockTicks += 1 + CPUUpdateTicksAccess32(address); - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - reg[base].I = temp; - } - } - break; - CASE_16(0x940) - { - // STMDB Rn, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - - STM_REG(1, 0); - STM_REG(2, 1); - STM_REG(4, 2); - STM_REG(8, 3); - STM_REG(16, 4); - STM_REG(32, 5); - STM_REG(64, 6); - STM_REG(128, 7); - - if(armMode == 0x11) - { - STM_REG(256, R8_FIQ); - STM_REG(512, R9_FIQ); - STM_REG(1024, R10_FIQ); - STM_REG(2048, R11_FIQ); - STM_REG(4096, R12_FIQ); - } - else - { - STM_REG(256, 8); - STM_REG(512, 9); - STM_REG(1024, 10); - STM_REG(2048, 11); - STM_REG(4096, 12); - } - - if(armMode != 0x10 && armMode != 0x1f) - { - STM_REG(8192, R13_USR); - STM_REG(16384, R14_USR); - } - else - { - STM_REG(8192, 13); - STM_REG(16384, 14); - } - - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - clockTicks += 1 + CPUUpdateTicksAccess32(address); - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - } - } - break; - CASE_16(0x960) - { - // STMDB Rn!, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - - STMW_REG(1, 0); - STMW_REG(2, 1); - STMW_REG(4, 2); - STMW_REG(8, 3); - STMW_REG(16, 4); - STMW_REG(32, 5); - STMW_REG(64, 6); - STMW_REG(128, 7); - - if(armMode == 0x11) - { - STMW_REG(256, R8_FIQ); - STMW_REG(512, R9_FIQ); - STMW_REG(1024, R10_FIQ); - STMW_REG(2048, R11_FIQ); - STMW_REG(4096, R12_FIQ); - } - else - { - STMW_REG(256, 8); - STMW_REG(512, 9); - STMW_REG(1024, 10); - STMW_REG(2048, 11); - STMW_REG(4096, 12); - } - - if(armMode != 0x10 && armMode != 0x1f) - { - STMW_REG(8192, R13_USR); - STMW_REG(16384, R14_USR); - } - else - { - STMW_REG(8192, 13); - STMW_REG(16384, 14); - } - - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - clockTicks += 1 + CPUUpdateTicksAccess32(address); - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - reg[base].I = temp; - } - } - break; - - CASE_16(0x980) - // STMIB Rn, {Rlist} - { - int base = (opcode & 0x000F0000) >> 16; - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - STM_REG(1, 0); - STM_REG(2, 1); - STM_REG(4, 2); - STM_REG(8, 3); - STM_REG(16, 4); - STM_REG(32, 5); - STM_REG(64, 6); - STM_REG(128, 7); - STM_REG(256, 8); - STM_REG(512, 9); - STM_REG(1024, 10); - STM_REG(2048, 11); - STM_REG(4096, 12); - STM_REG(8192, 13); - STM_REG(16384, 14); - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - clockTicks += 1 + CPUUpdateTicksAccess32(address); - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - } - } - break; - CASE_16(0x9a0) - { - // STMIB Rn!, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - u32 temp = reg[base].I + 4*(cpuBitsSet[opcode & 0xFF] + - cpuBitsSet[(opcode >> 8) & 255]); - STMW_REG(1, 0); - STMW_REG(2, 1); - STMW_REG(4, 2); - STMW_REG(8, 3); - STMW_REG(16, 4); - STMW_REG(32, 5); - STMW_REG(64, 6); - STMW_REG(128, 7); - STMW_REG(256, 8); - STMW_REG(512, 9); - STMW_REG(1024, 10); - STMW_REG(2048, 11); - STMW_REG(4096, 12); - STMW_REG(8192, 13); - STMW_REG(16384, 14); - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - { - reg[base].I = temp; - clockTicks += 1 + CPUUpdateTicksAccess32(address); - } - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - } - } - break; - CASE_16(0x9c0) - { - // STMIB Rn, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - STM_REG(1, 0); - STM_REG(2, 1); - STM_REG(4, 2); - STM_REG(8, 3); - STM_REG(16, 4); - STM_REG(32, 5); - STM_REG(64, 6); - STM_REG(128, 7); - if(armMode == 0x11) - { - STM_REG(256, R8_FIQ); - STM_REG(512, R9_FIQ); - STM_REG(1024, R10_FIQ); - STM_REG(2048, R11_FIQ); - STM_REG(4096, R12_FIQ); - } - else - { - STM_REG(256, 8); - STM_REG(512, 9); - STM_REG(1024, 10); - STM_REG(2048, 11); - STM_REG(4096, 12); - } - if(armMode != 0x10 && armMode != 0x1f) - { - STM_REG(8192, R13_USR); - STM_REG(16384, R14_USR); - } - else - { - STM_REG(8192, 13); - STM_REG(16384, 14); - } - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - clockTicks += 1 + CPUUpdateTicksAccess32(address); - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - } - } - break; - CASE_16(0x9e0) - { - // STMIB Rn!, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - u32 temp = reg[base].I + 4*(cpuBitsSet[opcode & 0xFF] + - cpuBitsSet[(opcode >> 8) & 255]); - STMW_REG(1, 0); - STMW_REG(2, 1); - STMW_REG(4, 2); - STMW_REG(8, 3); - STMW_REG(16, 4); - STMW_REG(32, 5); - STMW_REG(64, 6); - STMW_REG(128, 7); - if(armMode == 0x11) - { - STMW_REG(256, R8_FIQ); - STMW_REG(512, R9_FIQ); - STMW_REG(1024, R10_FIQ); - STMW_REG(2048, R11_FIQ); - STMW_REG(4096, R12_FIQ); - } - else - { - STMW_REG(256, 8); - STMW_REG(512, 9); - STMW_REG(1024, 10); - STMW_REG(2048, 11); - STMW_REG(4096, 12); - } - if(armMode != 0x10 && armMode != 0x1f) - { - STMW_REG(8192, R13_USR); - STMW_REG(16384, R14_USR); - } - else - { - STMW_REG(8192, 13); - STMW_REG(16384, 14); - } - if(opcode & 32768) - { - CPUWriteMemory(address, reg[15].I+4); - if(!offset) - { - reg[base].I = temp; - clockTicks += 1 + CPUUpdateTicksAccess32(address); - } - else - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); - } - } - break; - -#define LDM_REG(val,num) \ -if(opcode & (val)) {\ -reg[(num)].I = CPUReadMemory(address);\ -if(offset)\ -clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);\ -else {\ -clockTicks += 1 + CPUUpdateTicksAccess32(address);\ -offset = 1;\ -}\ -address += 4;\ -} - - CASE_16(0x810) - { - // LDMDA Rn, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - if(opcode & 32768) - { - reg[15].I = CPUReadMemory(address); - if (!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - CASE_16(0x830) - { - // LDMDA Rn!, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - if(opcode & 32768) - { - reg[15].I = CPUReadMemory(address); - if (!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - armNextPC = reg[15].I; - reg[15].I += 4; - } - if(!(opcode & (1 << base))) - reg[base].I = temp; - } - break; - CASE_16(0x850) - { - // LDMDA Rn, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - if(opcode & 0x8000) - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - - reg[15].I = CPUReadMemory(address); - if (!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - - CPUSwitchMode(reg[17].I & 0x1f, false); - if(armState) - { - armNextPC = reg[15].I & 0xFFFFFFFC; - reg[15].I = armNextPC + 4; - } - else - { - armNextPC = reg[15].I & 0xFFFFFFFE; - reg[15].I = armNextPC + 2; - } - } - else - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - - if(armMode == 0x11) - { - LDM_REG(256, R8_FIQ); - LDM_REG(512, R9_FIQ); - LDM_REG(1024, R10_FIQ); - LDM_REG(2048, R11_FIQ); - LDM_REG(4096, R12_FIQ); - } - else - { - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - } - - if(armMode != 0x10 && armMode != 0x1f) - { - LDM_REG(8192, R13_USR); - LDM_REG(16384, R14_USR); - } - else - { - LDM_REG(8192, 13); - LDM_REG(16384, 14); - } - } - } - break; - CASE_16(0x870) - { - // LDMDA Rn!, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (temp + 4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - if(opcode & 0x8000) - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - - reg[15].I = CPUReadMemory(address); - if(!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - - if(!(opcode & (1 << base))) - reg[base].I = temp; - - CPUSwitchMode(reg[17].I & 0x1f, false); - if(armState) - { - armNextPC = reg[15].I & 0xFFFFFFFC; - reg[15].I = armNextPC + 4; - } - else - { - armNextPC = reg[15].I & 0xFFFFFFFE; - reg[15].I = armNextPC + 2; - } - } - else - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - - if(armMode == 0x11) - { - LDM_REG(256, R8_FIQ); - LDM_REG(512, R9_FIQ); - LDM_REG(1024, R10_FIQ); - LDM_REG(2048, R11_FIQ); - LDM_REG(4096, R12_FIQ); - } - else - { - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - } - - if(armMode != 0x10 && armMode != 0x1f) - { - LDM_REG(8192, R13_USR); - LDM_REG(16384, R14_USR); - } - else - { - LDM_REG(8192, 13); - LDM_REG(16384, 14); - } - - if(!(opcode & (1 << base))) - reg[base].I = temp; - } - } - break; - - CASE_16(0x890) - { - // LDMIA Rn, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 address = reg[base].I & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - if(opcode & 32768) - { - reg[15].I = CPUReadMemory(address); - if (!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - CASE_16(0x8b0) - { - // LDMIA Rn!, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I + - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = reg[base].I & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - if(opcode & 32768) - { - reg[15].I = CPUReadMemory(address); - if (!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - armNextPC = reg[15].I; - reg[15].I += 4; - } - if(!(opcode & (1 << base))) - reg[base].I = temp; - } - break; - CASE_16(0x8d0) - { - // LDMIA Rn, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 address = reg[base].I & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - if(opcode & 0x8000) - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - - reg[15].I = CPUReadMemory(address); - if (!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - - CPUSwitchMode(reg[17].I & 0x1f, false); - if(armState) - { - armNextPC = reg[15].I & 0xFFFFFFFC; - reg[15].I = armNextPC + 4; - } - else - { - armNextPC = reg[15].I & 0xFFFFFFFE; - reg[15].I = armNextPC + 2; - } - } - else - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - - if(armMode == 0x11) - { - LDM_REG(256, R8_FIQ); - LDM_REG(512, R9_FIQ); - LDM_REG(1024, R10_FIQ); - LDM_REG(2048, R11_FIQ); - LDM_REG(4096, R12_FIQ); - } - else - { - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - } - - if(armMode != 0x10 && armMode != 0x1f) - { - LDM_REG(8192, R13_USR); - LDM_REG(16384, R14_USR); - } - else - { - LDM_REG(8192, 13); - LDM_REG(16384, 14); - } - } - } - break; - CASE_16(0x8f0) - { - // LDMIA Rn!, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I + - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = reg[base].I & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - if(opcode & 0x8000) - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - - reg[15].I = CPUReadMemory(address); - if(!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - - if(!(opcode & (1 << base))) - reg[base].I = temp; - - CPUSwitchMode(reg[17].I & 0x1f, false); - if(armState) - { - armNextPC = reg[15].I & 0xFFFFFFFC; - reg[15].I = armNextPC + 4; - } - else - { - armNextPC = reg[15].I & 0xFFFFFFFE; - reg[15].I = armNextPC + 2; - } - } - else - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - - if(armMode == 0x11) - { - LDM_REG(256, R8_FIQ); - LDM_REG(512, R9_FIQ); - LDM_REG(1024, R10_FIQ); - LDM_REG(2048, R11_FIQ); - LDM_REG(4096, R12_FIQ); - } - else - { - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - } - - if(armMode != 0x10 && armMode != 0x1f) - { - LDM_REG(8192, R13_USR); - LDM_REG(16384, R14_USR); - } - else - { - LDM_REG(8192, 13); - LDM_REG(16384, 14); - } - - if(!(opcode & (1 << base))) - reg[base].I = temp; - } - } - break; - - CASE_16(0x910) - { - // LDMDB Rn, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - if(opcode & 32768) - { - reg[15].I = CPUReadMemory(address); - if (!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - CASE_16(0x930) - { - // LDMDB Rn!, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - if(opcode & 32768) - { - reg[15].I = CPUReadMemory(address); - if (!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - armNextPC = reg[15].I; - reg[15].I += 4; - } - if(!(opcode & (1 << base))) - reg[base].I = temp; - } - break; - CASE_16(0x950) - { - // LDMDB Rn, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - if(opcode & 0x8000) - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - - reg[15].I = CPUReadMemory(address); - if (!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - - CPUSwitchMode(reg[17].I & 0x1f, false); - if(armState) - { - armNextPC = reg[15].I & 0xFFFFFFFC; - reg[15].I = armNextPC + 4; - } - else - { - armNextPC = reg[15].I & 0xFFFFFFFE; - reg[15].I = armNextPC + 2; - } - } - else - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - - if(armMode == 0x11) - { - LDM_REG(256, R8_FIQ); - LDM_REG(512, R9_FIQ); - LDM_REG(1024, R10_FIQ); - LDM_REG(2048, R11_FIQ); - LDM_REG(4096, R12_FIQ); - } - else - { - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - } - - if(armMode != 0x10 && armMode != 0x1f) - { - LDM_REG(8192, R13_USR); - LDM_REG(16384, R14_USR); - } - else - { - LDM_REG(8192, 13); - LDM_REG(16384, 14); - } - } - } - break; - CASE_16(0x970) - { - // LDMDB Rn!, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I - - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = temp & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - if(opcode & 0x8000) - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - - reg[15].I = CPUReadMemory(address); - if(!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - - if(!(opcode & (1 << base))) - reg[base].I = temp; - - CPUSwitchMode(reg[17].I & 0x1f, false); - if(armState) - { - armNextPC = reg[15].I & 0xFFFFFFFC; - reg[15].I = armNextPC + 4; - } - else - { - armNextPC = reg[15].I & 0xFFFFFFFE; - reg[15].I = armNextPC + 2; - } - } - else - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - - if(armMode == 0x11) - { - LDM_REG(256, R8_FIQ); - LDM_REG(512, R9_FIQ); - LDM_REG(1024, R10_FIQ); - LDM_REG(2048, R11_FIQ); - LDM_REG(4096, R12_FIQ); - } - else - { - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - } - - if(armMode != 0x10 && armMode != 0x1f) - { - LDM_REG(8192, R13_USR); - LDM_REG(16384, R14_USR); - } - else - { - LDM_REG(8192, 13); - LDM_REG(16384, 14); - } - - if(!(opcode & (1 << base))) - reg[base].I = temp; - } - } - break; - - CASE_16(0x990) - { - // LDMIB Rn, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - if(opcode & 32768) - { - reg[15].I = CPUReadMemory(address); - if (!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - armNextPC = reg[15].I; - reg[15].I += 4; - } - } - break; - CASE_16(0x9b0) - { - // LDMIB Rn!, {Rlist} - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I + - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - if(opcode & 32768) - { - reg[15].I = CPUReadMemory(address); - if (!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - armNextPC = reg[15].I; - reg[15].I += 4; - } - if(!(opcode & (1 << base))) - reg[base].I = temp; - } - break; - CASE_16(0x9d0) - { - // LDMIB Rn, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - if(opcode & 0x8000) - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - - reg[15].I = CPUReadMemory(address); - if (!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - - CPUSwitchMode(reg[17].I & 0x1f, false); - if(armState) - { - armNextPC = reg[15].I & 0xFFFFFFFC; - reg[15].I = armNextPC + 4; - } - else - { - armNextPC = reg[15].I & 0xFFFFFFFE; - reg[15].I = armNextPC + 2; - } - } - else - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - - if(armMode == 0x11) - { - LDM_REG(256, R8_FIQ); - LDM_REG(512, R9_FIQ); - LDM_REG(1024, R10_FIQ); - LDM_REG(2048, R11_FIQ); - LDM_REG(4096, R12_FIQ); - } - else - { - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - } - - if(armMode != 0x10 && armMode != 0x1f) - { - LDM_REG(8192, R13_USR); - LDM_REG(16384, R14_USR); - } - else - { - LDM_REG(8192, 13); - LDM_REG(16384, 14); - } - } - } - break; - CASE_16(0x9f0) - { - // LDMIB Rn!, {Rlist}^ - int base = (opcode & 0x000F0000) >> 16; - u32 temp = reg[base].I + - 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]); - u32 address = (reg[base].I+4) & 0xFFFFFFFC; - clockTicks += 2; - int offset = 0; - if(opcode & 0x8000) - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - LDM_REG(8192, 13); - LDM_REG(16384, 14); - - reg[15].I = CPUReadMemory(address); - if(!offset) - clockTicks += 2 + CPUUpdateTicksAccess32(address); - else - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); - - if(!(opcode & (1 << base))) - reg[base].I = temp; - - CPUSwitchMode(reg[17].I & 0x1f, false); - if(armState) - { - armNextPC = reg[15].I & 0xFFFFFFFC; - reg[15].I = armNextPC + 4; - } - else - { - armNextPC = reg[15].I & 0xFFFFFFFE; - reg[15].I = armNextPC + 2; - } - } - else - { - LDM_REG(1, 0); - LDM_REG(2, 1); - LDM_REG(4, 2); - LDM_REG(8, 3); - LDM_REG(16, 4); - LDM_REG(32, 5); - LDM_REG(64, 6); - LDM_REG(128, 7); - - if(armMode == 0x11) - { - LDM_REG(256, R8_FIQ); - LDM_REG(512, R9_FIQ); - LDM_REG(1024, R10_FIQ); - LDM_REG(2048, R11_FIQ); - LDM_REG(4096, R12_FIQ); - } - else - { - LDM_REG(256, 8); - LDM_REG(512, 9); - LDM_REG(1024, 10); - LDM_REG(2048, 11); - LDM_REG(4096, 12); - } - - if(armMode != 0x10 && armMode != 0x1f) - { - LDM_REG(8192, R13_USR); - LDM_REG(16384, R14_USR); - } - else - { - LDM_REG(8192, 13); - LDM_REG(16384, 14); - } - - if(!(opcode & (1 << base))) - reg[base].I = temp; - } - } - break; - CASE_256(0xa00) - { - // B - clockTicks += 3; - int offset = opcode & 0x00FFFFFF; - if(offset & 0x00800000) - { - offset |= 0xFF000000; - } - offset <<= 2; - reg[15].I += offset; - armNextPC = reg[15].I; - reg[15].I += 4; - } - break; - CASE_256(0xb00) - { - // BL - clockTicks += 3; - int offset = opcode & 0x00FFFFFF; - if(offset & 0x00800000) - { - offset |= 0xFF000000; - } - offset <<= 2; - reg[14].I = reg[15].I - 4; - reg[15].I += offset; - armNextPC = reg[15].I; - reg[15].I += 4; - } - break; - CASE_256(0xf00) - // SWI - clockTicks += 3; - CPUSoftwareInterrupt(opcode & 0x00FFFFFF); - break; -#ifdef GP_SUPPORT - case 0xe11: - case 0xe13: - case 0xe15: - case 0xe17: - case 0xe19: - case 0xe1b: - case 0xe1d: - case 0xe1f: - // MRC - break; - case 0xe01: - case 0xe03: - case 0xe05: - case 0xe07: - case 0xe09: - case 0xe0b: - case 0xe0d: - case 0xe0f: - // MRC - break; -#endif - default: -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_UNDEFINED) - log("Undefined ARM instruction %08x at %08x\n", opcode, - armNextPC-4); -#endif - CPUUndefinedException(); - break; - // END - } - } diff --git a/source/vba/armdis.cpp b/source/vba/armdis.cpp index 237373f..dde2b2c 100644 --- a/source/vba/armdis.cpp +++ b/source/vba/armdis.cpp @@ -1,809 +1,742 @@ -// 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. - -/************************************************************************/ -/* Arm/Thumb command set disassembler */ -/************************************************************************/ -#include - -#include "System.h" -#include "Port.h" -#include "GBA.h" -#include "armdis.h" -#include "elf.h" - -struct Opcodes - { - u32 mask; - u32 cval; - char *mnemonic; - }; - -#define debuggerReadMemory(addr) \ - READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) - -#define debuggerReadHalfWord(addr) \ - READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) - -#define debuggerReadByte(addr) \ - map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] - -const char hdig[] = "0123456789abcdef"; - -const char *decVals[16] = - { - "0","1","2","3","4","5","6","7","8", - "9","10","11","12","13","14","15" - }; - -const char *regs[16] = - { - "r0","r1","r2","r3","r4","r5","r6","r7", - "r8","r9","r10","r11","r12","sp","lr","pc" - }; - -const char *conditions[16] = - { - "eq","ne","cs","cc","mi","pl","vs","vc", - "hi","ls","ge","lt","gt","le","","nv" - }; - -const char *shifts[5] = - { - "lsl","lsr","asr","ror","rrx" - }; - -const char *armMultLoadStore[12] = - { - // non-stack - "da","ia","db","ib", - // stack store - "ed","ea","fd","fa", - // stack load - "fa","fd","ea","ed" - }; - -const Opcodes thumbOpcodes[] = - { - // Format 1 - {0xf800, 0x0000, "lsl %r0, %r3, %o"}, - {0xf800, 0x0800, "lsr %r0, %r3, %o"}, - {0xf800, 0x1000, "asr %r0, %r3, %o"}, - // Format 2 - {0xfe00, 0x1800, "add %r0, %r3, %r6"}, - {0xfe00, 0x1a00, "sub %r0, %r3, %r6"}, - {0xfe00, 0x1c00, "add %r0, %r3, %i"}, - {0xfe00, 0x1e00, "sub %r0, %r3, %i"}, - // Format 3 - {0xf800, 0x2000, "mov %r8, %O"}, - {0xf800, 0x2800, "cmp %r8, %O"}, - {0xf800, 0x3000, "add %r8, %O"}, - {0xf800, 0x3800, "sub %r8, %O"}, - // Format 4 - {0xffc0, 0x4000, "and %r0, %r3"}, - {0xffc0, 0x4040, "eor %r0, %r3"}, - {0xffc0, 0x4080, "lsl %r0, %r3"}, - {0xffc0, 0x40c0, "lsr %r0, %r3"}, - {0xffc0, 0x4100, "asr %r0, %r3"}, - {0xffc0, 0x4140, "adc %r0, %r3"}, - {0xffc0, 0x4180, "sbc %r0, %r3"}, - {0xffc0, 0x41c0, "ror %r0, %r3"}, - {0xffc0, 0x4200, "tst %r0, %r3"}, - {0xffc0, 0x4240, "neg %r0, %r3"}, - {0xffc0, 0x4280, "cmp %r0, %r3"}, - {0xffc0, 0x42c0, "cmn %r0, %r3"}, - {0xffc0, 0x4300, "orr %r0, %r3"}, - {0xffc0, 0x4340, "mul %r0, %r3"}, - {0xffc0, 0x4380, "bic %r0, %r3"}, - {0xffc0, 0x43c0, "mvn %r0, %r3"}, - // Format 5 - {0xff80, 0x4700, "bx %h36"}, - {0xfcc0, 0x4400, "[ ??? ]"}, - {0xff00, 0x4400, "add %h07, %h36"}, - {0xff00, 0x4500, "cmp %h07, %h36"}, - {0xff00, 0x4600, "mov %h07, %h36"}, - // Format 6 - {0xf800, 0x4800, "ldr %r8, [%I] (=%J)"}, - // Format 7 - {0xfa00, 0x5000, "str%b %r0, [%r3, %r6]"}, - {0xfa00, 0x5800, "ldr%b %r0, [%r3, %r6]"}, - // Format 8 - {0xfe00, 0x5200, "strh %r0, [%r3, %r6]"}, - {0xfe00, 0x5600, "ldrh %r0, [%r3, %r6]"}, - {0xfe00, 0x5a00, "ldsb %r0, [%r3, %r6]"}, - {0xfe00, 0x5e00, "ldsh %r0, [%r3, %r6]"}, - // Format 9 - {0xe800, 0x6000, "str%B %r0, [%r3, %p]"}, - {0xe800, 0x6800, "ldr%B %r0, [%r3, %p]"}, - // Format 10 - {0xf800, 0x8000, "strh %r0, [%r3, %e]"}, - {0xf800, 0x8800, "ldrh %r0, [%r3, %e]"}, - // Format 11 - {0xf800, 0x9000, "str %r8, [sp, %w]"}, - {0xf800, 0x9800, "ldr %r8, [sp, %w]"}, - // Format 12 - {0xf800, 0xa000, "add %r8, pc, %w (=%K)"}, - {0xf800, 0xa800, "add %r8, sp, %w"}, - // Format 13 - {0xff00, 0xb000, "add sp, %s"}, - // Format 14 - {0xffff, 0xb500, "push {lr}"}, - {0xff00, 0xb400, "push {%l}"}, - {0xff00, 0xb500, "push {%l,lr}"}, - {0xffff, 0xbd00, "pop {pc}"}, - {0xff00, 0xbd00, "pop {%l,pc}"}, - {0xff00, 0xbc00, "pop {%l}"}, - // Format 15 - {0xf800, 0xc000, "stmia %r8!, {%l}"}, - {0xf800, 0xc800, "ldmia %r8!, {%l}"}, - // Format 17 - {0xff00, 0xdf00, "swi %m"}, - // Format 16 - {0xf000, 0xd000, "b%c %W"}, - // Format 18 - {0xf800, 0xe000, "b %a"}, - // Format 19 - {0xf800, 0xf000, "bl %A"}, - {0xf800, 0xf800, "blh %Z"}, - {0xff00, 0xbe00, "bkpt %O"}, - // Unknown - {0x0000, 0x0000, "[ ??? ]"} - }; - -const Opcodes armOpcodes[] = - { - // Undefined - {0x0e000010, 0x06000010, "[ undefined ]"}, - // Branch instructions - {0x0ff000f0, 0x01200010, "bx%c %r0"}, - {0x0f000000, 0x0a000000, "b%c %o"}, - {0x0f000000, 0x0b000000, "bl%c %o"}, - {0x0f000000, 0x0f000000, "swi%c %q"}, - // PSR transfer - {0x0fbf0fff, 0x010f0000, "mrs%c %r3, %p"}, - {0x0db0f000, 0x0120f000, "msr%c %p, %i"}, - // Multiply instructions - {0x0fe000f0, 0x00000090, "mul%c%s %r4, %r0, %r2"}, - {0x0fe000f0, 0x00200090, "mla%c%s %r4, %r0, %r2, %r3"}, - {0x0fa000f0, 0x00800090, "%umull%c%s %r3, %r4, %r0, %r2"}, - {0x0fa000f0, 0x00a00090, "%umlal%c%s %r3, %r4, %r0, %r2"}, - // Load/Store instructions - {0x0fb00ff0, 0x01000090, "swp%c%b %r3, %r0, [%r4]"}, - {0x0fb000f0, 0x01000090, "[ ??? ]"}, - {0x0c100000, 0x04000000, "str%c%b%t %r3, %a"}, - {0x0c100000, 0x04100000, "ldr%c%b%t %r3, %a"}, - {0x0e100090, 0x00000090, "str%c%h %r3, %a"}, - {0x0e100090, 0x00100090, "ldr%c%h %r3, %a"}, - {0x0e100000, 0x08000000, "stm%c%m %r4%l"}, - {0x0e100000, 0x08100000, "ldm%c%m %r4%l"}, - // Data processing - {0x0de00000, 0x00000000, "and%c%s %r3, %r4, %i"}, - {0x0de00000, 0x00200000, "eor%c%s %r3, %r4, %i"}, - {0x0de00000, 0x00400000, "sub%c%s %r3, %r4, %i"}, - {0x0de00000, 0x00600000, "rsb%c%s %r3, %r4, %i"}, - {0x0de00000, 0x00800000, "add%c%s %r3, %r4, %i"}, - {0x0de00000, 0x00a00000, "adc%c%s %r3, %r4, %i"}, - {0x0de00000, 0x00c00000, "sbc%c%s %r3, %r4, %i"}, - {0x0de00000, 0x00e00000, "rsc%c%s %r3, %r4, %i"}, - {0x0de00000, 0x01000000, "tst%c%s %r4, %i"}, - {0x0de00000, 0x01200000, "teq%c%s %r4, %i"}, - {0x0de00000, 0x01400000, "cmp%c%s %r4, %i"}, - {0x0de00000, 0x01600000, "cmn%c%s %r4, %i"}, - {0x0de00000, 0x01800000, "orr%c%s %r3, %r4, %i"}, - {0x0de00000, 0x01a00000, "mov%c%s %r3, %i"}, - {0x0de00000, 0x01c00000, "bic%c%s %r3, %r4, %i"}, - {0x0de00000, 0x01e00000, "mvn%c%s %r3, %i"}, - // Coprocessor operations - {0x0f000010, 0x0e000000, "cdp%c %P, %N, %r3, %R4, %R0%V"}, - {0x0e100000, 0x0c000000, "stc%c%L %P, %r3, %A"}, - {0x0f100010, 0x0e000010, "mcr%c %P, %N, %r3, %R4, %R0%V"}, - {0x0f100010, 0x0e100010, "mrc%c %P, %N, %r3, %R4, %R0%V"}, - // Unknown - {0x00000000, 0x00000000, "[ ??? ]"} - }; - -char* addStr(char *dest, const char *src) -{ - while (*src) - { - *dest++ = *src++; - } - return dest; -} - -char* addHex(char *dest, int siz, u32 val) -{ - if (siz==0) - { - siz = 28; - while ( (((val>>siz)&15)==0) && (siz>=4) ) - siz -= 4; - siz += 4; - } - while (siz>0) - { - siz -= 4; - *dest++ = hdig[(val>>siz)&15]; - } - return dest; -} - -int disArm(u32 offset, char *dest, int flags) -{ - u32 opcode = debuggerReadMemory(offset); - - const Opcodes *sp = armOpcodes; - while( sp->cval != (opcode & sp->mask) ) - sp++; - - if (flags&DIS_VIEW_ADDRESS) - { - dest = addHex(dest, 32, offset); - *dest++ = ' '; - } - if (flags&DIS_VIEW_CODE) - { - dest = addHex(dest, 32, opcode); - *dest++ = ' '; - } - - char *src = sp->mnemonic; - while (*src) - { - if (*src!='%') - *dest++ = *src++; - else - { - src++; - switch (*src) - { - case 'c': - dest = addStr(dest, conditions[opcode>>28]); - break; - case 'r': - dest = addStr(dest, regs[(opcode>>((*(++src)-'0')*4))&15]); - break; - case 'o': - { - *dest++ = '$'; - int off = opcode&0xffffff; - if (off&0x800000) - off |= 0xff000000; - off <<= 2; - dest = addHex(dest, 32, offset+8+off); - } - break; - case 'i': - if (opcode&(1<<25)) - { - dest = addStr(dest, "#0x"); - int imm = opcode&0xff; - int rot = (opcode&0xf00)>>7; - int val = (imm<<(32-rot))|(imm>>rot); - dest = addHex(dest, 0, val); - } - else - { - dest = addStr(dest, regs[opcode&0x0f]); - int shi = (opcode>>5)&3; - int sdw = (opcode>>7)&0x1f; - if ((sdw==0)&&(shi==3)) - shi = 4; - if ( (sdw) || (opcode&0x10) || (shi)) - { - dest = addStr(dest, ", "); - dest = addStr(dest, shifts[shi]); - if (opcode&0x10) - { - *dest++ = ' '; - dest = addStr(dest, regs[(opcode>>8)&15]); - } - else - { - if (sdw==0 && ( (shi==1) || (shi==2) )) - sdw = 32; - if(shi != 4) - { - dest = addStr(dest, " #0x"); - dest = addHex(dest, 8, sdw); - } - } - } - } - break; - case 'p': - if (opcode&(1<<22)) - dest = addStr(dest, "spsr"); - else - dest = addStr(dest, "cpsr"); - if(opcode & 0x00F00000) - { - *dest++ = '_'; - if(opcode & 0x00080000) - *dest++ = 'f'; - if(opcode & 0x00040000) - *dest++ = 's'; - if(opcode & 0x00020000) - *dest++ = 'x'; - if(opcode & 0x00010000) - *dest++ = 'c'; - } - break; - case 's': - if (opcode&(1<<20)) - *dest++ = 's'; - break; - case 'S': - if (opcode&(1<<22)) - *dest++ = 's'; - break; - case 'u': - if (opcode&(1<<22)) - *dest++ = 's'; - else - *dest++ = 'u'; - break; - case 'b': - if (opcode&(1<<22)) - *dest++ = 'b'; - break; - case 'a': - if ((opcode&0x076f0000)==0x004f0000) - { - *dest++ = '['; - *dest++ = '$'; - int adr = offset+8; - int add = (opcode&15)|((opcode>>8)&0xf0); - if (opcode&(1<<23)) - adr += add; - else - adr -= add; - dest = addHex(dest, 32, adr); - *dest++ = ']'; - dest = addStr(dest, " (="); - *dest++ = '$'; - dest = addHex(dest ,32, debuggerReadMemory(adr)); - *dest++=')'; - } - if ((opcode&0x072f0000)==0x050f0000) - { - *dest++ = '['; - *dest++ = '$'; - int adr = offset+8; - if (opcode&(1<<23)) - adr += opcode&0xfff; - else - adr -= opcode&0xfff; - dest = addHex(dest, 32, adr); - *dest++ = ']'; - dest = addStr(dest, " (="); - *dest++ = '$'; - dest = addHex(dest ,32, debuggerReadMemory(adr)); - *dest++=')'; - } - else - { - int reg = (opcode>>16)&15; - *dest++ = '['; - dest = addStr(dest, regs[reg]); - if (!(opcode&(1<<24))) - *dest++ = ']'; - if ( ((opcode&(1<<25))&&(opcode&(1<<26))) || (!(opcode&(1<<22))&&!(opcode&(1<<26))) ) - { - dest = addStr(dest, ", "); - if (!(opcode&(1<<23))) - *dest++ = '-'; - dest = addStr(dest, regs[opcode&0x0f]); - int shi = (opcode>>5)&3; - if (opcode&(1<<26)) - { - if ( ((opcode>>7)&0x1f) || (opcode&0x10) || (shi==1) || (shi==2)) - { - dest = addStr(dest, ", "); - dest = addStr(dest, shifts[shi]); - if (opcode&0x10) - { - *dest++ = ' '; - dest = addStr(dest, regs[(opcode>>8)&15]); - } - else - { - int sdw = (opcode>>7)&0x1f; - if (sdw==0 && ( (shi==1) || (shi==2) )) - sdw = 32; - dest = addStr(dest, " #0x"); - dest = addHex(dest, 8, sdw); - } - } - } - } - else - { - int off; - if (opcode&(1<<26)) - off = opcode&0xfff; - else - off = (opcode&15)|((opcode>>4)&0xf0); - if (off) - { - dest = addStr(dest, ", "); - if (!(opcode&(1<<23))) - *dest++ = '-'; - dest = addStr(dest, "#0x"); - dest = addHex(dest, 0, off); - } - } - if (opcode&(1<<24)) - { - *dest++ = ']'; - if (opcode&(1<<21)) - *dest++ = '!'; - } - } - break; - case 't': - if ((opcode&0x01200000)==0x01200000) - *dest++ = 't'; - break; - case 'h': - if (opcode&(1<<6)) - *dest++ = 's'; - if (opcode&(1<<5)) - *dest++ = 'h'; - else - *dest++ = 'b'; - break; - case 'm': - if (((opcode>>16)&15)==13) - { - if(opcode & 0x00100000) - dest = addStr(dest, armMultLoadStore[8+((opcode>>23)&3)]); - else - dest = addStr(dest, armMultLoadStore[4+((opcode>>23)&3)]); - } - else - dest = addStr(dest, armMultLoadStore[(opcode>>23)&3]); - break; - case 'l': - if (opcode&(1<<21)) - *dest++ = '!'; - dest = addStr(dest, ", {"); - { - int rlst = opcode&0xffff; - int msk = 0; - int not_first = 0; - while (msk<16) - { - if (rlst&(1<>8)&15]); - break; - case 'N': - if (opcode&0x10) - dest = addStr(dest, decVals[(opcode>>21)&7]); - else - dest = addStr(dest, decVals[(opcode>>20)&15]); - break; - case 'R': - { - src++; - int reg = 4*(*src-'0'); - *dest++ = 'c'; - dest = addStr(dest, decVals[(opcode>>reg)&15]); - } - break; - case 'V': - { - int val = (opcode>>5)&7; - if (val) - { - dest = addStr(dest, ", "); - dest = addStr(dest, decVals[val]); - } - } - break; - case 'L': - if (opcode&(1<<22)) - *dest++ = 'l'; - break; - case 'A': - if ((opcode&0x012f0000)==0x010f0000) - { - int adr = offset+8; - int add = (opcode&0xff)<<2; - if (opcode&(1<<23)) - adr += add; - else - adr -= add; - *dest++ = '$'; - addHex(dest, 32, adr); - } - else - { - *dest++ = '['; - dest = addStr(dest, regs[(opcode>>16)&15]); - if (!(opcode&(1<<24))) - *dest++ = ']'; - int off = (opcode&0xff)<<2; - if (off) - { - dest = addStr(dest, ", "); - if (!(opcode&(1<<23))) - *dest++ = '-'; - dest = addStr(dest, "#0x"); - dest = addHex(dest, 0, off); - } - if (opcode&(1<<24)) - { - *dest++ = ']'; - if (opcode&(1<<21)) - *dest++ = '!'; - } - } - break; - } - src++; - } - } - *dest++ = 0; - - return 4; -} - -int disThumb(u32 offset, char *dest, int flags) -{ - u32 opcode = debuggerReadHalfWord(offset); - - const Opcodes *sp = thumbOpcodes; - int ret = 2; - while( sp->cval != (opcode & sp->mask) ) - sp++; - - if (flags&DIS_VIEW_ADDRESS) - { - dest = addHex(dest, 32, offset); - *dest++ = ' '; - } - if (flags&DIS_VIEW_CODE) - { - dest = addHex(dest, 16, opcode); - *dest++ = ' '; - } - - char *src = sp->mnemonic; - while (*src) - { - if (*src!='%') - *dest++ = *src++; - else - { - src++; - switch (*src) - { - case 'r': - src++; - dest = addStr(dest, regs[(opcode>>(*src-'0'))&7]); - break; - case 'o': - dest = addStr(dest, "#0x"); - { - int val = (opcode>>6)&0x1f; - dest = addHex(dest, 8, val); - } - break; - case 'p': - dest = addStr(dest, "#0x"); - { - int val = (opcode>>6)&0x1f; - if (!(opcode&(1<<12))) - val <<= 2; - dest = addHex(dest, 0, val); - } - break; - case 'e': - dest = addStr(dest, "#0x"); - dest = addHex(dest, 0, ((opcode>>6)&0x1f)<<1); - break; - case 'i': - dest = addStr(dest, "#0x"); - dest = addHex(dest, 0, (opcode>>6)&7); - break; - case 'h': - { - src++; - int reg = (opcode>>(*src-'0'))&7; - src++; - if (opcode&(1<<(*src-'0'))) - reg += 8; - dest = addStr(dest, regs[reg]); - } - break; - case 'O': - dest = addStr(dest, "#0x"); - dest = addHex(dest, 0, (opcode&0xff)); - break; - case 'I': - *dest++ = '$'; - dest = addHex(dest, 32, (offset&0xfffffffc)+4+((opcode&0xff)<<2)); - break; - case 'J': - { - u32 value = debuggerReadMemory((offset&0xfffffffc)+4+ - ((opcode & 0xff)<<2)); - *dest++ = '$'; - dest = addHex(dest, 32, value); - char *s = elfGetAddressSymbol(value); - if(*s) - { - *dest++ = ' '; - dest = addStr(dest, s); - } - } - break; - case 'K': - { - u32 value = (offset&0xfffffffc)+4+((opcode & 0xff)<<2); - *dest++ = '$'; - dest = addHex(dest, 32, value); - char *s = elfGetAddressSymbol(value); - if(*s) - { - *dest++ = ' '; - dest = addStr(dest, s); - } - } - break; - case 'b': - if (opcode&(1<<10)) - *dest++ = 'b'; - break; - case 'B': - if (opcode&(1<<12)) - *dest++ = 'b'; - break; - case 'w': - dest = addStr(dest, "#0x"); - dest = addHex(dest, 0, (opcode&0xff)<<2); - break; - case 'W': - *dest++ = '$'; - { - int add = opcode&0xff; - if (add&0x80) - add |= 0xffffff00; - dest = addHex(dest, 32, (offset&0xfffffffe)+4+(add<<1)); - } - break; - case 'c': - dest = addStr(dest, conditions[(opcode>>8)&15]); - break; - case 's': - if (opcode&(1<<7)) - *dest++ = '-'; - dest = addStr(dest, "#0x"); - dest = addHex(dest, 0, (opcode&0x7f)<<2); - break; - case 'l': - { - int rlst = opcode&0xff; - int msk = 0; - int not_first = 0; - while (msk<8) - { - if (rlst&(1< + +#include "System.h" +#include "Port.h" +#include "agb/GBA.h" +#include "armdis.h" +#include "elf.h" + +struct Opcodes { + u32 mask; + u32 cval; + const char *mnemonic; +}; + +#define debuggerReadMemory(addr) \ + READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) + +#define debuggerReadHalfWord(addr) \ + READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) + +#define debuggerReadByte(addr) \ + map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] + +const char hdig[] = "0123456789abcdef"; + +const char *decVals[16] = { + "0","1","2","3","4","5","6","7","8", + "9","10","11","12","13","14","15" +}; + +const char *regs[16] = { + "r0","r1","r2","r3","r4","r5","r6","r7", + "r8","r9","r10","r11","r12","sp","lr","pc" +}; + +const char *conditions[16] = { + "eq","ne","cs","cc","mi","pl","vs","vc", + "hi","ls","ge","lt","gt","le","","nv" +}; + +const char *shifts[5] = { + "lsl","lsr","asr","ror","rrx" +}; + +const char *armMultLoadStore[12] = { + // non-stack + "da","ia","db","ib", + // stack store + "ed","ea","fd","fa", + // stack load + "fa","fd","ea","ed" +}; + +const Opcodes thumbOpcodes[] = { + // Format 1 + {0xf800, 0x0000, "lsl %r0, %r3, %o"}, + {0xf800, 0x0800, "lsr %r0, %r3, %o"}, + {0xf800, 0x1000, "asr %r0, %r3, %o"}, + // Format 2 + {0xfe00, 0x1800, "add %r0, %r3, %r6"}, + {0xfe00, 0x1a00, "sub %r0, %r3, %r6"}, + {0xfe00, 0x1c00, "add %r0, %r3, %i"}, + {0xfe00, 0x1e00, "sub %r0, %r3, %i"}, + // Format 3 + {0xf800, 0x2000, "mov %r8, %O"}, + {0xf800, 0x2800, "cmp %r8, %O"}, + {0xf800, 0x3000, "add %r8, %O"}, + {0xf800, 0x3800, "sub %r8, %O"}, + // Format 4 + {0xffc0, 0x4000, "and %r0, %r3"}, + {0xffc0, 0x4040, "eor %r0, %r3"}, + {0xffc0, 0x4080, "lsl %r0, %r3"}, + {0xffc0, 0x40c0, "lsr %r0, %r3"}, + {0xffc0, 0x4100, "asr %r0, %r3"}, + {0xffc0, 0x4140, "adc %r0, %r3"}, + {0xffc0, 0x4180, "sbc %r0, %r3"}, + {0xffc0, 0x41c0, "ror %r0, %r3"}, + {0xffc0, 0x4200, "tst %r0, %r3"}, + {0xffc0, 0x4240, "neg %r0, %r3"}, + {0xffc0, 0x4280, "cmp %r0, %r3"}, + {0xffc0, 0x42c0, "cmn %r0, %r3"}, + {0xffc0, 0x4300, "orr %r0, %r3"}, + {0xffc0, 0x4340, "mul %r0, %r3"}, + {0xffc0, 0x4380, "bic %r0, %r3"}, + {0xffc0, 0x43c0, "mvn %r0, %r3"}, + // Format 5 + {0xff80, 0x4700, "bx %h36"}, + {0xfcc0, 0x4400, "[ ??? ]"}, + {0xff00, 0x4400, "add %h07, %h36"}, + {0xff00, 0x4500, "cmp %h07, %h36"}, + {0xff00, 0x4600, "mov %h07, %h36"}, + // Format 6 + {0xf800, 0x4800, "ldr %r8, [%I] (=%J)"}, + // Format 7 + {0xfa00, 0x5000, "str%b %r0, [%r3, %r6]"}, + {0xfa00, 0x5800, "ldr%b %r0, [%r3, %r6]"}, + // Format 8 + {0xfe00, 0x5200, "strh %r0, [%r3, %r6]"}, + {0xfe00, 0x5600, "ldsb %r0, [%r3, %r6]"}, + {0xfe00, 0x5a00, "ldrh %r0, [%r3, %r6]"}, + {0xfe00, 0x5e00, "ldsh %r0, [%r3, %r6]"}, + // Format 9 + {0xe800, 0x6000, "str%B %r0, [%r3, %p]"}, + {0xe800, 0x6800, "ldr%B %r0, [%r3, %p]"}, + // Format 10 + {0xf800, 0x8000, "strh %r0, [%r3, %e]"}, + {0xf800, 0x8800, "ldrh %r0, [%r3, %e]"}, + // Format 11 + {0xf800, 0x9000, "str %r8, [sp, %w]"}, + {0xf800, 0x9800, "ldr %r8, [sp, %w]"}, + // Format 12 + {0xf800, 0xa000, "add %r8, pc, %w (=%K)"}, + {0xf800, 0xa800, "add %r8, sp, %w"}, + // Format 13 + {0xff00, 0xb000, "add sp, %s"}, + // Format 14 + {0xffff, 0xb500, "push {lr}"}, + {0xff00, 0xb400, "push {%l}"}, + {0xff00, 0xb500, "push {%l,lr}"}, + {0xffff, 0xbd00, "pop {pc}"}, + {0xff00, 0xbd00, "pop {%l,pc}"}, + {0xff00, 0xbc00, "pop {%l}"}, + // Format 15 + {0xf800, 0xc000, "stmia %r8!, {%l}"}, + {0xf800, 0xc800, "ldmia %r8!, {%l}"}, + // Format 17 + {0xff00, 0xdf00, "swi %m"}, + // Format 16 + {0xf000, 0xd000, "b%c %W"}, + // Format 18 + {0xf800, 0xe000, "b %a"}, + // Format 19 + {0xf800, 0xf000, "bl %A"}, + {0xf800, 0xf800, "blh %Z"}, + {0xff00, 0xbe00, "bkpt %O"}, + // Unknown + {0x0000, 0x0000, "[ ??? ]"} +}; + +const Opcodes armOpcodes[] = { + // Undefined + {0x0e000010, 0x06000010, "[ undefined ]"}, + // Branch instructions + {0x0ff000f0, 0x01200010, "bx%c %r0"}, + {0x0f000000, 0x0a000000, "b%c %o"}, + {0x0f000000, 0x0b000000, "bl%c %o"}, + {0x0f000000, 0x0f000000, "swi%c %q"}, + // PSR transfer + {0x0fbf0fff, 0x010f0000, "mrs%c %r3, %p"}, + {0x0db0f000, 0x0120f000, "msr%c %p, %i"}, + // Multiply instructions + {0x0fe000f0, 0x00000090, "mul%c%s %r4, %r0, %r2"}, + {0x0fe000f0, 0x00200090, "mla%c%s %r4, %r0, %r2, %r3"}, + {0x0fa000f0, 0x00800090, "%umull%c%s %r3, %r4, %r0, %r2"}, + {0x0fa000f0, 0x00a00090, "%umlal%c%s %r3, %r4, %r0, %r2"}, + // Load/Store instructions + {0x0fb00ff0, 0x01000090, "swp%c%b %r3, %r0, [%r4]"}, + {0x0fb000f0, 0x01000090, "[ ??? ]"}, + {0x0c100000, 0x04000000, "str%c%b%t %r3, %a"}, + {0x0c100000, 0x04100000, "ldr%c%b%t %r3, %a"}, + {0x0e100090, 0x00000090, "str%c%h %r3, %a"}, + {0x0e100090, 0x00100090, "ldr%c%h %r3, %a"}, + {0x0e100000, 0x08000000, "stm%c%m %r4%l"}, + {0x0e100000, 0x08100000, "ldm%c%m %r4%l"}, + // Data processing + {0x0de00000, 0x00000000, "and%c%s %r3, %r4, %i"}, + {0x0de00000, 0x00200000, "eor%c%s %r3, %r4, %i"}, + {0x0de00000, 0x00400000, "sub%c%s %r3, %r4, %i"}, + {0x0de00000, 0x00600000, "rsb%c%s %r3, %r4, %i"}, + {0x0de00000, 0x00800000, "add%c%s %r3, %r4, %i"}, + {0x0de00000, 0x00a00000, "adc%c%s %r3, %r4, %i"}, + {0x0de00000, 0x00c00000, "sbc%c%s %r3, %r4, %i"}, + {0x0de00000, 0x00e00000, "rsc%c%s %r3, %r4, %i"}, + {0x0de00000, 0x01000000, "tst%c%s %r4, %i"}, + {0x0de00000, 0x01200000, "teq%c%s %r4, %i"}, + {0x0de00000, 0x01400000, "cmp%c%s %r4, %i"}, + {0x0de00000, 0x01600000, "cmn%c%s %r4, %i"}, + {0x0de00000, 0x01800000, "orr%c%s %r3, %r4, %i"}, + {0x0de00000, 0x01a00000, "mov%c%s %r3, %i"}, + {0x0de00000, 0x01c00000, "bic%c%s %r3, %r4, %i"}, + {0x0de00000, 0x01e00000, "mvn%c%s %r3, %i"}, + // Coprocessor operations + {0x0f000010, 0x0e000000, "cdp%c %P, %N, %r3, %R4, %R0%V"}, + {0x0e100000, 0x0c000000, "stc%c%L %P, %r3, %A"}, + {0x0f100010, 0x0e000010, "mcr%c %P, %N, %r3, %R4, %R0%V"}, + {0x0f100010, 0x0e100010, "mrc%c %P, %N, %r3, %R4, %R0%V"}, + // Unknown + {0x00000000, 0x00000000, "[ ??? ]"} +}; + +char* addStr(char *dest, const char *src){ + while (*src){ + *dest++ = *src++; + } + return dest; +} + +char* addHex(char *dest, int siz, u32 val){ + if (siz==0){ + siz = 28; + while ( (((val>>siz)&15)==0) && (siz>=4) ) + siz -= 4; + siz += 4; + } + while (siz>0){ + siz -= 4; + *dest++ = hdig[(val>>siz)&15]; + } + return dest; +} + +int disArm(u32 offset, char *dest, int flags){ + u32 opcode = debuggerReadMemory(offset); + + const Opcodes *sp = armOpcodes; + while( sp->cval != (opcode & sp->mask) ) + sp++; + + if (flags&DIS_VIEW_ADDRESS){ + dest = addHex(dest, 32, offset); + *dest++ = ' '; + } + if (flags&DIS_VIEW_CODE){ + dest = addHex(dest, 32, opcode); + *dest++ = ' '; + } + + const char *src = sp->mnemonic; + while (*src){ + if (*src!='%') + *dest++ = *src++; + else{ + src++; + switch (*src){ + case 'c': + dest = addStr(dest, conditions[opcode>>28]); + break; + case 'r': + dest = addStr(dest, regs[(opcode>>((*(++src)-'0')*4))&15]); + break; + case 'o': + { + *dest++ = '$'; + int off = opcode&0xffffff; + if (off&0x800000) + off |= 0xff000000; + off <<= 2; + dest = addHex(dest, 32, offset+8+off); + } + break; + case 'i': + if (opcode&(1<<25)){ + dest = addStr(dest, "#0x"); + int imm = opcode&0xff; + int rot = (opcode&0xf00)>>7; + int val = (imm<<(32-rot))|(imm>>rot); + dest = addHex(dest, 0, val); + } else{ + dest = addStr(dest, regs[opcode&0x0f]); + int shi = (opcode>>5)&3; + int sdw = (opcode>>7)&0x1f; + if ((sdw==0)&&(shi==3)) + shi = 4; + if ( (sdw) || (opcode&0x10) || (shi)) { + dest = addStr(dest, ", "); + dest = addStr(dest, shifts[shi]); + if (opcode&0x10){ + *dest++ = ' '; + dest = addStr(dest, regs[(opcode>>8)&15]); + } else { + if (sdw==0 && ( (shi==1) || (shi==2) )) + sdw = 32; + if(shi != 4) { + dest = addStr(dest, " #0x"); + dest = addHex(dest, 8, sdw); + } + } + } + } + break; + case 'p': + if (opcode&(1<<22)) + dest = addStr(dest, "spsr"); + else + dest = addStr(dest, "cpsr"); + if(opcode & 0x00F00000) { + *dest++ = '_'; + if(opcode & 0x00080000) + *dest++ = 'f'; + if(opcode & 0x00040000) + *dest++ = 's'; + if(opcode & 0x00020000) + *dest++ = 'x'; + if(opcode & 0x00010000) + *dest++ = 'c'; + } + break; + case 's': + if (opcode&(1<<20)) + *dest++ = 's'; + break; + case 'S': + if (opcode&(1<<22)) + *dest++ = 's'; + break; + case 'u': + if (opcode&(1<<22)) + *dest++ = 's'; + else + *dest++ = 'u'; + break; + case 'b': + if (opcode&(1<<22)) + *dest++ = 'b'; + break; + case 'a': + if ((opcode&0x076f0000)==0x004f0000){ + *dest++ = '['; + *dest++ = '$'; + int adr = offset+8; + int add = (opcode&15)|((opcode>>8)&0xf0); + if (opcode&(1<<23)) + adr += add; + else + adr -= add; + dest = addHex(dest, 32, adr); + *dest++ = ']'; + dest = addStr(dest, " (="); + *dest++ = '$'; + dest = addHex(dest ,32, debuggerReadMemory(adr)); + *dest++=')'; + } + if ((opcode&0x072f0000)==0x050f0000){ + *dest++ = '['; + *dest++ = '$'; + int adr = offset+8; + if (opcode&(1<<23)) + adr += opcode&0xfff; + else + adr -= opcode&0xfff; + dest = addHex(dest, 32, adr); + *dest++ = ']'; + dest = addStr(dest, " (="); + *dest++ = '$'; + dest = addHex(dest ,32, debuggerReadMemory(adr)); + *dest++=')'; + } else { + int reg = (opcode>>16)&15; + *dest++ = '['; + dest = addStr(dest, regs[reg]); + if (!(opcode&(1<<24))) + *dest++ = ']'; + if ( ((opcode&(1<<25))&&(opcode&(1<<26))) || (!(opcode&(1<<22))&&!(opcode&(1<<26))) ){ + dest = addStr(dest, ", "); + if (!(opcode&(1<<23))) + *dest++ = '-'; + dest = addStr(dest, regs[opcode&0x0f]); + int shi = (opcode>>5)&3; + if (opcode&(1<<26)){ + if ( ((opcode>>7)&0x1f) || (opcode&0x10) || (shi==1) || (shi==2)){ + dest = addStr(dest, ", "); + dest = addStr(dest, shifts[shi]); + if (opcode&0x10){ + *dest++ = ' '; + dest = addStr(dest, regs[(opcode>>8)&15]); + } else { + int sdw = (opcode>>7)&0x1f; + if (sdw==0 && ( (shi==1) || (shi==2) )) + sdw = 32; + dest = addStr(dest, " #0x"); + dest = addHex(dest, 8, sdw); + } + } + } + } else { + int off; + if (opcode&(1<<26)) + off = opcode&0xfff; + else + off = (opcode&15)|((opcode>>4)&0xf0); + if (off){ + dest = addStr(dest, ", "); + if (!(opcode&(1<<23))) + *dest++ = '-'; + dest = addStr(dest, "#0x"); + dest = addHex(dest, 0, off); + } + } + if (opcode&(1<<24)){ + *dest++ = ']'; + if (opcode&(1<<21)) + *dest++ = '!'; + } + } + break; + case 't': + if ((opcode&0x01200000)==0x01200000) + *dest++ = 't'; + break; + case 'h': + if (opcode&(1<<6)) + *dest++ = 's'; + if (opcode&(1<<5)) + *dest++ = 'h'; + else + *dest++ = 'b'; + break; + case 'm': + if (((opcode>>16)&15)==13) { + if(opcode & 0x00100000) + dest = addStr(dest, armMultLoadStore[8+((opcode>>23)&3)]); + else + dest = addStr(dest, armMultLoadStore[4+((opcode>>23)&3)]); + } else + dest = addStr(dest, armMultLoadStore[(opcode>>23)&3]); + break; + case 'l': + if (opcode&(1<<21)) + *dest++ = '!'; + dest = addStr(dest, ", {"); + { + int rlst = opcode&0xffff; + int msk = 0; + int not_first = 0; + while (msk<16){ + if (rlst&(1<>8)&15]); + break; + case 'N': + if (opcode&0x10) + dest = addStr(dest, decVals[(opcode>>21)&7]); + else + dest = addStr(dest, decVals[(opcode>>20)&15]); + break; + case 'R': + { + src++; + int reg = 4*(*src-'0'); + *dest++ = 'c'; + dest = addStr(dest, decVals[(opcode>>reg)&15]); + } + break; + case 'V': + { + int val = (opcode>>5)&7; + if (val){ + dest = addStr(dest, ", "); + dest = addStr(dest, decVals[val]); + } + } + break; + case 'L': + if (opcode&(1<<22)) + *dest++ = 'l'; + break; + case 'A': + if ((opcode&0x012f0000)==0x010f0000){ + int adr = offset+8; + int add = (opcode&0xff)<<2; + if (opcode&(1<<23)) + adr += add; + else + adr -= add; + *dest++ = '$'; + addHex(dest, 32, adr); + } else { + *dest++ = '['; + dest = addStr(dest, regs[(opcode>>16)&15]); + if (!(opcode&(1<<24))) + *dest++ = ']'; + int off = (opcode&0xff)<<2; + if (off){ + dest = addStr(dest, ", "); + if (!(opcode&(1<<23))) + *dest++ = '-'; + dest = addStr(dest, "#0x"); + dest = addHex(dest, 0, off); + } + if (opcode&(1<<24)){ + *dest++ = ']'; + if (opcode&(1<<21)) + *dest++ = '!'; + } + } + break; + } + src++; + } + } + *dest++ = 0; + + return 4; +} + +int disThumb(u32 offset, char *dest, int flags){ + u32 opcode = debuggerReadHalfWord(offset); + + const Opcodes *sp = thumbOpcodes; + int ret = 2; + while( sp->cval != (opcode & sp->mask) ) + sp++; + + if (flags&DIS_VIEW_ADDRESS){ + dest = addHex(dest, 32, offset); + *dest++ = ' '; + } + if (flags&DIS_VIEW_CODE){ + dest = addHex(dest, 16, opcode); + *dest++ = ' '; + } + + const char *src = sp->mnemonic; + while (*src){ + if (*src!='%') + *dest++ = *src++; + else { + src++; + switch (*src){ + case 'r': + src++; + dest = addStr(dest, regs[(opcode>>(*src-'0'))&7]); + break; + case 'o': + dest = addStr(dest, "#0x"); + { + int val = (opcode>>6)&0x1f; + dest = addHex(dest, 8, val); + } + break; + case 'p': + dest = addStr(dest, "#0x"); + { + int val = (opcode>>6)&0x1f; + if (!(opcode&(1<<12))) + val <<= 2; + dest = addHex(dest, 0, val); + } + break; + case 'e': + dest = addStr(dest, "#0x"); + dest = addHex(dest, 0, ((opcode>>6)&0x1f)<<1); + break; + case 'i': + dest = addStr(dest, "#0x"); + dest = addHex(dest, 0, (opcode>>6)&7); + break; + case 'h': + { + src++; + int reg = (opcode>>(*src-'0'))&7; + src++; + if (opcode&(1<<(*src-'0'))) + reg += 8; + dest = addStr(dest, regs[reg]); + } + break; + case 'O': + dest = addStr(dest, "#0x"); + dest = addHex(dest, 0, (opcode&0xff)); + break; + case 'I': + *dest++ = '$'; + dest = addHex(dest, 32, (offset&0xfffffffc)+4+((opcode&0xff)<<2)); + break; + case 'J': + { + u32 value = debuggerReadMemory((offset&0xfffffffc)+4+ + ((opcode & 0xff)<<2)); + *dest++ = '$'; + dest = addHex(dest, 32, value); + const char *s = elfGetAddressSymbol(value); + if(*s) { + *dest++ = ' '; + dest = addStr(dest, s); + } + } + break; + case 'K': + { + u32 value = (offset&0xfffffffc)+4+((opcode & 0xff)<<2); + *dest++ = '$'; + dest = addHex(dest, 32, value); + const char *s = elfGetAddressSymbol(value); + if(*s) { + *dest++ = ' '; + dest = addStr(dest, s); + } + } + break; + case 'b': + if (opcode&(1<<10)) + *dest++ = 'b'; + break; + case 'B': + if (opcode&(1<<12)) + *dest++ = 'b'; + break; + case 'w': + dest = addStr(dest, "#0x"); + dest = addHex(dest, 0, (opcode&0xff)<<2); + break; + case 'W': + *dest++ = '$'; + { + int add = opcode&0xff; + if (add&0x80) + add |= 0xffffff00; + dest = addHex(dest, 32, (offset&0xfffffffe)+4+(add<<1)); + } + break; + case 'c': + dest = addStr(dest, conditions[(opcode>>8)&15]); + break; + case 's': + if (opcode&(1<<7)) + *dest++ = '-'; + dest = addStr(dest, "#0x"); + dest = addHex(dest, 0, (opcode&0x7f)<<2); + break; + case 'l': + { + int rlst = opcode&0xff; + int msk = 0; + int not_first = 0; + while (msk<8){ + if (rlst&(1<>3) << systemRedShift |\ - ((g) >> 3) << systemGreenShift |\ - ((b) >> 3) << systemBlueShift\ - -static void fill_rgb_row_16(u16 *from, int src_width, u8 *row, int width) -{ - u8 *copy_start = row + src_width*3; - u8 *all_stop = row + width*3; - while (row < copy_start) - { - u16 color = *from++; - *row++ = ((color >> systemRedShift) & 0x1f) << 3; - *row++ = ((color >> systemGreenShift) & 0x1f) << 3; - *row++ = ((color >> systemBlueShift) & 0x1f) << 3; - } - // any remaining elements to be written to 'row' are a replica of the - // preceding pixel - u8 *p = row-3; - while (row < all_stop) - { - // we're guaranteed three elements per pixel; could unroll the loop - // further, especially with a Duff's Device, but the gains would be - // probably limited (judging by profiler output) - *row++ = *p++; - *row++ = *p++; - *row++ = *p++; - } -} - -static void fill_rgb_row_32(u32 *from, int src_width, u8 *row, int width) -{ - u8 *copy_start = row + src_width*3; - u8 *all_stop = row + width*3; - while (row < copy_start) - { - u32 color = *from++; - *row++ = ((color >> systemRedShift) & 0x1f) << 3; - *row++ = ((color >> systemGreenShift) & 0x1f) << 3; - *row++ = ((color >> systemBlueShift) & 0x1f) << 3; - } - // any remaining elements to be written to 'row' are a replica of the - // preceding pixel - u8 *p = row-3; - while (row < all_stop) - { - // we're guaranteed three elements per pixel; could unroll the loop - // further, especially with a Duff's Device, but the gains would be - // probably limited (judging by profiler output) - *row++ = *p++; - *row++ = *p++; - *row++ = *p++; - } -} - -void Bilinear(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, - u8 *dstPtr, u32 dstPitch, int width, int height) -{ - u16 *to = (u16 *)dstPtr; - u16 *to_odd = (u16 *)(dstPtr + dstPitch); - - int from_width = width; - u16 *from = (u16 *)srcPtr; - fill_rgb_row_16(from, from_width, rgb_row_cur, width+1); - - for(int y = 0; y < height; y++) - { - u16 *from_orig = from; - u16 *to_orig = to; - - if (y+1 < height) - fill_rgb_row_16(from+width+2, from_width, rgb_row_next, - width+1); - else - fill_rgb_row_16(from, from_width, rgb_row_next, width+1); - - // every pixel in the src region, is extended to 4 pixels in the - // destination, arranged in a square 'quad'; if the current src - // pixel is 'a', then in what follows 'b' is the src pixel to the - // right, 'c' is the src pixel below, and 'd' is the src pixel to - // the right and down - u8 *cur_row = rgb_row_cur; - u8 *next_row = rgb_row_next; - u8 *ar = cur_row++; - u8 *ag = cur_row++; - u8 *ab = cur_row++; - u8 *cr = next_row++; - u8 *cg = next_row++; - u8 *cb = next_row++; - for(int x=0; x < width; x++) - { - u8 *br = cur_row++; - u8 *bg = cur_row++; - u8 *bb = cur_row++; - u8 *dr = next_row++; - u8 *dg = next_row++; - u8 *db = next_row++; - - // upper left pixel in quad: just copy it in - *to++ = RGB(*ar, *ag, *ab); - - // upper right - *to++ = RGB((*ar+*br)>>1, (*ag+*bg)>>1, (*ab+*bb)>>1); - - // lower left - *to_odd++ = RGB((*ar+*cr)>>1, (*ag+*cg)>>1, (*ab+*cb)>>1); - - // lower right - *to_odd++ = RGB((*ar+*br+*cr+*dr)>>2, - (*ag+*bg+*cg+*dg)>>2, - (*ab+*bb+*cb+*db)>>2); - - // 'b' becomes 'a', 'd' becomes 'c' - ar = br; - ag = bg; - ab = bb; - cr = dr; - cg = dg; - cb = db; - } - - // the "next" rgb row becomes the current; the old current rgb row is - // recycled and serves as the new "next" row - u8 *temp; - temp = rgb_row_cur; - rgb_row_cur = rgb_row_next; - rgb_row_next = temp; - - // update the pointers for start of next pair of lines - from = (u16 *)((u8 *)from_orig + srcPitch); - to = (u16 *)((u8 *)to_orig + (dstPitch << 1)); - to_odd = (u16 *)((u8 *)to + dstPitch); - } -} - -void BilinearPlus(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, - u8 *dstPtr, u32 dstPitch, int width, int height) -{ - u16 *to = (u16 *)dstPtr; - u16 *to_odd = (u16 *)(dstPtr + dstPitch); - - int from_width = width; - u16 *from = (u16 *)srcPtr; - fill_rgb_row_16(from, from_width, rgb_row_cur, width+1); - - for(int y = 0; y < height; y++) - { - u16 *from_orig = from; - u16 *to_orig = to; - - if (y+1 < height) - fill_rgb_row_16(from+width+2, from_width, rgb_row_next, - width+1); - else - fill_rgb_row_16(from, from_width, rgb_row_next, width+1); - - // every pixel in the src region, is extended to 4 pixels in the - // destination, arranged in a square 'quad'; if the current src - // pixel is 'a', then in what follows 'b' is the src pixel to the - // right, 'c' is the src pixel below, and 'd' is the src pixel to - // the right and down - u8 *cur_row = rgb_row_cur; - u8 *next_row = rgb_row_next; - u8 *ar = cur_row++; - u8 *ag = cur_row++; - u8 *ab = cur_row++; - u8 *cr = next_row++; - u8 *cg = next_row++; - u8 *cb = next_row++; - for(int x=0; x < width; x++) - { - u8 *br = cur_row++; - u8 *bg = cur_row++; - u8 *bb = cur_row++; - u8 *dr = next_row++; - u8 *dg = next_row++; - u8 *db = next_row++; - - // upper left pixel in quad: just copy it in - //*to++ = manip.rgb(*ar, *ag, *ab); -#ifdef USE_ORIGINAL_BILINEAR_PLUS - *to++ = RGB( - (((*ar)<<2) +((*ar)) + (*cr+*br+*br) )>> 3, - (((*ag)<<2) +((*ag)) + (*cg+*bg+*bg) )>> 3, - (((*ab)<<2) +((*ab)) + (*cb+*bb+*bb) )>> 3); -#else - *to++ = RGB( - (((*ar)<<3) +((*ar)<<1) + (*cr+*br+*br+*cr) )>> 4, - (((*ag)<<3) +((*ag)<<1) + (*cg+*bg+*bg+*cg) )>> 4, - (((*ab)<<3) +((*ab)<<1) + (*cb+*bb+*bb+*cb) )>> 4); -#endif - - // upper right - *to++ = RGB((*ar+*br)>>1, (*ag+*bg)>>1, (*ab+*bb)>>1); - - // lower left - *to_odd++ = RGB((*ar+*cr)>>1, (*ag+*cg)>>1, (*ab+*cb)>>1); - - // lower right - *to_odd++ = RGB((*ar+*br+*cr+*dr)>>2, - (*ag+*bg+*cg+*dg)>>2, - (*ab+*bb+*cb+*db)>>2); - - // 'b' becomes 'a', 'd' becomes 'c' - ar = br; - ag = bg; - ab = bb; - cr = dr; - cg = dg; - cb = db; - } - - // the "next" rgb row becomes the current; the old current rgb row is - // recycled and serves as the new "next" row - u8 *temp; - temp = rgb_row_cur; - rgb_row_cur = rgb_row_next; - rgb_row_next = temp; - - // update the pointers for start of next pair of lines - from = (u16 *)((u8 *)from_orig + srcPitch); - to = (u16 *)((u8 *)to_orig + (dstPitch << 1)); - to_odd = (u16 *)((u8 *)to + dstPitch); - } -} - -void Bilinear32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, - u8 *dstPtr, u32 dstPitch, int width, int height) -{ - u32 *to = (u32 *)dstPtr; - u32 *to_odd = (u32 *)(dstPtr + dstPitch); - - int from_width = width; - if(width+1 < from_width) - from_width = width+1; - u32 *from = (u32 *)srcPtr; - fill_rgb_row_32(from, from_width, rgb_row_cur, width+1); - - for(int y = 0; y < height; y++) - { - u32 *from_orig = from; - u32 *to_orig = to; - - if (y+1 < height) - fill_rgb_row_32(from+width+1, from_width, rgb_row_next, - width+1); - else - fill_rgb_row_32(from, from_width, rgb_row_next, width+1); - - // every pixel in the src region, is extended to 4 pixels in the - // destination, arranged in a square 'quad'; if the current src - // pixel is 'a', then in what follows 'b' is the src pixel to the - // right, 'c' is the src pixel below, and 'd' is the src pixel to - // the right and down - u8 *cur_row = rgb_row_cur; - u8 *next_row = rgb_row_next; - u8 *ar = cur_row++; - u8 *ag = cur_row++; - u8 *ab = cur_row++; - u8 *cr = next_row++; - u8 *cg = next_row++; - u8 *cb = next_row++; - for(int x=0; x < width; x++) - { - u8 *br = cur_row++; - u8 *bg = cur_row++; - u8 *bb = cur_row++; - u8 *dr = next_row++; - u8 *dg = next_row++; - u8 *db = next_row++; - - // upper left pixel in quad: just copy it in - *to++ = RGB(*ar, *ag, *ab); - - // upper right - *to++ = RGB((*ar+*br)>>1, (*ag+*bg)>>1, (*ab+*bb)>>1); - - // lower left - *to_odd++ = RGB((*ar+*cr)>>1, (*ag+*cg)>>1, (*ab+*cb)>>1); - - // lower right - *to_odd++ = RGB((*ar+*br+*cr+*dr)>>2, - (*ag+*bg+*cg+*dg)>>2, - (*ab+*bb+*cb+*db)>>2); - - // 'b' becomes 'a', 'd' becomes 'c' - ar = br; - ag = bg; - ab = bb; - cr = dr; - cg = dg; - cb = db; - } - - // the "next" rgb row becomes the current; the old current rgb row is - // recycled and serves as the new "next" row - u8 *temp; - temp = rgb_row_cur; - rgb_row_cur = rgb_row_next; - rgb_row_next = temp; - - // update the pointers for start of next pair of lines - from = (u32 *)((u8 *)from_orig + srcPitch); - to = (u32 *)((u8 *)to_orig + (dstPitch << 1)); - to_odd = (u32 *)((u8 *)to + dstPitch); - } -} - -void BilinearPlus32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, - u8 *dstPtr, u32 dstPitch, int width, int height) -{ - u32 *to = (u32 *)dstPtr; - u32 *to_odd = (u32 *)(dstPtr + dstPitch); - - int from_width = width; - if(width+1 < from_width) - from_width = width+1; - u32 *from = (u32 *)srcPtr; - fill_rgb_row_32(from, from_width, rgb_row_cur, width+1); - - for(int y = 0; y < height; y++) - { - u32 *from_orig = from; - u32 *to_orig = to; - - if (y+1 < height) - fill_rgb_row_32(from+width+1, from_width, rgb_row_next, - width+1); - else - fill_rgb_row_32(from, from_width, rgb_row_next, width+1); - - // every pixel in the src region, is extended to 4 pixels in the - // destination, arranged in a square 'quad'; if the current src - // pixel is 'a', then in what follows 'b' is the src pixel to the - // right, 'c' is the src pixel below, and 'd' is the src pixel to - // the right and down - u8 *cur_row = rgb_row_cur; - u8 *next_row = rgb_row_next; - u8 *ar = cur_row++; - u8 *ag = cur_row++; - u8 *ab = cur_row++; - u8 *cr = next_row++; - u8 *cg = next_row++; - u8 *cb = next_row++; - for(int x=0; x < width; x++) - { - u8 *br = cur_row++; - u8 *bg = cur_row++; - u8 *bb = cur_row++; - u8 *dr = next_row++; - u8 *dg = next_row++; - u8 *db = next_row++; - - // upper left pixel in quad: just copy it in - //*to++ = manip.rgb(*ar, *ag, *ab); -#ifdef USE_ORIGINAL_BILINEAR_PLUS - *to++ = RGB( - (((*ar)<<2) +((*ar)) + (*cr+*br+*br) )>> 3, - (((*ag)<<2) +((*ag)) + (*cg+*bg+*bg) )>> 3, - (((*ab)<<2) +((*ab)) + (*cb+*bb+*bb) )>> 3); -#else - *to++ = RGB( - (((*ar)<<3) +((*ar)<<1) + (*cr+*br+*br+*cr) )>> 4, - (((*ag)<<3) +((*ag)<<1) + (*cg+*bg+*bg+*cg) )>> 4, - (((*ab)<<3) +((*ab)<<1) + (*cb+*bb+*bb+*cb) )>> 4); -#endif - - // upper right - *to++ = RGB((*ar+*br)>>1, (*ag+*bg)>>1, (*ab+*bb)>>1); - - // lower left - *to_odd++ = RGB((*ar+*cr)>>1, (*ag+*cg)>>1, (*ab+*cb)>>1); - - // lower right - *to_odd++ = RGB((*ar+*br+*cr+*dr)>>2, - (*ag+*bg+*cg+*dg)>>2, - (*ab+*bb+*cb+*db)>>2); - - // 'b' becomes 'a', 'd' becomes 'c' - ar = br; - ag = bg; - ab = bb; - cr = dr; - cg = dg; - cb = db; - } - - // the "next" rgb row becomes the current; the old current rgb row is - // recycled and serves as the new "next" row - u8 *temp; - temp = rgb_row_cur; - rgb_row_cur = rgb_row_next; - rgb_row_next = temp; - - // update the pointers for start of next pair of lines - from = (u32 *)((u8 *)from_orig + srcPitch); - to = (u32 *)((u8 *)to_orig + (dstPitch << 1)); - to_odd = (u32 *)((u8 *)to + dstPitch); - } -} - diff --git a/source/vba/bios.cpp b/source/vba/bios.cpp index 9a3d515..3e8bf3f 100644 --- a/source/vba/bios.cpp +++ b/source/vba/bios.cpp @@ -1,1293 +1,1165 @@ -// 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. - -#include -#include -#include - -#include "GBA.h" -#include "bios.h" -#include "GBAinline.h" -#include "Globals.h" - -s16 sineTable[256] = { - (s16)0x0000, (s16)0x0192, (s16)0x0323, (s16)0x04B5, (s16)0x0645, (s16)0x07D5, (s16)0x0964, (s16)0x0AF1, - (s16)0x0C7C, (s16)0x0E05, (s16)0x0F8C, (s16)0x1111, (s16)0x1294, (s16)0x1413, (s16)0x158F, (s16)0x1708, - (s16)0x187D, (s16)0x19EF, (s16)0x1B5D, (s16)0x1CC6, (s16)0x1E2B, (s16)0x1F8B, (s16)0x20E7, (s16)0x223D, - (s16)0x238E, (s16)0x24DA, (s16)0x261F, (s16)0x275F, (s16)0x2899, (s16)0x29CD, (s16)0x2AFA, (s16)0x2C21, - (s16)0x2D41, (s16)0x2E5A, (s16)0x2F6B, (s16)0x3076, (s16)0x3179, (s16)0x3274, (s16)0x3367, (s16)0x3453, - (s16)0x3536, (s16)0x3612, (s16)0x36E5, (s16)0x37AF, (s16)0x3871, (s16)0x392A, (s16)0x39DA, (s16)0x3A82, - (s16)0x3B20, (s16)0x3BB6, (s16)0x3C42, (s16)0x3CC5, (s16)0x3D3E, (s16)0x3DAE, (s16)0x3E14, (s16)0x3E71, - (s16)0x3EC5, (s16)0x3F0E, (s16)0x3F4E, (s16)0x3F84, (s16)0x3FB1, (s16)0x3FD3, (s16)0x3FEC, (s16)0x3FFB, - (s16)0x4000, (s16)0x3FFB, (s16)0x3FEC, (s16)0x3FD3, (s16)0x3FB1, (s16)0x3F84, (s16)0x3F4E, (s16)0x3F0E, - (s16)0x3EC5, (s16)0x3E71, (s16)0x3E14, (s16)0x3DAE, (s16)0x3D3E, (s16)0x3CC5, (s16)0x3C42, (s16)0x3BB6, - (s16)0x3B20, (s16)0x3A82, (s16)0x39DA, (s16)0x392A, (s16)0x3871, (s16)0x37AF, (s16)0x36E5, (s16)0x3612, - (s16)0x3536, (s16)0x3453, (s16)0x3367, (s16)0x3274, (s16)0x3179, (s16)0x3076, (s16)0x2F6B, (s16)0x2E5A, - (s16)0x2D41, (s16)0x2C21, (s16)0x2AFA, (s16)0x29CD, (s16)0x2899, (s16)0x275F, (s16)0x261F, (s16)0x24DA, - (s16)0x238E, (s16)0x223D, (s16)0x20E7, (s16)0x1F8B, (s16)0x1E2B, (s16)0x1CC6, (s16)0x1B5D, (s16)0x19EF, - (s16)0x187D, (s16)0x1708, (s16)0x158F, (s16)0x1413, (s16)0x1294, (s16)0x1111, (s16)0x0F8C, (s16)0x0E05, - (s16)0x0C7C, (s16)0x0AF1, (s16)0x0964, (s16)0x07D5, (s16)0x0645, (s16)0x04B5, (s16)0x0323, (s16)0x0192, - (s16)0x0000, (s16)0xFE6E, (s16)0xFCDD, (s16)0xFB4B, (s16)0xF9BB, (s16)0xF82B, (s16)0xF69C, (s16)0xF50F, - (s16)0xF384, (s16)0xF1FB, (s16)0xF074, (s16)0xEEEF, (s16)0xED6C, (s16)0xEBED, (s16)0xEA71, (s16)0xE8F8, - (s16)0xE783, (s16)0xE611, (s16)0xE4A3, (s16)0xE33A, (s16)0xE1D5, (s16)0xE075, (s16)0xDF19, (s16)0xDDC3, - (s16)0xDC72, (s16)0xDB26, (s16)0xD9E1, (s16)0xD8A1, (s16)0xD767, (s16)0xD633, (s16)0xD506, (s16)0xD3DF, - (s16)0xD2BF, (s16)0xD1A6, (s16)0xD095, (s16)0xCF8A, (s16)0xCE87, (s16)0xCD8C, (s16)0xCC99, (s16)0xCBAD, - (s16)0xCACA, (s16)0xC9EE, (s16)0xC91B, (s16)0xC851, (s16)0xC78F, (s16)0xC6D6, (s16)0xC626, (s16)0xC57E, - (s16)0xC4E0, (s16)0xC44A, (s16)0xC3BE, (s16)0xC33B, (s16)0xC2C2, (s16)0xC252, (s16)0xC1EC, (s16)0xC18F, - (s16)0xC13B, (s16)0xC0F2, (s16)0xC0B2, (s16)0xC07C, (s16)0xC04F, (s16)0xC02D, (s16)0xC014, (s16)0xC005, - (s16)0xC000, (s16)0xC005, (s16)0xC014, (s16)0xC02D, (s16)0xC04F, (s16)0xC07C, (s16)0xC0B2, (s16)0xC0F2, - (s16)0xC13B, (s16)0xC18F, (s16)0xC1EC, (s16)0xC252, (s16)0xC2C2, (s16)0xC33B, (s16)0xC3BE, (s16)0xC44A, - (s16)0xC4E0, (s16)0xC57E, (s16)0xC626, (s16)0xC6D6, (s16)0xC78F, (s16)0xC851, (s16)0xC91B, (s16)0xC9EE, - (s16)0xCACA, (s16)0xCBAD, (s16)0xCC99, (s16)0xCD8C, (s16)0xCE87, (s16)0xCF8A, (s16)0xD095, (s16)0xD1A6, - (s16)0xD2BF, (s16)0xD3DF, (s16)0xD506, (s16)0xD633, (s16)0xD767, (s16)0xD8A1, (s16)0xD9E1, (s16)0xDB26, - (s16)0xDC72, (s16)0xDDC3, (s16)0xDF19, (s16)0xE075, (s16)0xE1D5, (s16)0xE33A, (s16)0xE4A3, (s16)0xE611, - (s16)0xE783, (s16)0xE8F8, (s16)0xEA71, (s16)0xEBED, (s16)0xED6C, (s16)0xEEEF, (s16)0xF074, (s16)0xF1FB, - (s16)0xF384, (s16)0xF50F, (s16)0xF69C, (s16)0xF82B, (s16)0xF9BB, (s16)0xFB4B, (s16)0xFCDD, (s16)0xFE6E - }; - -void BIOS_ArcTan() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("ArcTan: %08x (VCOUNT=%2d)\n", - reg[0].I, - VCOUNT); - } -#endif - - s32 a = -((s32)(reg[0].I * reg[0].I)) >> 14; - s32 b = ((0xA9 * a) >> 14) + 0x390; - b = ((b * a) >> 14) + 0x91C; - b = ((b * a) >> 14) + 0xFB6; - b = ((b * a) >> 14) + 0x16AA; - b = ((b * a) >> 14) + 0x2081; - b = ((b * a) >> 14) + 0x3651; - b = ((b * a) >> 14) + 0xA2F9; - reg[0].I = (reg[0].I * b) >> 16; - -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("ArcTan: return=%08x\n", - reg[0].I); - } -#endif -} - -void BIOS_ArcTan2() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("ArcTan2: %08x,%08x (VCOUNT=%2d)\n", - reg[0].I, - reg[1].I, - VCOUNT); - } -#endif - - s16 x = reg[0].I; - s16 y = reg[1].I; - - if (y == 0) - { - reg[0].I = 0x8000 & x; - reg[3].I = 0x170; - } - else - { - if (x == 0) - { - reg[0].I = (0x8000 & y) + 0x4000; - reg[3].I = 0x170; - } - else - { - if (abs(x) > abs(y)) - { - reg[1].I = x; - reg[0].I = y << 14; - BIOS_Div(); - BIOS_ArcTan(); - if (x < 0) - reg[0].I = 0x8000 + reg[0].I; - else - reg[0].I = ((y & 0x8000) << 1 ) + reg[0].I; - reg[3].I = 0x170; - } - else - { - reg[0].I = x << 14; - BIOS_Div(); - BIOS_ArcTan(); - reg[0].I = (0x4000 + (y & 0x8000)) - reg[0].I; - reg[3].I = 0x170; - } - } - } - -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("ArcTan2: return=%08x\n", - reg[0].I); - } -#endif -} - -void BIOS_BitUnPack() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("BitUnPack: %08x,%08x,%08x (VCOUNT=%2d)\n", - reg[0].I, - reg[1].I, - reg[2].I, - VCOUNT); - } -#endif - - u32 source = reg[0].I; - u32 dest = reg[1].I; - u32 header = reg[2].I; - - int len = CPUReadHalfWord(header); - // check address - int bits = CPUReadByte(header+2); - int revbits = 8 - bits; - // u32 value = 0; - u32 base = CPUReadMemory(header+4); - bool addBase = (base & 0x80000000) ? true : false; - base &= 0x7fffffff; - int dataSize = CPUReadByte(header+3); - - int data = 0; - int bitwritecount = 0; - while(1) - { - len -= 1; - if(len < 0) - break; - int mask = 0xff >> revbits; - u8 b = CPUReadByte(source); - source++; - int bitcount = 0; - while(1) - { - if(bitcount >= 8) - break; - u32 d = b & mask; - u32 temp = d >> bitcount; - if(!temp && addBase) - { - temp += base; - } - data |= temp << bitwritecount; - bitwritecount += dataSize; - if(bitwritecount >= 32) - { - CPUWriteMemory(dest, data); - dest += 4; - data = 0; - bitwritecount = 0; - } - mask <<= bits; - bitcount += bits; - } - } -} - -void BIOS_BgAffineSet() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("BgAffineSet: %08x,%08x,%08x (VCOUNT=%2d)\n", - reg[0].I, - reg[1].I, - reg[2].I, - VCOUNT); - } -#endif - - u32 src = reg[0].I; - u32 dest = reg[1].I; - int num = reg[2].I; - - for(int i = 0; i < num; i++) - { - s32 cx = CPUReadMemory(src); - src+=4; - s32 cy = CPUReadMemory(src); - src+=4; - s16 dispx = CPUReadHalfWord(src); - src+=2; - s16 dispy = CPUReadHalfWord(src); - src+=2; - s16 rx = CPUReadHalfWord(src); - src+=2; - s16 ry = CPUReadHalfWord(src); - src+=2; - u16 theta = CPUReadHalfWord(src)>>8; - src+=4; // keep structure alignment - s32 a = sineTable[(theta+0x40)&255]; - s32 b = sineTable[theta]; - - s16 dx = (rx * a)>>14; - s16 dmx = (rx * b)>>14; - s16 dy = (ry * b)>>14; - s16 dmy = (ry * a)>>14; - - CPUWriteHalfWord(dest, dx); - dest += 2; - CPUWriteHalfWord(dest, -dmx); - dest += 2; - CPUWriteHalfWord(dest, dy); - dest += 2; - CPUWriteHalfWord(dest, dmy); - dest += 2; - - s32 startx = cx - dx * dispx + dmx * dispy; - s32 starty = cy - dy * dispx - dmy * dispy; - - CPUWriteMemory(dest, startx); - dest += 4; - CPUWriteMemory(dest, starty); - dest += 4; - } -} - -void BIOS_CpuSet() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("CpuSet: 0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I, - reg[2].I, VCOUNT); - } -#endif - - u32 source = reg[0].I; - u32 dest = reg[1].I; - u32 cnt = reg[2].I; - - if(((source & 0xe000000) == 0) || - ((source + (((cnt << 11)>>9) & 0x1fffff)) & 0xe000000) == 0) - return; - - int count = cnt & 0x1FFFFF; - - // 32-bit ? - if((cnt >> 26) & 1) - { - // needed for 32-bit mode! - source &= 0xFFFFFFFC; - dest &= 0xFFFFFFFC; - // fill ? - if((cnt >> 24) & 1) - { - u32 value = CPUReadMemory(source); - while(count) - { - CPUWriteMemory(dest, value); - dest += 4; - count--; - } - } - else - { - // copy - while(count) - { - CPUWriteMemory(dest, CPUReadMemory(source)); - source += 4; - dest += 4; - count--; - } - } - } - else - { - // 16-bit fill? - if((cnt >> 24) & 1) - { - u16 value = CPUReadHalfWord(source); - while(count) - { - CPUWriteHalfWord(dest, value); - dest += 2; - count--; - } - } - else - { - // copy - while(count) - { - CPUWriteHalfWord(dest, CPUReadHalfWord(source)); - source += 2; - dest += 2; - count--; - } - } - } -} - -void BIOS_CpuFastSet() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("CpuFastSet: 0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I, - reg[2].I, VCOUNT); - } -#endif - - u32 source = reg[0].I; - u32 dest = reg[1].I; - u32 cnt = reg[2].I; - - if(((source & 0xe000000) == 0) || - ((source + (((cnt << 11)>>9) & 0x1fffff)) & 0xe000000) == 0) - return; - - // needed for 32-bit mode! - source &= 0xFFFFFFFC; - dest &= 0xFFFFFFFC; - - int count = cnt & 0x1FFFFF; - - // fill? - if((cnt >> 24) & 1) - { - while(count > 0) - { - // BIOS always transfers 32 bytes at a time - u32 value = CPUReadMemory(source); - for(int i = 0; i < 8; i++) - { - CPUWriteMemory(dest, value); - dest += 4; - } - count -= 8; - } - } - else - { - // copy - while(count > 0) - { - // BIOS always transfers 32 bytes at a time - for(int i = 0; i < 8; i++) - { - CPUWriteMemory(dest, CPUReadMemory(source)); - source += 4; - dest += 4; - } - count -= 8; - } - } -} - -void BIOS_Diff8bitUnFilterWram() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("Diff8bitUnFilterWram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, - reg[1].I, VCOUNT); - } -#endif - - u32 source = reg[0].I; - u32 dest = reg[1].I; - - u32 header = CPUReadMemory(source); - source += 4; - - if(((source & 0xe000000) == 0) || - ((source + ((header >> 8) & 0x1fffff) & 0xe000000) == 0)) - return; - - int len = header >> 8; - - u8 data = CPUReadByte(source++); - CPUWriteByte(dest++, data); - len--; - - while(len > 0) - { - u8 diff = CPUReadByte(source++); - data += diff; - CPUWriteByte(dest++, data); - len--; - } -} - -void BIOS_Diff8bitUnFilterVram() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("Diff8bitUnFilterVram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, - reg[1].I, VCOUNT); - } -#endif - - u32 source = reg[0].I; - u32 dest = reg[1].I; - - u32 header = CPUReadMemory(source); - source += 4; - - if(((source & 0xe000000) == 0) || - ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) - return; - - int len = header >> 8; - - u8 data = CPUReadByte(source++); - u16 writeData = data; - int shift = 8; - int bytes = 1; - - while(len >= 2) - { - u8 diff = CPUReadByte(source++); - data += diff; - writeData |= (data << shift); - bytes++; - shift += 8; - if(bytes == 2) - { - CPUWriteHalfWord(dest, writeData); - dest += 2; - len -= 2; - bytes = 0; - writeData = 0; - shift = 0; - } - } -} - -void BIOS_Diff16bitUnFilter() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("Diff16bitUnFilter: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, - reg[1].I, VCOUNT); - } -#endif - - u32 source = reg[0].I; - u32 dest = reg[1].I; - - u32 header = CPUReadMemory(source); - source += 4; - - if(((source & 0xe000000) == 0) || - ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) - return; - - int len = header >> 8; - - u16 data = CPUReadHalfWord(source); - source += 2; - CPUWriteHalfWord(dest, data); - dest += 2; - len -= 2; - - while(len >= 2) - { - u16 diff = CPUReadHalfWord(source); - source += 2; - data += diff; - CPUWriteHalfWord(dest, data); - dest += 2; - len -= 2; - } -} - -void BIOS_Div() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("Div: 0x%08x,0x%08x (VCOUNT=%d)\n", - reg[0].I, - reg[1].I, - VCOUNT); - } -#endif - - int number = reg[0].I; - int denom = reg[1].I; - - if(denom != 0) - { - reg[0].I = number / denom; - reg[1].I = number % denom; - s32 temp = (s32)reg[0].I; - reg[3].I = temp < 0 ? (u32)-temp : (u32)temp; - } -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("Div: return=0x%08x,0x%08x,0x%08x\n", - reg[0].I, - reg[1].I, - reg[3].I); - } -#endif -} - -void BIOS_DivARM() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("DivARM: 0x%08x, (VCOUNT=%d)\n", - reg[0].I, - VCOUNT); - } -#endif - - u32 temp = reg[0].I; - reg[0].I = reg[1].I; - reg[1].I = temp; - BIOS_Div(); -} - -void BIOS_HuffUnComp() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("HuffUnComp: 0x%08x,0x%08x (VCOUNT=%d)\n", - reg[0].I, - reg[1].I, - VCOUNT); - } -#endif - - u32 source = reg[0].I; - u32 dest = reg[1].I; - - u32 header = CPUReadMemory(source); - source += 4; - - if(((source & 0xe000000) == 0) || - ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) - return; - - u8 treeSize = CPUReadByte(source++); - - u32 treeStart = source; - - source += (treeSize<<1) + 1; - - int len = header >> 8; - - u32 mask = 0x80000000; - u32 data = CPUReadMemory(source); - source += 4; - - int pos = 0; - u8 rootNode = CPUReadByte(treeStart); - u8 currentNode = rootNode; - bool writeData = false; - int byteShift = 0; - int byteCount = 0; - u32 writeValue = 0; - - if((header & 0x0F) == 8) - { - while(len > 0) - { - // take left - if(pos == 0) - pos++; - else - pos += (((currentNode & 0x3F)+1)<<1); - - if(data & mask) - { - // right - if(currentNode & 0x40) - writeData = true; - currentNode = CPUReadByte(treeStart+pos+1); - } - else - { - // left - if(currentNode & 0x80) - writeData = true; - currentNode = CPUReadByte(treeStart+pos); - } - - if(writeData) - { - writeValue |= (currentNode << byteShift); - byteCount++; - byteShift += 8; - - pos = 0; - currentNode = rootNode; - writeData = false; - - if(byteCount == 4) - { - byteCount = 0; - byteShift = 0; - CPUWriteMemory(dest, writeValue); - writeValue = 0; - dest += 4; - len -= 4; - } - } - mask >>= 1; - if(mask == 0) - { - mask = 0x80000000; - data = CPUReadMemory(source); - source += 4; - } - } - } - else - { - int halfLen = 0; - int value = 0; - while(len > 0) - { - // take left - if(pos == 0) - pos++; - else - pos += (((currentNode & 0x3F)+1)<<1); - - if((data & mask)) - { - // right - if(currentNode & 0x40) - writeData = true; - currentNode = CPUReadByte(treeStart+pos+1); - } - else - { - // left - if(currentNode & 0x80) - writeData = true; - currentNode = CPUReadByte(treeStart+pos); - } - - if(writeData) - { - if(halfLen == 0) - value |= currentNode; - else - value |= (currentNode<<4); - - halfLen += 4; - if(halfLen == 8) - { - writeValue |= (value << byteShift); - byteCount++; - byteShift += 8; - - halfLen = 0; - value = 0; - - if(byteCount == 4) - { - byteCount = 0; - byteShift = 0; - CPUWriteMemory(dest, writeValue); - dest += 4; - writeValue = 0; - len -= 4; - } - } - pos = 0; - currentNode = rootNode; - writeData = false; - } - mask >>= 1; - if(mask == 0) - { - mask = 0x80000000; - data = CPUReadMemory(source); - source += 4; - } - } - } -} - -void BIOS_LZ77UnCompVram() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("LZ77UnCompVram: 0x%08x,0x%08x (VCOUNT=%d)\n", - reg[0].I, - reg[1].I, - VCOUNT); - } -#endif - - u32 source = reg[0].I; - u32 dest = reg[1].I; - - u32 header = CPUReadMemory(source); - source += 4; - - if(((source & 0xe000000) == 0) || - ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) - return; - - int byteCount = 0; - int byteShift = 0; - u32 writeValue = 0; - - int len = header >> 8; - - while(len > 0) - { - u8 d = CPUReadByte(source++); - - if(d) - { - for(int i = 0; i < 8; i++) - { - if(d & 0x80) - { - u16 data = CPUReadByte(source++) << 8; - data |= CPUReadByte(source++); - int length = (data >> 12) + 3; - int offset = (data & 0x0FFF); - u32 windowOffset = dest + byteCount - offset - 1; - for(int i = 0; i < length; i++) - { - writeValue |= (CPUReadByte(windowOffset++) << byteShift); - byteShift += 8; - byteCount++; - - if(byteCount == 2) - { - CPUWriteHalfWord(dest, writeValue); - dest += 2; - byteCount = 0; - byteShift = 0; - writeValue = 0; - } - len--; - if(len == 0) - return; - } - } - else - { - writeValue |= (CPUReadByte(source++) << byteShift); - byteShift += 8; - byteCount++; - if(byteCount == 2) - { - CPUWriteHalfWord(dest, writeValue); - dest += 2; - byteCount = 0; - byteShift = 0; - writeValue = 0; - } - len--; - if(len == 0) - return; - } - d <<= 1; - } - } - else - { - for(int i = 0; i < 8; i++) - { - writeValue |= (CPUReadByte(source++) << byteShift); - byteShift += 8; - byteCount++; - if(byteCount == 2) - { - CPUWriteHalfWord(dest, writeValue); - dest += 2; - byteShift = 0; - byteCount = 0; - writeValue = 0; - } - len--; - if(len == 0) - return; - } - } - } -} - -void BIOS_LZ77UnCompWram() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("LZ77UnCompWram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I, - VCOUNT); - } -#endif - - u32 source = reg[0].I; - u32 dest = reg[1].I; - - u32 header = CPUReadMemory(source); - source += 4; - - if(((source & 0xe000000) == 0) || - ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) - return; - - int len = header >> 8; - - while(len > 0) - { - u8 d = CPUReadByte(source++); - - if(d) - { - for(int i = 0; i < 8; i++) - { - if(d & 0x80) - { - u16 data = CPUReadByte(source++) << 8; - data |= CPUReadByte(source++); - int length = (data >> 12) + 3; - int offset = (data & 0x0FFF); - u32 windowOffset = dest - offset - 1; - for(int i = 0; i < length; i++) - { - CPUWriteByte(dest++, CPUReadByte(windowOffset++)); - len--; - if(len == 0) - return; - } - } - else - { - CPUWriteByte(dest++, CPUReadByte(source++)); - len--; - if(len == 0) - return; - } - d <<= 1; - } - } - else - { - for(int i = 0; i < 8; i++) - { - CPUWriteByte(dest++, CPUReadByte(source++)); - len--; - if(len == 0) - return; - } - } - } -} - -void BIOS_ObjAffineSet() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("ObjAffineSet: 0x%08x,0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n", - reg[0].I, - reg[1].I, - reg[2].I, - reg[3].I, - VCOUNT); - } -#endif - - u32 src = reg[0].I; - u32 dest = reg[1].I; - int num = reg[2].I; - int offset = reg[3].I; - - for(int i = 0; i < num; i++) - { - s16 rx = CPUReadHalfWord(src); - src+=2; - s16 ry = CPUReadHalfWord(src); - src+=2; - u16 theta = CPUReadHalfWord(src)>>8; - src+=4; // keep structure alignment - - s32 a = (s32)sineTable[(theta+0x40)&255]; - s32 b = (s32)sineTable[theta]; - - s16 dx = ((s32)rx * a)>>14; - s16 dmx = ((s32)rx * b)>>14; - s16 dy = ((s32)ry * b)>>14; - s16 dmy = ((s32)ry * a)>>14; - - CPUWriteHalfWord(dest, dx); - dest += offset; - CPUWriteHalfWord(dest, -dmx); - dest += offset; - CPUWriteHalfWord(dest, dy); - dest += offset; - CPUWriteHalfWord(dest, dmy); - dest += offset; - } -} - -void BIOS_RegisterRamReset(u32 flags) -{ - // no need to trace here. this is only called directly from GBA.cpp - // to emulate bios initialization - - if(flags) - { - if(flags & 0x01) - { - // clear work RAM - memset(workRAM, 0, 0x40000); - } - if(flags & 0x02) - { - // clear internal RAM - memset(internalRAM, 0, 0x7e00); // don't clear 0x7e00-0x7fff - } - if(flags & 0x04) - { - // clear palette RAM - memset(paletteRAM, 0, 0x400); - } - if(flags & 0x08) - { - // clear VRAM - memset(vram, 0, 0x18000); - } - if(flags & 0x10) - { - // clean OAM - memset(oam, 0, 0x400); - } - - if(flags & 0x80) - { - int i; - for(i = 0; i < 8; i++) - CPUUpdateRegister(0x200+i*2, 0); - - CPUUpdateRegister(0x202, 0xFFFF); - - for(i = 0; i < 8; i++) - CPUUpdateRegister(0x4+i*2, 0); - - for(i = 0; i < 16; i++) - CPUUpdateRegister(0x20+i*2, 0); - - for(i = 0; i < 24; i++) - CPUUpdateRegister(0xb0+i*2, 0); - - CPUUpdateRegister(0x130, 0); - CPUUpdateRegister(0x20, 0x100); - CPUUpdateRegister(0x30, 0x100); - CPUUpdateRegister(0x26, 0x100); - CPUUpdateRegister(0x36, 0x100); - } - - if(flags & 0x20) - { - int i; - for(i = 0; i < 8; i++) - CPUUpdateRegister(0x110+i*2, 0); - CPUUpdateRegister(0x134, 0x8000); - for(i = 0; i < 7; i++) - CPUUpdateRegister(0x140+i*2, 0); - } - - if(flags & 0x40) - { - int i; - CPUWriteByte(0x4000084, 0); - CPUWriteByte(0x4000084, 0x80); - CPUWriteMemory(0x4000080, 0x880e0000); - CPUUpdateRegister(0x88, CPUReadHalfWord(0x4000088)&0x3ff); - CPUWriteByte(0x4000070, 0x70); - for(i = 0; i < 8; i++) - CPUUpdateRegister(0x90+i*2, 0); - CPUWriteByte(0x4000070, 0); - for(i = 0; i < 8; i++) - CPUUpdateRegister(0x90+i*2, 0); - CPUWriteByte(0x4000084, 0); - } - } -} - -void BIOS_RegisterRamReset() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("RegisterRamReset: 0x%08x (VCOUNT=%d)\n", - reg[0].I, - VCOUNT); - } -#endif - - BIOS_RegisterRamReset(reg[0].I); -} - -void BIOS_RLUnCompVram() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("RLUnCompVram: 0x%08x,0x%08x (VCOUNT=%d)\n", - reg[0].I, - reg[1].I, - VCOUNT); - } -#endif - - u32 source = reg[0].I; - u32 dest = reg[1].I; - - u32 header = CPUReadMemory(source); - source += 4; - - if(((source & 0xe000000) == 0) || - ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) - return; - - int len = header >> 8; - int byteCount = 0; - int byteShift = 0; - u32 writeValue = 0; - - while(len > 0) - { - u8 d = CPUReadByte(source++); - int l = d & 0x7F; - if(d & 0x80) - { - u8 data = CPUReadByte(source++); - l += 3; - for(int i = 0;i < l; i++) - { - writeValue |= (data << byteShift); - byteShift += 8; - byteCount++; - - if(byteCount == 2) - { - CPUWriteHalfWord(dest, writeValue); - dest += 2; - byteCount = 0; - byteShift = 0; - writeValue = 0; - } - len--; - if(len == 0) - return; - } - } - else - { - l++; - for(int i = 0; i < l; i++) - { - writeValue |= (CPUReadByte(source++) << byteShift); - byteShift += 8; - byteCount++; - if(byteCount == 2) - { - CPUWriteHalfWord(dest, writeValue); - dest += 2; - byteCount = 0; - byteShift = 0; - writeValue = 0; - } - len--; - if(len == 0) - return; - } - } - } -} - -void BIOS_RLUnCompWram() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("RLUnCompWram: 0x%08x,0x%08x (VCOUNT=%d)\n", - reg[0].I, - reg[1].I, - VCOUNT); - } -#endif - - u32 source = reg[0].I; - u32 dest = reg[1].I; - - u32 header = CPUReadMemory(source); - source += 4; - - if(((source & 0xe000000) == 0) || - ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) - return; - - int len = header >> 8; - - while(len > 0) - { - u8 d = CPUReadByte(source++); - int l = d & 0x7F; - if(d & 0x80) - { - u8 data = CPUReadByte(source++); - l += 3; - for(int i = 0;i < l; i++) - { - CPUWriteByte(dest++, data); - len--; - if(len == 0) - return; - } - } - else - { - l++; - for(int i = 0; i < l; i++) - { - CPUWriteByte(dest++, CPUReadByte(source++)); - len--; - if(len == 0) - return; - } - } - } -} - -void BIOS_SoftReset() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("SoftReset: (VCOUNT=%d)\n", VCOUNT); - } -#endif - - armState = true; - armMode = 0x1F; - armIrqEnable = false; - C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false; - reg[13].I = 0x03007F00; - reg[14].I = 0x00000000; - reg[16].I = 0x00000000; - reg[R13_IRQ].I = 0x03007FA0; - reg[R14_IRQ].I = 0x00000000; - reg[SPSR_IRQ].I = 0x00000000; - reg[R13_SVC].I = 0x03007FE0; - reg[R14_SVC].I = 0x00000000; - reg[SPSR_SVC].I = 0x00000000; - u8 b = internalRAM[0x7ffa]; - - memset(&internalRAM[0x7e00], 0, 0x200); - - if(b) - { - armNextPC = 0x02000000; - reg[15].I = 0x02000004; - } - else - { - armNextPC = 0x08000000; - reg[15].I = 0x08000004; - } -} - -void BIOS_Sqrt() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("Sqrt: %08x (VCOUNT=%2d)\n", - reg[0].I, - VCOUNT); - } -#endif - reg[0].I = (u32)sqrt((double)reg[0].I); -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("Sqrt: return=%08x\n", - reg[0].I); - } -#endif -} - -void BIOS_MidiKey2Freq() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("MidiKey2Freq: WaveData=%08x mk=%08x fp=%08x\n", - reg[0].I, - reg[1].I, - reg[2].I); - } -#endif - int freq = CPUReadMemory(reg[0].I+4); - double tmp; - tmp = ((double)(180 - reg[1].I)) - ((double)reg[2].I / 256.f); - tmp = pow((double)2.f, tmp / 12.f); - reg[0].I = (int)((double)freq / tmp); - -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("MidiKey2Freq: return %08x\n", - reg[0].I); - } -#endif -} - -void BIOS_SndDriverJmpTableCopy() -{ -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_SWI) - { - log("SndDriverJmpTableCopy: dest=%08x\n", - reg[0].I); - } -#endif - for(int i = 0; i < 0x24; i++) - { - CPUWriteMemory(reg[0].I, 0x9c); - reg[0].I += 4; - } -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2005-2006 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. + +#include +#include +#include + +#include "agb/GBA.h" +#include "bios.h" +#include "agb/GBAinline.h" +#include "Globals.h" + +s16 sineTable[256] = { + (s16)0x0000, (s16)0x0192, (s16)0x0323, (s16)0x04B5, (s16)0x0645, (s16)0x07D5, (s16)0x0964, (s16)0x0AF1, + (s16)0x0C7C, (s16)0x0E05, (s16)0x0F8C, (s16)0x1111, (s16)0x1294, (s16)0x1413, (s16)0x158F, (s16)0x1708, + (s16)0x187D, (s16)0x19EF, (s16)0x1B5D, (s16)0x1CC6, (s16)0x1E2B, (s16)0x1F8B, (s16)0x20E7, (s16)0x223D, + (s16)0x238E, (s16)0x24DA, (s16)0x261F, (s16)0x275F, (s16)0x2899, (s16)0x29CD, (s16)0x2AFA, (s16)0x2C21, + (s16)0x2D41, (s16)0x2E5A, (s16)0x2F6B, (s16)0x3076, (s16)0x3179, (s16)0x3274, (s16)0x3367, (s16)0x3453, + (s16)0x3536, (s16)0x3612, (s16)0x36E5, (s16)0x37AF, (s16)0x3871, (s16)0x392A, (s16)0x39DA, (s16)0x3A82, + (s16)0x3B20, (s16)0x3BB6, (s16)0x3C42, (s16)0x3CC5, (s16)0x3D3E, (s16)0x3DAE, (s16)0x3E14, (s16)0x3E71, + (s16)0x3EC5, (s16)0x3F0E, (s16)0x3F4E, (s16)0x3F84, (s16)0x3FB1, (s16)0x3FD3, (s16)0x3FEC, (s16)0x3FFB, + (s16)0x4000, (s16)0x3FFB, (s16)0x3FEC, (s16)0x3FD3, (s16)0x3FB1, (s16)0x3F84, (s16)0x3F4E, (s16)0x3F0E, + (s16)0x3EC5, (s16)0x3E71, (s16)0x3E14, (s16)0x3DAE, (s16)0x3D3E, (s16)0x3CC5, (s16)0x3C42, (s16)0x3BB6, + (s16)0x3B20, (s16)0x3A82, (s16)0x39DA, (s16)0x392A, (s16)0x3871, (s16)0x37AF, (s16)0x36E5, (s16)0x3612, + (s16)0x3536, (s16)0x3453, (s16)0x3367, (s16)0x3274, (s16)0x3179, (s16)0x3076, (s16)0x2F6B, (s16)0x2E5A, + (s16)0x2D41, (s16)0x2C21, (s16)0x2AFA, (s16)0x29CD, (s16)0x2899, (s16)0x275F, (s16)0x261F, (s16)0x24DA, + (s16)0x238E, (s16)0x223D, (s16)0x20E7, (s16)0x1F8B, (s16)0x1E2B, (s16)0x1CC6, (s16)0x1B5D, (s16)0x19EF, + (s16)0x187D, (s16)0x1708, (s16)0x158F, (s16)0x1413, (s16)0x1294, (s16)0x1111, (s16)0x0F8C, (s16)0x0E05, + (s16)0x0C7C, (s16)0x0AF1, (s16)0x0964, (s16)0x07D5, (s16)0x0645, (s16)0x04B5, (s16)0x0323, (s16)0x0192, + (s16)0x0000, (s16)0xFE6E, (s16)0xFCDD, (s16)0xFB4B, (s16)0xF9BB, (s16)0xF82B, (s16)0xF69C, (s16)0xF50F, + (s16)0xF384, (s16)0xF1FB, (s16)0xF074, (s16)0xEEEF, (s16)0xED6C, (s16)0xEBED, (s16)0xEA71, (s16)0xE8F8, + (s16)0xE783, (s16)0xE611, (s16)0xE4A3, (s16)0xE33A, (s16)0xE1D5, (s16)0xE075, (s16)0xDF19, (s16)0xDDC3, + (s16)0xDC72, (s16)0xDB26, (s16)0xD9E1, (s16)0xD8A1, (s16)0xD767, (s16)0xD633, (s16)0xD506, (s16)0xD3DF, + (s16)0xD2BF, (s16)0xD1A6, (s16)0xD095, (s16)0xCF8A, (s16)0xCE87, (s16)0xCD8C, (s16)0xCC99, (s16)0xCBAD, + (s16)0xCACA, (s16)0xC9EE, (s16)0xC91B, (s16)0xC851, (s16)0xC78F, (s16)0xC6D6, (s16)0xC626, (s16)0xC57E, + (s16)0xC4E0, (s16)0xC44A, (s16)0xC3BE, (s16)0xC33B, (s16)0xC2C2, (s16)0xC252, (s16)0xC1EC, (s16)0xC18F, + (s16)0xC13B, (s16)0xC0F2, (s16)0xC0B2, (s16)0xC07C, (s16)0xC04F, (s16)0xC02D, (s16)0xC014, (s16)0xC005, + (s16)0xC000, (s16)0xC005, (s16)0xC014, (s16)0xC02D, (s16)0xC04F, (s16)0xC07C, (s16)0xC0B2, (s16)0xC0F2, + (s16)0xC13B, (s16)0xC18F, (s16)0xC1EC, (s16)0xC252, (s16)0xC2C2, (s16)0xC33B, (s16)0xC3BE, (s16)0xC44A, + (s16)0xC4E0, (s16)0xC57E, (s16)0xC626, (s16)0xC6D6, (s16)0xC78F, (s16)0xC851, (s16)0xC91B, (s16)0xC9EE, + (s16)0xCACA, (s16)0xCBAD, (s16)0xCC99, (s16)0xCD8C, (s16)0xCE87, (s16)0xCF8A, (s16)0xD095, (s16)0xD1A6, + (s16)0xD2BF, (s16)0xD3DF, (s16)0xD506, (s16)0xD633, (s16)0xD767, (s16)0xD8A1, (s16)0xD9E1, (s16)0xDB26, + (s16)0xDC72, (s16)0xDDC3, (s16)0xDF19, (s16)0xE075, (s16)0xE1D5, (s16)0xE33A, (s16)0xE4A3, (s16)0xE611, + (s16)0xE783, (s16)0xE8F8, (s16)0xEA71, (s16)0xEBED, (s16)0xED6C, (s16)0xEEEF, (s16)0xF074, (s16)0xF1FB, + (s16)0xF384, (s16)0xF50F, (s16)0xF69C, (s16)0xF82B, (s16)0xF9BB, (s16)0xFB4B, (s16)0xFCDD, (s16)0xFE6E +}; + +void BIOS_ArcTan() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("ArcTan: %08x (VCOUNT=%2d)\n", + reg[0].I, + VCOUNT); + } +#endif + + s32 a = -(((s32)(reg[0].I*reg[0].I)) >> 14); + s32 b = ((0xA9 * a) >> 14) + 0x390; + b = ((b * a) >> 14) + 0x91C; + b = ((b * a) >> 14) + 0xFB6; + b = ((b * a) >> 14) + 0x16AA; + b = ((b * a) >> 14) + 0x2081; + b = ((b * a) >> 14) + 0x3651; + b = ((b * a) >> 14) + 0xA2F9; + a = ((s32)reg[0].I * b) >> 16; + reg[0].I = a; + +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("ArcTan: return=%08x\n", + reg[0].I); + } +#endif +} + +void BIOS_ArcTan2() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("ArcTan2: %08x,%08x (VCOUNT=%2d)\n", + reg[0].I, + reg[1].I, + VCOUNT); + } +#endif + + s32 x = reg[0].I; + s32 y = reg[1].I; + u32 res = 0; + if (y == 0) { + res = ((x>>16) & 0x8000); + } else { + if (x == 0) { + res = ((y>>16) & 0x8000) + 0x4000; + } else { + if ((abs(x) > abs(y)) || ((abs(x) == abs(y)) && (!((x<0) && (y<0))))) { + reg[1].I = x; + reg[0].I = y << 14; + BIOS_Div(); + BIOS_ArcTan(); + if (x < 0) + res = 0x8000 + reg[0].I; + else + res = (((y>>16) & 0x8000)<<1) + reg[0].I; + } else { + reg[0].I = x << 14; + BIOS_Div(); + BIOS_ArcTan(); + res = (0x4000 + ((y>>16) & 0x8000)) - reg[0].I; + } + } + } + reg[0].I = res; + +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("ArcTan2: return=%08x\n", + reg[0].I); + } +#endif +} + +void BIOS_BitUnPack() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("BitUnPack: %08x,%08x,%08x (VCOUNT=%2d)\n", + reg[0].I, + reg[1].I, + reg[2].I, + VCOUNT); + } +#endif + + u32 source = reg[0].I; + u32 dest = reg[1].I; + u32 header = reg[2].I; + + int len = CPUReadHalfWord(header); + // check address + if(((source & 0xe000000) == 0) || + ((source + len) & 0xe000000) == 0) + return; + + int bits = CPUReadByte(header+2); + int revbits = 8 - bits; + // u32 value = 0; + u32 base = CPUReadMemory(header+4); + bool addBase = (base & 0x80000000) ? true : false; + base &= 0x7fffffff; + int dataSize = CPUReadByte(header+3); + + int data = 0; + int bitwritecount = 0; + while(1) { + len -= 1; + if(len < 0) + break; + int mask = 0xff >> revbits; + u8 b = CPUReadByte(source); + source++; + int bitcount = 0; + while(1) { + if(bitcount >= 8) + break; + u32 d = b & mask; + u32 temp = d >> bitcount; + if(d || addBase) { + temp += base; + } + data |= temp << bitwritecount; + bitwritecount += dataSize; + if(bitwritecount >= 32) { + CPUWriteMemory(dest, data); + dest += 4; + data = 0; + bitwritecount = 0; + } + mask <<= bits; + bitcount += bits; + } + } +} + +void BIOS_GetBiosChecksum() +{ + reg[0].I=0xBAAE187F; +} + +void BIOS_BgAffineSet() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("BgAffineSet: %08x,%08x,%08x (VCOUNT=%2d)\n", + reg[0].I, + reg[1].I, + reg[2].I, + VCOUNT); + } +#endif + + u32 src = reg[0].I; + u32 dest = reg[1].I; + int num = reg[2].I; + + for(int i = 0; i < num; i++) { + s32 cx = CPUReadMemory(src); + src+=4; + s32 cy = CPUReadMemory(src); + src+=4; + s16 dispx = CPUReadHalfWord(src); + src+=2; + s16 dispy = CPUReadHalfWord(src); + src+=2; + s16 rx = CPUReadHalfWord(src); + src+=2; + s16 ry = CPUReadHalfWord(src); + src+=2; + u16 theta = CPUReadHalfWord(src)>>8; + src+=4; // keep structure alignment + s32 a = sineTable[(theta+0x40)&255]; + s32 b = sineTable[theta]; + + s16 dx = (rx * a)>>14; + s16 dmx = (rx * b)>>14; + s16 dy = (ry * b)>>14; + s16 dmy = (ry * a)>>14; + + CPUWriteHalfWord(dest, dx); + dest += 2; + CPUWriteHalfWord(dest, -dmx); + dest += 2; + CPUWriteHalfWord(dest, dy); + dest += 2; + CPUWriteHalfWord(dest, dmy); + dest += 2; + + s32 startx = cx - dx * dispx + dmx * dispy; + s32 starty = cy - dy * dispx - dmy * dispy; + + CPUWriteMemory(dest, startx); + dest += 4; + CPUWriteMemory(dest, starty); + dest += 4; + } +} + +void BIOS_CpuSet() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("CpuSet: 0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I, + reg[2].I, VCOUNT); + } +#endif + + u32 source = reg[0].I; + u32 dest = reg[1].I; + u32 cnt = reg[2].I; + + if(((source & 0xe000000) == 0) || + ((source + (((cnt << 11)>>9) & 0x1fffff)) & 0xe000000) == 0) + return; + + int count = cnt & 0x1FFFFF; + + // 32-bit ? + if((cnt >> 26) & 1) { + // needed for 32-bit mode! + source &= 0xFFFFFFFC; + dest &= 0xFFFFFFFC; + // fill ? + if((cnt >> 24) & 1) { + u32 value = (source>0x0EFFFFFF ? 0x1CAD1CAD : CPUReadMemory(source)); + while(count) { + CPUWriteMemory(dest, value); + dest += 4; + count--; + } + } else { + // copy + while(count) { + CPUWriteMemory(dest, (source>0x0EFFFFFF ? 0x1CAD1CAD : CPUReadMemory(source))); + source += 4; + dest += 4; + count--; + } + } + } else { + // 16-bit fill? + if((cnt >> 24) & 1) { + u16 value = (source>0x0EFFFFFF ? 0x1CAD : CPUReadHalfWord(source)); + while(count) { + CPUWriteHalfWord(dest, value); + dest += 2; + count--; + } + } else { + // copy + while(count) { + CPUWriteHalfWord(dest, (source>0x0EFFFFFF ? 0x1CAD : CPUReadHalfWord(source))); + source += 2; + dest += 2; + count--; + } + } + } +} + +void BIOS_CpuFastSet() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("CpuFastSet: 0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I, + reg[2].I, VCOUNT); + } +#endif + + u32 source = reg[0].I; + u32 dest = reg[1].I; + u32 cnt = reg[2].I; + + if(((source & 0xe000000) == 0) || + ((source + (((cnt << 11)>>9) & 0x1fffff)) & 0xe000000) == 0) + return; + + // needed for 32-bit mode! + source &= 0xFFFFFFFC; + dest &= 0xFFFFFFFC; + + int count = cnt & 0x1FFFFF; + + // fill? + if((cnt >> 24) & 1) { + while(count > 0) { + // BIOS always transfers 32 bytes at a time + u32 value = (source>0x0EFFFFFF ? 0xBAFFFFFB : CPUReadMemory(source)); + for(int i = 0; i < 8; i++) { + CPUWriteMemory(dest, value); + dest += 4; + } + count -= 8; + } + } else { + // copy + while(count > 0) { + // BIOS always transfers 32 bytes at a time + for(int i = 0; i < 8; i++) { + CPUWriteMemory(dest, (source>0x0EFFFFFF ? 0xBAFFFFFB :CPUReadMemory(source))); + source += 4; + dest += 4; + } + count -= 8; + } + } +} + +void BIOS_Diff8bitUnFilterWram() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("Diff8bitUnFilterWram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, + reg[1].I, VCOUNT); + } +#endif + + u32 source = reg[0].I; + u32 dest = reg[1].I; + + u32 header = CPUReadMemory(source); + source += 4; + + if(((source & 0xe000000) == 0) || + ((source + ((header >> 8) & 0x1fffff) & 0xe000000) == 0)) + return; + + int len = header >> 8; + + u8 data = CPUReadByte(source++); + CPUWriteByte(dest++, data); + len--; + + while(len > 0) { + u8 diff = CPUReadByte(source++); + data += diff; + CPUWriteByte(dest++, data); + len--; + } +} + +void BIOS_Diff8bitUnFilterVram() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("Diff8bitUnFilterVram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, + reg[1].I, VCOUNT); + } +#endif + + u32 source = reg[0].I; + u32 dest = reg[1].I; + + u32 header = CPUReadMemory(source); + source += 4; + + if(((source & 0xe000000) == 0) || + ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) + return; + + int len = header >> 8; + + u8 data = CPUReadByte(source++); + u16 writeData = data; + int shift = 8; + int bytes = 1; + + while(len >= 2) { + u8 diff = CPUReadByte(source++); + data += diff; + writeData |= (data << shift); + bytes++; + shift += 8; + if(bytes == 2) { + CPUWriteHalfWord(dest, writeData); + dest += 2; + len -= 2; + bytes = 0; + writeData = 0; + shift = 0; + } + } +} + +void BIOS_Diff16bitUnFilter() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("Diff16bitUnFilter: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, + reg[1].I, VCOUNT); + } +#endif + + u32 source = reg[0].I; + u32 dest = reg[1].I; + + u32 header = CPUReadMemory(source); + source += 4; + + if(((source & 0xe000000) == 0) || + ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) + return; + + int len = header >> 8; + + u16 data = CPUReadHalfWord(source); + source += 2; + CPUWriteHalfWord(dest, data); + dest += 2; + len -= 2; + + while(len >= 2) { + u16 diff = CPUReadHalfWord(source); + source += 2; + data += diff; + CPUWriteHalfWord(dest, data); + dest += 2; + len -= 2; + } +} + +void BIOS_Div() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("Div: 0x%08x,0x%08x (VCOUNT=%d)\n", + reg[0].I, + reg[1].I, + VCOUNT); + } +#endif + + int number = reg[0].I; + int denom = reg[1].I; + + if(denom != 0) { + reg[0].I = number / denom; + reg[1].I = number % denom; + s32 temp = (s32)reg[0].I; + reg[3].I = temp < 0 ? (u32)-temp : (u32)temp; + } +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("Div: return=0x%08x,0x%08x,0x%08x\n", + reg[0].I, + reg[1].I, + reg[3].I); + } +#endif +} + +void BIOS_DivARM() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("DivARM: 0x%08x, (VCOUNT=%d)\n", + reg[0].I, + VCOUNT); + } +#endif + + u32 temp = reg[0].I; + reg[0].I = reg[1].I; + reg[1].I = temp; + BIOS_Div(); +} + +void BIOS_HuffUnComp() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("HuffUnComp: 0x%08x,0x%08x (VCOUNT=%d)\n", + reg[0].I, + reg[1].I, + VCOUNT); + } +#endif + + u32 source = reg[0].I; + u32 dest = reg[1].I; + + u32 header = CPUReadMemory(source); + source += 4; + + if(((source & 0xe000000) == 0) || + ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) + return; + + u8 treeSize = CPUReadByte(source++); + + u32 treeStart = source; + + source += ((treeSize+1)<<1)-1; // minus because we already skipped one byte + + int len = header >> 8; + + u32 mask = 0x80000000; + u32 data = CPUReadMemory(source); + source += 4; + + int pos = 0; + u8 rootNode = CPUReadByte(treeStart); + u8 currentNode = rootNode; + bool writeData = false; + int byteShift = 0; + int byteCount = 0; + u32 writeValue = 0; + + if((header & 0x0F) == 8) { + while(len > 0) { + // take left + if(pos == 0) + pos++; + else + pos += (((currentNode & 0x3F)+1)<<1); + + if(data & mask) { + // right + if(currentNode & 0x40) + writeData = true; + currentNode = CPUReadByte(treeStart+pos+1); + } else { + // left + if(currentNode & 0x80) + writeData = true; + currentNode = CPUReadByte(treeStart+pos); + } + + if(writeData) { + writeValue |= (currentNode << byteShift); + byteCount++; + byteShift += 8; + + pos = 0; + currentNode = rootNode; + writeData = false; + + if(byteCount == 4) { + byteCount = 0; + byteShift = 0; + CPUWriteMemory(dest, writeValue); + writeValue = 0; + dest += 4; + len -= 4; + } + } + mask >>= 1; + if(mask == 0) { + mask = 0x80000000; + data = CPUReadMemory(source); + source += 4; + } + } + } else { + int halfLen = 0; + int value = 0; + while(len > 0) { + // take left + if(pos == 0) + pos++; + else + pos += (((currentNode & 0x3F)+1)<<1); + + if((data & mask)) { + // right + if(currentNode & 0x40) + writeData = true; + currentNode = CPUReadByte(treeStart+pos+1); + } else { + // left + if(currentNode & 0x80) + writeData = true; + currentNode = CPUReadByte(treeStart+pos); + } + + if(writeData) { + if(halfLen == 0) + value |= currentNode; + else + value |= (currentNode<<4); + + halfLen += 4; + if(halfLen == 8) { + writeValue |= (value << byteShift); + byteCount++; + byteShift += 8; + + halfLen = 0; + value = 0; + + if(byteCount == 4) { + byteCount = 0; + byteShift = 0; + CPUWriteMemory(dest, writeValue); + dest += 4; + writeValue = 0; + len -= 4; + } + } + pos = 0; + currentNode = rootNode; + writeData = false; + } + mask >>= 1; + if(mask == 0) { + mask = 0x80000000; + data = CPUReadMemory(source); + source += 4; + } + } + } +} + +void BIOS_LZ77UnCompVram() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("LZ77UnCompVram: 0x%08x,0x%08x (VCOUNT=%d)\n", + reg[0].I, + reg[1].I, + VCOUNT); + } +#endif + + u32 source = reg[0].I; + u32 dest = reg[1].I; + + u32 header = CPUReadMemory(source); + source += 4; + + if(((source & 0xe000000) == 0) || + ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) + return; + + int byteCount = 0; + int byteShift = 0; + u32 writeValue = 0; + + int len = header >> 8; + + while(len > 0) { + u8 d = CPUReadByte(source++); + + if(d) { + for(int i = 0; i < 8; i++) { + if(d & 0x80) { + u16 data = CPUReadByte(source++) << 8; + data |= CPUReadByte(source++); + int length = (data >> 12) + 3; + int offset = (data & 0x0FFF); + u32 windowOffset = dest + byteCount - offset - 1; + for(int i = 0; i < length; i++) { + writeValue |= (CPUReadByte(windowOffset++) << byteShift); + byteShift += 8; + byteCount++; + + if(byteCount == 2) { + CPUWriteHalfWord(dest, writeValue); + dest += 2; + byteCount = 0; + byteShift = 0; + writeValue = 0; + } + len--; + if(len == 0) + return; + } + } else { + writeValue |= (CPUReadByte(source++) << byteShift); + byteShift += 8; + byteCount++; + if(byteCount == 2) { + CPUWriteHalfWord(dest, writeValue); + dest += 2; + byteCount = 0; + byteShift = 0; + writeValue = 0; + } + len--; + if(len == 0) + return; + } + d <<= 1; + } + } else { + for(int i = 0; i < 8; i++) { + writeValue |= (CPUReadByte(source++) << byteShift); + byteShift += 8; + byteCount++; + if(byteCount == 2) { + CPUWriteHalfWord(dest, writeValue); + dest += 2; + byteShift = 0; + byteCount = 0; + writeValue = 0; + } + len--; + if(len == 0) + return; + } + } + } +} + +void BIOS_LZ77UnCompWram() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("LZ77UnCompWram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I, + VCOUNT); + } +#endif + + u32 source = reg[0].I; + u32 dest = reg[1].I; + + u32 header = CPUReadMemory(source); + source += 4; + + if(((source & 0xe000000) == 0) || + ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) + return; + + int len = header >> 8; + + while(len > 0) { + u8 d = CPUReadByte(source++); + + if(d) { + for(int i = 0; i < 8; i++) { + if(d & 0x80) { + u16 data = CPUReadByte(source++) << 8; + data |= CPUReadByte(source++); + int length = (data >> 12) + 3; + int offset = (data & 0x0FFF); + u32 windowOffset = dest - offset - 1; + for(int i = 0; i < length; i++) { + CPUWriteByte(dest++, CPUReadByte(windowOffset++)); + len--; + if(len == 0) + return; + } + } else { + CPUWriteByte(dest++, CPUReadByte(source++)); + len--; + if(len == 0) + return; + } + d <<= 1; + } + } else { + for(int i = 0; i < 8; i++) { + CPUWriteByte(dest++, CPUReadByte(source++)); + len--; + if(len == 0) + return; + } + } + } +} + +void BIOS_ObjAffineSet() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("ObjAffineSet: 0x%08x,0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n", + reg[0].I, + reg[1].I, + reg[2].I, + reg[3].I, + VCOUNT); + } +#endif + + u32 src = reg[0].I; + u32 dest = reg[1].I; + int num = reg[2].I; + int offset = reg[3].I; + + for(int i = 0; i < num; i++) { + s16 rx = CPUReadHalfWord(src); + src+=2; + s16 ry = CPUReadHalfWord(src); + src+=2; + u16 theta = CPUReadHalfWord(src)>>8; + src+=4; // keep structure alignment + + s32 a = (s32)sineTable[(theta+0x40)&255]; + s32 b = (s32)sineTable[theta]; + + s16 dx = ((s32)rx * a)>>14; + s16 dmx = ((s32)rx * b)>>14; + s16 dy = ((s32)ry * b)>>14; + s16 dmy = ((s32)ry * a)>>14; + + CPUWriteHalfWord(dest, dx); + dest += offset; + CPUWriteHalfWord(dest, -dmx); + dest += offset; + CPUWriteHalfWord(dest, dy); + dest += offset; + CPUWriteHalfWord(dest, dmy); + dest += offset; + } +} + +void BIOS_RegisterRamReset(u32 flags) +{ + // no need to trace here. this is only called directly from GBA.cpp + // to emulate bios initialization + + CPUUpdateRegister(0x0, 0x80); + + if(flags) { + if(flags & 0x01) { + // clear work RAM + memset(workRAM, 0, 0x40000); + } + if(flags & 0x02) { + // clear internal RAM + memset(internalRAM, 0, 0x7e00); // don't clear 0x7e00-0x7fff + } + if(flags & 0x04) { + // clear palette RAM + memset(paletteRAM, 0, 0x400); + } + if(flags & 0x08) { + // clear VRAM + memset(vram, 0, 0x18000); + } + if(flags & 0x10) { + // clean OAM + memset(oam, 0, 0x400); + } + + if(flags & 0x80) { + int i; + for(i = 0; i < 0x10; i++) + CPUUpdateRegister(0x200+i*2, 0); + + for(i = 0; i < 0xF; i++) + CPUUpdateRegister(0x4+i*2, 0); + + for(i = 0; i < 0x20; i++) + CPUUpdateRegister(0x20+i*2, 0); + + for(i = 0; i < 0x18; i++) + CPUUpdateRegister(0xb0+i*2, 0); + + CPUUpdateRegister(0x130, 0); + CPUUpdateRegister(0x20, 0x100); + CPUUpdateRegister(0x30, 0x100); + CPUUpdateRegister(0x26, 0x100); + CPUUpdateRegister(0x36, 0x100); + } + + if(flags & 0x20) { + int i; + for(i = 0; i < 8; i++) + CPUUpdateRegister(0x110+i*2, 0); + CPUUpdateRegister(0x134, 0x8000); + for(i = 0; i < 7; i++) + CPUUpdateRegister(0x140+i*2, 0); + } + + if(flags & 0x40) { + int i; + CPUWriteByte(0x4000084, 0); + CPUWriteByte(0x4000084, 0x80); + CPUWriteMemory(0x4000080, 0x880e0000); + CPUUpdateRegister(0x88, CPUReadHalfWord(0x4000088)&0x3ff); + CPUWriteByte(0x4000070, 0x70); + for(i = 0; i < 8; i++) + CPUUpdateRegister(0x90+i*2, 0); + CPUWriteByte(0x4000070, 0); + for(i = 0; i < 8; i++) + CPUUpdateRegister(0x90+i*2, 0); + CPUWriteByte(0x4000084, 0); + } + } +} + +void BIOS_RegisterRamReset() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("RegisterRamReset: 0x%08x (VCOUNT=%d)\n", + reg[0].I, + VCOUNT); + } +#endif + + BIOS_RegisterRamReset(reg[0].I); +} + +void BIOS_RLUnCompVram() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("RLUnCompVram: 0x%08x,0x%08x (VCOUNT=%d)\n", + reg[0].I, + reg[1].I, + VCOUNT); + } +#endif + + u32 source = reg[0].I; + u32 dest = reg[1].I; + + u32 header = CPUReadMemory(source & 0xFFFFFFFC); + source += 4; + + if(((source & 0xe000000) == 0) || + ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) + return; + + int len = header >> 8; + int byteCount = 0; + int byteShift = 0; + u32 writeValue = 0; + + while(len > 0) { + u8 d = CPUReadByte(source++); + int l = d & 0x7F; + if(d & 0x80) { + u8 data = CPUReadByte(source++); + l += 3; + for(int i = 0;i < l; i++) { + writeValue |= (data << byteShift); + byteShift += 8; + byteCount++; + + if(byteCount == 2) { + CPUWriteHalfWord(dest, writeValue); + dest += 2; + byteCount = 0; + byteShift = 0; + writeValue = 0; + } + len--; + if(len == 0) + return; + } + } else { + l++; + for(int i = 0; i < l; i++) { + writeValue |= (CPUReadByte(source++) << byteShift); + byteShift += 8; + byteCount++; + if(byteCount == 2) { + CPUWriteHalfWord(dest, writeValue); + dest += 2; + byteCount = 0; + byteShift = 0; + writeValue = 0; + } + len--; + if(len == 0) + return; + } + } + } +} + +void BIOS_RLUnCompWram() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("RLUnCompWram: 0x%08x,0x%08x (VCOUNT=%d)\n", + reg[0].I, + reg[1].I, + VCOUNT); + } +#endif + + u32 source = reg[0].I; + u32 dest = reg[1].I; + + u32 header = CPUReadMemory(source & 0xFFFFFFFC); + source += 4; + + if(((source & 0xe000000) == 0) || + ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0) + return; + + int len = header >> 8; + + while(len > 0) { + u8 d = CPUReadByte(source++); + int l = d & 0x7F; + if(d & 0x80) { + u8 data = CPUReadByte(source++); + l += 3; + for(int i = 0;i < l; i++) { + CPUWriteByte(dest++, data); + len--; + if(len == 0) + return; + } + } else { + l++; + for(int i = 0; i < l; i++) { + CPUWriteByte(dest++, CPUReadByte(source++)); + len--; + if(len == 0) + return; + } + } + } +} + +void BIOS_SoftReset() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("SoftReset: (VCOUNT=%d)\n", VCOUNT); + } +#endif + + armState = true; + armMode = 0x1F; + armIrqEnable = false; + C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false; + reg[13].I = 0x03007F00; + reg[14].I = 0x00000000; + reg[16].I = 0x00000000; + reg[R13_IRQ].I = 0x03007FA0; + reg[R14_IRQ].I = 0x00000000; + reg[SPSR_IRQ].I = 0x00000000; + reg[R13_SVC].I = 0x03007FE0; + reg[R14_SVC].I = 0x00000000; + reg[SPSR_SVC].I = 0x00000000; + u8 b = internalRAM[0x7ffa]; + + memset(&internalRAM[0x7e00], 0, 0x200); + + if(b) { + armNextPC = 0x02000000; + reg[15].I = 0x02000004; + } else { + armNextPC = 0x08000000; + reg[15].I = 0x08000004; + } +} + +void BIOS_Sqrt() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("Sqrt: %08x (VCOUNT=%2d)\n", + reg[0].I, + VCOUNT); + } +#endif + reg[0].I = (u32)sqrt((double)reg[0].I); +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("Sqrt: return=%08x\n", + reg[0].I); + } +#endif +} + +void BIOS_MidiKey2Freq() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("MidiKey2Freq: WaveData=%08x mk=%08x fp=%08x\n", + reg[0].I, + reg[1].I, + reg[2].I); + } +#endif + int freq = CPUReadMemory(reg[0].I+4); + double tmp; + tmp = ((double)(180 - reg[1].I)) - ((double)reg[2].I / 256.f); + tmp = pow((double)2.f, tmp / 12.f); + reg[0].I = (int)((double)freq / tmp); + +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("MidiKey2Freq: return %08x\n", + reg[0].I); + } +#endif +} + +void BIOS_SndDriverJmpTableCopy() +{ +#ifdef GBA_LOGGING + if(systemVerbose & VERBOSE_SWI) { + log("SndDriverJmpTableCopy: dest=%08x\n", + reg[0].I); + } +#endif + for(int i = 0; i < 0x24; i++) { + CPUWriteMemory(reg[0].I, 0x9c); + reg[0].I += 4; + } +} diff --git a/source/vba/bios.h b/source/vba/bios.h index 58b3417..538a0c9 100644 --- a/source/vba/bios.h +++ b/source/vba/bios.h @@ -1,46 +1,47 @@ -// -*- 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_BIOS_H -#define VBA_BIOS_H - -extern void BIOS_ArcTan(); -extern void BIOS_ArcTan2(); -extern void BIOS_BitUnPack(); -extern void BIOS_BgAffineSet(); -extern void BIOS_CpuSet(); -extern void BIOS_CpuFastSet(); -extern void BIOS_Diff8bitUnFilterWram(); -extern void BIOS_Diff8bitUnFilterVram(); -extern void BIOS_Diff16bitUnFilter(); -extern void BIOS_Div(); -extern void BIOS_DivARM(); -extern void BIOS_HuffUnComp(); -extern void BIOS_LZ77UnCompVram(); -extern void BIOS_LZ77UnCompWram(); -extern void BIOS_ObjAffineSet(); -extern void BIOS_RegisterRamReset(); -extern void BIOS_RegisterRamReset(u32); -extern void BIOS_RLUnCompVram(); -extern void BIOS_RLUnCompWram(); -extern void BIOS_SoftReset(); -extern void BIOS_Sqrt(); -extern void BIOS_MidiKey2Freq(); -extern void BIOS_SndDriverJmpTableCopy(); -#endif // VBA_BIOS_H +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004-2006 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_BIOS_H +#define VBA_BIOS_H + +extern void BIOS_ArcTan(); +extern void BIOS_ArcTan2(); +extern void BIOS_BitUnPack(); +extern void BIOS_GetBiosChecksum(); +extern void BIOS_BgAffineSet(); +extern void BIOS_CpuSet(); +extern void BIOS_CpuFastSet(); +extern void BIOS_Diff8bitUnFilterWram(); +extern void BIOS_Diff8bitUnFilterVram(); +extern void BIOS_Diff16bitUnFilter(); +extern void BIOS_Div(); +extern void BIOS_DivARM(); +extern void BIOS_HuffUnComp(); +extern void BIOS_LZ77UnCompVram(); +extern void BIOS_LZ77UnCompWram(); +extern void BIOS_ObjAffineSet(); +extern void BIOS_RegisterRamReset(); +extern void BIOS_RegisterRamReset(u32); +extern void BIOS_RLUnCompVram(); +extern void BIOS_RLUnCompWram(); +extern void BIOS_SoftReset(); +extern void BIOS_Sqrt(); +extern void BIOS_MidiKey2Freq(); +extern void BIOS_SndDriverJmpTableCopy(); +#endif // VBA_BIOS_H diff --git a/source/vba/gb/GB.cpp b/source/vba/dmg/GB.cpp similarity index 99% rename from source/vba/gb/GB.cpp rename to source/vba/dmg/GB.cpp index c655b5c..05d3fb1 100644 --- a/source/vba/gb/GB.cpp +++ b/source/vba/dmg/GB.cpp @@ -2548,9 +2548,11 @@ bool gbReadSaveState(const char *name) bool gbWritePNGFile(const char *fileName) { - if(gbBorderOn) - return utilWritePNGFile(fileName, 256, 224, pix); - return utilWritePNGFile(fileName, 160, 144, pix); + // if(gbBorderOn) + // return utilWritePNGFile(fileName, 256, 224, pix); +// return utilWritePNGFile(fileName, 160, 144, pix); + +return false; } bool gbWriteBMPFile(const char *fileName) diff --git a/source/vba/gb/GB.h b/source/vba/dmg/GB.h similarity index 100% rename from source/vba/gb/GB.h rename to source/vba/dmg/GB.h diff --git a/source/vba/gb/gbCheats.cpp b/source/vba/dmg/gbCheats.cpp similarity index 100% rename from source/vba/gb/gbCheats.cpp rename to source/vba/dmg/gbCheats.cpp diff --git a/source/vba/gb/gbCheats.h b/source/vba/dmg/gbCheats.h similarity index 100% rename from source/vba/gb/gbCheats.h rename to source/vba/dmg/gbCheats.h diff --git a/source/vba/gb/gbCodes.h b/source/vba/dmg/gbCodes.h similarity index 100% rename from source/vba/gb/gbCodes.h rename to source/vba/dmg/gbCodes.h diff --git a/source/vba/gb/gbCodesCB.h b/source/vba/dmg/gbCodesCB.h similarity index 100% rename from source/vba/gb/gbCodesCB.h rename to source/vba/dmg/gbCodesCB.h diff --git a/source/vba/gb/gbDis.cpp b/source/vba/dmg/gbDis.cpp similarity index 100% rename from source/vba/gb/gbDis.cpp rename to source/vba/dmg/gbDis.cpp diff --git a/source/vba/gb/gbGfx.cpp b/source/vba/dmg/gbGfx.cpp similarity index 99% rename from source/vba/gb/gbGfx.cpp rename to source/vba/dmg/gbGfx.cpp index ba863af..d829516 100644 --- a/source/vba/gb/gbGfx.cpp +++ b/source/vba/dmg/gbGfx.cpp @@ -18,7 +18,7 @@ #include -#include "../GBA.h" +#include "../agb/GBA.h" #include "gbGlobals.h" #include "gbSGB.h" diff --git a/source/vba/gb/gbGlobals.cpp b/source/vba/dmg/gbGlobals.cpp similarity index 98% rename from source/vba/gb/gbGlobals.cpp rename to source/vba/dmg/gbGlobals.cpp index 90b1af1..435878a 100644 --- a/source/vba/gb/gbGlobals.cpp +++ b/source/vba/dmg/gbGlobals.cpp @@ -16,7 +16,7 @@ // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include "../GBA.h" +#include "../agb/GBA.h" u8 *gbMemoryMap[16]; diff --git a/source/vba/gb/gbGlobals.h b/source/vba/dmg/gbGlobals.h similarity index 100% rename from source/vba/gb/gbGlobals.h rename to source/vba/dmg/gbGlobals.h diff --git a/source/vba/gb/gbMemory.cpp b/source/vba/dmg/gbMemory.cpp similarity index 99% rename from source/vba/gb/gbMemory.cpp rename to source/vba/dmg/gbMemory.cpp index 5d23b55..40c722a 100644 --- a/source/vba/gb/gbMemory.cpp +++ b/source/vba/dmg/gbMemory.cpp @@ -16,7 +16,7 @@ // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include "../GBA.h" +#include "../agb/GBA.h" #include "../Port.h" #include "gbGlobals.h" #include "gbMemory.h" diff --git a/source/vba/gb/gbMemory.h b/source/vba/dmg/gbMemory.h similarity index 100% rename from source/vba/gb/gbMemory.h rename to source/vba/dmg/gbMemory.h diff --git a/source/vba/gb/gbPrinter.cpp b/source/vba/dmg/gbPrinter.cpp similarity index 99% rename from source/vba/gb/gbPrinter.cpp rename to source/vba/dmg/gbPrinter.cpp index 8bb1b66..bb3c5db 100644 --- a/source/vba/gb/gbPrinter.cpp +++ b/source/vba/dmg/gbPrinter.cpp @@ -18,7 +18,7 @@ #include #include -#include "../GBA.h" +#include "../agb/GBA.h" u8 gbPrinterStatus = 0; int gbPrinterState = 0; diff --git a/source/vba/gb/gbPrinter.h b/source/vba/dmg/gbPrinter.h similarity index 100% rename from source/vba/gb/gbPrinter.h rename to source/vba/dmg/gbPrinter.h diff --git a/source/vba/gb/gbSGB.cpp b/source/vba/dmg/gbSGB.cpp similarity index 100% rename from source/vba/gb/gbSGB.cpp rename to source/vba/dmg/gbSGB.cpp diff --git a/source/vba/gb/gbSGB.h b/source/vba/dmg/gbSGB.h similarity index 100% rename from source/vba/gb/gbSGB.h rename to source/vba/dmg/gbSGB.h diff --git a/source/vba/gb/gbSound.cpp b/source/vba/dmg/gbSound.cpp similarity index 100% rename from source/vba/gb/gbSound.cpp rename to source/vba/dmg/gbSound.cpp diff --git a/source/vba/gb/gbSound.h b/source/vba/dmg/gbSound.h similarity index 100% rename from source/vba/gb/gbSound.h rename to source/vba/dmg/gbSound.h diff --git a/source/vba/elf.cpp b/source/vba/elf.cpp index 25cce47..da7e418 100644 --- a/source/vba/elf.cpp +++ b/source/vba/elf.cpp @@ -1,3248 +1,2994 @@ -// 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. - -#include "sdfileio.h" -#include -#include -#include - -#include "GBA.h" -#include "Port.h" -#include "elf.h" -#include "NLS.h" - -#define elfReadMemory(addr) \ - READ32LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) - -#define DW_TAG_array_type 0x01 -#define DW_TAG_enumeration_type 0x04 -#define DW_TAG_formal_parameter 0x05 -#define DW_TAG_label 0x0a -#define DW_TAG_lexical_block 0x0b -#define DW_TAG_member 0x0d -#define DW_TAG_pointer_type 0x0f -#define DW_TAG_reference_type 0x10 -#define DW_TAG_compile_unit 0x11 -#define DW_TAG_structure_type 0x13 -#define DW_TAG_subroutine_type 0x15 -#define DW_TAG_typedef 0x16 -#define DW_TAG_union_type 0x17 -#define DW_TAG_unspecified_parameters 0x18 -#define DW_TAG_inheritance 0x1c -#define DW_TAG_inlined_subroutine 0x1d -#define DW_TAG_subrange_type 0x21 -#define DW_TAG_base_type 0x24 -#define DW_TAG_const_type 0x26 -#define DW_TAG_enumerator 0x28 -#define DW_TAG_subprogram 0x2e -#define DW_TAG_variable 0x34 -#define DW_TAG_volatile_type 0x35 - -#define DW_AT_sibling 0x01 -#define DW_AT_location 0x02 -#define DW_AT_name 0x03 -#define DW_AT_byte_size 0x0b -#define DW_AT_bit_offset 0x0c -#define DW_AT_bit_size 0x0d -#define DW_AT_stmt_list 0x10 -#define DW_AT_low_pc 0x11 -#define DW_AT_high_pc 0x12 -#define DW_AT_language 0x13 -#define DW_AT_compdir 0x1b -#define DW_AT_const_value 0x1c -#define DW_AT_containing_type 0x1d -#define DW_AT_inline 0x20 -#define DW_AT_producer 0x25 -#define DW_AT_prototyped 0x27 -#define DW_AT_upper_bound 0x2f -#define DW_AT_abstract_origin 0x31 -#define DW_AT_accessibility 0x32 -#define DW_AT_artificial 0x34 -#define DW_AT_data_member_location 0x38 -#define DW_AT_decl_file 0x3a -#define DW_AT_decl_line 0x3b -#define DW_AT_declaration 0x3c -#define DW_AT_encoding 0x3e -#define DW_AT_external 0x3f -#define DW_AT_frame_base 0x40 -#define DW_AT_macro_info 0x43 -#define DW_AT_specification 0x47 -#define DW_AT_type 0x49 -#define DW_AT_virtuality 0x4c -#define DW_AT_vtable_elem_location 0x4d -// DWARF 2.1/3.0 extensions -#define DW_AT_entry_pc 0x52 -#define DW_AT_ranges 0x55 -// ARM Compiler extensions -#define DW_AT_proc_body 0x2000 -#define DW_AT_save_offset 0x2001 -#define DW_AT_user_2002 0x2002 -// MIPS extensions -#define DW_AT_MIPS_linkage_name 0x2007 - -#define DW_FORM_addr 0x01 -#define DW_FORM_data2 0x05 -#define DW_FORM_data4 0x06 -#define DW_FORM_string 0x08 -#define DW_FORM_block 0x09 -#define DW_FORM_block1 0x0a -#define DW_FORM_data1 0x0b -#define DW_FORM_flag 0x0c -#define DW_FORM_sdata 0x0d -#define DW_FORM_strp 0x0e -#define DW_FORM_udata 0x0f -#define DW_FORM_ref_addr 0x10 -#define DW_FORM_ref4 0x13 -#define DW_FORM_ref_udata 0x15 -#define DW_FORM_indirect 0x16 - -#define DW_OP_addr 0x03 -#define DW_OP_plus_uconst 0x23 -#define DW_OP_reg0 0x50 -#define DW_OP_reg1 0x51 -#define DW_OP_reg2 0x52 -#define DW_OP_reg3 0x53 -#define DW_OP_reg4 0x54 -#define DW_OP_reg5 0x55 -#define DW_OP_reg6 0x56 -#define DW_OP_reg7 0x57 -#define DW_OP_reg8 0x58 -#define DW_OP_reg9 0x59 -#define DW_OP_reg10 0x5a -#define DW_OP_reg11 0x5b -#define DW_OP_reg12 0x5c -#define DW_OP_reg13 0x5d -#define DW_OP_reg14 0x5e -#define DW_OP_reg15 0x5f -#define DW_OP_fbreg 0x91 - -#define DW_LNS_extended_op 0x00 -#define DW_LNS_copy 0x01 -#define DW_LNS_advance_pc 0x02 -#define DW_LNS_advance_line 0x03 -#define DW_LNS_set_file 0x04 -#define DW_LNS_set_column 0x05 -#define DW_LNS_negate_stmt 0x06 -#define DW_LNS_set_basic_block 0x07 -#define DW_LNS_const_add_pc 0x08 -#define DW_LNS_fixed_advance_pc 0x09 - -#define DW_LNE_end_sequence 0x01 -#define DW_LNE_set_address 0x02 -#define DW_LNE_define_file 0x03 - -#define DW_CFA_advance_loc 0x01 -#define DW_CFA_offset 0x02 -#define DW_CFA_restore 0x03 -#define DW_CFA_set_loc 0x01 -#define DW_CFA_advance_loc1 0x02 -#define DW_CFA_advance_loc2 0x03 -#define DW_CFA_advance_loc4 0x04 -#define DW_CFA_offset_extended 0x05 -#define DW_CFA_restore_extended 0x06 -#define DW_CFA_undefined 0x07 -#define DW_CFA_same_value 0x08 -#define DW_CFA_register 0x09 -#define DW_CFA_remember_state 0x0a -#define DW_CFA_restore_state 0x0b -#define DW_CFA_def_cfa 0x0c -#define DW_CFA_def_cfa_register 0x0d -#define DW_CFA_def_cfa_offset 0x0e -#define DW_CFA_nop 0x00 - -#define CASE_TYPE_TAG \ - case DW_TAG_const_type:\ - case DW_TAG_volatile_type:\ - case DW_TAG_pointer_type:\ - case DW_TAG_base_type:\ - case DW_TAG_array_type:\ - case DW_TAG_structure_type:\ - case DW_TAG_union_type:\ - case DW_TAG_typedef:\ - case DW_TAG_subroutine_type:\ - case DW_TAG_enumeration_type:\ - case DW_TAG_enumerator:\ - case DW_TAG_reference_type - -struct ELFcie - { - ELFcie *next; - u32 offset; - u8 *augmentation; - u32 codeAlign; - s32 dataAlign; - int returnAddress; - u8 *data; - u32 dataLen; - }; - -struct ELFfde - { - ELFcie *cie; - u32 address; - u32 end; - u8 *data; - u32 dataLen; - }; - -enum ELFRegMode { - REG_NOT_SET, - REG_OFFSET, - REG_REGISTER -}; - - -struct ELFFrameStateRegister - { - ELFRegMode mode; - int reg; - s32 offset; - }; - -struct ELFFrameStateRegisters - { - ELFFrameStateRegister regs[16]; - ELFFrameStateRegisters *previous; - }; - -enum ELFCfaMode { - CFA_NOT_SET, - CFA_REG_OFFSET -}; - -struct ELFFrameState - { - ELFFrameStateRegisters registers; - - ELFCfaMode cfaMode; - int cfaRegister; - s32 cfaOffset; - - u32 pc; - - int dataAlign; - int codeAlign; - int returnAddress; - }; - -extern bool cpuIsMultiBoot; - -Symbol *elfSymbols = NULL; -char *elfSymbolsStrTab = NULL; -int elfSymbolsCount = 0; - -ELFSectionHeader **elfSectionHeaders = NULL; -char *elfSectionHeadersStringTable = NULL; -int elfSectionHeadersCount = 0; -u8 *elfFileData = NULL; - -CompileUnit *elfCompileUnits = NULL; -DebugInfo *elfDebugInfo = NULL; -char *elfDebugStrings = NULL; - -ELFcie *elfCies = NULL; -ELFfde **elfFdes = NULL; -int elfFdeCount = 0; - -CompileUnit *elfCurrentUnit = NULL; - -u32 elfRead4Bytes(u8 *); -u16 elfRead2Bytes(u8 *); - -CompileUnit *elfGetCompileUnit(u32 addr) -{ - if(elfCompileUnits) - { - CompileUnit *unit = elfCompileUnits; - while(unit) - { - if(unit->lowPC) - { - if(addr >= unit->lowPC && addr < unit->highPC) - return unit; - } - else - { - ARanges *r = unit->ranges; - if(r) - { - int count = r->count; - for(int j = 0; j < count; j++) - { - if(addr >= r->ranges[j].lowPC && addr < r->ranges[j].highPC) - return unit; - } - } - } - unit = unit->next; - } - } - return NULL; -} - -char *elfGetAddressSymbol(u32 addr) -{ - static char buffer[256]; - - CompileUnit *unit = elfGetCompileUnit(addr); - // found unit, need to find function - if(unit) - { - Function *func = unit->functions; - while(func) - { - if(addr >= func->lowPC && addr < func->highPC) - { - int offset = addr - func->lowPC; - char *name = func->name; - if(!name) - name = ""; - if(offset) - sprintf(buffer, "%s+%d", name, offset); - else - strcpy(buffer, name); - return buffer; - } - func = func->next; - } - } - - if(elfSymbolsCount) - { - for(int i = 0; i < elfSymbolsCount; i++) - { - Symbol *s = &elfSymbols[i]; - if((addr >= s->value) && addr < (s->value+s->size)) - { - int offset = addr-s->value; - char *name = s->name; - if(name == NULL) - name = ""; - if(offset) - sprintf(buffer, "%s+%d", name, addr-s->value); - else - strcpy(buffer, name); - return buffer; - } - else if(addr == s->value) - { - if(s->name) - strcpy(buffer, s->name); - else - strcpy(buffer, ""); - return buffer; - } - } - } - - return ""; -} - -bool elfFindLineInModule(u32 *addr, char *name, int line) -{ - CompileUnit *unit = elfCompileUnits; - - while(unit) - { - if(unit->lineInfoTable) - { - int i; - int count = unit->lineInfoTable->fileCount; - char *found = NULL; - for(i = 0; i < count; i++) - { - if(strcmp(name, unit->lineInfoTable->files[i]) == 0) - { - found = unit->lineInfoTable->files[i]; - break; - } - } - // found a matching filename... try to find line now - if(found) - { - LineInfoItem *table = unit->lineInfoTable->lines; - count = unit->lineInfoTable->number; - for(i = 0; i < count; i++) - { - if(table[i].file == found && table[i].line == line) - { - *addr = table[i].address; - return true; - } - } - // we can only find a single match - return false; - } - } - unit = unit->next; - } - return false; -} - -int elfFindLine(CompileUnit *unit, Function * /* func */, u32 addr, char **f) -{ - int currentLine = -1; - if(unit->hasLineInfo) - { - int count = unit->lineInfoTable->number; - LineInfoItem *table = unit->lineInfoTable->lines; - int i; - for(i = 0; i < count; i++) - { - if(addr <= table[i].address) - break; - } - if(i == count) - i--; - *f = table[i].file; - currentLine = table[i].line; - } - return currentLine; -} - -bool elfFindLineInUnit(u32 *addr, CompileUnit *unit, int line) -{ - if(unit->hasLineInfo) - { - int count = unit->lineInfoTable->number; - LineInfoItem *table = unit->lineInfoTable->lines; - int i; - for(i = 0; i < count; i++) - { - if(line == table[i].line) - { - *addr = table[i].address; - return true; - } - } - } - return false; -} - -bool elfGetCurrentFunction(u32 addr, Function **f, CompileUnit **u) -{ - CompileUnit *unit = elfGetCompileUnit(addr); - // found unit, need to find function - if(unit) - { - Function *func = unit->functions; - while(func) - { - if(addr >= func->lowPC && addr < func->highPC) - { - *f = func; - *u = unit; - return true; - } - func = func->next; - } - } - return false; -} - -bool elfGetObject(char *name, Function *f, CompileUnit *u, Object **o) -{ - if(f && u) - { - Object *v = f->variables; - - while(v) - { - if(strcmp(name, v->name) == 0) - { - *o = v; - return true; - } - v = v->next; - } - v = f->parameters; - while(v) - { - if(strcmp(name, v->name) == 0) - { - *o = v; - return true; - } - v = v->next; - } - v = u->variables; - while(v) - { - if(strcmp(name, v->name) == 0) - { - *o = v; - return true; - } - v = v->next; - } - } - - CompileUnit *c = elfCompileUnits; - - while(c) - { - if(c != u) - { - Object *v = c->variables; - while(v) - { - if(strcmp(name, v->name) == 0) - { - *o = v; - return true; - } - v = v->next; - } - } - c = c->next; - } - - return false; -} - -char *elfGetSymbol(int i, u32 *value, u32 *size, int *type) -{ - if(i < elfSymbolsCount) - { - Symbol *s = &elfSymbols[i]; - *value = s->value; - *size = s->size; - *type = s->type; - return s->name; - } - return NULL; -} - -bool elfGetSymbolAddress(char *sym, u32 *addr, u32 *size, int *type) -{ - if(elfSymbolsCount) - { - for(int i = 0; i < elfSymbolsCount; i++) - { - Symbol *s = &elfSymbols[i]; - if(strcmp(sym, s->name) == 0) - { - *addr = s->value; - *size = s->size; - *type = s->type; - return true; - } - } - } - return false; -} - -ELFfde *elfGetFde(u32 address) -{ - if(elfFdes) - { - int i; - for(i = 0; i < elfFdeCount; i++) - { - if(address >= elfFdes[i]->address && - address < elfFdes[i]->end) - { - return elfFdes[i]; - } - } - } - - return NULL; -} - -void elfExecuteCFAInstructions(ELFFrameState *state, u8 *data, u32 len, - u32 pc) -{ - u8 *end = data + len; - int bytes; - int reg; - ELFFrameStateRegisters *fs; - - while(data < end && state->pc < pc) - { - u8 op = *data++; - - switch(op >> 6) - { - case DW_CFA_advance_loc: - state->pc += (op & 0x3f) * state->codeAlign; - break; - case DW_CFA_offset: - reg = op & 0x3f; - state->registers.regs[reg].mode = REG_OFFSET; - state->registers.regs[reg].offset = state->dataAlign * - (s32)elfReadLEB128(data, &bytes); - data += bytes; - break; - case DW_CFA_restore: - // we don't care much about the other possible settings, - // so just setting to unset is enough for now - state->registers.regs[op & 0x3f].mode = REG_NOT_SET; - break; - case 0: - switch(op & 0x3f) - { - case DW_CFA_nop: - break; - case DW_CFA_advance_loc1: - state->pc += state->codeAlign * (*data++); - break; - case DW_CFA_advance_loc2: - state->pc += state->codeAlign * elfRead2Bytes(data); - data += 2; - break; - case DW_CFA_advance_loc4: - state->pc += state->codeAlign * elfRead4Bytes(data); - data += 4; - break; - case DW_CFA_offset_extended: - reg = elfReadLEB128(data, &bytes); - data += bytes; - state->registers.regs[reg].mode = REG_OFFSET; - state->registers.regs[reg].offset = state->dataAlign * - (s32)elfReadLEB128(data, &bytes); - data += bytes; - break; - case DW_CFA_restore_extended: - case DW_CFA_undefined: - case DW_CFA_same_value: - reg = elfReadLEB128(data, &bytes); - data += bytes; - state->registers.regs[reg].mode = REG_NOT_SET; - break; - case DW_CFA_register: - reg = elfReadLEB128(data, &bytes); - data += bytes; - state->registers.regs[reg].mode = REG_REGISTER; - state->registers.regs[reg].reg = elfReadLEB128(data, &bytes); - data += bytes; - break; - case DW_CFA_remember_state: - fs = (ELFFrameStateRegisters *)calloc(1, - sizeof(ELFFrameStateRegisters)); - memcpy(fs, &state->registers, sizeof(ELFFrameStateRegisters)); - state->registers.previous = fs; - break; - case DW_CFA_restore_state: - if(state->registers.previous == NULL) - { - printf("Error: previous frame state is NULL.\n"); - return; - } - fs = state->registers.previous; - memcpy(&state->registers, fs, sizeof(ELFFrameStateRegisters)); - free(fs); - break; - case DW_CFA_def_cfa: - state->cfaRegister = elfReadLEB128(data, &bytes); - data += bytes; - state->cfaOffset = (s32)elfReadLEB128(data, &bytes); - data += bytes; - state->cfaMode = CFA_REG_OFFSET; - break; - case DW_CFA_def_cfa_register: - state->cfaRegister = elfReadLEB128(data, &bytes); - data += bytes; - state->cfaMode = CFA_REG_OFFSET; - break; - case DW_CFA_def_cfa_offset: - state->cfaOffset = (s32)elfReadLEB128(data, &bytes); - data += bytes; - state->cfaMode = CFA_REG_OFFSET; - break; - default: - printf("Unknown CFA opcode %08x\n", op); - return; - } - break; - default: - printf("Unknown CFA opcode %08x\n", op); - return; - } - } -} - -ELFFrameState *elfGetFrameState(ELFfde *fde, u32 address) -{ - ELFFrameState *state = (ELFFrameState *)calloc(1, sizeof(ELFFrameState)); - state->pc = fde->address; - state->dataAlign = fde->cie->dataAlign; - state->codeAlign = fde->cie->codeAlign; - state->returnAddress = fde->cie->returnAddress; - - elfExecuteCFAInstructions(state, - fde->cie->data, - fde->cie->dataLen, - 0xffffffff); - elfExecuteCFAInstructions(state, - fde->data, - fde->dataLen, - address); - - return state; -} - -void elfPrintCallChain(u32 address) -{ - int count = 1; - - reg_pair regs[15]; - reg_pair newRegs[15]; - - memcpy(®s[0], ®[0], sizeof(reg_pair) * 15); - - while(count < 20) - { - char *addr = elfGetAddressSymbol(address); - if(*addr == 0) - addr = "???"; - - printf("%08x %s\n", address, addr); - - ELFfde *fde = elfGetFde(address); - - if(fde == NULL) - { - break; - } - - ELFFrameState *state = elfGetFrameState(fde, address); - - if(!state) - { - break; - } - - if(state->cfaMode == CFA_REG_OFFSET) - { - memcpy(&newRegs[0], ®s[0], sizeof(reg_pair) * 15); - u32 addr = 0; - for(int i = 0; i < 15; i++) - { - ELFFrameStateRegister *r = &state->registers. - regs[i]; - - switch(r->mode) - { - case REG_NOT_SET: - newRegs[i].I = regs[i].I; - break; - case REG_OFFSET: - newRegs[i].I = elfReadMemory(regs[state->cfaRegister].I + - state->cfaOffset + - r->offset); - break; - case REG_REGISTER: - newRegs[i].I = regs[r->reg].I; - break; - default: - printf("Unknown register mode: %d\n", r->mode); - break; - } - } - memcpy(regs, newRegs, sizeof(reg_pair)*15); - addr = newRegs[14].I; - addr &= 0xfffffffe; - address = addr; - count++; - } - else - { - printf("CFA not set\n"); - break; - } - if(state->registers.previous) - { - ELFFrameStateRegisters *prev = state->registers.previous; - - while(prev) - { - ELFFrameStateRegisters *p = prev->previous; - free(prev); - prev = p; - } - } - free(state); - } -} - -u32 elfDecodeLocation(Function *f, ELFBlock *o, LocationType *type, u32 base) -{ - u32 framebase = 0; - if(f && f->frameBase) - { - ELFBlock *b = f->frameBase; - switch(*b->data) - { - case DW_OP_reg0: - case DW_OP_reg1: - case DW_OP_reg2: - case DW_OP_reg3: - case DW_OP_reg4: - case DW_OP_reg5: - case DW_OP_reg6: - case DW_OP_reg7: - case DW_OP_reg8: - case DW_OP_reg9: - case DW_OP_reg10: - case DW_OP_reg11: - case DW_OP_reg12: - case DW_OP_reg13: - case DW_OP_reg14: - case DW_OP_reg15: - framebase = reg[*b->data-0x50].I; - break; - default: - fprintf(stderr, "Unknown frameBase %02x\n", *b->data); - break; - } - } - - ELFBlock *loc = o; - u32 location = 0; - int bytes = 0; - if(loc) - { - switch(*loc->data) - { - case DW_OP_addr: - location = elfRead4Bytes(loc->data+1); - *type = LOCATION_memory; - break; - case DW_OP_plus_uconst: - location = base + elfReadLEB128(loc->data+1, &bytes); - *type = LOCATION_memory; - break; - case DW_OP_reg0: - case DW_OP_reg1: - case DW_OP_reg2: - case DW_OP_reg3: - case DW_OP_reg4: - case DW_OP_reg5: - case DW_OP_reg6: - case DW_OP_reg7: - case DW_OP_reg8: - case DW_OP_reg9: - case DW_OP_reg10: - case DW_OP_reg11: - case DW_OP_reg12: - case DW_OP_reg13: - case DW_OP_reg14: - case DW_OP_reg15: - location = *loc->data - 0x50; - *type = LOCATION_register; - break; - case DW_OP_fbreg: - { - int bytes; - s32 off = elfReadSignedLEB128(loc->data+1, &bytes); - location = framebase + off; - *type = LOCATION_memory; - } - break; - default: - fprintf(stderr, "Unknown location %02x\n", *loc->data); - break; - } - } - return location; -} - -u32 elfDecodeLocation(Function *f, ELFBlock *o, LocationType *type) -{ - return elfDecodeLocation(f, o, type, 0); -} - -// reading function - -u32 elfRead4Bytes(u8 *data) -{ - u32 value = *data++; - value |= (*data++ << 8); - value |= (*data++ << 16); - value |= (*data << 24); - return value; -} - -u16 elfRead2Bytes(u8 *data) -{ - u16 value = *data++; - value |= (*data << 8); - return value; -} - -char *elfReadString(u8 *data, int *bytesRead) -{ - if(*data == 0) - { - *bytesRead = 1; - return NULL; - } - *bytesRead = strlen((char *)data) + 1; - return (char *)data; -} - -s32 elfReadSignedLEB128(u8 *data, int *bytesRead) -{ - s32 result = 0; - int shift = 0; - int count = 0; - - u8 byte; - do - { - byte = *data++; - count++; - result |= (byte & 0x7f) << shift; - shift += 7; - } - while(byte & 0x80); - if((shift < 32) && (byte & 0x40)) - result |= -(1 << shift); - *bytesRead = count; - return result; -} - -u32 elfReadLEB128(u8 *data, int *bytesRead) -{ - u32 result = 0; - int shift = 0; - int count = 0; - u8 byte; - do - { - byte = *data++; - count++; - result |= (byte & 0x7f) << shift; - shift += 7; - } - while(byte & 0x80); - *bytesRead = count; - return result; -} - -u8 *elfReadSection(u8 *data, ELFSectionHeader *sh) -{ - return data + READ32LE(&sh->offset); -} - -ELFSectionHeader *elfGetSectionByName(char *name) -{ - for(int i = 0; i < elfSectionHeadersCount; i++) - { - if(strcmp(name, - &elfSectionHeadersStringTable[READ32LE(&elfSectionHeaders[i]-> - name)]) == 0) - { - return elfSectionHeaders[i]; - } - } - return NULL; -} - -ELFSectionHeader *elfGetSectionByNumber(int number) -{ - if(number < elfSectionHeadersCount) - { - return elfSectionHeaders[number]; - } - return NULL; -} - -CompileUnit *elfGetCompileUnitForData(u8 *data) -{ - u8 *end = elfCurrentUnit->top + 4 + elfCurrentUnit->length; - - if(data >= elfCurrentUnit->top && data < end) - return elfCurrentUnit; - - CompileUnit *unit = elfCompileUnits; - - while(unit) - { - end = unit->top + 4 + unit->length; - - if(data >= unit->top && data < end) - return unit; - - unit = unit->next; - } - - printf("Error: cannot find reference to compile unit at offset %08x\n", - (int)(data - elfDebugInfo->infodata)); - exit(-1); -} - -u8 *elfReadAttribute(u8 *data, ELFAttr *attr) -{ - int bytes; - int form = attr->form; -start: - switch(form) - { - case DW_FORM_addr: - attr->value = elfRead4Bytes(data); - data += 4; - break; - case DW_FORM_data2: - attr->value = elfRead2Bytes(data); - data += 2; - break; - case DW_FORM_data4: - attr->value = elfRead4Bytes(data); - data += 4; - break; - case DW_FORM_string: - attr->string = (char *)data; - data += strlen(attr->string)+1; - break; - case DW_FORM_strp: - attr->string = elfDebugStrings + elfRead4Bytes(data); - data += 4; - break; - case DW_FORM_block: - attr->block = (ELFBlock *)malloc(sizeof(ELFBlock)); - attr->block->length = elfReadLEB128(data, &bytes); - data += bytes; - attr->block->data = data; - data += attr->block->length; - break; - case DW_FORM_block1: - attr->block = (ELFBlock *)malloc(sizeof(ELFBlock)); - attr->block->length = *data++; - attr->block->data = data; - data += attr->block->length; - break; - case DW_FORM_data1: - attr->value = *data++; - break; - case DW_FORM_flag: - attr->flag = (*data++) ? true : false; - break; - case DW_FORM_sdata: - attr->value = elfReadSignedLEB128(data, &bytes); - data += bytes; - break; - case DW_FORM_udata: - attr->value = elfReadLEB128(data, &bytes); - data += bytes; - break; - case DW_FORM_ref_addr: - attr->value = (elfDebugInfo->infodata + elfRead4Bytes(data)) - - elfGetCompileUnitForData(data)->top; - data += 4; - break; - case DW_FORM_ref4: - attr->value = elfRead4Bytes(data); - data += 4; - break; - case DW_FORM_ref_udata: - attr->value = (elfDebugInfo->infodata + - (elfGetCompileUnitForData(data)->top - - elfDebugInfo->infodata) + - elfReadLEB128(data, &bytes)) - - elfCurrentUnit->top; - data += bytes; - break; - case DW_FORM_indirect: - form = elfReadLEB128(data, &bytes); - data += bytes; - goto start; - default: - fprintf(stderr, "Unsupported FORM %02x\n", form); - exit(-1); - } - return data; -} - -ELFAbbrev *elfGetAbbrev(ELFAbbrev **table, u32 number) -{ - int hash = number % 121; - - ELFAbbrev *abbrev = table[hash]; - - while(abbrev) - { - if(abbrev->number == number) - return abbrev; - abbrev = abbrev->next; - } - return NULL; -} - -ELFAbbrev **elfReadAbbrevs(u8 *data, u32 offset) -{ - data += offset; - ELFAbbrev **abbrevs = (ELFAbbrev **)calloc(sizeof(ELFAbbrev *)*121,1); - int bytes = 0; - u32 number = elfReadLEB128(data, &bytes); - data += bytes; - while(number) - { - ELFAbbrev *abbrev = (ELFAbbrev *)calloc(sizeof(ELFAbbrev),1); - - // read tag information - abbrev->number = number; - abbrev->tag = elfReadLEB128(data, &bytes); - data += bytes; - abbrev->hasChildren = *data++ ? true: false; - - // read attributes - int name = elfReadLEB128(data, &bytes); - data += bytes; - int form = elfReadLEB128(data, &bytes); - data += bytes; - - while(name) - { - if((abbrev->numAttrs % 4) == 0) - { - abbrev->attrs = (ELFAttr *)realloc(abbrev->attrs, - (abbrev->numAttrs + 4) * - sizeof(ELFAttr)); - } - abbrev->attrs[abbrev->numAttrs].name = name; - abbrev->attrs[abbrev->numAttrs++].form = form; - - name = elfReadLEB128(data, &bytes); - data += bytes; - form = elfReadLEB128(data, &bytes); - data += bytes; - } - - int hash = number % 121; - abbrev->next = abbrevs[hash]; - abbrevs[hash] = abbrev; - - number = elfReadLEB128(data, &bytes); - data += bytes; - - if(elfGetAbbrev(abbrevs, number) != NULL) - break; - } - - return abbrevs; -} - -void elfParseCFA(u8 *top) -{ - ELFSectionHeader *h = elfGetSectionByName(".debug_frame"); - - if(h == NULL) - { - return; - } - - u8 *data = elfReadSection(top, h); - - u8 *topOffset = data; - - u8 *end = data + READ32LE(&h->size); - - ELFcie *cies = NULL; - - while(data < end) - { - u32 offset = data - topOffset; - u32 len = elfRead4Bytes(data); - data += 4; - - u8 *dataEnd = data + len; - - u32 id = elfRead4Bytes(data); - data += 4; - - if(id == 0xffffffff) - { - // skip version - *data++; - - ELFcie *cie = (ELFcie *)calloc(1, sizeof(ELFcie)); - - cie->next = cies; - cies = cie; - - cie->offset = offset; - - cie->augmentation = data; - while(*data) - data++; - data++; - - if(*cie->augmentation) - { - fprintf(stderr, "Error: augmentation not supported\n"); - exit(-1); - } - - int bytes; - cie->codeAlign = elfReadLEB128(data, &bytes); - data += bytes; - - cie->dataAlign = elfReadSignedLEB128(data, &bytes); - data += bytes; - - cie->returnAddress = *data++; - - cie->data = data; - cie->dataLen = dataEnd - data; - } - else - { - ELFfde *fde = (ELFfde *)calloc(1, sizeof(ELFfde)); - - ELFcie *cie = cies; - - while(cie != NULL) - { - if(cie->offset == id) - break; - cie = cie->next; - } - - if(!cie) - { - fprintf(stderr, "Cannot find CIE %08x\n", id); - exit(-1); - } - - fde->cie = cie; - - fde->address = elfRead4Bytes(data); - data += 4; - - fde->end = fde->address + elfRead4Bytes(data); - data += 4; - - fde->data = data; - fde->dataLen = dataEnd - data; - - if((elfFdeCount %10) == 0) - { - elfFdes = (ELFfde **)realloc(elfFdes, (elfFdeCount+10) * - sizeof(ELFfde *)); - } - elfFdes[elfFdeCount++] = fde; - } - data = dataEnd; - } - - elfCies = cies; -} - -void elfAddLine(LineInfo *l, u32 a, int file, int line, int *max) -{ - if(l->number == *max) - { - *max += 1000; - l->lines = (LineInfoItem *)realloc(l->lines, *max*sizeof(LineInfoItem)); - } - LineInfoItem *li = &l->lines[l->number]; - li->file = l->files[file-1]; - li->address = a; - li->line = line; - l->number++; -} - -void elfParseLineInfo(CompileUnit *unit, u8 *top) -{ - ELFSectionHeader *h = elfGetSectionByName(".debug_line"); - if(h == NULL) - { - fprintf(stderr, "No line information found\n"); - return; - } - LineInfo *l = unit->lineInfoTable = (LineInfo *)calloc(1, sizeof(LineInfo)); - l->number = 0; - int max = 1000; - l->lines = (LineInfoItem *)malloc(1000*sizeof(LineInfoItem)); - - u8 *data = elfReadSection(top, h); - data += unit->lineInfo; - u32 totalLen = elfRead4Bytes(data); - data += 4; - u8 *end = data + totalLen; - // u16 version = elfRead2Bytes(data); - data += 2; - // u32 offset = elfRead4Bytes(data); - data += 4; - int minInstrSize = *data++; - int defaultIsStmt = *data++; - int lineBase = (s8)*data++; - int lineRange = *data++; - int opcodeBase = *data++; - u8 *stdOpLen = (u8 *)malloc(opcodeBase * sizeof(u8)); - stdOpLen[0] = 1; - int i; - for(i = 1; i < opcodeBase; i++) - stdOpLen[i] = *data++; - - free(stdOpLen);// todo - int bytes = 0; - - char *s; - while((s = elfReadString(data, &bytes)) != NULL) - { - data += bytes; - // fprintf(stderr, "Directory is %s\n", s); - } - data += bytes; - int count = 4; - int index = 0; - l->files = (char **)malloc(sizeof(char *)*count); - - while((s = elfReadString(data, &bytes)) != NULL) - { - l->files[index++] = s; - - data += bytes; - // directory - elfReadLEB128(data, &bytes); - data += bytes; - // time - elfReadLEB128(data, &bytes); - data += bytes; - // size - elfReadLEB128(data, &bytes); - data += bytes; - // fprintf(stderr, "File is %s\n", s); - if(index == count) - { - count += 4; - l->files = (char **)realloc(l->files, sizeof(char *)*count); - } - } - l->fileCount = index; - data += bytes; - - while(data < end) - { - u32 address = 0; - int file = 1; - int line = 1; - int col = 0; - int isStmt = defaultIsStmt; - int basicBlock = 0; - int endSeq = 0; - - while(!endSeq) - { - int op = *data++; - switch(op) - { - case DW_LNS_extended_op: - { - data++; - op = *data++; - switch(op) - { - case DW_LNE_end_sequence: - endSeq = 1; - break; - case DW_LNE_set_address: - address = elfRead4Bytes(data); - data += 4; - break; - default: - fprintf(stderr, "Unknown extended LINE opcode %02x\n", op); - exit(-1); - } - } - break; - case DW_LNS_copy: - // fprintf(stderr, "Address %08x line %d (%d)\n", address, line, file); - elfAddLine(l, address, file, line, &max); - basicBlock = 0; - break; - case DW_LNS_advance_pc: - address += minInstrSize * elfReadLEB128(data, &bytes); - data += bytes; - break; - case DW_LNS_advance_line: - line += elfReadSignedLEB128(data, &bytes); - data += bytes; - break; - case DW_LNS_set_file: - file = elfReadLEB128(data, &bytes); - data += bytes; - break; - case DW_LNS_set_column: - col = elfReadLEB128(data, &bytes); - data += bytes; - break; - case DW_LNS_negate_stmt: - isStmt = !isStmt; - break; - case DW_LNS_set_basic_block: - basicBlock = 1; - break; - case DW_LNS_const_add_pc: - address += (minInstrSize *((255 - opcodeBase)/lineRange)); - break; - case DW_LNS_fixed_advance_pc: - address += elfRead2Bytes(data); - data += 2; - break; - default: - op = op - opcodeBase; - address += (op / lineRange) * minInstrSize; - line += lineBase + (op % lineRange); - elfAddLine(l, address, file, line, &max); - // fprintf(stderr, "Address %08x line %d (%d)\n", address, line,file); - basicBlock = 1; - break; - } - } - } - l->lines = (LineInfoItem *)realloc(l->lines, l->number*sizeof(LineInfoItem)); -} - -u8 *elfSkipData(u8 *data, ELFAbbrev *abbrev, ELFAbbrev **abbrevs) -{ - int i; - int bytes; - - for(i = 0; i < abbrev->numAttrs; i++) - { - data = elfReadAttribute(data, &abbrev->attrs[i]); - if(abbrev->attrs[i].form == DW_FORM_block1) - free(abbrev->attrs[i].block); - } - - if(abbrev->hasChildren) - { - int nesting = 1; - while(nesting) - { - u32 abbrevNum = elfReadLEB128(data, &bytes); - data += bytes; - - if(!abbrevNum) - { - nesting--; - continue; - } - - abbrev = elfGetAbbrev(abbrevs, abbrevNum); - - for(i = 0; i < abbrev->numAttrs; i++) - { - data = elfReadAttribute(data, &abbrev->attrs[i]); - if(abbrev->attrs[i].form == DW_FORM_block1) - free(abbrev->attrs[i].block); - } - - if(abbrev->hasChildren) - { - nesting++; - } - } - } - return data; -} - -Type *elfParseType(CompileUnit *unit, u32); -u8 *elfParseObject(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, - Object **object); -u8 *elfParseFunction(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, - Function **function); -void elfCleanUp(Function *); - -void elfAddType(Type *type, CompileUnit *unit, u32 offset) -{ - if(type->next == NULL) - { - if(unit->types != type && type->offset == 0) - { - type->offset = offset; - type->next = unit->types; - unit->types = type; - } - } -} - -void elfParseType(u8 *data, u32 offset, ELFAbbrev *abbrev, CompileUnit *unit, - Type **type) -{ - switch(abbrev->tag) - { - case DW_TAG_typedef: - { - u32 typeref = 0; - char *name = NULL; - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_name: - name = attr->string; - break; - case DW_AT_type: - typeref = attr->value; - break; - case DW_AT_decl_file: - case DW_AT_decl_line: - break; - default: - fprintf(stderr, "Unknown attribute for typedef %02x\n", attr->name); - break; - } - } - if(abbrev->hasChildren) - fprintf(stderr, "Unexpected children for typedef\n"); - *type = elfParseType(unit, typeref); - if(name) - (*type)->name = name; - return; - } - break; - case DW_TAG_union_type: - case DW_TAG_structure_type: - { - Type *t = (Type *)calloc(sizeof(Type), 1); - if(abbrev->tag == DW_TAG_structure_type) - t->type = TYPE_struct; - else - t->type = TYPE_union; - - Struct *s = (Struct *)calloc(sizeof(Struct), 1); - t->structure = s; - elfAddType(t, unit, offset); - - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_name: - t->name = attr->string; - break; - case DW_AT_byte_size: - t->size = attr->value; - break; - case DW_AT_decl_file: - case DW_AT_decl_line: - case DW_AT_sibling: - case DW_AT_containing_type: // todo? - case DW_AT_declaration: - case DW_AT_specification: // TODO: - break; - default: - fprintf(stderr, "Unknown attribute for struct %02x\n", attr->name); - break; - } - } - if(abbrev->hasChildren) - { - int bytes; - u32 num = elfReadLEB128(data, &bytes); - data += bytes; - int index = 0; - while(num) - { - ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num); - - switch(abbr->tag) - { - case DW_TAG_member: - { - if((index % 4) == 0) - s->members = (Member *)realloc(s->members, - sizeof(Member)*(index+4)); - Member *m = &s->members[index]; - m->location = NULL; - m->bitOffset = 0; - m->bitSize = 0; - m->byteSize = 0; - for(int i = 0; i < abbr->numAttrs; i++) - { - ELFAttr *attr = &abbr->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_name: - m->name = attr->string; - break; - case DW_AT_type: - m->type = elfParseType(unit, attr->value); - break; - case DW_AT_data_member_location: - m->location = attr->block; - break; - case DW_AT_byte_size: - m->byteSize = attr->value; - break; - case DW_AT_bit_offset: - m->bitOffset = attr->value; - break; - case DW_AT_bit_size: - m->bitSize = attr->value; - break; - case DW_AT_decl_file: - case DW_AT_decl_line: - case DW_AT_accessibility: - case DW_AT_artificial: // todo? - break; - default: - fprintf(stderr, "Unknown member attribute %02x\n", - attr->name); - } - } - index++; - } - break; - case DW_TAG_subprogram: - { - Function *fnc = NULL; - data = elfParseFunction(data, abbr, unit, &fnc); - if(fnc != NULL) - { - if(unit->lastFunction) - unit->lastFunction->next = fnc; - else - unit->functions = fnc; - unit->lastFunction = fnc; - } - } - break; - case DW_TAG_inheritance: - // TODO: add support - data = elfSkipData(data, abbr, unit->abbrevs); - break; -CASE_TYPE_TAG: - // skip types... parsed only when used - data = elfSkipData(data, abbr, unit->abbrevs); - break; - case DW_TAG_variable: - data = elfSkipData(data, abbr, unit->abbrevs); - break; - default: - fprintf(stderr, "Unknown struct tag %02x %s\n", abbr->tag, t->name); - data = elfSkipData(data, abbr, unit->abbrevs); - break; - } - num = elfReadLEB128(data, &bytes); - data += bytes; - } - s->memberCount = index; - } - *type = t; - return; - } - break; - case DW_TAG_base_type: - { - Type *t = (Type *)calloc(sizeof(Type), 1); - - t->type = TYPE_base; - elfAddType(t, unit, offset); - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_name: - t->name = attr->string; - break; - case DW_AT_encoding: - t->encoding = attr->value; - break; - case DW_AT_byte_size: - t->size = attr->value; - break; - case DW_AT_bit_size: - t->bitSize = attr->value; - break; - default: - fprintf(stderr, "Unknown attribute for base type %02x\n", - attr->name); - break; - } - } - if(abbrev->hasChildren) - fprintf(stderr, "Unexpected children for base type\n"); - *type = t; - return; - } - break; - case DW_TAG_pointer_type: - { - Type *t = (Type *)calloc(sizeof(Type), 1); - - t->type = TYPE_pointer; - - elfAddType(t, unit, offset); - - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data =elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_type: - t->pointer = elfParseType(unit, attr->value); - break; - case DW_AT_byte_size: - t->size = attr->value; - break; - default: - fprintf(stderr, "Unknown pointer type attribute %02x\n", attr->name); - break; - } - } - if(abbrev->hasChildren) - fprintf(stderr, "Unexpected children for pointer type\n"); - *type = t; - return; - } - break; - case DW_TAG_reference_type: - { - Type *t = (Type *)calloc(sizeof(Type), 1); - - t->type = TYPE_reference; - - elfAddType(t, unit, offset); - - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data =elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_type: - t->pointer = elfParseType(unit, attr->value); - break; - case DW_AT_byte_size: - t->size = attr->value; - break; - default: - fprintf(stderr, "Unknown ref type attribute %02x\n", attr->name); - break; - } - } - if(abbrev->hasChildren) - fprintf(stderr, "Unexpected children for ref type\n"); - *type = t; - return; - } - break; - case DW_TAG_volatile_type: - { - u32 typeref = 0; - - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_type: - typeref = attr->value; - break; - default: - fprintf(stderr, "Unknown volatile attribute for type %02x\n", - attr->name); - break; - } - } - if(abbrev->hasChildren) - fprintf(stderr, "Unexpected children for volatile type\n"); - *type = elfParseType(unit, typeref); - return; - } - break; - case DW_TAG_const_type: - { - u32 typeref = 0; - - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_type: - typeref = attr->value; - break; - default: - fprintf(stderr, "Unknown const attribute for type %02x\n", - attr->name); - break; - } - } - if(abbrev->hasChildren) - fprintf(stderr, "Unexpected children for const type\n"); - *type = elfParseType(unit, typeref); - return; - } - break; - case DW_TAG_enumeration_type: - { - Type *t = (Type *)calloc(sizeof(Type), 1); - t->type = TYPE_enum; - Enum *e = (Enum *)calloc(sizeof(Enum), 1); - t->enumeration = e; - elfAddType(t, unit, offset); - int count = 0; - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_name: - t->name = attr->string; - break; - case DW_AT_byte_size: - t->size = attr->value; - break; - case DW_AT_sibling: - case DW_AT_decl_file: - case DW_AT_decl_line: - break; - default: - fprintf(stderr, "Unknown enum attribute %02x\n", attr->name); - } - } - if(abbrev->hasChildren) - { - int bytes; - u32 num = elfReadLEB128(data, &bytes); - data += bytes; - while(num) - { - ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num); - - switch(abbr->tag) - { - case DW_TAG_enumerator: - { - count++; - e->members = (EnumMember *)realloc(e->members, - count*sizeof(EnumMember)); - EnumMember *m = &e->members[count-1]; - for(int i = 0; i < abbr->numAttrs; i++) - { - ELFAttr *attr = &abbr->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_name: - m->name = attr->string; - break; - case DW_AT_const_value: - m->value = attr->value; - break; - default: - fprintf(stderr, "Unknown sub param attribute %02x\n", - attr->name); - } - } - } - break; - default: - fprintf(stderr, "Unknown enum tag %02x\n", abbr->tag); - data = elfSkipData(data, abbr, unit->abbrevs); - break; - } - num = elfReadLEB128(data, &bytes); - data += bytes; - } - } - e->count = count; - *type = t; - return; - } - break; - case DW_TAG_subroutine_type: - { - Type *t = (Type *)calloc(sizeof(Type), 1); - t->type = TYPE_function; - FunctionType *f = (FunctionType *)calloc(sizeof(FunctionType), 1); - t->function = f; - elfAddType(t, unit, offset); - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_prototyped: - case DW_AT_sibling: - break; - case DW_AT_type: - f->returnType = elfParseType(unit, attr->value); - break; - default: - fprintf(stderr, "Unknown subroutine attribute %02x\n", attr->name); - } - } - if(abbrev->hasChildren) - { - int bytes; - u32 num = elfReadLEB128(data, &bytes); - data += bytes; - Object *lastVar = NULL; - while(num) - { - ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num); - - switch(abbr->tag) - { - case DW_TAG_formal_parameter: - { - Object *o; - data = elfParseObject(data, abbr, unit, &o); - if(f->args) - lastVar->next = o; - else - f->args = o; - lastVar = o; - } - break; - case DW_TAG_unspecified_parameters: - // no use in the debugger yet - data = elfSkipData(data, abbr, unit->abbrevs); - break; -CASE_TYPE_TAG: - // skip types... parsed only when used - data = elfSkipData(data, abbr, unit->abbrevs); - break; - default: - fprintf(stderr, "Unknown subroutine tag %02x\n", abbr->tag); - data = elfSkipData(data, abbr, unit->abbrevs); - break; - } - num = elfReadLEB128(data, &bytes); - data += bytes; - } - } - *type = t; - return; - } - break; - case DW_TAG_array_type: - { - u32 typeref = 0; - int i; - Array *array = (Array *)calloc(sizeof(Array), 1); - Type *t = (Type *)calloc(sizeof(Type), 1); - t->type = TYPE_array; - elfAddType(t, unit, offset); - - for(i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_sibling: - break; - case DW_AT_type: - typeref = attr->value; - array->type = elfParseType(unit, typeref); - break; - default: - fprintf(stderr, "Unknown array attribute %02x\n", attr->name); - } - } - if(abbrev->hasChildren) - { - int bytes; - u32 num = elfReadLEB128(data, &bytes); - data += bytes; - int index = 0; - int maxBounds = 0; - while(num) - { - ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num); - - switch(abbr->tag) - { - case DW_TAG_subrange_type: - { - if(maxBounds == index) - { - maxBounds += 4; - array->bounds = (int *)realloc(array->bounds, - sizeof(int)*maxBounds); - } - for(int i = 0; i < abbr->numAttrs; i++) - { - ELFAttr *attr = &abbr->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_upper_bound: - array->bounds[index] = attr->value+1; - break; - case DW_AT_type: // ignore - break; - default: - fprintf(stderr, "Unknown subrange attribute %02x\n", - attr->name); - } - } - index++; - } - break; - default: - fprintf(stderr, "Unknown array tag %02x\n", abbr->tag); - data = elfSkipData(data, abbr, unit->abbrevs); - break; - } - num = elfReadLEB128(data, &bytes); - data += bytes; - } - array->maxBounds = index; - } - t->size = array->type->size; - for(i = 0; i < array->maxBounds; i++) - t->size *= array->bounds[i]; - t->array = array; - *type = t; - return; - } - break; - default: - fprintf(stderr, "Unknown type TAG %02x\n", abbrev->tag); - exit(-1); - } -} - -Type *elfParseType(CompileUnit *unit, u32 offset) -{ - Type *t = unit->types; - - while(t) - { - if(t->offset == offset) - return t; - t = t->next; - } - if(offset == 0) - { - Type *t = (Type *)calloc(sizeof(Type), 1); - t->type = TYPE_void; - t->offset = 0; - elfAddType(t, unit, 0); - return t; - } - u8 *data = unit->top + offset; - int bytes; - int abbrevNum = elfReadLEB128(data, &bytes); - data += bytes; - Type *type = NULL; - - ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); - - elfParseType(data, offset, abbrev, unit, &type); - return type; -} - -void elfGetObjectAttributes(CompileUnit *unit, u32 offset, Object *o) -{ - u8 *data = unit->top + offset; - int bytes; - u32 abbrevNum = elfReadLEB128(data, &bytes); - data += bytes; - - if(!abbrevNum) - { - return; - } - - ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); - - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_location: - o->location = attr->block; - break; - case DW_AT_name: - if(o->name == NULL) - o->name = attr->string; - break; - case DW_AT_MIPS_linkage_name: - o->name = attr->string; - break; - case DW_AT_decl_file: - o->file = attr->value; - break; - case DW_AT_decl_line: - o->line = attr->value; - break; - case DW_AT_type: - o->type = elfParseType(unit, attr->value); - break; - case DW_AT_external: - o->external = attr->flag; - break; - case DW_AT_const_value: - case DW_AT_abstract_origin: - case DW_AT_declaration: - case DW_AT_artificial: - // todo - break; - case DW_AT_specification: - // TODO: - break; - default: - fprintf(stderr, "Unknown object attribute %02x\n", attr->name); - break; - } - } -} - -u8 *elfParseObject(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, - Object **object) -{ - Object *o = (Object *)calloc(sizeof(Object), 1); - - o->next = NULL; - - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_location: - o->location = attr->block; - break; - case DW_AT_name: - if(o->name == NULL) - o->name = attr->string; - break; - case DW_AT_MIPS_linkage_name: - o->name = attr->string; - break; - case DW_AT_decl_file: - o->file = attr->value; - break; - case DW_AT_decl_line: - o->line = attr->value; - break; - case DW_AT_type: - o->type = elfParseType(unit, attr->value); - break; - case DW_AT_external: - o->external = attr->flag; - break; - case DW_AT_abstract_origin: - elfGetObjectAttributes(unit, attr->value, o); - break; - case DW_AT_const_value: - case DW_AT_declaration: - case DW_AT_artificial: - break; - case DW_AT_specification: - // TODO: - break; - default: - fprintf(stderr, "Unknown object attribute %02x\n", attr->name); - break; - } - } - *object = o; - return data; -} - -u8 *elfParseBlock(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, - Function *func, Object **lastVar) -{ - int bytes; - u32 start = func->lowPC; - u32 end = func->highPC; - - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_sibling: - break; - case DW_AT_low_pc: - start = attr->value; - break; - case DW_AT_high_pc: - end = attr->value; - break; - case DW_AT_ranges: // ignore for now - break; - default: - fprintf(stderr, "Unknown block attribute %02x\n", attr->name); - break; - } - } - - if(abbrev->hasChildren) - { - int nesting = 1; - - while(nesting) - { - u32 abbrevNum = elfReadLEB128(data, &bytes); - data += bytes; - - if(!abbrevNum) - { - nesting--; - continue; - } - - abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); - - switch(abbrev->tag) - { -CASE_TYPE_TAG: // types only parsed when used - case DW_TAG_label: // not needed - data = elfSkipData(data, abbrev, unit->abbrevs); - break; - case DW_TAG_lexical_block: - data = elfParseBlock(data, abbrev, unit, func, lastVar); - break; - case DW_TAG_subprogram: - { - Function *f = NULL; - data = elfParseFunction(data, abbrev, unit, &f); - if(f != NULL) - { - if(unit->lastFunction) - unit->lastFunction->next = f; - else - unit->functions = f; - unit->lastFunction = f; - } - } - break; - case DW_TAG_variable: - { - Object *o; - data = elfParseObject(data, abbrev, unit, &o); - if(o->startScope == 0) - o->startScope = start; - if(o->endScope == 0) - o->endScope = 0; - if(func->variables) - (*lastVar)->next = o; - else - func->variables = o; - *lastVar = o; - } - break; - case DW_TAG_inlined_subroutine: - // TODO: - data = elfSkipData(data, abbrev, unit->abbrevs); - break; - default: - { - fprintf(stderr, "Unknown block TAG %02x\n", abbrev->tag); - data = elfSkipData(data, abbrev, unit->abbrevs); - } - break; - } - } - } - return data; -} - -void elfGetFunctionAttributes(CompileUnit *unit, u32 offset, Function *func) -{ - u8 *data = unit->top + offset; - int bytes; - u32 abbrevNum = elfReadLEB128(data, &bytes); - data += bytes; - - if(!abbrevNum) - { - return; - } - - ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); - - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - - switch(attr->name) - { - case DW_AT_sibling: - break; - case DW_AT_name: - if(func->name == NULL) - func->name = attr->string; - break; - case DW_AT_MIPS_linkage_name: - func->name = attr->string; - break; - case DW_AT_low_pc: - func->lowPC = attr->value; - break; - case DW_AT_high_pc: - func->highPC = attr->value; - break; - case DW_AT_decl_file: - func->file = attr->value; - break; - case DW_AT_decl_line: - func->line = attr->value; - break; - case DW_AT_external: - func->external = attr->flag; - break; - case DW_AT_frame_base: - func->frameBase = attr->block; - break; - case DW_AT_type: - func->returnType = elfParseType(unit, attr->value); - break; - case DW_AT_inline: - case DW_AT_specification: - case DW_AT_declaration: - case DW_AT_artificial: - case DW_AT_prototyped: - case DW_AT_proc_body: - case DW_AT_save_offset: - case DW_AT_user_2002: - case DW_AT_virtuality: - case DW_AT_containing_type: - case DW_AT_accessibility: - // todo; - break; - case DW_AT_vtable_elem_location: - free(attr->block); - break; - default: - fprintf(stderr, "Unknown function attribute %02x\n", attr->name); - break; - } - } - - return; -} - -u8 *elfParseFunction(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, - Function **f) -{ - Function *func = (Function *)calloc(sizeof(Function), 1); - *f = func; - - int bytes; - bool mangled = false; - bool declaration = false; - for(int i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - switch(attr->name) - { - case DW_AT_sibling: - break; - case DW_AT_name: - if(func->name == NULL) - func->name = attr->string; - break; - case DW_AT_MIPS_linkage_name: - func->name = attr->string; - mangled = true; - break; - case DW_AT_low_pc: - func->lowPC = attr->value; - break; - case DW_AT_high_pc: - func->highPC = attr->value; - break; - case DW_AT_prototyped: - break; - case DW_AT_decl_file: - func->file = attr->value; - break; - case DW_AT_decl_line: - func->line = attr->value; - break; - case DW_AT_external: - func->external = attr->flag; - break; - case DW_AT_frame_base: - func->frameBase = attr->block; - break; - case DW_AT_type: - func->returnType = elfParseType(unit, attr->value); - break; - case DW_AT_abstract_origin: - elfGetFunctionAttributes(unit, attr->value, func); - break; - case DW_AT_declaration: - declaration = attr->flag; - break; - case DW_AT_inline: - case DW_AT_specification: - case DW_AT_artificial: - case DW_AT_proc_body: - case DW_AT_save_offset: - case DW_AT_user_2002: - case DW_AT_virtuality: - case DW_AT_containing_type: - case DW_AT_accessibility: - // todo; - break; - case DW_AT_vtable_elem_location: - free(attr->block); - break; - default: - fprintf(stderr, "Unknown function attribute %02x\n", attr->name); - break; - } - } - - if(declaration) - { - elfCleanUp(func); - free(func); - *f = NULL; - - while(1) - { - u32 abbrevNum = elfReadLEB128(data, &bytes); - data += bytes; - - if(!abbrevNum) - { - return data; - } - - abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); - - data = elfSkipData(data, abbrev, unit->abbrevs); - } - } - - if(abbrev->hasChildren) - { - int nesting = 1; - Object *lastParam = NULL; - Object *lastVar = NULL; - - while(nesting) - { - u32 abbrevNum = elfReadLEB128(data, &bytes); - data += bytes; - - if(!abbrevNum) - { - nesting--; - continue; - } - - abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); - - switch(abbrev->tag) - { -CASE_TYPE_TAG: // no need to parse types. only parsed when used - case DW_TAG_label: // not needed - data = elfSkipData(data, abbrev, unit->abbrevs); - break; - case DW_TAG_subprogram: - { - Function *fnc=NULL; - data = elfParseFunction(data, abbrev, unit, &fnc); - if(fnc != NULL) - { - if(unit->lastFunction == NULL) - unit->functions = fnc; - else - unit->lastFunction->next = fnc; - unit->lastFunction = fnc; - } - } - break; - case DW_TAG_lexical_block: - { - data = elfParseBlock(data, abbrev, unit, func, &lastVar); - } - break; - case DW_TAG_formal_parameter: - { - Object *o; - data = elfParseObject(data, abbrev, unit, &o); - if(func->parameters) - lastParam->next = o; - else - func->parameters = o; - lastParam = o; - } - break; - case DW_TAG_variable: - { - Object *o; - data = elfParseObject(data, abbrev, unit, &o); - if(func->variables) - lastVar->next = o; - else - func->variables = o; - lastVar = o; - } - break; - case DW_TAG_unspecified_parameters: - case DW_TAG_inlined_subroutine: - { - // todo - for(int i = 0; i < abbrev->numAttrs; i++) - { - data = elfReadAttribute(data, &abbrev->attrs[i]); - if(abbrev->attrs[i].form == DW_FORM_block1) - free(abbrev->attrs[i].block); - } - - if(abbrev->hasChildren) - nesting++; - } - break; - default: - { - fprintf(stderr, "Unknown function TAG %02x\n", abbrev->tag); - data = elfSkipData(data, abbrev, unit->abbrevs); - } - break; - } - } - } - return data; -} - -u8 *elfParseUnknownData(u8 *data, ELFAbbrev *abbrev, ELFAbbrev **abbrevs) -{ - int i; - int bytes; - // switch(abbrev->tag) { - // default: - fprintf(stderr, "Unknown TAG %02x\n", abbrev->tag); - - for(i = 0; i < abbrev->numAttrs; i++) - { - data = elfReadAttribute(data, &abbrev->attrs[i]); - if(abbrev->attrs[i].form == DW_FORM_block1) - free(abbrev->attrs[i].block); - } - - if(abbrev->hasChildren) - { - int nesting = 1; - while(nesting) - { - u32 abbrevNum = elfReadLEB128(data, &bytes); - data += bytes; - - if(!abbrevNum) - { - nesting--; - continue; - } - - abbrev = elfGetAbbrev(abbrevs, abbrevNum); - - fprintf(stderr, "Unknown TAG %02x\n", abbrev->tag); - - for(i = 0; i < abbrev->numAttrs; i++) - { - data = elfReadAttribute(data, &abbrev->attrs[i]); - if(abbrev->attrs[i].form == DW_FORM_block1) - free(abbrev->attrs[i].block); - } - - if(abbrev->hasChildren) - { - nesting++; - } - } - } - // } - return data; -} - -u8 *elfParseCompileUnitChildren(u8 *data, CompileUnit *unit) -{ - int bytes; - u32 abbrevNum = elfReadLEB128(data, &bytes); - data += bytes; - Object *lastObj = NULL; - while(abbrevNum) - { - ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); - switch(abbrev->tag) - { - case DW_TAG_subprogram: - { - Function *func = NULL; - data = elfParseFunction(data, abbrev, unit, &func); - if(func != NULL) - { - if(unit->lastFunction) - unit->lastFunction->next = func; - else - unit->functions = func; - unit->lastFunction = func; - } - } - break; -CASE_TYPE_TAG: - data = elfSkipData(data, abbrev, unit->abbrevs); - break; - case DW_TAG_variable: - { - Object *var = NULL; - data = elfParseObject(data, abbrev, unit, &var); - if(lastObj) - lastObj->next = var; - else - unit->variables = var; - lastObj = var; - } - break; - default: - data = elfParseUnknownData(data, abbrev, unit->abbrevs); - break; - } - - abbrevNum = elfReadLEB128(data, &bytes); - data += bytes; - } - return data; -} - - -CompileUnit *elfParseCompUnit(u8 *data, u8 *abbrevData) -{ - int bytes; - u8 *top = data; - - u32 length = elfRead4Bytes(data); - data += 4; - - u16 version = elfRead2Bytes(data); - data += 2; - - u32 offset = elfRead4Bytes(data); - data += 4; - - u8 addrSize = *data++; - - if(version != 2) - { - fprintf(stderr, "Unsupported debugging information version %d\n", version); - return NULL; - } - - if(addrSize != 4) - { - fprintf(stderr, "Unsupported address size %d\n", addrSize); - return NULL; - } - - ELFAbbrev **abbrevs = elfReadAbbrevs(abbrevData, offset); - - u32 abbrevNum = elfReadLEB128(data, &bytes); - data += bytes; - - ELFAbbrev *abbrev = elfGetAbbrev(abbrevs, abbrevNum); - - CompileUnit *unit = (CompileUnit *)calloc(sizeof(CompileUnit), 1); - unit->top = top; - unit->length = length; - unit->abbrevs = abbrevs; - unit->next = NULL; - - elfCurrentUnit = unit; - - int i; - - for(i = 0; i < abbrev->numAttrs; i++) - { - ELFAttr *attr = &abbrev->attrs[i]; - data = elfReadAttribute(data, attr); - - switch(attr->name) - { - case DW_AT_name: - unit->name = attr->string; - break; - case DW_AT_stmt_list: - unit->hasLineInfo = true; - unit->lineInfo = attr->value; - break; - case DW_AT_low_pc: - unit->lowPC = attr->value; - break; - case DW_AT_high_pc: - unit->highPC = attr->value; - break; - case DW_AT_compdir: - unit->compdir = attr->string; - break; - // ignore - case DW_AT_language: - case DW_AT_producer: - case DW_AT_macro_info: - case DW_AT_entry_pc: - break; - default: - fprintf(stderr, "Unknown attribute %02x\n", attr->name); - break; - } - } - - if(abbrev->hasChildren) - elfParseCompileUnitChildren(data, unit); - - return unit; -} - -void elfParseAranges(u8 *data) -{ - ELFSectionHeader *sh = elfGetSectionByName(".debug_aranges"); - if(sh == NULL) - { - fprintf(stderr, "No aranges found\n"); - return; - } - - data = elfReadSection(data, sh); - u8 *end = data + READ32LE(&sh->size); - - int max = 4; - ARanges *ranges = (ARanges *)calloc(sizeof(ARanges), 4); - - int index = 0; - - while(data < end) - { - u32 len = elfRead4Bytes(data); - data += 4; - // u16 version = elfRead2Bytes(data); - data += 2; - u32 offset = elfRead4Bytes(data); - data += 4; - // u8 addrSize = *data++; - // u8 segSize = *data++; - data += 2; // remove if uncommenting above - data += 4; - ranges[index].count = (len-20)/8; - ranges[index].offset = offset; - ranges[index].ranges = (ARange *)calloc(sizeof(ARange), (len-20)/8); - int i = 0; - while(true) - { - u32 addr = elfRead4Bytes(data); - data += 4; - u32 len = elfRead4Bytes(data); - data += 4; - if(addr == 0 && len == 0) - break; - ranges[index].ranges[i].lowPC = addr; - ranges[index].ranges[i].highPC = addr+len; - i++; - } - index++; - if(index == max) - { - max += 4; - ranges = (ARanges *)realloc(ranges, max*sizeof(ARanges)); - } - } - elfDebugInfo->numRanges = index; - elfDebugInfo->ranges = ranges; -} - -void elfReadSymtab(u8 *data) -{ - ELFSectionHeader *sh = elfGetSectionByName(".symtab"); - int table = READ32LE(&sh->link); - - char *strtable = (char *)elfReadSection(data, elfGetSectionByNumber(table)); - - ELFSymbol *symtab = (ELFSymbol *)elfReadSection(data, sh); - - int count = READ32LE(&sh->size) / sizeof(ELFSymbol); - elfSymbolsCount = 0; - - elfSymbols = (Symbol *)malloc(sizeof(Symbol)*count); - - int i; - - for(i = 0; i < count; i++) - { - ELFSymbol *s = &symtab[i]; - int type = s->info & 15; - int binding = s->info >> 4; - - if(binding) - { - Symbol *sym = &elfSymbols[elfSymbolsCount]; - sym->name = &strtable[READ32LE(&s->name)]; - sym->binding = binding; - sym->type = type; - sym->value = READ32LE(&s->value); - sym->size = READ32LE(&s->size); - elfSymbolsCount++; - } - } - for(i = 0; i < count; i++) - { - ELFSymbol *s = &symtab[i]; - int bind = s->info>>4; - int type = s->info & 15; - - if(!bind) - { - Symbol *sym = &elfSymbols[elfSymbolsCount]; - sym->name = &strtable[READ32LE(&s->name)]; - sym->binding = (s->info >> 4); - sym->type = type; - sym->value = READ32LE(&s->value); - sym->size = READ32LE(&s->size); - elfSymbolsCount++; - } - } - elfSymbolsStrTab = strtable; - // free(symtab); -} - -bool elfReadProgram(ELFHeader *eh, u8 *data, int& size, bool parseDebug) -{ - int count = READ16LE(&eh->e_phnum); - int i; - - if(READ32LE(&eh->e_entry) == 0x2000000) - cpuIsMultiBoot = true; - - // read program headers... should probably move this code down - u8 *p = data + READ32LE(&eh->e_phoff); - size = 0; - for(i = 0; i < count; i++) - { - ELFProgramHeader *ph = (ELFProgramHeader *)p; - p += sizeof(ELFProgramHeader); - if(READ16LE(&eh->e_phentsize) != sizeof(ELFProgramHeader)) - { - p += READ16LE(&eh->e_phentsize) - sizeof(ELFProgramHeader); - } - - // printf("PH %d %08x %08x %08x %08x %08x %08x %08x %08x\n", - // i, ph->type, ph->offset, ph->vaddr, ph->paddr, - // ph->filesz, ph->memsz, ph->flags, ph->align); - if(cpuIsMultiBoot) - { - if(READ32LE(&ph->paddr) >= 0x2000000 && - READ32LE(&ph->paddr) <= 0x203ffff) - { - memcpy(&workRAM[READ32LE(&ph->paddr) & 0x3ffff], - data + READ32LE(&ph->offset), - READ32LE(&ph->filesz)); - } - } - else - { - if(READ32LE(&ph->paddr) >= 0x8000000 && - READ32LE(&ph->paddr) <= 0x9ffffff) - { - memcpy(&rom[READ32LE(&ph->paddr) & 0x1ffffff], - data + READ32LE(&ph->offset), - READ32LE(&ph->filesz)); - size += READ32LE(&ph->filesz); - } - } - } - - char *stringTable = NULL; - - // read section headers - p = data + READ32LE(&eh->e_shoff); - count = READ16LE(&eh->e_shnum); - - ELFSectionHeader **sh = (ELFSectionHeader **) - malloc(sizeof(ELFSectionHeader *) * count); - - for(i = 0; i < count; i++) - { - sh[i] = (ELFSectionHeader *)p; - p += sizeof(ELFSectionHeader); - if(READ16LE(&eh->e_shentsize) != sizeof(ELFSectionHeader)) - p += READ16LE(&eh->e_shentsize) - sizeof(ELFSectionHeader); - } - - if(READ16LE(&eh->e_shstrndx) != 0) - { - stringTable = (char *)elfReadSection(data, - sh[READ16LE(&eh->e_shstrndx)]); - } - - elfSectionHeaders = sh; - elfSectionHeadersStringTable = stringTable; - elfSectionHeadersCount = count; - - for(i = 0; i < count; i++) - { - // printf("SH %d %-20s %08x %08x %08x %08x %08x %08x %08x %08x\n", - // i, &stringTable[sh[i]->name], sh[i]->name, sh[i]->type, - // sh[i]->flags, sh[i]->addr, sh[i]->offset, sh[i]->size, - // sh[i]->link, sh[i]->info); - if(READ32LE(&sh[i]->flags) & 2) - { // load section - if(cpuIsMultiBoot) - { - if(READ32LE(&sh[i]->addr) >= 0x2000000 && - READ32LE(&sh[i]->addr) <= 0x203ffff) - { - memcpy(&workRAM[READ32LE(&sh[i]->addr) & 0x3ffff], data + - READ32LE(&sh[i]->offset), - READ32LE(&sh[i]->size)); - } - } - else - { - if(READ32LE(&sh[i]->addr) >= 0x8000000 && - READ32LE(&sh[i]->addr) <= 0x9ffffff) - { - memcpy(&rom[READ32LE(&sh[i]->addr) & 0x1ffffff], - data + READ32LE(&sh[i]->offset), - READ32LE(&sh[i]->size)); - size += READ32LE(&sh[i]->size); - } - } - } - } - - if(parseDebug) - { - fprintf(stderr, "Parsing debug info\n"); - - ELFSectionHeader *dbgHeader = elfGetSectionByName(".debug_info"); - if(dbgHeader == NULL) - { - fprintf(stderr, "Cannot find debug information\n"); - goto end; - } - - ELFSectionHeader *h = elfGetSectionByName(".debug_abbrev"); - if(h == NULL) - { - fprintf(stderr, "Cannot find abbreviation table\n"); - goto end; - } - - elfDebugInfo = (DebugInfo *)calloc(sizeof(DebugInfo), 1); - u8 *abbrevdata = elfReadSection(data, h); - - h = elfGetSectionByName(".debug_str"); - - if(h == NULL) - elfDebugStrings = NULL; - else - elfDebugStrings = (char *)elfReadSection(data, h); - - u8 *debugdata = elfReadSection(data, dbgHeader); - - elfDebugInfo->debugdata = data; - elfDebugInfo->infodata = debugdata; - - u32 total = READ32LE(&dbgHeader->size); - u8 *end = debugdata + total; - u8 *ddata = debugdata; - - CompileUnit *last = NULL; - CompileUnit *unit = NULL; - - while(ddata < end) - { - unit = elfParseCompUnit(ddata, abbrevdata); - unit->offset = ddata-debugdata; - elfParseLineInfo(unit, data); - if(last == NULL) - elfCompileUnits = unit; - else - last->next = unit; - last = unit; - ddata += 4 + unit->length; - } - elfParseAranges(data); - CompileUnit *comp = elfCompileUnits; - while(comp) - { - ARanges *r = elfDebugInfo->ranges; - for(int i = 0; i < elfDebugInfo->numRanges; i++) - if(r[i].offset == comp->offset) - { - comp->ranges = &r[i]; - break; - } - comp = comp->next; - } - elfParseCFA(data); - elfReadSymtab(data); - } -end: - if(sh) - { - free(sh); - } - - elfSectionHeaders = NULL; - elfSectionHeadersStringTable = NULL; - elfSectionHeadersCount = 0; - - return true; -} - -extern bool parseDebug; - -bool elfRead(const char *name, int& siz, FILE* f) -{ - - fseek(f, 0, SEEK_END); - long size = ftell(f); - - elfFileData = (u8 *)malloc(size); - gen_fseek(f, 0, SEEK_SET); - gen_fread(elfFileData, 1, size, f); - gen_fclose(f); - - ELFHeader *header = (ELFHeader *)elfFileData; - - if(READ32LE(&header->magic) != 0x464C457F || - READ16LE(&header->e_machine) != 40 || - header->clazz != 1) - { - systemMessage(0, N_("Not a valid ELF file %s"), name); - free(elfFileData); - elfFileData = NULL; - return false; - } - - if(!elfReadProgram(header, elfFileData, siz, parseDebug)) - { - free(elfFileData); - elfFileData = NULL; - return false; - } - - return true; -} - -void elfCleanUp(Object *o) -{ - free(o->location); -} - -void elfCleanUp(Function *func) -{ - Object *o = func->parameters; - while(o) - { - elfCleanUp(o); - Object *next = o->next; - free(o); - o = next; - } - - o = func->variables; - while(o) - { - elfCleanUp(o); - Object *next = o->next; - free(o); - o = next; - } - free(func->frameBase); -} - -void elfCleanUp(ELFAbbrev **abbrevs) -{ - for(int i = 0; i < 121; i++) - { - ELFAbbrev *abbrev = abbrevs[i]; - - while(abbrev) - { - free(abbrev->attrs); - ELFAbbrev *next = abbrev->next; - free(abbrev); - - abbrev = next; - } - } -} - -void elfCleanUp(Type *t) -{ - switch(t->type) - { - case TYPE_function: - if(t->function) - { - Object *o = t->function->args; - while(o) - { - elfCleanUp(o); - Object *next = o->next; - free(o); - o = next; - } - free(t->function); - } - break; - case TYPE_array: - if(t->array) - { - free(t->array->bounds); - free(t->array); - } - break; - case TYPE_struct: - case TYPE_union: - if(t->structure) - { - for(int i = 0; i < t->structure->memberCount; i++) - { - free(t->structure->members[i].location); - } - free(t->structure->members); - free(t->structure); - } - break; - case TYPE_enum: - if(t->enumeration) - { - free(t->enumeration->members); - free(t->enumeration); - } - break; - case TYPE_base: - case TYPE_pointer: - case TYPE_void: - case TYPE_reference: - break; // nothing to do - } -} - -void elfCleanUp(CompileUnit *comp) -{ - elfCleanUp(comp->abbrevs); - free(comp->abbrevs); - Function *func = comp->functions; - while(func) - { - elfCleanUp(func); - Function *next = func->next; - free(func); - func = next; - } - Type *t = comp->types; - while(t) - { - elfCleanUp(t); - Type *next = t->next; - free(t); - t = next; - } - Object *o = comp->variables; - while(o) - { - elfCleanUp(o); - Object *next = o->next; - free(o); - o = next; - } - if(comp->lineInfoTable) - { - free(comp->lineInfoTable->lines); - free(comp->lineInfoTable->files); - free(comp->lineInfoTable); - } -} - -void elfCleanUp() -{ - CompileUnit *comp = elfCompileUnits; - - while(comp) - { - elfCleanUp(comp); - CompileUnit *next = comp->next; - free(comp); - comp = next; - } - elfCompileUnits = NULL; - free(elfSymbols); - elfSymbols = NULL; - // free(elfSymbolsStrTab); - elfSymbolsStrTab = NULL; - - elfDebugStrings = NULL; - if(elfDebugInfo) - { - int num = elfDebugInfo->numRanges; - int i; - for(i = 0; i < num; i++) - { - free(elfDebugInfo->ranges[i].ranges); - } - free(elfDebugInfo->ranges); - free(elfDebugInfo); - elfDebugInfo = NULL; - } - - if(elfFdes) - { - if(elfFdeCount) - { - for(int i = 0; i < elfFdeCount; i++) - free(elfFdes[i]); - } - free(elfFdes); - - elfFdes = NULL; - elfFdeCount = 0; - } - - ELFcie *cie = elfCies; - while(cie) - { - ELFcie *next = cie->next; - free(cie); - cie = next; - } - elfCies = NULL; - - if(elfFileData) - { - free(elfFileData); - elfFileData = NULL; - } -} +// 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. + +#include +#include +#include + +#include "agb/GBA.h" +#include "Port.h" +#include "elf.h" +#include "NLS.h" + +#define elfReadMemory(addr) \ + READ32LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) + +#define DW_TAG_array_type 0x01 +#define DW_TAG_enumeration_type 0x04 +#define DW_TAG_formal_parameter 0x05 +#define DW_TAG_label 0x0a +#define DW_TAG_lexical_block 0x0b +#define DW_TAG_member 0x0d +#define DW_TAG_pointer_type 0x0f +#define DW_TAG_reference_type 0x10 +#define DW_TAG_compile_unit 0x11 +#define DW_TAG_structure_type 0x13 +#define DW_TAG_subroutine_type 0x15 +#define DW_TAG_typedef 0x16 +#define DW_TAG_union_type 0x17 +#define DW_TAG_unspecified_parameters 0x18 +#define DW_TAG_inheritance 0x1c +#define DW_TAG_inlined_subroutine 0x1d +#define DW_TAG_subrange_type 0x21 +#define DW_TAG_base_type 0x24 +#define DW_TAG_const_type 0x26 +#define DW_TAG_enumerator 0x28 +#define DW_TAG_subprogram 0x2e +#define DW_TAG_variable 0x34 +#define DW_TAG_volatile_type 0x35 + +#define DW_AT_sibling 0x01 +#define DW_AT_location 0x02 +#define DW_AT_name 0x03 +#define DW_AT_byte_size 0x0b +#define DW_AT_bit_offset 0x0c +#define DW_AT_bit_size 0x0d +#define DW_AT_stmt_list 0x10 +#define DW_AT_low_pc 0x11 +#define DW_AT_high_pc 0x12 +#define DW_AT_language 0x13 +#define DW_AT_compdir 0x1b +#define DW_AT_const_value 0x1c +#define DW_AT_containing_type 0x1d +#define DW_AT_inline 0x20 +#define DW_AT_producer 0x25 +#define DW_AT_prototyped 0x27 +#define DW_AT_upper_bound 0x2f +#define DW_AT_abstract_origin 0x31 +#define DW_AT_accessibility 0x32 +#define DW_AT_artificial 0x34 +#define DW_AT_data_member_location 0x38 +#define DW_AT_decl_file 0x3a +#define DW_AT_decl_line 0x3b +#define DW_AT_declaration 0x3c +#define DW_AT_encoding 0x3e +#define DW_AT_external 0x3f +#define DW_AT_frame_base 0x40 +#define DW_AT_macro_info 0x43 +#define DW_AT_specification 0x47 +#define DW_AT_type 0x49 +#define DW_AT_virtuality 0x4c +#define DW_AT_vtable_elem_location 0x4d +// DWARF 2.1/3.0 extensions +#define DW_AT_entry_pc 0x52 +#define DW_AT_ranges 0x55 +// ARM Compiler extensions +#define DW_AT_proc_body 0x2000 +#define DW_AT_save_offset 0x2001 +#define DW_AT_user_2002 0x2002 +// MIPS extensions +#define DW_AT_MIPS_linkage_name 0x2007 + +#define DW_FORM_addr 0x01 +#define DW_FORM_data2 0x05 +#define DW_FORM_data4 0x06 +#define DW_FORM_string 0x08 +#define DW_FORM_block 0x09 +#define DW_FORM_block1 0x0a +#define DW_FORM_data1 0x0b +#define DW_FORM_flag 0x0c +#define DW_FORM_sdata 0x0d +#define DW_FORM_strp 0x0e +#define DW_FORM_udata 0x0f +#define DW_FORM_ref_addr 0x10 +#define DW_FORM_ref4 0x13 +#define DW_FORM_ref_udata 0x15 +#define DW_FORM_indirect 0x16 + +#define DW_OP_addr 0x03 +#define DW_OP_plus_uconst 0x23 +#define DW_OP_reg0 0x50 +#define DW_OP_reg1 0x51 +#define DW_OP_reg2 0x52 +#define DW_OP_reg3 0x53 +#define DW_OP_reg4 0x54 +#define DW_OP_reg5 0x55 +#define DW_OP_reg6 0x56 +#define DW_OP_reg7 0x57 +#define DW_OP_reg8 0x58 +#define DW_OP_reg9 0x59 +#define DW_OP_reg10 0x5a +#define DW_OP_reg11 0x5b +#define DW_OP_reg12 0x5c +#define DW_OP_reg13 0x5d +#define DW_OP_reg14 0x5e +#define DW_OP_reg15 0x5f +#define DW_OP_fbreg 0x91 + +#define DW_LNS_extended_op 0x00 +#define DW_LNS_copy 0x01 +#define DW_LNS_advance_pc 0x02 +#define DW_LNS_advance_line 0x03 +#define DW_LNS_set_file 0x04 +#define DW_LNS_set_column 0x05 +#define DW_LNS_negate_stmt 0x06 +#define DW_LNS_set_basic_block 0x07 +#define DW_LNS_const_add_pc 0x08 +#define DW_LNS_fixed_advance_pc 0x09 + +#define DW_LNE_end_sequence 0x01 +#define DW_LNE_set_address 0x02 +#define DW_LNE_define_file 0x03 + +#define DW_CFA_advance_loc 0x01 +#define DW_CFA_offset 0x02 +#define DW_CFA_restore 0x03 +#define DW_CFA_set_loc 0x01 +#define DW_CFA_advance_loc1 0x02 +#define DW_CFA_advance_loc2 0x03 +#define DW_CFA_advance_loc4 0x04 +#define DW_CFA_offset_extended 0x05 +#define DW_CFA_restore_extended 0x06 +#define DW_CFA_undefined 0x07 +#define DW_CFA_same_value 0x08 +#define DW_CFA_register 0x09 +#define DW_CFA_remember_state 0x0a +#define DW_CFA_restore_state 0x0b +#define DW_CFA_def_cfa 0x0c +#define DW_CFA_def_cfa_register 0x0d +#define DW_CFA_def_cfa_offset 0x0e +#define DW_CFA_nop 0x00 + +#define CASE_TYPE_TAG \ + case DW_TAG_const_type:\ + case DW_TAG_volatile_type:\ + case DW_TAG_pointer_type:\ + case DW_TAG_base_type:\ + case DW_TAG_array_type:\ + case DW_TAG_structure_type:\ + case DW_TAG_union_type:\ + case DW_TAG_typedef:\ + case DW_TAG_subroutine_type:\ + case DW_TAG_enumeration_type:\ + case DW_TAG_enumerator:\ + case DW_TAG_reference_type + +struct ELFcie { + ELFcie *next; + u32 offset; + u8 *augmentation; + u32 codeAlign; + s32 dataAlign; + int returnAddress; + u8 *data; + u32 dataLen; +}; + +struct ELFfde { + ELFcie *cie; + u32 address; + u32 end; + u8 *data; + u32 dataLen; +}; + +enum ELFRegMode { + REG_NOT_SET, + REG_OFFSET, + REG_REGISTER +}; + + +struct ELFFrameStateRegister { + ELFRegMode mode; + int reg; + s32 offset; +}; + +struct ELFFrameStateRegisters { + ELFFrameStateRegister regs[16]; + ELFFrameStateRegisters *previous; +}; + +enum ELFCfaMode { + CFA_NOT_SET, + CFA_REG_OFFSET +}; + +struct ELFFrameState { + ELFFrameStateRegisters registers; + + ELFCfaMode cfaMode; + int cfaRegister; + s32 cfaOffset; + + u32 pc; + + int dataAlign; + int codeAlign; + int returnAddress; +}; + +extern bool cpuIsMultiBoot; + +Symbol *elfSymbols = NULL; +char *elfSymbolsStrTab = NULL; +int elfSymbolsCount = 0; + +ELFSectionHeader **elfSectionHeaders = NULL; +char *elfSectionHeadersStringTable = NULL; +int elfSectionHeadersCount = 0; +u8 *elfFileData = NULL; + +CompileUnit *elfCompileUnits = NULL; +DebugInfo *elfDebugInfo = NULL; +char *elfDebugStrings = NULL; + +ELFcie *elfCies = NULL; +ELFfde **elfFdes = NULL; +int elfFdeCount = 0; + +CompileUnit *elfCurrentUnit = NULL; + +u32 elfRead4Bytes(u8 *); +u16 elfRead2Bytes(u8 *); + +CompileUnit *elfGetCompileUnit(u32 addr) +{ + if(elfCompileUnits) { + CompileUnit *unit = elfCompileUnits; + while(unit) { + if(unit->lowPC) { + if(addr >= unit->lowPC && addr < unit->highPC) + return unit; + } else { + ARanges *r = unit->ranges; + if(r) { + int count = r->count; + for(int j = 0; j < count; j++) { + if(addr >= r->ranges[j].lowPC && addr < r->ranges[j].highPC) + return unit; + } + } + } + unit = unit->next; + } + } + return NULL; +} + +const char *elfGetAddressSymbol(u32 addr) +{ + static char buffer[256]; + + CompileUnit *unit = elfGetCompileUnit(addr); + // found unit, need to find function + if(unit) { + Function *func = unit->functions; + while(func) { + if(addr >= func->lowPC && addr < func->highPC) { + int offset = addr - func->lowPC; + const char *name = func->name; + if(!name) + name = ""; + if(offset) + sprintf(buffer, "%s+%d", name, offset); + else + strcpy(buffer, name); + return buffer; + } + func = func->next; + } + } + + if(elfSymbolsCount) { + for(int i = 0; i < elfSymbolsCount; i++) { + Symbol *s = &elfSymbols[i]; + if((addr >= s->value) && addr < (s->value+s->size)) { + int offset = addr-s->value; + const char *name = s->name; + if(name == NULL) + name = ""; + if(offset) + sprintf(buffer, "%s+%d", name, addr-s->value); + else + strcpy(buffer, name); + return buffer; + } else if(addr == s->value) { + if(s->name) + strcpy(buffer, s->name); + else + strcpy(buffer, ""); + return buffer; + } + } + } + + return ""; +} + +bool elfFindLineInModule(u32 *addr, const char *name, int line) +{ + CompileUnit *unit = elfCompileUnits; + + while(unit) { + if(unit->lineInfoTable) { + int i; + int count = unit->lineInfoTable->fileCount; + char *found = NULL; + for(i = 0; i < count; i++) { + if(strcmp(name, unit->lineInfoTable->files[i]) == 0) { + found = unit->lineInfoTable->files[i]; + break; + } + } + // found a matching filename... try to find line now + if(found) { + LineInfoItem *table = unit->lineInfoTable->lines; + count = unit->lineInfoTable->number; + for(i = 0; i < count; i++) { + if(table[i].file == found && table[i].line == line) { + *addr = table[i].address; + return true; + } + } + // we can only find a single match + return false; + } + } + unit = unit->next; + } + return false; +} + +int elfFindLine(CompileUnit *unit, Function * /* func */, u32 addr, const char **f) +{ + int currentLine = -1; + if(unit->hasLineInfo) { + int count = unit->lineInfoTable->number; + LineInfoItem *table = unit->lineInfoTable->lines; + int i; + for(i = 0; i < count; i++) { + if(addr <= table[i].address) + break; + } + if(i == count) + i--; + *f = table[i].file; + currentLine = table[i].line; + } + return currentLine; +} + +bool elfFindLineInUnit(u32 *addr, CompileUnit *unit, int line) +{ + if(unit->hasLineInfo) { + int count = unit->lineInfoTable->number; + LineInfoItem *table = unit->lineInfoTable->lines; + int i; + for(i = 0; i < count; i++) { + if(line == table[i].line) { + *addr = table[i].address; + return true; + } + } + } + return false; +} + +bool elfGetCurrentFunction(u32 addr, Function **f, CompileUnit **u) +{ + CompileUnit *unit = elfGetCompileUnit(addr); + // found unit, need to find function + if(unit) { + Function *func = unit->functions; + while(func) { + if(addr >= func->lowPC && addr < func->highPC) { + *f = func; + *u = unit; + return true; + } + func = func->next; + } + } + return false; +} + +bool elfGetObject(const char *name, Function *f, CompileUnit *u, Object **o) +{ + if(f && u) { + Object *v = f->variables; + + while(v) { + if(strcmp(name, v->name) == 0) { + *o = v; + return true; + } + v = v->next; + } + v = f->parameters; + while(v) { + if(strcmp(name, v->name) == 0) { + *o = v; + return true; + } + v = v->next; + } + v = u->variables; + while(v) { + if(strcmp(name, v->name) == 0) { + *o = v; + return true; + } + v = v->next; + } + } + + CompileUnit *c = elfCompileUnits; + + while(c) { + if(c != u) { + Object *v = c->variables; + while(v) { + if(strcmp(name, v->name) == 0) { + *o = v; + return true; + } + v = v->next; + } + } + c = c->next; + } + + return false; +} + +const char *elfGetSymbol(int i, u32 *value, u32 *size, int *type) +{ + if(i < elfSymbolsCount) { + Symbol *s = &elfSymbols[i]; + *value = s->value; + *size = s->size; + *type = s->type; + return s->name; + } + return NULL; +} + +bool elfGetSymbolAddress(const char *sym, u32 *addr, u32 *size, int *type) +{ + if(elfSymbolsCount) { + for(int i = 0; i < elfSymbolsCount; i++) { + Symbol *s = &elfSymbols[i]; + if(strcmp(sym, s->name) == 0) { + *addr = s->value; + *size = s->size; + *type = s->type; + return true; + } + } + } + return false; +} + +ELFfde *elfGetFde(u32 address) +{ + if(elfFdes) { + int i; + for(i = 0; i < elfFdeCount; i++) { + if(address >= elfFdes[i]->address && + address < elfFdes[i]->end) { + return elfFdes[i]; + } + } + } + + return NULL; +} + +void elfExecuteCFAInstructions(ELFFrameState *state, u8 *data, u32 len, + u32 pc) +{ + u8 *end = data + len; + int bytes; + int reg; + ELFFrameStateRegisters *fs; + + while(data < end && state->pc < pc) { + u8 op = *data++; + + switch(op >> 6) { + case DW_CFA_advance_loc: + state->pc += (op & 0x3f) * state->codeAlign; + break; + case DW_CFA_offset: + reg = op & 0x3f; + state->registers.regs[reg].mode = REG_OFFSET; + state->registers.regs[reg].offset = state->dataAlign * + (s32)elfReadLEB128(data, &bytes); + data += bytes; + break; + case DW_CFA_restore: + // we don't care much about the other possible settings, + // so just setting to unset is enough for now + state->registers.regs[op & 0x3f].mode = REG_NOT_SET; + break; + case 0: + switch(op & 0x3f) { + case DW_CFA_nop: + break; + case DW_CFA_advance_loc1: + state->pc += state->codeAlign * (*data++); + break; + case DW_CFA_advance_loc2: + state->pc += state->codeAlign * elfRead2Bytes(data); + data += 2; + break; + case DW_CFA_advance_loc4: + state->pc += state->codeAlign * elfRead4Bytes(data); + data += 4; + break; + case DW_CFA_offset_extended: + reg = elfReadLEB128(data, &bytes); + data += bytes; + state->registers.regs[reg].mode = REG_OFFSET; + state->registers.regs[reg].offset = state->dataAlign * + (s32)elfReadLEB128(data, &bytes); + data += bytes; + break; + case DW_CFA_restore_extended: + case DW_CFA_undefined: + case DW_CFA_same_value: + reg = elfReadLEB128(data, &bytes); + data += bytes; + state->registers.regs[reg].mode = REG_NOT_SET; + break; + case DW_CFA_register: + reg = elfReadLEB128(data, &bytes); + data += bytes; + state->registers.regs[reg].mode = REG_REGISTER; + state->registers.regs[reg].reg = elfReadLEB128(data, &bytes); + data += bytes; + break; + case DW_CFA_remember_state: + fs = (ELFFrameStateRegisters *)calloc(1, + sizeof(ELFFrameStateRegisters)); + memcpy(fs, &state->registers, sizeof(ELFFrameStateRegisters)); + state->registers.previous = fs; + break; + case DW_CFA_restore_state: + if(state->registers.previous == NULL) { + printf("Error: previous frame state is NULL.\n"); + return; + } + fs = state->registers.previous; + memcpy(&state->registers, fs, sizeof(ELFFrameStateRegisters)); + free(fs); + break; + case DW_CFA_def_cfa: + state->cfaRegister = elfReadLEB128(data, &bytes); + data += bytes; + state->cfaOffset = (s32)elfReadLEB128(data, &bytes); + data += bytes; + state->cfaMode = CFA_REG_OFFSET; + break; + case DW_CFA_def_cfa_register: + state->cfaRegister = elfReadLEB128(data, &bytes); + data += bytes; + state->cfaMode = CFA_REG_OFFSET; + break; + case DW_CFA_def_cfa_offset: + state->cfaOffset = (s32)elfReadLEB128(data, &bytes); + data += bytes; + state->cfaMode = CFA_REG_OFFSET; + break; + default: + printf("Unknown CFA opcode %08x\n", op); + return; + } + break; + default: + printf("Unknown CFA opcode %08x\n", op); + return; + } + } +} + +ELFFrameState *elfGetFrameState(ELFfde *fde, u32 address) +{ + ELFFrameState *state = (ELFFrameState *)calloc(1, sizeof(ELFFrameState)); + state->pc = fde->address; + state->dataAlign = fde->cie->dataAlign; + state->codeAlign = fde->cie->codeAlign; + state->returnAddress = fde->cie->returnAddress; + + elfExecuteCFAInstructions(state, + fde->cie->data, + fde->cie->dataLen, + 0xffffffff); + elfExecuteCFAInstructions(state, + fde->data, + fde->dataLen, + address); + + return state; +} + +void elfPrintCallChain(u32 address) +{ + int count = 1; + + reg_pair regs[15]; + reg_pair newRegs[15]; + + memcpy(®s[0], ®[0], sizeof(reg_pair) * 15); + + while(count < 20) { + const char *addr = elfGetAddressSymbol(address); + if(*addr == 0) + addr = "???"; + + printf("%08x %s\n", address, addr); + + ELFfde *fde = elfGetFde(address); + + if(fde == NULL) { + break; + } + + ELFFrameState *state = elfGetFrameState(fde, address); + + if(!state) { + break; + } + + if(state->cfaMode == CFA_REG_OFFSET) { + memcpy(&newRegs[0], ®s[0], sizeof(reg_pair) * 15); + u32 addr = 0; + for(int i = 0; i < 15; i++) { + ELFFrameStateRegister *r = &state->registers. + regs[i]; + + switch(r->mode) { + case REG_NOT_SET: + newRegs[i].I = regs[i].I; + break; + case REG_OFFSET: + newRegs[i].I = elfReadMemory(regs[state->cfaRegister].I + + state->cfaOffset + + r->offset); + break; + case REG_REGISTER: + newRegs[i].I = regs[r->reg].I; + break; + default: + printf("Unknown register mode: %d\n", r->mode); + break; + } + } + memcpy(regs, newRegs, sizeof(reg_pair)*15); + addr = newRegs[14].I; + addr &= 0xfffffffe; + address = addr; + count++; + } else { + printf("CFA not set\n"); + break; + } + if(state->registers.previous) { + ELFFrameStateRegisters *prev = state->registers.previous; + + while(prev) { + ELFFrameStateRegisters *p = prev->previous; + free(prev); + prev = p; + } + } + free(state); + } +} + +u32 elfDecodeLocation(Function *f, ELFBlock *o, LocationType *type, u32 base) +{ + u32 framebase = 0; + if(f && f->frameBase) { + ELFBlock *b = f->frameBase; + switch(*b->data) { + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + framebase = reg[*b->data-0x50].I; + break; + default: + fprintf(stderr, "Unknown frameBase %02x\n", *b->data); + break; + } + } + + ELFBlock *loc = o; + u32 location = 0; + int bytes = 0; + if(loc) { + switch(*loc->data) { + case DW_OP_addr: + location = elfRead4Bytes(loc->data+1); + *type = LOCATION_memory; + break; + case DW_OP_plus_uconst: + location = base + elfReadLEB128(loc->data+1, &bytes); + *type = LOCATION_memory; + break; + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + location = *loc->data - 0x50; + *type = LOCATION_register; + break; + case DW_OP_fbreg: + { + int bytes; + s32 off = elfReadSignedLEB128(loc->data+1, &bytes); + location = framebase + off; + *type = LOCATION_memory; + } + break; + default: + fprintf(stderr, "Unknown location %02x\n", *loc->data); + break; + } + } + return location; +} + +u32 elfDecodeLocation(Function *f, ELFBlock *o, LocationType *type) +{ + return elfDecodeLocation(f, o, type, 0); +} + +// reading function + +u32 elfRead4Bytes(u8 *data) +{ + u32 value = *data++; + value |= (*data++ << 8); + value |= (*data++ << 16); + value |= (*data << 24); + return value; +} + +u16 elfRead2Bytes(u8 *data) +{ + u16 value = *data++; + value |= (*data << 8); + return value; +} + +char *elfReadString(u8 *data, int *bytesRead) +{ + if(*data == 0) { + *bytesRead = 1; + return NULL; + } + *bytesRead = (int)strlen((char *)data) + 1; + return (char *)data; +} + +s32 elfReadSignedLEB128(u8 *data, int *bytesRead) +{ + s32 result = 0; + int shift = 0; + int count = 0; + + u8 byte; + do { + byte = *data++; + count++; + result |= (byte & 0x7f) << shift; + shift += 7; + } while(byte & 0x80); + if((shift < 32) && (byte & 0x40)) + result |= -(1 << shift); + *bytesRead = count; + return result; +} + +u32 elfReadLEB128(u8 *data, int *bytesRead) +{ + u32 result = 0; + int shift = 0; + int count = 0; + u8 byte; + do { + byte = *data++; + count++; + result |= (byte & 0x7f) << shift; + shift += 7; + } while(byte & 0x80); + *bytesRead = count; + return result; +} + +u8 *elfReadSection(u8 *data, ELFSectionHeader *sh) +{ + return data + READ32LE(&sh->offset); +} + +ELFSectionHeader *elfGetSectionByName(const char *name) +{ + for(int i = 0; i < elfSectionHeadersCount; i++) { + if(strcmp(name, + &elfSectionHeadersStringTable[READ32LE(&elfSectionHeaders[i]-> + name)]) == 0) { + return elfSectionHeaders[i]; + } + } + return NULL; +} + +ELFSectionHeader *elfGetSectionByNumber(int number) +{ + if(number < elfSectionHeadersCount) { + return elfSectionHeaders[number]; + } + return NULL; +} + +CompileUnit *elfGetCompileUnitForData(u8 *data) +{ + u8 *end = elfCurrentUnit->top + 4 + elfCurrentUnit->length; + + if(data >= elfCurrentUnit->top && data < end) + return elfCurrentUnit; + + CompileUnit *unit = elfCompileUnits; + + while(unit) { + end = unit->top + 4 + unit->length; + + if(data >= unit->top && data < end) + return unit; + + unit = unit->next; + } + + printf("Error: cannot find reference to compile unit at offset %08x\n", + (int)(data - elfDebugInfo->infodata)); + exit(-1); +} + +u8 *elfReadAttribute(u8 *data, ELFAttr *attr) +{ + int bytes; + int form = attr->form; + start: + switch(form) { + case DW_FORM_addr: + attr->value = elfRead4Bytes(data); + data += 4; + break; + case DW_FORM_data2: + attr->value = elfRead2Bytes(data); + data += 2; + break; + case DW_FORM_data4: + attr->value = elfRead4Bytes(data); + data += 4; + break; + case DW_FORM_string: + attr->string = (char *)data; + data += strlen(attr->string)+1; + break; + case DW_FORM_strp: + attr->string = elfDebugStrings + elfRead4Bytes(data); + data += 4; + break; + case DW_FORM_block: + attr->block = (ELFBlock *)malloc(sizeof(ELFBlock)); + attr->block->length = elfReadLEB128(data, &bytes); + data += bytes; + attr->block->data = data; + data += attr->block->length; + break; + case DW_FORM_block1: + attr->block = (ELFBlock *)malloc(sizeof(ELFBlock)); + attr->block->length = *data++; + attr->block->data = data; + data += attr->block->length; + break; + case DW_FORM_data1: + attr->value = *data++; + break; + case DW_FORM_flag: + attr->flag = (*data++) ? true : false; + break; + case DW_FORM_sdata: + attr->value = elfReadSignedLEB128(data, &bytes); + data += bytes; + break; + case DW_FORM_udata: + attr->value = elfReadLEB128(data, &bytes); + data += bytes; + break; + case DW_FORM_ref_addr: + attr->value = (u32)((elfDebugInfo->infodata + elfRead4Bytes(data)) - elfGetCompileUnitForData(data)->top); + data += 4; + break; + case DW_FORM_ref4: + attr->value = elfRead4Bytes(data); + data += 4; + break; + case DW_FORM_ref_udata: + attr->value = (u32)((elfDebugInfo->infodata + (elfGetCompileUnitForData(data)->top - elfDebugInfo->infodata) + elfReadLEB128(data, &bytes)) - elfCurrentUnit->top); + data += bytes; + break; + case DW_FORM_indirect: + form = elfReadLEB128(data, &bytes); + data += bytes; + goto start; + default: + fprintf(stderr, "Unsupported FORM %02x\n", form); + exit(-1); + } + return data; +} + +ELFAbbrev *elfGetAbbrev(ELFAbbrev **table, u32 number) +{ + int hash = number % 121; + + ELFAbbrev *abbrev = table[hash]; + + while(abbrev) { + if(abbrev->number == number) + return abbrev; + abbrev = abbrev->next; + } + return NULL; +} + +ELFAbbrev **elfReadAbbrevs(u8 *data, u32 offset) +{ + data += offset; + ELFAbbrev **abbrevs = (ELFAbbrev **)calloc(sizeof(ELFAbbrev *)*121,1); + int bytes = 0; + u32 number = elfReadLEB128(data, &bytes); + data += bytes; + while(number) { + ELFAbbrev *abbrev = (ELFAbbrev *)calloc(sizeof(ELFAbbrev),1); + + // read tag information + abbrev->number = number; + abbrev->tag = elfReadLEB128(data, &bytes); + data += bytes; + abbrev->hasChildren = *data++ ? true: false; + + // read attributes + int name = elfReadLEB128(data, &bytes); + data += bytes; + int form = elfReadLEB128(data, &bytes); + data += bytes; + + while(name) { + if((abbrev->numAttrs % 4) == 0) { + abbrev->attrs = (ELFAttr *)realloc(abbrev->attrs, + (abbrev->numAttrs + 4) * + sizeof(ELFAttr)); + } + abbrev->attrs[abbrev->numAttrs].name = name; + abbrev->attrs[abbrev->numAttrs++].form = form; + + name = elfReadLEB128(data, &bytes); + data += bytes; + form = elfReadLEB128(data, &bytes); + data += bytes; + } + + int hash = number % 121; + abbrev->next = abbrevs[hash]; + abbrevs[hash] = abbrev; + + number = elfReadLEB128(data, &bytes); + data += bytes; + + if(elfGetAbbrev(abbrevs, number) != NULL) + break; + } + + return abbrevs; +} + +void elfParseCFA(u8 *top) +{ + ELFSectionHeader *h = elfGetSectionByName(".debug_frame"); + + if(h == NULL) { + return; + } + + u8 *data = elfReadSection(top, h); + + u8 *topOffset = data; + + u8 *end = data + READ32LE(&h->size); + + ELFcie *cies = NULL; + + while(data < end) { + u32 offset = (u32)(data - topOffset); + u32 len = elfRead4Bytes(data); + data += 4; + + u8 *dataEnd = data + len; + + u32 id = elfRead4Bytes(data); + data += 4; + + if(id == 0xffffffff) { + // skip version + *data++; + + ELFcie *cie = (ELFcie *)calloc(1, sizeof(ELFcie)); + + cie->next = cies; + cies = cie; + + cie->offset = offset; + + cie->augmentation = data; + while(*data) + data++; + data++; + + if(*cie->augmentation) { + fprintf(stderr, "Error: augmentation not supported\n"); + exit(-1); + } + + int bytes; + cie->codeAlign = elfReadLEB128(data, &bytes); + data += bytes; + + cie->dataAlign = elfReadSignedLEB128(data, &bytes); + data += bytes; + + cie->returnAddress = *data++; + + cie->data = data; + cie->dataLen = (u32)(dataEnd - data); + } else { + ELFfde *fde = (ELFfde *)calloc(1, sizeof(ELFfde)); + + ELFcie *cie = cies; + + while(cie != NULL) { + if(cie->offset == id) + break; + cie = cie->next; + } + + if(!cie) { + fprintf(stderr, "Cannot find CIE %08x\n", id); + exit(-1); + } + + fde->cie = cie; + + fde->address = elfRead4Bytes(data); + data += 4; + + fde->end = fde->address + elfRead4Bytes(data); + data += 4; + + fde->data = data; + fde->dataLen = (u32)(dataEnd - data); + + if((elfFdeCount %10) == 0) { + elfFdes = (ELFfde **)realloc(elfFdes, (elfFdeCount+10) * + sizeof(ELFfde *)); + } + elfFdes[elfFdeCount++] = fde; + } + data = dataEnd; + } + + elfCies = cies; +} + +void elfAddLine(LineInfo *l, u32 a, int file, int line, int *max) +{ + if(l->number == *max) { + *max += 1000; + l->lines = (LineInfoItem *)realloc(l->lines, *max*sizeof(LineInfoItem)); + } + LineInfoItem *li = &l->lines[l->number]; + li->file = l->files[file-1]; + li->address = a; + li->line = line; + l->number++; +} + +void elfParseLineInfo(CompileUnit *unit, u8 *top) +{ + ELFSectionHeader *h = elfGetSectionByName(".debug_line"); + if(h == NULL) { + fprintf(stderr, "No line information found\n"); + return; + } + LineInfo *l = unit->lineInfoTable = (LineInfo *)calloc(1, sizeof(LineInfo)); + l->number = 0; + int max = 1000; + l->lines = (LineInfoItem *)malloc(1000*sizeof(LineInfoItem)); + + u8 *data = elfReadSection(top, h); + data += unit->lineInfo; + u32 totalLen = elfRead4Bytes(data); + data += 4; + u8 *end = data + totalLen; + // u16 version = elfRead2Bytes(data); + data += 2; + // u32 offset = elfRead4Bytes(data); + data += 4; + int minInstrSize = *data++; + int defaultIsStmt = *data++; + int lineBase = (s8)*data++; + int lineRange = *data++; + int opcodeBase = *data++; + u8 *stdOpLen = (u8 *)malloc(opcodeBase * sizeof(u8)); + stdOpLen[0] = 1; + int i; + for(i = 1; i < opcodeBase; i++) + stdOpLen[i] = *data++; + + free(stdOpLen);// todo + int bytes = 0; + + char *s; + while((s = elfReadString(data, &bytes)) != NULL) { + data += bytes; + // fprintf(stderr, "Directory is %s\n", s); + } + data += bytes; + int count = 4; + int index = 0; + l->files = (char **)malloc(sizeof(char *)*count); + + while((s = elfReadString(data, &bytes)) != NULL) { + l->files[index++] = s; + + data += bytes; + // directory + elfReadLEB128(data, &bytes); + data += bytes; + // time + elfReadLEB128(data, &bytes); + data += bytes; + // size + elfReadLEB128(data, &bytes); + data += bytes; + // fprintf(stderr, "File is %s\n", s); + if(index == count) { + count += 4; + l->files = (char **)realloc(l->files, sizeof(char *)*count); + } + } + l->fileCount = index; + data += bytes; + + while(data < end) { + u32 address = 0; + int file = 1; + int line = 1; + int col = 0; + int isStmt = defaultIsStmt; + int basicBlock = 0; + int endSeq = 0; + + while(!endSeq) { + int op = *data++; + switch(op) { + case DW_LNS_extended_op: + { + data++; + op = *data++; + switch(op) { + case DW_LNE_end_sequence: + endSeq = 1; + break; + case DW_LNE_set_address: + address = elfRead4Bytes(data); + data += 4; + break; + default: + fprintf(stderr, "Unknown extended LINE opcode %02x\n", op); + exit(-1); + } + } + break; + case DW_LNS_copy: + // fprintf(stderr, "Address %08x line %d (%d)\n", address, line, file); + elfAddLine(l, address, file, line, &max); + basicBlock = 0; + break; + case DW_LNS_advance_pc: + address += minInstrSize * elfReadLEB128(data, &bytes); + data += bytes; + break; + case DW_LNS_advance_line: + line += elfReadSignedLEB128(data, &bytes); + data += bytes; + break; + case DW_LNS_set_file: + file = elfReadLEB128(data, &bytes); + data += bytes; + break; + case DW_LNS_set_column: + col = elfReadLEB128(data, &bytes); + data += bytes; + break; + case DW_LNS_negate_stmt: + isStmt = !isStmt; + break; + case DW_LNS_set_basic_block: + basicBlock = 1; + break; + case DW_LNS_const_add_pc: + address += (minInstrSize *((255 - opcodeBase)/lineRange)); + break; + case DW_LNS_fixed_advance_pc: + address += elfRead2Bytes(data); + data += 2; + break; + default: + op = op - opcodeBase; + address += (op / lineRange) * minInstrSize; + line += lineBase + (op % lineRange); + elfAddLine(l, address, file, line, &max); + // fprintf(stderr, "Address %08x line %d (%d)\n", address, line,file); + basicBlock = 1; + break; + } + } + } + l->lines = (LineInfoItem *)realloc(l->lines, l->number*sizeof(LineInfoItem)); +} + +u8 *elfSkipData(u8 *data, ELFAbbrev *abbrev, ELFAbbrev **abbrevs) +{ + int i; + int bytes; + + for(i = 0; i < abbrev->numAttrs; i++) { + data = elfReadAttribute(data, &abbrev->attrs[i]); + if(abbrev->attrs[i].form == DW_FORM_block1) + free(abbrev->attrs[i].block); + } + + if(abbrev->hasChildren) { + int nesting = 1; + while(nesting) { + u32 abbrevNum = elfReadLEB128(data, &bytes); + data += bytes; + + if(!abbrevNum) { + nesting--; + continue; + } + + abbrev = elfGetAbbrev(abbrevs, abbrevNum); + + for(i = 0; i < abbrev->numAttrs; i++) { + data = elfReadAttribute(data, &abbrev->attrs[i]); + if(abbrev->attrs[i].form == DW_FORM_block1) + free(abbrev->attrs[i].block); + } + + if(abbrev->hasChildren) { + nesting++; + } + } + } + return data; +} + +Type *elfParseType(CompileUnit *unit, u32); +u8 *elfParseObject(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, + Object **object); +u8 *elfParseFunction(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, + Function **function); +void elfCleanUp(Function *); + +void elfAddType(Type *type, CompileUnit *unit, u32 offset) +{ + if(type->next == NULL) { + if(unit->types != type && type->offset == 0) { + type->offset = offset; + type->next = unit->types; + unit->types = type; + } + } +} + +void elfParseType(u8 *data, u32 offset, ELFAbbrev *abbrev, CompileUnit *unit, + Type **type) +{ + switch(abbrev->tag) { + case DW_TAG_typedef: + { + u32 typeref = 0; + char *name = NULL; + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_name: + name = attr->string; + break; + case DW_AT_type: + typeref = attr->value; + break; + case DW_AT_decl_file: + case DW_AT_decl_line: + break; + default: + fprintf(stderr, "Unknown attribute for typedef %02x\n", attr->name); + break; + } + } + if(abbrev->hasChildren) + fprintf(stderr, "Unexpected children for typedef\n"); + *type = elfParseType(unit, typeref); + if(name) + (*type)->name = name; + return; + } + break; + case DW_TAG_union_type: + case DW_TAG_structure_type: + { + Type *t = (Type *)calloc(sizeof(Type), 1); + if(abbrev->tag == DW_TAG_structure_type) + t->type = TYPE_struct; + else + t->type = TYPE_union; + + Struct *s = (Struct *)calloc(sizeof(Struct), 1); + t->structure = s; + elfAddType(t, unit, offset); + + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_name: + t->name = attr->string; + break; + case DW_AT_byte_size: + t->size = attr->value; + break; + case DW_AT_decl_file: + case DW_AT_decl_line: + case DW_AT_sibling: + case DW_AT_containing_type: // todo? + case DW_AT_declaration: + case DW_AT_specification: // TODO: + break; + default: + fprintf(stderr, "Unknown attribute for struct %02x\n", attr->name); + break; + } + } + if(abbrev->hasChildren) { + int bytes; + u32 num = elfReadLEB128(data, &bytes); + data += bytes; + int index = 0; + while(num) { + ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num); + + switch(abbr->tag) { + case DW_TAG_member: + { + if((index % 4) == 0) + s->members = (Member *)realloc(s->members, + sizeof(Member)*(index+4)); + Member *m = &s->members[index]; + m->location = NULL; + m->bitOffset = 0; + m->bitSize = 0; + m->byteSize = 0; + for(int i = 0; i < abbr->numAttrs; i++) { + ELFAttr *attr = &abbr->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_name: + m->name = attr->string; + break; + case DW_AT_type: + m->type = elfParseType(unit, attr->value); + break; + case DW_AT_data_member_location: + m->location = attr->block; + break; + case DW_AT_byte_size: + m->byteSize = attr->value; + break; + case DW_AT_bit_offset: + m->bitOffset = attr->value; + break; + case DW_AT_bit_size: + m->bitSize = attr->value; + break; + case DW_AT_decl_file: + case DW_AT_decl_line: + case DW_AT_accessibility: + case DW_AT_artificial: // todo? + break; + default: + fprintf(stderr, "Unknown member attribute %02x\n", + attr->name); + } + } + index++; + } + break; + case DW_TAG_subprogram: + { + Function *fnc = NULL; + data = elfParseFunction(data, abbr, unit, &fnc); + if(fnc != NULL) { + if(unit->lastFunction) + unit->lastFunction->next = fnc; + else + unit->functions = fnc; + unit->lastFunction = fnc; + } + } + break; + case DW_TAG_inheritance: + // TODO: add support + data = elfSkipData(data, abbr, unit->abbrevs); + break; + CASE_TYPE_TAG: + // skip types... parsed only when used + data = elfSkipData(data, abbr, unit->abbrevs); + break; + case DW_TAG_variable: + data = elfSkipData(data, abbr, unit->abbrevs); + break; + default: + fprintf(stderr, "Unknown struct tag %02x %s\n", abbr->tag, t->name); + data = elfSkipData(data, abbr, unit->abbrevs); + break; + } + num = elfReadLEB128(data, &bytes); + data += bytes; + } + s->memberCount = index; + } + *type = t; + return; + } + break; + case DW_TAG_base_type: + { + Type *t = (Type *)calloc(sizeof(Type), 1); + + t->type = TYPE_base; + elfAddType(t, unit, offset); + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_name: + t->name = attr->string; + break; + case DW_AT_encoding: + t->encoding = attr->value; + break; + case DW_AT_byte_size: + t->size = attr->value; + break; + case DW_AT_bit_size: + t->bitSize = attr->value; + break; + default: + fprintf(stderr, "Unknown attribute for base type %02x\n", + attr->name); + break; + } + } + if(abbrev->hasChildren) + fprintf(stderr, "Unexpected children for base type\n"); + *type = t; + return; + } + break; + case DW_TAG_pointer_type: + { + Type *t = (Type *)calloc(sizeof(Type), 1); + + t->type = TYPE_pointer; + + elfAddType(t, unit, offset); + + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data =elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_type: + t->pointer = elfParseType(unit, attr->value); + break; + case DW_AT_byte_size: + t->size = attr->value; + break; + default: + fprintf(stderr, "Unknown pointer type attribute %02x\n", attr->name); + break; + } + } + if(abbrev->hasChildren) + fprintf(stderr, "Unexpected children for pointer type\n"); + *type = t; + return; + } + break; + case DW_TAG_reference_type: + { + Type *t = (Type *)calloc(sizeof(Type), 1); + + t->type = TYPE_reference; + + elfAddType(t, unit, offset); + + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data =elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_type: + t->pointer = elfParseType(unit, attr->value); + break; + case DW_AT_byte_size: + t->size = attr->value; + break; + default: + fprintf(stderr, "Unknown ref type attribute %02x\n", attr->name); + break; + } + } + if(abbrev->hasChildren) + fprintf(stderr, "Unexpected children for ref type\n"); + *type = t; + return; + } + break; + case DW_TAG_volatile_type: + { + u32 typeref = 0; + + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_type: + typeref = attr->value; + break; + default: + fprintf(stderr, "Unknown volatile attribute for type %02x\n", + attr->name); + break; + } + } + if(abbrev->hasChildren) + fprintf(stderr, "Unexpected children for volatile type\n"); + *type = elfParseType(unit, typeref); + return; + } + break; + case DW_TAG_const_type: + { + u32 typeref = 0; + + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_type: + typeref = attr->value; + break; + default: + fprintf(stderr, "Unknown const attribute for type %02x\n", + attr->name); + break; + } + } + if(abbrev->hasChildren) + fprintf(stderr, "Unexpected children for const type\n"); + *type = elfParseType(unit, typeref); + return; + } + break; + case DW_TAG_enumeration_type: + { + Type *t = (Type *)calloc(sizeof(Type), 1); + t->type = TYPE_enum; + Enum *e = (Enum *)calloc(sizeof(Enum), 1); + t->enumeration = e; + elfAddType(t, unit, offset); + int count = 0; + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_name: + t->name = attr->string; + break; + case DW_AT_byte_size: + t->size = attr->value; + break; + case DW_AT_sibling: + case DW_AT_decl_file: + case DW_AT_decl_line: + break; + default: + fprintf(stderr, "Unknown enum attribute %02x\n", attr->name); + } + } + if(abbrev->hasChildren) { + int bytes; + u32 num = elfReadLEB128(data, &bytes); + data += bytes; + while(num) { + ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num); + + switch(abbr->tag) { + case DW_TAG_enumerator: + { + count++; + e->members = (EnumMember *)realloc(e->members, + count*sizeof(EnumMember)); + EnumMember *m = &e->members[count-1]; + for(int i = 0; i < abbr->numAttrs; i++) { + ELFAttr *attr = &abbr->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_name: + m->name = attr->string; + break; + case DW_AT_const_value: + m->value = attr->value; + break; + default: + fprintf(stderr, "Unknown sub param attribute %02x\n", + attr->name); + } + } + } + break; + default: + fprintf(stderr, "Unknown enum tag %02x\n", abbr->tag); + data = elfSkipData(data, abbr, unit->abbrevs); + break; + } + num = elfReadLEB128(data, &bytes); + data += bytes; + } + } + e->count = count; + *type = t; + return; + } + break; + case DW_TAG_subroutine_type: + { + Type *t = (Type *)calloc(sizeof(Type), 1); + t->type = TYPE_function; + FunctionType *f = (FunctionType *)calloc(sizeof(FunctionType), 1); + t->function = f; + elfAddType(t, unit, offset); + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_prototyped: + case DW_AT_sibling: + break; + case DW_AT_type: + f->returnType = elfParseType(unit, attr->value); + break; + default: + fprintf(stderr, "Unknown subroutine attribute %02x\n", attr->name); + } + } + if(abbrev->hasChildren) { + int bytes; + u32 num = elfReadLEB128(data, &bytes); + data += bytes; + Object *lastVar = NULL; + while(num) { + ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num); + + switch(abbr->tag) { + case DW_TAG_formal_parameter: + { + Object *o; + data = elfParseObject(data, abbr, unit, &o); + if(f->args) + lastVar->next = o; + else + f->args = o; + lastVar = o; + } + break; + case DW_TAG_unspecified_parameters: + // no use in the debugger yet + data = elfSkipData(data, abbr, unit->abbrevs); + break; + CASE_TYPE_TAG: + // skip types... parsed only when used + data = elfSkipData(data, abbr, unit->abbrevs); + break; + default: + fprintf(stderr, "Unknown subroutine tag %02x\n", abbr->tag); + data = elfSkipData(data, abbr, unit->abbrevs); + break; + } + num = elfReadLEB128(data, &bytes); + data += bytes; + } + } + *type = t; + return; + } + break; + case DW_TAG_array_type: + { + u32 typeref = 0; + int i; + Array *array = (Array *)calloc(sizeof(Array), 1); + Type *t = (Type *)calloc(sizeof(Type), 1); + t->type = TYPE_array; + elfAddType(t, unit, offset); + + for(i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_sibling: + break; + case DW_AT_type: + typeref = attr->value; + array->type = elfParseType(unit, typeref); + break; + default: + fprintf(stderr, "Unknown array attribute %02x\n", attr->name); + } + } + if(abbrev->hasChildren) { + int bytes; + u32 num = elfReadLEB128(data, &bytes); + data += bytes; + int index = 0; + int maxBounds = 0; + while(num) { + ELFAbbrev *abbr = elfGetAbbrev(unit->abbrevs, num); + + switch(abbr->tag) { + case DW_TAG_subrange_type: + { + if(maxBounds == index) { + maxBounds += 4; + array->bounds = (int *)realloc(array->bounds, + sizeof(int)*maxBounds); + } + for(int i = 0; i < abbr->numAttrs; i++) { + ELFAttr *attr = &abbr->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_upper_bound: + array->bounds[index] = attr->value+1; + break; + case DW_AT_type: // ignore + break; + default: + fprintf(stderr, "Unknown subrange attribute %02x\n", + attr->name); + } + } + index++; + } + break; + default: + fprintf(stderr, "Unknown array tag %02x\n", abbr->tag); + data = elfSkipData(data, abbr, unit->abbrevs); + break; + } + num = elfReadLEB128(data, &bytes); + data += bytes; + } + array->maxBounds = index; + } + t->size = array->type->size; + for(i = 0; i < array->maxBounds; i++) + t->size *= array->bounds[i]; + t->array = array; + *type = t; + return; + } + break; + default: + fprintf(stderr, "Unknown type TAG %02x\n", abbrev->tag); + exit(-1); + } +} + +Type *elfParseType(CompileUnit *unit, u32 offset) +{ + Type *t = unit->types; + + while(t) { + if(t->offset == offset) + return t; + t = t->next; + } + if(offset == 0) { + Type *t = (Type *)calloc(sizeof(Type), 1); + t->type = TYPE_void; + t->offset = 0; + elfAddType(t, unit, 0); + return t; + } + u8 *data = unit->top + offset; + int bytes; + int abbrevNum = elfReadLEB128(data, &bytes); + data += bytes; + Type *type = NULL; + + ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); + + elfParseType(data, offset, abbrev, unit, &type); + return type; +} + +void elfGetObjectAttributes(CompileUnit *unit, u32 offset, Object *o) +{ + u8 *data = unit->top + offset; + int bytes; + u32 abbrevNum = elfReadLEB128(data, &bytes); + data += bytes; + + if(!abbrevNum) { + return; + } + + ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); + + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_location: + o->location = attr->block; + break; + case DW_AT_name: + if(o->name == NULL) + o->name = attr->string; + break; + case DW_AT_MIPS_linkage_name: + o->name = attr->string; + break; + case DW_AT_decl_file: + o->file = attr->value; + break; + case DW_AT_decl_line: + o->line = attr->value; + break; + case DW_AT_type: + o->type = elfParseType(unit, attr->value); + break; + case DW_AT_external: + o->external = attr->flag; + break; + case DW_AT_const_value: + case DW_AT_abstract_origin: + case DW_AT_declaration: + case DW_AT_artificial: + // todo + break; + case DW_AT_specification: + // TODO: + break; + default: + fprintf(stderr, "Unknown object attribute %02x\n", attr->name); + break; + } + } +} + +u8 *elfParseObject(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, + Object **object) +{ + Object *o = (Object *)calloc(sizeof(Object), 1); + + o->next = NULL; + + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_location: + o->location = attr->block; + break; + case DW_AT_name: + if(o->name == NULL) + o->name = attr->string; + break; + case DW_AT_MIPS_linkage_name: + o->name = attr->string; + break; + case DW_AT_decl_file: + o->file = attr->value; + break; + case DW_AT_decl_line: + o->line = attr->value; + break; + case DW_AT_type: + o->type = elfParseType(unit, attr->value); + break; + case DW_AT_external: + o->external = attr->flag; + break; + case DW_AT_abstract_origin: + elfGetObjectAttributes(unit, attr->value, o); + break; + case DW_AT_const_value: + case DW_AT_declaration: + case DW_AT_artificial: + break; + case DW_AT_specification: + // TODO: + break; + default: + fprintf(stderr, "Unknown object attribute %02x\n", attr->name); + break; + } + } + *object = o; + return data; +} + +u8 *elfParseBlock(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, + Function *func, Object **lastVar) +{ + int bytes; + u32 start = func->lowPC; + u32 end = func->highPC; + + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_sibling: + break; + case DW_AT_low_pc: + start = attr->value; + break; + case DW_AT_high_pc: + end = attr->value; + break; + case DW_AT_ranges: // ignore for now + break; + default: + fprintf(stderr, "Unknown block attribute %02x\n", attr->name); + break; + } + } + + if(abbrev->hasChildren) { + int nesting = 1; + + while(nesting) { + u32 abbrevNum = elfReadLEB128(data, &bytes); + data += bytes; + + if(!abbrevNum) { + nesting--; + continue; + } + + abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); + + switch(abbrev->tag) { + CASE_TYPE_TAG: // types only parsed when used + case DW_TAG_label: // not needed + data = elfSkipData(data, abbrev, unit->abbrevs); + break; + case DW_TAG_lexical_block: + data = elfParseBlock(data, abbrev, unit, func, lastVar); + break; + case DW_TAG_subprogram: + { + Function *f = NULL; + data = elfParseFunction(data, abbrev, unit, &f); + if(f != NULL) { + if(unit->lastFunction) + unit->lastFunction->next = f; + else + unit->functions = f; + unit->lastFunction = f; + } + } + break; + case DW_TAG_variable: + { + Object *o; + data = elfParseObject(data, abbrev, unit, &o); + if(o->startScope == 0) + o->startScope = start; + if(o->endScope == 0) + o->endScope = 0; + if(func->variables) + (*lastVar)->next = o; + else + func->variables = o; + *lastVar = o; + } + break; + case DW_TAG_inlined_subroutine: + // TODO: + data = elfSkipData(data, abbrev, unit->abbrevs); + break; + default: + { + fprintf(stderr, "Unknown block TAG %02x\n", abbrev->tag); + data = elfSkipData(data, abbrev, unit->abbrevs); + } + break; + } + } + } + return data; +} + +void elfGetFunctionAttributes(CompileUnit *unit, u32 offset, Function *func) +{ + u8 *data = unit->top + offset; + int bytes; + u32 abbrevNum = elfReadLEB128(data, &bytes); + data += bytes; + + if(!abbrevNum) { + return; + } + + ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); + + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + + switch(attr->name) { + case DW_AT_sibling: + break; + case DW_AT_name: + if(func->name == NULL) + func->name = attr->string; + break; + case DW_AT_MIPS_linkage_name: + func->name = attr->string; + break; + case DW_AT_low_pc: + func->lowPC = attr->value; + break; + case DW_AT_high_pc: + func->highPC = attr->value; + break; + case DW_AT_decl_file: + func->file = attr->value; + break; + case DW_AT_decl_line: + func->line = attr->value; + break; + case DW_AT_external: + func->external = attr->flag; + break; + case DW_AT_frame_base: + func->frameBase = attr->block; + break; + case DW_AT_type: + func->returnType = elfParseType(unit, attr->value); + break; + case DW_AT_inline: + case DW_AT_specification: + case DW_AT_declaration: + case DW_AT_artificial: + case DW_AT_prototyped: + case DW_AT_proc_body: + case DW_AT_save_offset: + case DW_AT_user_2002: + case DW_AT_virtuality: + case DW_AT_containing_type: + case DW_AT_accessibility: + // todo; + break; + case DW_AT_vtable_elem_location: + free(attr->block); + break; + default: + fprintf(stderr, "Unknown function attribute %02x\n", attr->name); + break; + } + } + + return; +} + +u8 *elfParseFunction(u8 *data, ELFAbbrev *abbrev, CompileUnit *unit, + Function **f) +{ + Function *func = (Function *)calloc(sizeof(Function), 1); + *f = func; + + int bytes; + bool mangled = false; + bool declaration = false; + for(int i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + switch(attr->name) { + case DW_AT_sibling: + break; + case DW_AT_name: + if(func->name == NULL) + func->name = attr->string; + break; + case DW_AT_MIPS_linkage_name: + func->name = attr->string; + mangled = true; + break; + case DW_AT_low_pc: + func->lowPC = attr->value; + break; + case DW_AT_high_pc: + func->highPC = attr->value; + break; + case DW_AT_prototyped: + break; + case DW_AT_decl_file: + func->file = attr->value; + break; + case DW_AT_decl_line: + func->line = attr->value; + break; + case DW_AT_external: + func->external = attr->flag; + break; + case DW_AT_frame_base: + func->frameBase = attr->block; + break; + case DW_AT_type: + func->returnType = elfParseType(unit, attr->value); + break; + case DW_AT_abstract_origin: + elfGetFunctionAttributes(unit, attr->value, func); + break; + case DW_AT_declaration: + declaration = attr->flag; + break; + case DW_AT_inline: + case DW_AT_specification: + case DW_AT_artificial: + case DW_AT_proc_body: + case DW_AT_save_offset: + case DW_AT_user_2002: + case DW_AT_virtuality: + case DW_AT_containing_type: + case DW_AT_accessibility: + // todo; + break; + case DW_AT_vtable_elem_location: + free(attr->block); + break; + default: + fprintf(stderr, "Unknown function attribute %02x\n", attr->name); + break; + } + } + + if(declaration) { + elfCleanUp(func); + free(func); + *f = NULL; + + while(1) { + u32 abbrevNum = elfReadLEB128(data, &bytes); + data += bytes; + + if(!abbrevNum) { + return data; + } + + abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); + + data = elfSkipData(data, abbrev, unit->abbrevs); + } + } + + if(abbrev->hasChildren) { + int nesting = 1; + Object *lastParam = NULL; + Object *lastVar = NULL; + + while(nesting) { + u32 abbrevNum = elfReadLEB128(data, &bytes); + data += bytes; + + if(!abbrevNum) { + nesting--; + continue; + } + + abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); + + switch(abbrev->tag) { + CASE_TYPE_TAG: // no need to parse types. only parsed when used + case DW_TAG_label: // not needed + data = elfSkipData(data, abbrev, unit->abbrevs); + break; + case DW_TAG_subprogram: + { + Function *fnc=NULL; + data = elfParseFunction(data, abbrev, unit, &fnc); + if(fnc != NULL) { + if(unit->lastFunction == NULL) + unit->functions = fnc; + else + unit->lastFunction->next = fnc; + unit->lastFunction = fnc; + } + } + break; + case DW_TAG_lexical_block: + { + data = elfParseBlock(data, abbrev, unit, func, &lastVar); + } + break; + case DW_TAG_formal_parameter: + { + Object *o; + data = elfParseObject(data, abbrev, unit, &o); + if(func->parameters) + lastParam->next = o; + else + func->parameters = o; + lastParam = o; + } + break; + case DW_TAG_variable: + { + Object *o; + data = elfParseObject(data, abbrev, unit, &o); + if(func->variables) + lastVar->next = o; + else + func->variables = o; + lastVar = o; + } + break; + case DW_TAG_unspecified_parameters: + case DW_TAG_inlined_subroutine: + { + // todo + for(int i = 0; i < abbrev->numAttrs; i++) { + data = elfReadAttribute(data, &abbrev->attrs[i]); + if(abbrev->attrs[i].form == DW_FORM_block1) + free(abbrev->attrs[i].block); + } + + if(abbrev->hasChildren) + nesting++; + } + break; + default: + { + fprintf(stderr, "Unknown function TAG %02x\n", abbrev->tag); + data = elfSkipData(data, abbrev, unit->abbrevs); + } + break; + } + } + } + return data; +} + +u8 *elfParseUnknownData(u8 *data, ELFAbbrev *abbrev, ELFAbbrev **abbrevs) +{ + int i; + int bytes; + // switch(abbrev->tag) { + // default: + fprintf(stderr, "Unknown TAG %02x\n", abbrev->tag); + + for(i = 0; i < abbrev->numAttrs; i++) { + data = elfReadAttribute(data, &abbrev->attrs[i]); + if(abbrev->attrs[i].form == DW_FORM_block1) + free(abbrev->attrs[i].block); + } + + if(abbrev->hasChildren) { + int nesting = 1; + while(nesting) { + u32 abbrevNum = elfReadLEB128(data, &bytes); + data += bytes; + + if(!abbrevNum) { + nesting--; + continue; + } + + abbrev = elfGetAbbrev(abbrevs, abbrevNum); + + fprintf(stderr, "Unknown TAG %02x\n", abbrev->tag); + + for(i = 0; i < abbrev->numAttrs; i++) { + data = elfReadAttribute(data, &abbrev->attrs[i]); + if(abbrev->attrs[i].form == DW_FORM_block1) + free(abbrev->attrs[i].block); + } + + if(abbrev->hasChildren) { + nesting++; + } + } + } + // } + return data; +} + +u8 *elfParseCompileUnitChildren(u8 *data, CompileUnit *unit) +{ + int bytes; + u32 abbrevNum = elfReadLEB128(data, &bytes); + data += bytes; + Object *lastObj = NULL; + while(abbrevNum) { + ELFAbbrev *abbrev = elfGetAbbrev(unit->abbrevs, abbrevNum); + switch(abbrev->tag) { + case DW_TAG_subprogram: + { + Function *func = NULL; + data = elfParseFunction(data, abbrev, unit, &func); + if(func != NULL) { + if(unit->lastFunction) + unit->lastFunction->next = func; + else + unit->functions = func; + unit->lastFunction = func; + } + } + break; + CASE_TYPE_TAG: + data = elfSkipData(data, abbrev, unit->abbrevs); + break; + case DW_TAG_variable: + { + Object *var = NULL; + data = elfParseObject(data, abbrev, unit, &var); + if(lastObj) + lastObj->next = var; + else + unit->variables = var; + lastObj = var; + } + break; + default: + data = elfParseUnknownData(data, abbrev, unit->abbrevs); + break; + } + + abbrevNum = elfReadLEB128(data, &bytes); + data += bytes; + } + return data; +} + + +CompileUnit *elfParseCompUnit(u8 *data, u8 *abbrevData) +{ + int bytes; + u8 *top = data; + + u32 length = elfRead4Bytes(data); + data += 4; + + u16 version = elfRead2Bytes(data); + data += 2; + + u32 offset = elfRead4Bytes(data); + data += 4; + + u8 addrSize = *data++; + + if(version != 2) { + fprintf(stderr, "Unsupported debugging information version %d\n", version); + return NULL; + } + + if(addrSize != 4) { + fprintf(stderr, "Unsupported address size %d\n", addrSize); + return NULL; + } + + ELFAbbrev **abbrevs = elfReadAbbrevs(abbrevData, offset); + + u32 abbrevNum = elfReadLEB128(data, &bytes); + data += bytes; + + ELFAbbrev *abbrev = elfGetAbbrev(abbrevs, abbrevNum); + + CompileUnit *unit = (CompileUnit *)calloc(sizeof(CompileUnit), 1); + unit->top = top; + unit->length = length; + unit->abbrevs = abbrevs; + unit->next = NULL; + + elfCurrentUnit = unit; + + int i; + + for(i = 0; i < abbrev->numAttrs; i++) { + ELFAttr *attr = &abbrev->attrs[i]; + data = elfReadAttribute(data, attr); + + switch(attr->name) { + case DW_AT_name: + unit->name = attr->string; + break; + case DW_AT_stmt_list: + unit->hasLineInfo = true; + unit->lineInfo = attr->value; + break; + case DW_AT_low_pc: + unit->lowPC = attr->value; + break; + case DW_AT_high_pc: + unit->highPC = attr->value; + break; + case DW_AT_compdir: + unit->compdir = attr->string; + break; + // ignore + case DW_AT_language: + case DW_AT_producer: + case DW_AT_macro_info: + case DW_AT_entry_pc: + break; + default: + fprintf(stderr, "Unknown attribute %02x\n", attr->name); + break; + } + } + + if(abbrev->hasChildren) + elfParseCompileUnitChildren(data, unit); + + return unit; +} + +void elfParseAranges(u8 *data) +{ + ELFSectionHeader *sh = elfGetSectionByName(".debug_aranges"); + if(sh == NULL) { + fprintf(stderr, "No aranges found\n"); + return; + } + + data = elfReadSection(data, sh); + u8 *end = data + READ32LE(&sh->size); + + int max = 4; + ARanges *ranges = (ARanges *)calloc(sizeof(ARanges), 4); + + int index = 0; + + while(data < end) { + u32 len = elfRead4Bytes(data); + data += 4; + // u16 version = elfRead2Bytes(data); + data += 2; + u32 offset = elfRead4Bytes(data); + data += 4; + // u8 addrSize = *data++; + // u8 segSize = *data++; + data += 2; // remove if uncommenting above + data += 4; + ranges[index].count = (len-20)/8; + ranges[index].offset = offset; + ranges[index].ranges = (ARange *)calloc(sizeof(ARange), (len-20)/8); + int i = 0; + while(true) { + u32 addr = elfRead4Bytes(data); + data += 4; + u32 len = elfRead4Bytes(data); + data += 4; + if(addr == 0 && len == 0) + break; + ranges[index].ranges[i].lowPC = addr; + ranges[index].ranges[i].highPC = addr+len; + i++; + } + index++; + if(index == max) { + max += 4; + ranges = (ARanges *)realloc(ranges, max*sizeof(ARanges)); + } + } + elfDebugInfo->numRanges = index; + elfDebugInfo->ranges = ranges; +} + +void elfReadSymtab(u8 *data) +{ + ELFSectionHeader *sh = elfGetSectionByName(".symtab"); + int table = READ32LE(&sh->link); + + char *strtable = (char *)elfReadSection(data, elfGetSectionByNumber(table)); + + ELFSymbol *symtab = (ELFSymbol *)elfReadSection(data, sh); + + int count = READ32LE(&sh->size) / sizeof(ELFSymbol); + elfSymbolsCount = 0; + + elfSymbols = (Symbol *)malloc(sizeof(Symbol)*count); + + int i; + + for(i = 0; i < count; i++) { + ELFSymbol *s = &symtab[i]; + int type = s->info & 15; + int binding = s->info >> 4; + + if(binding) { + Symbol *sym = &elfSymbols[elfSymbolsCount]; + sym->name = &strtable[READ32LE(&s->name)]; + sym->binding = binding; + sym->type = type; + sym->value = READ32LE(&s->value); + sym->size = READ32LE(&s->size); + elfSymbolsCount++; + } + } + for(i = 0; i < count; i++) { + ELFSymbol *s = &symtab[i]; + int bind = s->info>>4; + int type = s->info & 15; + + if(!bind) { + Symbol *sym = &elfSymbols[elfSymbolsCount]; + sym->name = &strtable[READ32LE(&s->name)]; + sym->binding = (s->info >> 4); + sym->type = type; + sym->value = READ32LE(&s->value); + sym->size = READ32LE(&s->size); + elfSymbolsCount++; + } + } + elfSymbolsStrTab = strtable; + // free(symtab); +} + +bool elfReadProgram(ELFHeader *eh, u8 *data, int& size, bool parseDebug) +{ + int count = READ16LE(&eh->e_phnum); + int i; + + if(READ32LE(&eh->e_entry) == 0x2000000) + cpuIsMultiBoot = true; + + // read program headers... should probably move this code down + u8 *p = data + READ32LE(&eh->e_phoff); + size = 0; + for(i = 0; i < count; i++) { + ELFProgramHeader *ph = (ELFProgramHeader *)p; + p += sizeof(ELFProgramHeader); + if(READ16LE(&eh->e_phentsize) != sizeof(ELFProgramHeader)) { + p += READ16LE(&eh->e_phentsize) - sizeof(ELFProgramHeader); + } + + // printf("PH %d %08x %08x %08x %08x %08x %08x %08x %08x\n", + // i, ph->type, ph->offset, ph->vaddr, ph->paddr, + // ph->filesz, ph->memsz, ph->flags, ph->align); + if(cpuIsMultiBoot) { + if(READ32LE(&ph->paddr) >= 0x2000000 && + READ32LE(&ph->paddr) <= 0x203ffff) { + memcpy(&workRAM[READ32LE(&ph->paddr) & 0x3ffff], + data + READ32LE(&ph->offset), + READ32LE(&ph->filesz)); + size += READ32LE(&ph->filesz); + } + } else { + if(READ32LE(&ph->paddr) >= 0x8000000 && + READ32LE(&ph->paddr) <= 0x9ffffff) { + memcpy(&rom[READ32LE(&ph->paddr) & 0x1ffffff], + data + READ32LE(&ph->offset), + READ32LE(&ph->filesz)); + size += READ32LE(&ph->filesz); + } + } + } + + char *stringTable = NULL; + + // read section headers + p = data + READ32LE(&eh->e_shoff); + count = READ16LE(&eh->e_shnum); + + ELFSectionHeader **sh = (ELFSectionHeader **) + malloc(sizeof(ELFSectionHeader *) * count); + + for(i = 0; i < count; i++) { + sh[i] = (ELFSectionHeader *)p; + p += sizeof(ELFSectionHeader); + if(READ16LE(&eh->e_shentsize) != sizeof(ELFSectionHeader)) + p += READ16LE(&eh->e_shentsize) - sizeof(ELFSectionHeader); + } + + if(READ16LE(&eh->e_shstrndx) != 0) { + stringTable = (char *)elfReadSection(data, + sh[READ16LE(&eh->e_shstrndx)]); + } + + elfSectionHeaders = sh; + elfSectionHeadersStringTable = stringTable; + elfSectionHeadersCount = count; + + for(i = 0; i < count; i++) { + // printf("SH %d %-20s %08x %08x %08x %08x %08x %08x %08x %08x\n", + // i, &stringTable[sh[i]->name], sh[i]->name, sh[i]->type, + // sh[i]->flags, sh[i]->addr, sh[i]->offset, sh[i]->size, + // sh[i]->link, sh[i]->info); + if(READ32LE(&sh[i]->flags) & 2) { // load section + if(cpuIsMultiBoot) { + if(READ32LE(&sh[i]->addr) >= 0x2000000 && + READ32LE(&sh[i]->addr) <= 0x203ffff) { + memcpy(&workRAM[READ32LE(&sh[i]->addr) & 0x3ffff], data + + READ32LE(&sh[i]->offset), + READ32LE(&sh[i]->size)); + size += READ32LE(&sh[i]->size); + } + } else { + if(READ32LE(&sh[i]->addr) >= 0x8000000 && + READ32LE(&sh[i]->addr) <= 0x9ffffff) { + memcpy(&rom[READ32LE(&sh[i]->addr) & 0x1ffffff], + data + READ32LE(&sh[i]->offset), + READ32LE(&sh[i]->size)); + size += READ32LE(&sh[i]->size); + } + } + } + } + + if(parseDebug) { + fprintf(stderr, "Parsing debug info\n"); + + ELFSectionHeader *dbgHeader = elfGetSectionByName(".debug_info"); + if(dbgHeader == NULL) { + fprintf(stderr, "Cannot find debug information\n"); + goto end; + } + + ELFSectionHeader *h = elfGetSectionByName(".debug_abbrev"); + if(h == NULL) { + fprintf(stderr, "Cannot find abbreviation table\n"); + goto end; + } + + elfDebugInfo = (DebugInfo *)calloc(sizeof(DebugInfo), 1); + u8 *abbrevdata = elfReadSection(data, h); + + h = elfGetSectionByName(".debug_str"); + + if(h == NULL) + elfDebugStrings = NULL; + else + elfDebugStrings = (char *)elfReadSection(data, h); + + u8 *debugdata = elfReadSection(data, dbgHeader); + + elfDebugInfo->debugdata = data; + elfDebugInfo->infodata = debugdata; + + u32 total = READ32LE(&dbgHeader->size); + u8 *end = debugdata + total; + u8 *ddata = debugdata; + + CompileUnit *last = NULL; + CompileUnit *unit = NULL; + + while(ddata < end) { + unit = elfParseCompUnit(ddata, abbrevdata); + unit->offset = (u32)(ddata-debugdata); + elfParseLineInfo(unit, data); + if(last == NULL) + elfCompileUnits = unit; + else + last->next = unit; + last = unit; + ddata += 4 + unit->length; + } + elfParseAranges(data); + CompileUnit *comp = elfCompileUnits; + while(comp) { + ARanges *r = elfDebugInfo->ranges; + for(int i = 0; i < elfDebugInfo->numRanges; i++) + if(r[i].offset == comp->offset) { + comp->ranges = &r[i]; + break; + } + comp = comp->next; + } + elfParseCFA(data); + elfReadSymtab(data); + } + end: + if(sh) { + free(sh); + } + + elfSectionHeaders = NULL; + elfSectionHeadersStringTable = NULL; + elfSectionHeadersCount = 0; + + return true; +} + +extern bool parseDebug; + +bool elfRead(const char *name, int& siz, FILE *f) +{ + fseek(f, 0, SEEK_END); + long size = ftell(f); + elfFileData = (u8 *)malloc(size); + fseek(f, 0, SEEK_SET); + fread(elfFileData, 1, size, f); + fclose(f); + + ELFHeader *header = (ELFHeader *)elfFileData; + + if(READ32LE(&header->magic) != 0x464C457F || + READ16LE(&header->e_machine) != 40 || + header->clazz != 1) { + systemMessage(0, N_("Not a valid ELF file %s"), name); + free(elfFileData); + elfFileData = NULL; + return false; + } + + if(!elfReadProgram(header, elfFileData, siz, parseDebug)) { + free(elfFileData); + elfFileData = NULL; + return false; + } + + return true; +} + +void elfCleanUp(Object *o) +{ + free(o->location); +} + +void elfCleanUp(Function *func) +{ + Object *o = func->parameters; + while(o) { + elfCleanUp(o); + Object *next = o->next; + free(o); + o = next; + } + + o = func->variables; + while(o) { + elfCleanUp(o); + Object *next = o->next; + free(o); + o = next; + } + free(func->frameBase); +} + +void elfCleanUp(ELFAbbrev **abbrevs) +{ + for(int i = 0; i < 121; i++) { + ELFAbbrev *abbrev = abbrevs[i]; + + while(abbrev) { + free(abbrev->attrs); + ELFAbbrev *next = abbrev->next; + free(abbrev); + + abbrev = next; + } + } +} + +void elfCleanUp(Type *t) +{ + switch(t->type) { + case TYPE_function: + if(t->function) { + Object *o = t->function->args; + while(o) { + elfCleanUp(o); + Object *next = o->next; + free(o); + o = next; + } + free(t->function); + } + break; + case TYPE_array: + if(t->array) { + free(t->array->bounds); + free(t->array); + } + break; + case TYPE_struct: + case TYPE_union: + if(t->structure) { + for(int i = 0; i < t->structure->memberCount; i++) { + free(t->structure->members[i].location); + } + free(t->structure->members); + free(t->structure); + } + break; + case TYPE_enum: + if(t->enumeration) { + free(t->enumeration->members); + free(t->enumeration); + } + break; + case TYPE_base: + case TYPE_pointer: + case TYPE_void: + case TYPE_reference: + break; // nothing to do + } +} + +void elfCleanUp(CompileUnit *comp) +{ + elfCleanUp(comp->abbrevs); + free(comp->abbrevs); + Function *func = comp->functions; + while(func) { + elfCleanUp(func); + Function *next = func->next; + free(func); + func = next; + } + Type *t = comp->types; + while(t) { + elfCleanUp(t); + Type *next = t->next; + free(t); + t = next; + } + Object *o = comp->variables; + while(o) { + elfCleanUp(o); + Object *next = o->next; + free(o); + o = next; + } + if(comp->lineInfoTable) { + free(comp->lineInfoTable->lines); + free(comp->lineInfoTable->files); + free(comp->lineInfoTable); + } +} + +void elfCleanUp() +{ + CompileUnit *comp = elfCompileUnits; + + while(comp) { + elfCleanUp(comp); + CompileUnit *next = comp->next; + free(comp); + comp = next; + } + elfCompileUnits = NULL; + free(elfSymbols); + elfSymbols = NULL; + // free(elfSymbolsStrTab); + elfSymbolsStrTab = NULL; + + elfDebugStrings = NULL; + if(elfDebugInfo) { + int num = elfDebugInfo->numRanges; + int i; + for(i = 0; i < num; i++) { + free(elfDebugInfo->ranges[i].ranges); + } + free(elfDebugInfo->ranges); + free(elfDebugInfo); + elfDebugInfo = NULL; + } + + if(elfFdes) { + if(elfFdeCount) { + for(int i = 0; i < elfFdeCount; i++) + free(elfFdes[i]); + } + free(elfFdes); + + elfFdes = NULL; + elfFdeCount = 0; + } + + ELFcie *cie = elfCies; + while(cie) { + ELFcie *next = cie->next; + free(cie); + cie = next; + } + elfCies = NULL; + + if(elfFileData) { + free(elfFileData); + elfFileData = NULL; + } +} diff --git a/source/vba/elf.h b/source/vba/elf.h index b2e070a..8f8898a 100644 --- a/source/vba/elf.h +++ b/source/vba/elf.h @@ -1,311 +1,283 @@ -// -*- 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_ELF_H -#define VBA_ELF_H -#include -#include -#include -#include -#include - -enum LocationType { - LOCATION_register, - LOCATION_memory, - LOCATION_value -}; - -#define DW_ATE_boolean 0x02 -#define DW_ATE_signed 0x05 -#define DW_ATE_unsigned 0x07 -#define DW_ATE_unsigned_char 0x08 - -struct ELFHeader - { - u32 magic; - u8 clazz; - u8 data; - u8 version; - u8 pad[9]; - u16 e_type; - u16 e_machine; - u32 e_version; - u32 e_entry; - u32 e_phoff; - u32 e_shoff; - u32 e_flags; - u16 e_ehsize; - u16 e_phentsize; - u16 e_phnum; - u16 e_shentsize; - u16 e_shnum; - u16 e_shstrndx; - }; - -struct ELFProgramHeader - { - u32 type; - u32 offset; - u32 vaddr; - u32 paddr; - u32 filesz; - u32 memsz; - u32 flags; - u32 align; - }; - -struct ELFSectionHeader - { - u32 name; - u32 type; - u32 flags; - u32 addr; - u32 offset; - u32 size; - u32 link; - u32 info; - u32 addralign; - u32 entsize; - }; - -struct ELFSymbol - { - u32 name; - u32 value; - u32 size; - u8 info; - u8 other; - u16 shndx; - }; - -struct ELFBlock - { - int length; - u8 *data; - }; - -struct ELFAttr - { - u32 name; - u32 form; - union { - u32 value; - char *string; - u8 *data; - bool flag; - ELFBlock *block; - }; - }; - -struct ELFAbbrev - { - u32 number; - u32 tag; - bool hasChildren; - int numAttrs; - ELFAttr *attrs; - ELFAbbrev *next; - }; - -enum TypeEnum { - TYPE_base, - TYPE_pointer, - TYPE_function, - TYPE_void, - TYPE_array, - TYPE_struct, - TYPE_reference, - TYPE_enum, - TYPE_union -}; - -struct Type; -struct Object; - -struct FunctionType - { - Type *returnType; - Object *args; - }; - -struct Member - { - char *name; - Type *type; - int bitSize; - int bitOffset; - int byteSize; - ELFBlock *location; - }; - -struct Struct - { - int memberCount; - Member *members; - }; - -struct Array - { - Type *type; - int maxBounds; - int *bounds; - }; - -struct EnumMember - { - char *name; - u32 value; - }; - -struct Enum - { - int count; - EnumMember *members; - }; - -struct Type - { - u32 offset; - TypeEnum type; - char *name; - int encoding; - int size; - int bitSize; - union { - Type *pointer; - FunctionType *function; - Array *array; - Struct *structure; - Enum *enumeration; - }; - Type *next; - }; - -struct Object - { - char *name; - int file; - int line; - bool external; - Type *type; - ELFBlock *location; - u32 startScope; - u32 endScope; - Object *next; - }; - -struct Function - { - char *name; - u32 lowPC; - u32 highPC; - int file; - int line; - bool external; - Type *returnType; - Object *parameters; - Object *variables; - ELFBlock *frameBase; - Function *next; - }; - -struct LineInfoItem - { - u32 address; - char *file; - int line; - }; - -struct LineInfo - { - int fileCount; - char **files; - int number; - LineInfoItem *lines; - }; - -struct ARange - { - u32 lowPC; - u32 highPC; - }; - -struct ARanges - { - u32 offset; - int count; - ARange *ranges; - }; - -struct CompileUnit - { - u32 length; - u8 *top; - u32 offset; - ELFAbbrev **abbrevs; - ARanges *ranges; - char *name; - char *compdir; - u32 lowPC; - u32 highPC; - bool hasLineInfo; - u32 lineInfo; - LineInfo *lineInfoTable; - Function *functions; - Function *lastFunction; - Object *variables; - Type *types; - CompileUnit *next; - }; - -struct DebugInfo - { - u8 *debugfile; - u8 *abbrevdata; - u8 *debugdata; - u8 *infodata; - int numRanges; - ARanges *ranges; - }; - -struct Symbol - { - char *name; - int type; - int binding; - u32 address; - u32 value; - u32 size; - }; - -extern u32 elfReadLEB128(u8 *, int *); -extern s32 elfReadSignedLEB128(u8 *, int *); -extern bool elfRead(const char *, int &, FILE* f); -extern bool elfGetSymbolAddress(char *,u32 *, u32 *, int *); -extern char *elfGetAddressSymbol(u32); -extern char *elfGetSymbol(int, u32 *, u32 *, int *); -extern void elfCleanUp(); -extern bool elfGetCurrentFunction(u32, Function **, CompileUnit **c); -extern bool elfGetObject(char *, Function *, CompileUnit *, Object **); -extern bool elfFindLineInUnit(u32 *, CompileUnit *, int); -extern bool elfFindLineInModule(u32 *, char *, int); -u32 elfDecodeLocation(Function *, ELFBlock *, LocationType *); -u32 elfDecodeLocation(Function *, ELFBlock *, LocationType *, u32); -int elfFindLine(CompileUnit *unit, Function *func, u32 addr, char **); -#endif +// -*- 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_ELF_H +#define VBA_ELF_H + +enum LocationType { + LOCATION_register, + LOCATION_memory, + LOCATION_value +}; + +#define DW_ATE_boolean 0x02 +#define DW_ATE_signed 0x05 +#define DW_ATE_unsigned 0x07 +#define DW_ATE_unsigned_char 0x08 + +struct ELFHeader { + u32 magic; + u8 clazz; + u8 data; + u8 version; + u8 pad[9]; + u16 e_type; + u16 e_machine; + u32 e_version; + u32 e_entry; + u32 e_phoff; + u32 e_shoff; + u32 e_flags; + u16 e_ehsize; + u16 e_phentsize; + u16 e_phnum; + u16 e_shentsize; + u16 e_shnum; + u16 e_shstrndx; +}; + +struct ELFProgramHeader { + u32 type; + u32 offset; + u32 vaddr; + u32 paddr; + u32 filesz; + u32 memsz; + u32 flags; + u32 align; +}; + +struct ELFSectionHeader { + u32 name; + u32 type; + u32 flags; + u32 addr; + u32 offset; + u32 size; + u32 link; + u32 info; + u32 addralign; + u32 entsize; +}; + +struct ELFSymbol { + u32 name; + u32 value; + u32 size; + u8 info; + u8 other; + u16 shndx; +}; + +struct ELFBlock { + int length; + u8 *data; +}; + +struct ELFAttr { + u32 name; + u32 form; + union { + u32 value; + char *string; + u8 *data; + bool flag; + ELFBlock *block; + }; +}; + +struct ELFAbbrev { + u32 number; + u32 tag; + bool hasChildren; + int numAttrs; + ELFAttr *attrs; + ELFAbbrev *next; +}; + +enum TypeEnum { + TYPE_base, + TYPE_pointer, + TYPE_function, + TYPE_void, + TYPE_array, + TYPE_struct, + TYPE_reference, + TYPE_enum, + TYPE_union +}; + +struct Type; +struct Object; + +struct FunctionType { + Type *returnType; + Object *args; +}; + +struct Member { + char *name; + Type *type; + int bitSize; + int bitOffset; + int byteSize; + ELFBlock *location; +}; + +struct Struct { + int memberCount; + Member *members; +}; + +struct Array { + Type *type; + int maxBounds; + int *bounds; +}; + +struct EnumMember { + char *name; + u32 value; +}; + +struct Enum { + int count; + EnumMember *members; +}; + +struct Type { + u32 offset; + TypeEnum type; + const char *name; + int encoding; + int size; + int bitSize; + union { + Type *pointer; + FunctionType *function; + Array *array; + Struct *structure; + Enum *enumeration; + }; + Type *next; +}; + +struct Object { + char *name; + int file; + int line; + bool external; + Type *type; + ELFBlock *location; + u32 startScope; + u32 endScope; + Object *next; +}; + +struct Function { + char *name; + u32 lowPC; + u32 highPC; + int file; + int line; + bool external; + Type *returnType; + Object *parameters; + Object *variables; + ELFBlock *frameBase; + Function *next; +}; + +struct LineInfoItem { + u32 address; + char *file; + int line; +}; + +struct LineInfo { + int fileCount; + char **files; + int number; + LineInfoItem *lines; +}; + +struct ARange { + u32 lowPC; + u32 highPC; +}; + +struct ARanges { + u32 offset; + int count; + ARange *ranges; +}; + +struct CompileUnit { + u32 length; + u8 *top; + u32 offset; + ELFAbbrev **abbrevs; + ARanges *ranges; + char *name; + char *compdir; + u32 lowPC; + u32 highPC; + bool hasLineInfo; + u32 lineInfo; + LineInfo *lineInfoTable; + Function *functions; + Function *lastFunction; + Object *variables; + Type *types; + CompileUnit *next; +}; + +struct DebugInfo { + u8 *debugfile; + u8 *abbrevdata; + u8 *debugdata; + u8 *infodata; + int numRanges; + ARanges *ranges; +}; + +struct Symbol { + const char *name; + int type; + int binding; + u32 address; + u32 value; + u32 size; +}; + +extern u32 elfReadLEB128(u8 *, int *); +extern s32 elfReadSignedLEB128(u8 *, int *); +extern bool elfRead(const char *, int &, FILE *f); +extern bool elfGetSymbolAddress(const char *,u32 *, u32 *, int *); +extern const char *elfGetAddressSymbol(u32); +extern const char *elfGetSymbol(int, u32 *, u32 *, int *); +extern void elfCleanUp(); +extern bool elfGetCurrentFunction(u32, Function **, CompileUnit **c); +extern bool elfGetObject(const char *, Function *, CompileUnit *, Object **); +extern bool elfFindLineInUnit(u32 *, CompileUnit *, int); +extern bool elfFindLineInModule(u32 *, const char *, int); +u32 elfDecodeLocation(Function *, ELFBlock *, LocationType *); +u32 elfDecodeLocation(Function *, ELFBlock *, LocationType *, u32); +int elfFindLine(CompileUnit *unit, Function *func, u32 addr, const char **); +#endif diff --git a/source/vba/exprNode.h b/source/vba/exprNode.h deleted file mode 100644 index f32614d..0000000 --- a/source/vba/exprNode.h +++ /dev/null @@ -1,69 +0,0 @@ -// -*- 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. - -struct Node - { - Type *type; - u32 location; - u32 objLocation; - LocationType locType; - int value; - int index; - char *name; - Node *expression; - Member *member; - void (*print)(Node *); - bool (*resolve)(Node *, Function *f, CompileUnit *u); - }; - -extern void exprNodeCleanUp(); - -extern Node *exprNodeIdentifier(); -extern void exprNodeIdentifierPrint(Node *); -extern bool exprNodeIdentifierResolve(Node *, Function *, CompileUnit *); - -extern Node *exprNodeNumber(); -extern void exprNodeNumberPrint(Node *); -extern bool exprNodeNumberResolve(Node *, Function *, CompileUnit *); - -extern Node *exprNodeStar(Node *); -extern void exprNodeStarPrint(Node *); -extern bool exprNodeStarResolve(Node *, Function *, CompileUnit *); - -extern Node *exprNodeDot(Node *, Node *); -extern void exprNodeDotPrint(Node *); -extern bool exprNodeDotResolve(Node *, Function *, CompileUnit *); - -extern Node *exprNodeArrow(Node *, Node *); -extern void exprNodeArrowPrint(Node *); -extern bool exprNodeArrowResolve(Node *, Function *, CompileUnit *); - -extern Node *exprNodeAddr(Node *); -extern void exprNodeAddrPrint(Node *); -extern bool exprNodeAddrResolve(Node *, Function *, CompileUnit *); - -extern Node *exprNodeSizeof(Node *); -extern void exprNodeSizeofPrint(Node *); -extern bool exprNodeSizeofResolve(Node *, Function *, CompileUnit *); - -extern Node *exprNodeArray(Node *, Node *); -extern void exprNodeArrayPrint(Node *); -extern bool exprNodeArrayResolve(Node *, Function *, CompileUnit *); - -#define YYSTYPE struct Node * diff --git a/source/vba/getopt.c b/source/vba/getopt.c deleted file mode 100644 index 6da738c..0000000 --- a/source/vba/getopt.c +++ /dev/null @@ -1,1061 +0,0 @@ -/* Getopt for GNU. - NOTE: getopt is now part of the C library, so if you don't know what - "Keep this file name-space clean" means, talk to drepper@gnu.org - before changing it! - - Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98 - Free Software Foundation, Inc. - - NOTE: This source is derived from an old version taken from the GNU C - Library (glibc). - - 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. */ - -/* This tells Alpha OSF/1 not to define a getopt prototype in . - Ditto for AIX 3.2 and . */ -#ifndef _NO_PROTO -# define _NO_PROTO -#endif - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if !defined __STDC__ || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -# ifndef const -# define const -# endif -#endif - -#include -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 -# include -# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -# define ELIDE_CODE -# endif -#endif - -#ifndef ELIDE_CODE - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -/* Don't include stdlib.h for non-GNU C libraries because some of them - contain conflicting prototypes for getopt. */ -# include -# include -#endif /* GNU C library. */ - -#ifdef VMS -# include -# if HAVE_STRING_H - 0 -# include -# endif -#endif - -#ifndef _ -/* This is for other GNU distributions with internationalized messages. - When compiling libc, the _ macro is predefined. */ -# ifdef HAVE_LIBINTL_H -# include -# define _(msgid) gettext (msgid) -# else -# define _(msgid) (msgid) -# endif -#endif - -#ifdef _MSC_VER -#include -#endif - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. - - Setting the environment variable POSIXLY_CORRECT disables permutation. - Then the behavior is completely standard. - - GNU application programs can use a third alternative mode in which - they can distinguish the relative order of options and other arguments. */ - -#include "getopt.h" - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -char *optarg = NULL; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -/* 1003.2 says this must be 1 before any call. */ -int optind = 1; - -/* Formerly, initialization of getopt depended on optind==0, which - causes problems with re-calling getopt as programs generally don't - know that. */ - -int __getopt_initialized = 0; - -/* The next char to be scanned in the option-element - in which the last option character we returned was found. - This allows us to pick up the scan where we left off. - - If this is zero, or a null string, it means resume the scan - by advancing to the next ARGV-element. */ - -static char *nextchar; - -/* Callers store zero here to inhibit the error message - for unrecognized options. */ - -int opterr = 1; - -/* Set to an option character which was unrecognized. - This must be initialized on some systems to avoid linking in the - system's own getopt implementation. */ - -int optopt = '?'; - -/* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, - the default is REQUIRE_ORDER if the environment variable - POSIXLY_CORRECT is defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; - stop option processing when the first non-option is seen. - This is what Unix does. - This mode of operation is selected by either setting the environment - variable POSIXLY_CORRECT, or using `+' as the first character - of the list of option characters. - - PERMUTE is the default. We permute the contents of ARGV as we scan, - so that eventually all the non-options are at the end. This allows options - to be given in any order, even with programs that were not written to - expect this. - - RETURN_IN_ORDER is an option available to programs that were written - to expect options and other ARGV-elements in any order and that care about - the ordering of the two. We describe each non-option ARGV-element - as if it were the argument of an option with character code 1. - Using `-' as the first character of the list of option characters - selects this mode of operation. - - The special argument `--' forces an end of option-scanning regardless - of the value of `ordering'. In the case of RETURN_IN_ORDER, only - `--' can cause `getopt' to return -1 with `optind' != ARGC. */ - -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; - -/* Value of POSIXLY_CORRECT environment variable. */ -static char *posixly_correct; - -#ifdef __GNU_LIBRARY__ -/* We want to avoid inclusion of string.h with non-GNU libraries - because there are many ways it can cause trouble. - On some systems, it contains special magic macros that don't work - in GCC. */ -# include -# define my_index strchr -#else - -# if HAVE_STRING_H -# include -# else -# if HAVE_STRINGS_H -# include -# endif -# endif - -/* Avoid depending on library functions or files -whose names are inconsistent. */ - -#ifndef getenv -extern char *getenv (); -#endif - -static char * -my_index (str, chr) -const char *str; -int chr; -{ - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } - return 0; -} - -/* If using GCC, we can safely declare strlen this way. -If not using GCC, it is ok not to declare it. */ -#ifdef __GNUC__ -/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. -That was relevant to code that was here before. */ -# if (!defined __STDC__ || !__STDC__) && !defined strlen -/* gcc with -traditional declares the built-in strlen to return int, -and has done so at least since version 2.4.5. -- rms. */ -extern int strlen (const char *); -# endif /* not __STDC__ */ -#endif /* __GNUC__ */ - -#endif /* not __GNU_LIBRARY__ */ - -/* Handle permutation of arguments. */ - -/* Describe the part of ARGV that contains non-options that have - been skipped. `first_nonopt' is the index in ARGV of the first of them; - `last_nonopt' is the index after the last of them. */ - -static int first_nonopt; -static int last_nonopt; - -#ifdef _LIBC -/* Bash 2.0 gives us an environment variable containing flags - indicating ARGV elements that should not be considered arguments. */ - -/* Defined in getopt_init.c */ -extern char *__getopt_nonoption_flags; - -static int nonoption_flags_max_len; -static int nonoption_flags_len; - -static int original_argc; -static char *const *original_argv; - -/* Make sure the environment variable bash 2.0 puts in the environment - is valid for the getopt call we must make sure that the ARGV passed - to getopt is that one passed to the process. */ -static void -__attribute__ ((unused)) -store_args_and_env (int argc, char *const *argv) -{ - /* XXX This is no good solution. We should rather copy the args so - that we can compare them later. But we must not use malloc(3). */ - original_argc = argc; - original_argv = argv; -} -# ifdef text_set_element -text_set_element (__libc_subinit, store_args_and_env); -# endif /* text_set_element */ - -# define SWAP_FLAGS(ch1, ch2) \ - if (nonoption_flags_len > 0) \ - { \ - char __tmp = __getopt_nonoption_flags[ch1]; \ - __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ - __getopt_nonoption_flags[ch2] = __tmp; \ - } -#else /* !_LIBC */ -# define SWAP_FLAGS(ch1, ch2) -#endif /* _LIBC */ - -/* Exchange two adjacent subsequences of ARGV. - One subsequence is elements [first_nonopt,last_nonopt) - which contains all the non-options that have been skipped so far. - The other is elements [last_nonopt,optind), which contains all - the options processed since those non-options were skipped. - - `first_nonopt' and `last_nonopt' are relocated so that they describe - the new indices of the non-options in ARGV after they are moved. */ - -#if defined __STDC__ && __STDC__ -static void exchange (char **); -#endif - -static void -exchange (argv) -char **argv; -{ - int bottom = first_nonopt; - int middle = last_nonopt; - int top = optind; - char *tem; - - /* Exchange the shorter segment with the far end of the longer segment. - That puts the shorter segment into the right place. - It leaves the longer segment in the right place overall, - but it consists of two parts that need to be swapped next. */ - -#ifdef _LIBC - /* First make sure the handling of the `__getopt_nonoption_flags' - string can work normally. Our top argument must be in the range - of the string. */ - if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) - { - /* We must extend the array. The user plays games with us and - presents new arguments. */ - char *new_str = malloc (top + 1); - if (new_str == NULL) - nonoption_flags_len = nonoption_flags_max_len = 0; - else - { - memset (__mempcpy (new_str, __getopt_nonoption_flags, - nonoption_flags_max_len), - '\0', top + 1 - nonoption_flags_max_len); - nonoption_flags_max_len = top + 1; - __getopt_nonoption_flags = new_str; - } - } -#endif - - while (top > middle && middle > bottom) - { - if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } - else - { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - SWAP_FLAGS (bottom + i, middle + i); - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } - } - - /* Update records for the slots the non-options now occupy. */ - - first_nonopt += (optind - last_nonopt); - last_nonopt = optind; -} - -/* Initialize the internal data when the first call is made. */ - -#if defined __STDC__ && __STDC__ -static const char *_getopt_initialize (int, char *const *, const char *); -#endif -static const char * -_getopt_initialize (argc, argv, optstring) -int argc; -char *const *argv; -const char *optstring; -{ - /* Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ - - first_nonopt = last_nonopt = optind; - - nextchar = NULL; - - posixly_correct = getenv ("POSIXLY_CORRECT"); - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (posixly_correct != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; - -#ifdef _LIBC - if (posixly_correct == NULL - && argc == original_argc && argv == original_argv) - { - if (nonoption_flags_max_len == 0) - { - if (__getopt_nonoption_flags == NULL - || __getopt_nonoption_flags[0] == '\0') - nonoption_flags_max_len = -1; - else - { - const char *orig_str = __getopt_nonoption_flags; - int len = nonoption_flags_max_len = strlen (orig_str); - if (nonoption_flags_max_len < argc) - nonoption_flags_max_len = argc; - __getopt_nonoption_flags = - (char *) malloc (nonoption_flags_max_len); - if (__getopt_nonoption_flags == NULL) - nonoption_flags_max_len = -1; - else - memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), - '\0', nonoption_flags_max_len - len); - } - } - nonoption_flags_len = nonoption_flags_max_len; - } - else - nonoption_flags_len = 0; -#endif - - return optstring; -} - -/* Scan elements of ARGV (whose length is ARGC) for option characters - given in OPTSTRING. - - If an element of ARGV starts with '-', and is not exactly "-" or "--", - then it is an option element. The characters of this element - (aside from the initial '-') are option characters. If `getopt' - is called repeatedly, it returns successively each of the option characters - from each of the option elements. - - If `getopt' finds another option character, it returns that character, - updating `optind' and `nextchar' so that the next call to `getopt' can - resume the scan with the following option character or ARGV-element. - - If there are no more option characters, `getopt' returns -1. - Then `optind' is the index in ARGV of the first ARGV-element - that is not an option. (The ARGV-elements have been permuted - so that those that are not options now come last.) - - OPTSTRING is a string containing the legitimate option characters. - If an option character is seen that is not listed in OPTSTRING, - return '?' after printing an error message. If you set `opterr' to - zero, the error message is suppressed but we still return '?'. - - If a char in OPTSTRING is followed by a colon, that means it wants an arg, - so the following text in the same ARGV-element, or the text of the following - ARGV-element, is returned in `optarg'. Two colons mean an option that - wants an optional arg; if there is text in the current ARGV-element, - it is returned in `optarg', otherwise `optarg' is set to zero. - - If OPTSTRING starts with `-' or `+', it requests different methods of - handling the non-option ARGV-elements. - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - - Long-named options begin with `--' instead of `-'. - Their names may be abbreviated as long as the abbreviation is unique - or is an exact match for some defined option. If they have an - argument, it follows the option name in the same ARGV-element, separated - from the option name by a `=', or else the in next ARGV-element. - When `getopt' finds a long-named option, it returns 0 if that option's - `flag' field is nonzero, the value of the option's `val' field - if the `flag' field is zero. - - The elements of ARGV aren't really const, because we permute them. - But we pretend they're const in the prototype to be compatible - with other systems. - - LONGOPTS is a vector of `struct option' terminated by an - element containing a name which is zero. - - LONGIND returns the index in LONGOPT of the long-named option found. - It is only valid when a long-named option has been found by the most - recent call. - - If LONG_ONLY is nonzero, '-' as well as '--' can introduce - long-named options. */ - -int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) -int argc; -char *const *argv; -const char *optstring; -const struct option *longopts; -int *longind; -int long_only; -{ - optarg = NULL; - - if (optind == 0 || !__getopt_initialized) - { - if (optind == 0) - optind = 1; /* Don't scan ARGV[0], the program name. */ - optstring = _getopt_initialize (argc, argv, optstring); - __getopt_initialized = 1; - } - - /* Test whether ARGV[optind] points to a non-option argument. - Either it does not have option syntax, or there is an environment flag - from the shell indicating it is not an option. The later information - is only used when the used in the GNU libc. */ -#ifdef _LIBC -# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ - || (optind < nonoption_flags_len \ - && __getopt_nonoption_flags[optind] == '1')) -#else -# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') -#endif - - if (nextchar == NULL || *nextchar == '\0') - { - /* Advance to the next ARGV-element. */ - - /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been - moved back by the user (who may also have changed the arguments). */ - if (last_nonopt > optind) - last_nonopt = optind; - if (first_nonopt > optind) - first_nonopt = optind; - - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; - - /* Skip any additional non-options - and extend the range of non-options previously skipped. */ - - while (optind < argc && NONOPTION_P) - optind++; - last_nonopt = optind; - } - - /* The special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ - - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; - - optind = argc; - } - - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ - - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return -1; - } - - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ - - if (NONOPTION_P) - { - if (ordering == REQUIRE_ORDER) - return -1; - optarg = argv[optind++]; - return 1; - } - - /* We have found another option-ARGV-element. - Skip the initial punctuation. */ - - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); - } - - /* Decode the current option-ARGV-element. */ - - /* Check whether the ARGV-element is a long option. - - If long_only and the ARGV-element has the form "-f", where f is - a valid short option, don't consider it an abbreviated form of - a long option that starts with f. Otherwise there would be no - way to give the -f short option. - - On the other hand, if there's a long option "fubar" and - the ARGV-element is "-fu", do consider that an abbreviation of - the long option, just like "--fu", and not "-f" with arg "u". - - This distinction seems to be the most useful approach. */ - - if (longopts != NULL - && (argv[optind][1] == '-' - || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = -1; - int option_index; - - for (nameend = nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) - == (unsigned int) strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - optopt = 0; - return '?'; - } - - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (opterr) - { - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - _("%s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - _("%s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[optind - 1][0], pfound->name); - - nextchar += strlen (nextchar); - - optopt = pfound->val; - return '?'; - } - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' - || my_index (optstring, *nextchar) == NULL) - { - if (opterr) - { - if (argv[optind][1] == '-') - /* --option */ - fprintf (stderr, _("%s: unrecognized option `--%s'\n"), - argv[0], nextchar); - else - /* +option or -option */ - fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[optind][0], nextchar); - } - nextchar = (char *) ""; - optind++; - optopt = 0; - return '?'; - } - } - - /* Look at and handle the next short option-character. */ - - { - char c = *nextchar++; - char *temp = my_index (optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') - { - if (opterr) - { - if (posixly_correct) - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, _("%s: illegal option -- %c\n"), - argv[0], c); - else - fprintf (stderr, _("%s: invalid option -- %c\n"), - argv[0], c); - } - optopt = c; - return '?'; - } - /* Convenience. Treat POSIX -W foo same as long option --foo */ - if (temp[0] == 'W' && temp[1] == ';') - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = 0; - int option_index; - - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, _("%s: option requires an argument -- %c\n"), - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - return c; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - - /* optarg is now the argument, see if it's in the - table of longopts. */ - - for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) == strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - return '?'; - } - if (pfound != NULL) - { - option_index = indfound; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (opterr) - fprintf (stderr, _("\ - %s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); - - nextchar += strlen (nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - nextchar = NULL; - return 'W'; /* Let the application handle it. */ - } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = NULL; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, - _("%s: option requires an argument -- %c\n"), - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } -} - -int -getopt (argc, argv, optstring) -int argc; -char *const *argv; -const char *optstring; -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); -} - -#endif /* Not ELIDE_CODE. */ - -#ifdef TEST - -/* Compile with -DTEST to make an executable for use in testing - the above definition of `getopt'. */ - -int -main (argc, argv) -int argc; -char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - - c = getopt (argc, argv, "abc:d:0123456789"); - if (c == -1) - break; - - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ diff --git a/source/vba/getopt.h b/source/vba/getopt.h deleted file mode 100644 index 1931abf..0000000 --- a/source/vba/getopt.h +++ /dev/null @@ -1,142 +0,0 @@ -/* Declarations for getopt. - Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 2000 - Free Software Foundation, Inc. - - NOTE: The canonical source of this file is maintained with the GNU C Library. - Bugs can be reported to bug-glibc@gnu.org. - - 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 _GETOPT_H -#define _GETOPT_H 1 - -#ifdef __cplusplus -extern "C" - { -#endif - - /* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - - extern char *optarg; - - /* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - - extern int optind; - - /* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - - extern int opterr; - - /* Set to an option character which was unrecognized. */ - - extern int optopt; - - /* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - - struct option - { -#if defined (__STDC__) && __STDC__ - const char *name; -#else - char *name; -#endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; - }; - - /* Names for the values of the `has_arg' field of `struct option'. */ - -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -#if defined (__STDC__) && __STDC__ - /* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is - undefined, we haven't run the autoconf check so provide the - declaration without arguments. If it is 0, we checked and failed - to find the declaration so provide a fully prototyped one. If it - is 1, we found it so don't provide any declaration at all. */ -#if defined (__GNU_LIBRARY__) || (defined (HAVE_DECL_GETOPT) && !HAVE_DECL_GETOPT) - /* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ - extern int getopt (int argc, char *const *argv, const char *shortopts); -#else /* not __GNU_LIBRARY__ */ -# if !defined (HAVE_DECL_GETOPT) - extern int getopt (); -# endif -#endif /* __GNU_LIBRARY__ */ - extern int getopt_long (int argc, char *const *argv, const char *shortopts, - const struct option *longopts, int *longind); - extern int getopt_long_only (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind); - - /* Internal only. Users should not call this directly. */ - extern int _getopt_internal (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind, - int long_only); -#else /* not __STDC__ */ - extern int getopt (); - extern int getopt_long (); - extern int getopt_long_only (); - - extern int _getopt_internal (); -#endif /* __STDC__ */ - -#ifdef __cplusplus - } -#endif - -#endif /* getopt.h */ diff --git a/source/vba/getopt1.c b/source/vba/getopt1.c deleted file mode 100644 index 5302231..0000000 --- a/source/vba/getopt1.c +++ /dev/null @@ -1,191 +0,0 @@ -/* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 - Free Software Foundation, Inc. - - NOTE: This source is derived from an old version taken from the GNU C - Library (glibc). - - 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. */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "getopt.h" - -#if !defined __STDC__ || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 -#include -#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -#define ELIDE_CODE -#endif -#endif - -#ifndef ELIDE_CODE - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -#include -#endif - -#ifndef NULL -#define NULL 0 -#endif - -int -getopt_long (argc, argv, options, long_options, opt_index) -int argc; -char *const *argv; -const char *options; -const struct option *long_options; -int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 0); -} - -/* Like getopt_long, but '-' as well as '--' can indicate a long option. - If an option that starts with '-' (not '--') doesn't match a long option, - but does match a short option, it is parsed as a short option - instead. */ - -int -getopt_long_only (argc, argv, options, long_options, opt_index) -int argc; -char *const *argv; -const char *options; -const struct option *long_options; -int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 1); -} - - -#endif /* Not ELIDE_CODE. */ - -#ifdef TEST - -#include - -int -main (argc, argv) -int argc; -char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - int option_index = 0; - static struct option long_options[] = - { - {"add", 1, 0, 0 - }, - {"append", 0, 0, 0}, - {"delete", 1, 0, 0}, - {"verbose", 0, 0, 0}, - {"create", 0, 0, 0}, - {"file", 1, 0, 0}, - {0, 0, 0, 0} - }; - - c = getopt_long (argc, argv, "abc:d:0123456789", - long_options, &option_index); - if (c == -1) - break; - - switch (c) - { - case 0: - printf ("option %s", long_options[option_index].name); - if (optarg) - printf (" with arg %s", optarg); - printf ("\n"); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case 'd': - printf ("option d with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ diff --git a/source/vba/interframe.cpp b/source/vba/interframe.cpp index 44e688d..67de876 100644 --- a/source/vba/interframe.cpp +++ b/source/vba/interframe.cpp @@ -1,643 +1,581 @@ -// 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. - -#include "System.h" -#include -#include - -#ifdef MMX -extern "C" bool cpu_mmx; -#endif - -/* - * Thanks to Kawaks' Mr. K for the code - - Incorporated into vba by Anthony Di Franco -*/ - -static u8 *frm1 = NULL; -static u8 *frm2 = NULL; -static u8 *frm3 = NULL; - -extern int RGB_LOW_BITS_MASK; -extern u32 qRGB_COLOR_MASK[2]; - -static void Init() -{ - frm1 = (u8 *)calloc(322*242,4); - // 1 frame ago - frm2 = (u8 *)calloc(322*242,4); - // 2 frames ago - frm3 = (u8 *)calloc(322*242,4); - // 3 frames ago -} - -void InterframeCleanup() -{ - if(frm1) - free(frm1); - if(frm2) - free(frm2); - if(frm3) - free(frm3); - frm1 = frm2 = frm3 = NULL; -} - -#ifdef MMX -static void SmartIB_MMX(u8 *srcPtr, u32 srcPitch, int width, int height) -{ - u16 *src0 = (u16 *)srcPtr; - u16 *src1 = (u16 *)frm1; - u16 *src2 = (u16 *)frm2; - u16 *src3 = (u16 *)frm3; - - int count = width >> 2; - - for(int i = 0; i < height; i++) - { -#ifdef __GNUC__ - asm volatile ( - "push %4\n" - "movq 0(%5), %%mm7\n" // colorMask - "0:\n" - "movq 0(%0), %%mm0\n" // src0 - "movq 0(%1), %%mm1\n" // src1 - "movq 0(%2), %%mm2\n" // src2 - "movq 0(%3), %%mm3\n" // src3 - "movq %%mm0, 0(%3)\n" // src3 = src0 - "movq %%mm0, %%mm4\n" - "movq %%mm1, %%mm5\n" - "pcmpeqw %%mm2, %%mm5\n" // src1 == src2 (A) - "pcmpeqw %%mm3, %%mm4\n" // src3 == src0 (B) - "por %%mm5, %%mm4\n" // A | B - "movq %%mm2, %%mm5\n" - "pcmpeqw %%mm0, %%mm5\n" // src0 == src2 (C) - "pcmpeqw %%mm1, %%mm3\n" // src1 == src3 (D) - "por %%mm3, %%mm5\n" // C|D - "pandn %%mm5, %%mm4\n" // (!(A|B))&(C|D) - "movq %%mm0, %%mm2\n" - "pand %%mm7, %%mm2\n" // color & colorMask - "pand %%mm7, %%mm1\n" // src1 & colorMask - "psrlw $1, %%mm2\n" // (color & colorMask) >> 1 (E) - "psrlw $1, %%mm1\n" // (src & colorMask) >> 1 (F) - "paddw %%mm2, %%mm1\n" // E+F - "pand %%mm4, %%mm1\n" // (E+F) & res - "pandn %%mm0, %%mm4\n" // color& !res - - "por %%mm1, %%mm4\n" - "movq %%mm4, 0(%0)\n" // src0 = res - - "addl $8, %0\n" - "addl $8, %1\n" - "addl $8, %2\n" - "addl $8, %3\n" - - "decl %4\n" - "jnz 0b\n" - "pop %4\n" - "emms\n" - : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (src3) - : "r" (count), "r" (qRGB_COLOR_MASK) - ); -#else - __asm { - movq mm7, qword ptr [qRGB_COLOR_MASK]; - mov eax, src0; - mov ebx, src1; - mov ecx, src2; - mov edx, src3; - mov edi, count; - label0: - movq mm0, qword ptr [eax]; // src0 - movq mm1, qword ptr [ebx]; // src1 - movq mm2, qword ptr [ecx]; // src2 - movq mm3, qword ptr [edx]; // src3 - movq qword ptr [edx], mm0; // src3 = src0 - movq mm4, mm0; - movq mm5, mm1; - pcmpeqw mm5, mm2; // src1 == src2 (A) - pcmpeqw mm4, mm3; // src3 == src0 (B) - por mm4, mm5; // A | B - movq mm5, mm2; - pcmpeqw mm5, mm0; // src0 == src2 (C) - pcmpeqw mm3, mm1; // src1 == src3 (D) - por mm5, mm3; // C|D - pandn mm4, mm5; // (!(A|B))&(C|D) - movq mm2, mm0; - pand mm2, mm7; // color & colorMask - pand mm1, mm7; // src1 & colorMask - psrlw mm2, 1; // (color & colorMask) >> 1 (E) - psrlw mm1, 1; // (src & colorMask) >> 1 (F) - paddw mm1, mm2; // E+F - pand mm1, mm4; // (E+F) & res - pandn mm4, mm0; // color & !res - - por mm4, mm1; - movq qword ptr [eax], mm4; // src0 = res - - add eax, 8; - add ebx, 8; - add ecx, 8; - add edx, 8; - - dec edi; - jnz label0; - mov src0, eax; - mov src1, ebx; - mov src2, ecx; - mov src3, edx; - emms; - } -#endif - src0+=2; - src1+=2; - src2+=2; - src3+=2; - } - - /* Swap buffers around */ - u8 *temp = frm1; - frm1 = frm3; - frm3 = frm2; - frm2 = temp; -} -#endif - -void SmartIB(u8 *srcPtr, u32 srcPitch, int width, int height) -{ - if(frm1 == NULL) - { - Init(); - } -#ifdef MMX - if(cpu_mmx) - { - SmartIB_MMX(srcPtr, srcPitch, width, height); - return; - } -#endif - - u16 colorMask = ~RGB_LOW_BITS_MASK; - - u16 *src0 = (u16 *)srcPtr; - u16 *src1 = (u16 *)frm1; - u16 *src2 = (u16 *)frm2; - u16 *src3 = (u16 *)frm3; - - int sPitch = srcPitch >> 1; - - int pos = 0; - for (int j = 0; j < height; j++) - for (int i = 0; i < sPitch; i++) - { - u16 color = src0[pos]; - src0[pos] = - (src1[pos] != src2[pos]) && - (src3[pos] != color) && - ((color == src2[pos]) || (src1[pos] == src3[pos])) - ? (((color & colorMask) >> 1) + ((src1[pos] & colorMask) >> 1)) : - color; - src3[pos] = color; /* oldest buffer now holds newest frame */ - pos++; - } - - /* Swap buffers around */ - u8 *temp = frm1; - frm1 = frm3; - frm3 = frm2; - frm2 = temp; -} - -#ifdef MMX -static void SmartIB32_MMX(u8 *srcPtr, u32 srcPitch, int width, int height) -{ - u32 *src0 = (u32 *)srcPtr; - u32 *src1 = (u32 *)frm1; - u32 *src2 = (u32 *)frm2; - u32 *src3 = (u32 *)frm3; - - int count = width >> 1; - - for(int i = 0; i < height; i++) - { -#ifdef __GNUC__ - asm volatile ( - "push %4\n" - "movq 0(%5), %%mm7\n" // colorMask - "0:\n" - "movq 0(%0), %%mm0\n" // src0 - "movq 0(%1), %%mm1\n" // src1 - "movq 0(%2), %%mm2\n" // src2 - "movq 0(%3), %%mm3\n" // src3 - "movq %%mm0, 0(%3)\n" // src3 = src0 - "movq %%mm0, %%mm4\n" - "movq %%mm1, %%mm5\n" - "pcmpeqd %%mm2, %%mm5\n" // src1 == src2 (A) - "pcmpeqd %%mm3, %%mm4\n" // src3 == src0 (B) - "por %%mm5, %%mm4\n" // A | B - "movq %%mm2, %%mm5\n" - "pcmpeqd %%mm0, %%mm5\n" // src0 == src2 (C) - "pcmpeqd %%mm1, %%mm3\n" // src1 == src3 (D) - "por %%mm3, %%mm5\n" // C|D - "pandn %%mm5, %%mm4\n" // (!(A|B))&(C|D) - "movq %%mm0, %%mm2\n" - "pand %%mm7, %%mm2\n" // color & colorMask - "pand %%mm7, %%mm1\n" // src1 & colorMask - "psrld $1, %%mm2\n" // (color & colorMask) >> 1 (E) - "psrld $1, %%mm1\n" // (src & colorMask) >> 1 (F) - "paddd %%mm2, %%mm1\n" // E+F - "pand %%mm4, %%mm1\n" // (E+F) & res - "pandn %%mm0, %%mm4\n" // color& !res - - "por %%mm1, %%mm4\n" - "movq %%mm4, 0(%0)\n" // src0 = res - - "addl $8, %0\n" - "addl $8, %1\n" - "addl $8, %2\n" - "addl $8, %3\n" - - "decl %4\n" - "jnz 0b\n" - "pop %4\n" - "emms\n" - : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (src3) - : "r" (count), "r" (qRGB_COLOR_MASK) - ); -#else - __asm { - movq mm7, qword ptr [qRGB_COLOR_MASK]; - mov eax, src0; - mov ebx, src1; - mov ecx, src2; - mov edx, src3; - mov edi, count; - label0: - movq mm0, qword ptr [eax]; // src0 - movq mm1, qword ptr [ebx]; // src1 - movq mm2, qword ptr [ecx]; // src2 - movq mm3, qword ptr [edx]; // src3 - movq qword ptr [edx], mm0; // src3 = src0 - movq mm4, mm0; - movq mm5, mm1; - pcmpeqd mm5, mm2; // src1 == src2 (A) - pcmpeqd mm4, mm3; // src3 == src0 (B) - por mm4, mm5; // A | B - movq mm5, mm2; - pcmpeqd mm5, mm0; // src0 == src2 (C) - pcmpeqd mm3, mm1; // src1 == src3 (D) - por mm5, mm3; // C|D - pandn mm4, mm5; // (!(A|B))&(C|D) - movq mm2, mm0; - pand mm2, mm7; // color & colorMask - pand mm1, mm7; // src1 & colorMask - psrld mm2, 1; // (color & colorMask) >> 1 (E) - psrld mm1, 1; // (src & colorMask) >> 1 (F) - paddd mm1, mm2; // E+F - pand mm1, mm4; // (E+F) & res - pandn mm4, mm0; // color & !res - - por mm4, mm1; - movq qword ptr [eax], mm4; // src0 = res - - add eax, 8; - add ebx, 8; - add ecx, 8; - add edx, 8; - - dec edi; - jnz label0; - mov src0, eax; - mov src1, ebx; - mov src2, ecx; - mov src3, edx; - emms; - } -#endif - - src0++; - src1++; - src2++; - src3++; - } - /* Swap buffers around */ - u8 *temp = frm1; - frm1 = frm3; - frm3 = frm2; - frm2 = temp; -} -#endif - -void SmartIB32(u8 *srcPtr, u32 srcPitch, int width, int height) -{ - if(frm1 == NULL) - { - Init(); - } -#ifdef MMX - if(cpu_mmx) - { - SmartIB32_MMX(srcPtr, srcPitch, width, height); - return; - } -#endif - - u32 *src0 = (u32 *)srcPtr; - u32 *src1 = (u32 *)frm1; - u32 *src2 = (u32 *)frm2; - u32 *src3 = (u32 *)frm3; - - u32 colorMask = 0xfefefe; - - int sPitch = srcPitch >> 2; - int pos = 0; - - for (int j = 0; j < height; j++) - for (int i = 0; i < sPitch; i++) - { - u32 color = src0[pos]; - src0[pos] = - (src1[pos] != src2[pos]) && - (src3[pos] != color) && - ((color == src2[pos]) || (src1[pos] == src3[pos])) - ? (((color & colorMask) >> 1) + ((src1[pos] & colorMask) >> 1)) : - color; - src3[pos] = color; /* oldest buffer now holds newest frame */ - pos++; - } - - /* Swap buffers around */ - u8 *temp = frm1; - frm1 = frm3; - frm3 = frm2; - frm2 = temp; -} - -#ifdef MMX -static void MotionBlurIB_MMX(u8 *srcPtr, u32 srcPitch, int width, int height) -{ - u16 *src0 = (u16 *)srcPtr; - u16 *src1 = (u16 *)frm1; - - int count = width >> 2; - - for(int i = 0; i < height; i++) - { -#ifdef __GNUC__ - asm volatile ( - "push %2\n" - "movq 0(%3), %%mm7\n" // colorMask - "0:\n" - "movq 0(%0), %%mm0\n" // src0 - "movq 0(%1), %%mm1\n" // src1 - "movq %%mm0, 0(%1)\n" // src1 = src0 - "pand %%mm7, %%mm0\n" // color & colorMask - "pand %%mm7, %%mm1\n" // src1 & colorMask - "psrlw $1, %%mm0\n" // (color & colorMask) >> 1 (E) - "psrlw $1, %%mm1\n" // (src & colorMask) >> 1 (F) - "paddw %%mm1, %%mm0\n" // E+F - - "movq %%mm0, 0(%0)\n" // src0 = res - - "addl $8, %0\n" - "addl $8, %1\n" - - "decl %2\n" - "jnz 0b\n" - "pop %2\n" - "emms\n" - : "+r" (src0), "+r" (src1) - : "r" (count), "r" (qRGB_COLOR_MASK) - ); -#else - __asm { - movq mm7, qword ptr [qRGB_COLOR_MASK]; - mov eax, src0; - mov ebx, src1; - mov edi, count; - label0: - movq mm0, qword ptr [eax]; // src0 - movq mm1, qword ptr [ebx]; // src1 - movq qword ptr [ebx], mm0; // src1 = src0 - pand mm0, mm7; // color & colorMask - pand mm1, mm7; // src1 & colorMask - psrlw mm0, 1; // (color & colorMask) >> 1 (E) - psrlw mm1, 1; // (src & colorMask) >> 1 (F) - paddw mm0, mm1; // E+F - - movq qword ptr [eax], mm0; // src0 = res - - add eax, 8; - add ebx, 8; - - dec edi; - jnz label0; - mov src0, eax; - mov src1, ebx; - emms; - } -#endif - src0+=2; - src1+=2; - } -} -#endif - -void MotionBlurIB(u8 *srcPtr, u32 srcPitch, int width, int height) -{ - if(frm1 == NULL) - { - Init(); - } - -#ifdef MMX - if(cpu_mmx) - { - MotionBlurIB_MMX(srcPtr, srcPitch, width, height); - return; - } -#endif - - u16 colorMask = ~RGB_LOW_BITS_MASK; - - u16 *src0 = (u16 *)srcPtr; - u16 *src1 = (u16 *)frm1; - - int sPitch = srcPitch >> 1; - - int pos = 0; - for (int j = 0; j < height; j++) - for (int i = 0; i < sPitch; i++) - { - u16 color = src0[pos]; - src0[pos] = - (((color & colorMask) >> 1) + ((src1[pos] & colorMask) >> 1)); - src1[pos] = color; - pos++; - } -} - -#ifdef MMX -static void MotionBlurIB32_MMX(u8 *srcPtr, u32 srcPitch, int width, int height) -{ - u32 *src0 = (u32 *)srcPtr; - u32 *src1 = (u32 *)frm1; - - int count = width >> 1; - - for(int i = 0; i < height; i++) - { -#ifdef __GNUC__ - asm volatile ( - "push %2\n" - "movq 0(%3), %%mm7\n" // colorMask - "0:\n" - "movq 0(%0), %%mm0\n" // src0 - "movq 0(%1), %%mm1\n" // src1 - "movq %%mm0, 0(%1)\n" // src1 = src0 - "pand %%mm7, %%mm0\n" // color & colorMask - "pand %%mm7, %%mm1\n" // src1 & colorMask - "psrld $1, %%mm0\n" // (color & colorMask) >> 1 (E) - "psrld $1, %%mm1\n" // (src & colorMask) >> 1 (F) - "paddd %%mm1, %%mm0\n" // E+F - - "movq %%mm0, 0(%0)\n" // src0 = res - - "addl $8, %0\n" - "addl $8, %1\n" - - "decl %2\n" - "jnz 0b\n" - "pop %2\n" - "emms\n" - : "+r" (src0), "+r" (src1) - : "r" (count), "r" (qRGB_COLOR_MASK) - ); -#else - __asm { - movq mm7, qword ptr [qRGB_COLOR_MASK]; - mov eax, src0; - mov ebx, src1; - mov edi, count; - label0: - movq mm0, qword ptr [eax]; // src0 - movq mm1, qword ptr [ebx]; // src1 - movq qword ptr [ebx], mm0; // src1 = src0 - pand mm0, mm7; // color & colorMask - pand mm1, mm7; // src1 & colorMask - psrld mm0, 1; // (color & colorMask) >> 1 (E) - psrld mm1, 1; // (src & colorMask) >> 1 (F) - paddd mm0, mm1; // E+F - - movq qword ptr [eax], mm0; // src0 = res - - add eax, 8; - add ebx, 8; - - dec edi; - jnz label0; - mov src0, eax; - mov src1, ebx; - emms; - } -#endif - src0++; - src1++; - } -} -#endif - -void MotionBlurIB32(u8 *srcPtr, u32 srcPitch, int width, int height) -{ - if(frm1 == NULL) - { - Init(); - } - -#ifdef MMX - if(cpu_mmx) - { - MotionBlurIB32_MMX(srcPtr, srcPitch, width, height); - return; - } -#endif - - u32 *src0 = (u32 *)srcPtr; - u32 *src1 = (u32 *)frm1; - - u32 colorMask = 0xfefefe; - - int sPitch = srcPitch >> 2; - int pos = 0; - - for (int j = 0; j < height; j++) - for (int i = 0; i < sPitch; i++) - { - u32 color = src0[pos]; - src0[pos] = (((color & colorMask) >> 1) + - ((src1[pos] & colorMask) >> 1)); - src1[pos] = color; - pos++; - } -} - -static int count = 0; - -void InterlaceIB(u8 *srcPtr, u32 srcPitch, int width, int height) -{ - if(frm1 == NULL) - { - Init(); - } - - u16 colorMask = ~RGB_LOW_BITS_MASK; - - u16 *src0 = (u16 *)srcPtr; - u16 *src1 = (u16 *)frm1; - - int sPitch = srcPitch >> 1; - - int pos = 0; - for (int j = 0; j < height; j++) - { - bool render = count ? (j & 1) != 0 : (j & 1) == 0; - if(render) - { - for (int i = 0; i < sPitch; i++) - { - u16 color = src0[pos]; - src0[pos] = - (((color & colorMask) >> 1) + ((((src1[pos] & colorMask) >> 1) & colorMask) >> 1)); - src1[pos] = color; - pos++; - } - } - else - { - for (int i = 0; i < sPitch; i++) - { - u16 color = src0[pos]; - src0[pos] = - (((((color & colorMask) >> 1) & colorMask) >> 1) + ((src1[pos] & colorMask) >> 1)); - src1[pos] = color; - pos++; - } - } - } - count = count ^ 1; -} +// 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. + +#include "System.h" +#include +#include + +#ifdef MMX +extern "C" bool cpu_mmx; +#endif + +/* + * Thanks to Kawaks' Mr. K for the code + + Incorporated into vba by Anthony Di Franco +*/ + +static u8 *frm1 = NULL; +static u8 *frm2 = NULL; +static u8 *frm3 = NULL; + +extern int RGB_LOW_BITS_MASK; +extern u32 qRGB_COLOR_MASK[2]; + +static void Init() +{ + frm1 = (u8 *)calloc(322*242,4); + // 1 frame ago + frm2 = (u8 *)calloc(322*242,4); + // 2 frames ago + frm3 = (u8 *)calloc(322*242,4); + // 3 frames ago +} + +void InterframeCleanup() +{ + if(frm1) + free(frm1); + if(frm2) + free(frm2); + if(frm3) + free(frm3); + frm1 = frm2 = frm3 = NULL; +} + +#ifdef MMX +static void SmartIB_MMX(u8 *srcPtr, u32 srcPitch, int width, int height) +{ + u16 *src0 = (u16 *)srcPtr; + u16 *src1 = (u16 *)frm1; + u16 *src2 = (u16 *)frm2; + u16 *src3 = (u16 *)frm3; + + int count = width >> 2; + + for(int i = 0; i < height; i++) { +#ifdef __GNUC__ + asm volatile ( + "push %4\n" + "movq 0(%5), %%mm7\n" // colorMask + "0:\n" + "movq 0(%0), %%mm0\n" // src0 + "movq 0(%1), %%mm1\n" // src1 + "movq 0(%2), %%mm2\n" // src2 + "movq 0(%3), %%mm3\n" // src3 + "movq %%mm0, 0(%3)\n" // src3 = src0 + "movq %%mm0, %%mm4\n" + "movq %%mm1, %%mm5\n" + "pcmpeqw %%mm2, %%mm5\n" // src1 == src2 (A) + "pcmpeqw %%mm3, %%mm4\n" // src3 == src0 (B) + "por %%mm5, %%mm4\n" // A | B + "movq %%mm2, %%mm5\n" + "pcmpeqw %%mm0, %%mm5\n" // src0 == src2 (C) + "pcmpeqw %%mm1, %%mm3\n" // src1 == src3 (D) + "por %%mm3, %%mm5\n" // C|D + "pandn %%mm5, %%mm4\n" // (!(A|B))&(C|D) + "movq %%mm0, %%mm2\n" + "pand %%mm7, %%mm2\n" // color & colorMask + "pand %%mm7, %%mm1\n" // src1 & colorMask + "psrlw $1, %%mm2\n" // (color & colorMask) >> 1 (E) + "psrlw $1, %%mm1\n" // (src & colorMask) >> 1 (F) + "paddw %%mm2, %%mm1\n" // E+F + "pand %%mm4, %%mm1\n" // (E+F) & res + "pandn %%mm0, %%mm4\n" // color& !res + + "por %%mm1, %%mm4\n" + "movq %%mm4, 0(%0)\n" // src0 = res + + "addl $8, %0\n" + "addl $8, %1\n" + "addl $8, %2\n" + "addl $8, %3\n" + + "decl %4\n" + "jnz 0b\n" + "pop %4\n" + "emms\n" + : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (src3) + : "r" (count), "r" (qRGB_COLOR_MASK) + ); +#else + __asm { + movq mm7, qword ptr [qRGB_COLOR_MASK]; + mov eax, src0; + mov ebx, src1; + mov ecx, src2; + mov edx, src3; + mov edi, count; + label0: + movq mm0, qword ptr [eax]; // src0 + movq mm1, qword ptr [ebx]; // src1 + movq mm2, qword ptr [ecx]; // src2 + movq mm3, qword ptr [edx]; // src3 + movq qword ptr [edx], mm0; // src3 = src0 + movq mm4, mm0; + movq mm5, mm1; + pcmpeqw mm5, mm2; // src1 == src2 (A) + pcmpeqw mm4, mm3; // src3 == src0 (B) + por mm4, mm5; // A | B + movq mm5, mm2; + pcmpeqw mm5, mm0; // src0 == src2 (C) + pcmpeqw mm3, mm1; // src1 == src3 (D) + por mm5, mm3; // C|D + pandn mm4, mm5; // (!(A|B))&(C|D) + movq mm2, mm0; + pand mm2, mm7; // color & colorMask + pand mm1, mm7; // src1 & colorMask + psrlw mm2, 1; // (color & colorMask) >> 1 (E) + psrlw mm1, 1; // (src & colorMask) >> 1 (F) + paddw mm1, mm2; // E+F + pand mm1, mm4; // (E+F) & res + pandn mm4, mm0; // color & !res + + por mm4, mm1; + movq qword ptr [eax], mm4; // src0 = res + + add eax, 8; + add ebx, 8; + add ecx, 8; + add edx, 8; + + dec edi; + jnz label0; + mov src0, eax; + mov src1, ebx; + mov src2, ecx; + mov src3, edx; + emms; + } +#endif + src0+=2; + src1+=2; + src2+=2; + src3+=2; + } + + /* Swap buffers around */ + u8 *temp = frm1; + frm1 = frm3; + frm3 = frm2; + frm2 = temp; +} +#endif + +void SmartIB(u8 *srcPtr, u32 srcPitch, int width, int height) +{ + if(frm1 == NULL) { + Init(); + } +#ifdef MMX + if(cpu_mmx) { + SmartIB_MMX(srcPtr, srcPitch, width, height); + return; + } +#endif + + u16 colorMask = ~RGB_LOW_BITS_MASK; + + u16 *src0 = (u16 *)srcPtr; + u16 *src1 = (u16 *)frm1; + u16 *src2 = (u16 *)frm2; + u16 *src3 = (u16 *)frm3; + + int sPitch = srcPitch >> 1; + + int pos = 0; + for (int j = 0; j < height; j++) + for (int i = 0; i < sPitch; i++) { + u16 color = src0[pos]; + src0[pos] = + (src1[pos] != src2[pos]) && + (src3[pos] != color) && + ((color == src2[pos]) || (src1[pos] == src3[pos])) + ? (((color & colorMask) >> 1) + ((src1[pos] & colorMask) >> 1)) : + color; + src3[pos] = color; /* oldest buffer now holds newest frame */ + pos++; + } + + /* Swap buffers around */ + u8 *temp = frm1; + frm1 = frm3; + frm3 = frm2; + frm2 = temp; +} + +#ifdef MMX +static void SmartIB32_MMX(u8 *srcPtr, u32 srcPitch, int width, int height) +{ + u32 *src0 = (u32 *)srcPtr; + u32 *src1 = (u32 *)frm1; + u32 *src2 = (u32 *)frm2; + u32 *src3 = (u32 *)frm3; + + int count = width >> 1; + + for(int i = 0; i < height; i++) { +#ifdef __GNUC__ + asm volatile ( + "push %4\n" + "movq 0(%5), %%mm7\n" // colorMask + "0:\n" + "movq 0(%0), %%mm0\n" // src0 + "movq 0(%1), %%mm1\n" // src1 + "movq 0(%2), %%mm2\n" // src2 + "movq 0(%3), %%mm3\n" // src3 + "movq %%mm0, 0(%3)\n" // src3 = src0 + "movq %%mm0, %%mm4\n" + "movq %%mm1, %%mm5\n" + "pcmpeqd %%mm2, %%mm5\n" // src1 == src2 (A) + "pcmpeqd %%mm3, %%mm4\n" // src3 == src0 (B) + "por %%mm5, %%mm4\n" // A | B + "movq %%mm2, %%mm5\n" + "pcmpeqd %%mm0, %%mm5\n" // src0 == src2 (C) + "pcmpeqd %%mm1, %%mm3\n" // src1 == src3 (D) + "por %%mm3, %%mm5\n" // C|D + "pandn %%mm5, %%mm4\n" // (!(A|B))&(C|D) + "movq %%mm0, %%mm2\n" + "pand %%mm7, %%mm2\n" // color & colorMask + "pand %%mm7, %%mm1\n" // src1 & colorMask + "psrld $1, %%mm2\n" // (color & colorMask) >> 1 (E) + "psrld $1, %%mm1\n" // (src & colorMask) >> 1 (F) + "paddd %%mm2, %%mm1\n" // E+F + "pand %%mm4, %%mm1\n" // (E+F) & res + "pandn %%mm0, %%mm4\n" // color& !res + + "por %%mm1, %%mm4\n" + "movq %%mm4, 0(%0)\n" // src0 = res + + "addl $8, %0\n" + "addl $8, %1\n" + "addl $8, %2\n" + "addl $8, %3\n" + + "decl %4\n" + "jnz 0b\n" + "pop %4\n" + "emms\n" + : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (src3) + : "r" (count), "r" (qRGB_COLOR_MASK) + ); +#else + __asm { + movq mm7, qword ptr [qRGB_COLOR_MASK]; + mov eax, src0; + mov ebx, src1; + mov ecx, src2; + mov edx, src3; + mov edi, count; + label0: + movq mm0, qword ptr [eax]; // src0 + movq mm1, qword ptr [ebx]; // src1 + movq mm2, qword ptr [ecx]; // src2 + movq mm3, qword ptr [edx]; // src3 + movq qword ptr [edx], mm0; // src3 = src0 + movq mm4, mm0; + movq mm5, mm1; + pcmpeqd mm5, mm2; // src1 == src2 (A) + pcmpeqd mm4, mm3; // src3 == src0 (B) + por mm4, mm5; // A | B + movq mm5, mm2; + pcmpeqd mm5, mm0; // src0 == src2 (C) + pcmpeqd mm3, mm1; // src1 == src3 (D) + por mm5, mm3; // C|D + pandn mm4, mm5; // (!(A|B))&(C|D) + movq mm2, mm0; + pand mm2, mm7; // color & colorMask + pand mm1, mm7; // src1 & colorMask + psrld mm2, 1; // (color & colorMask) >> 1 (E) + psrld mm1, 1; // (src & colorMask) >> 1 (F) + paddd mm1, mm2; // E+F + pand mm1, mm4; // (E+F) & res + pandn mm4, mm0; // color & !res + + por mm4, mm1; + movq qword ptr [eax], mm4; // src0 = res + + add eax, 8; + add ebx, 8; + add ecx, 8; + add edx, 8; + + dec edi; + jnz label0; + mov src0, eax; + mov src1, ebx; + mov src2, ecx; + mov src3, edx; + emms; + } +#endif + + src0++; + src1++; + src2++; + src3++; + } + /* Swap buffers around */ + u8 *temp = frm1; + frm1 = frm3; + frm3 = frm2; + frm2 = temp; +} +#endif + +void SmartIB32(u8 *srcPtr, u32 srcPitch, int width, int height) +{ + if(frm1 == NULL) { + Init(); + } +#ifdef MMX + if(cpu_mmx) { + SmartIB32_MMX(srcPtr, srcPitch, width, height); + return; + } +#endif + + u32 *src0 = (u32 *)srcPtr; + u32 *src1 = (u32 *)frm1; + u32 *src2 = (u32 *)frm2; + u32 *src3 = (u32 *)frm3; + + u32 colorMask = 0xfefefe; + + int sPitch = srcPitch >> 2; + int pos = 0; + + for (int j = 0; j < height; j++) + for (int i = 0; i < sPitch; i++) { + u32 color = src0[pos]; + src0[pos] = + (src1[pos] != src2[pos]) && + (src3[pos] != color) && + ((color == src2[pos]) || (src1[pos] == src3[pos])) + ? (((color & colorMask) >> 1) + ((src1[pos] & colorMask) >> 1)) : + color; + src3[pos] = color; /* oldest buffer now holds newest frame */ + pos++; + } + + /* Swap buffers around */ + u8 *temp = frm1; + frm1 = frm3; + frm3 = frm2; + frm2 = temp; +} + +#ifdef MMX +static void MotionBlurIB_MMX(u8 *srcPtr, u32 srcPitch, int width, int height) +{ + u16 *src0 = (u16 *)srcPtr; + u16 *src1 = (u16 *)frm1; + + int count = width >> 2; + + for(int i = 0; i < height; i++) { +#ifdef __GNUC__ + asm volatile ( + "push %2\n" + "movq 0(%3), %%mm7\n" // colorMask + "0:\n" + "movq 0(%0), %%mm0\n" // src0 + "movq 0(%1), %%mm1\n" // src1 + "movq %%mm0, 0(%1)\n" // src1 = src0 + "pand %%mm7, %%mm0\n" // color & colorMask + "pand %%mm7, %%mm1\n" // src1 & colorMask + "psrlw $1, %%mm0\n" // (color & colorMask) >> 1 (E) + "psrlw $1, %%mm1\n" // (src & colorMask) >> 1 (F) + "paddw %%mm1, %%mm0\n" // E+F + + "movq %%mm0, 0(%0)\n" // src0 = res + + "addl $8, %0\n" + "addl $8, %1\n" + + "decl %2\n" + "jnz 0b\n" + "pop %2\n" + "emms\n" + : "+r" (src0), "+r" (src1) + : "r" (count), "r" (qRGB_COLOR_MASK) + ); +#else + __asm { + movq mm7, qword ptr [qRGB_COLOR_MASK]; + mov eax, src0; + mov ebx, src1; + mov edi, count; + label0: + movq mm0, qword ptr [eax]; // src0 + movq mm1, qword ptr [ebx]; // src1 + movq qword ptr [ebx], mm0; // src1 = src0 + pand mm0, mm7; // color & colorMask + pand mm1, mm7; // src1 & colorMask + psrlw mm0, 1; // (color & colorMask) >> 1 (E) + psrlw mm1, 1; // (src & colorMask) >> 1 (F) + paddw mm0, mm1; // E+F + + movq qword ptr [eax], mm0; // src0 = res + + add eax, 8; + add ebx, 8; + + dec edi; + jnz label0; + mov src0, eax; + mov src1, ebx; + emms; + } +#endif + src0+=2; + src1+=2; + } +} +#endif + +void MotionBlurIB(u8 *srcPtr, u32 srcPitch, int width, int height) +{ + if(frm1 == NULL) { + Init(); + } + +#ifdef MMX + if(cpu_mmx) { + MotionBlurIB_MMX(srcPtr, srcPitch, width, height); + return; + } +#endif + + u16 colorMask = ~RGB_LOW_BITS_MASK; + + u16 *src0 = (u16 *)srcPtr; + u16 *src1 = (u16 *)frm1; + + int sPitch = srcPitch >> 1; + + int pos = 0; + for (int j = 0; j < height; j++) + for (int i = 0; i < sPitch; i++) { + u16 color = src0[pos]; + src0[pos] = + (((color & colorMask) >> 1) + ((src1[pos] & colorMask) >> 1)); + src1[pos] = color; + pos++; + } +} + +#ifdef MMX +static void MotionBlurIB32_MMX(u8 *srcPtr, u32 srcPitch, int width, int height) +{ + u32 *src0 = (u32 *)srcPtr; + u32 *src1 = (u32 *)frm1; + + int count = width >> 1; + + for(int i = 0; i < height; i++) { +#ifdef __GNUC__ + asm volatile ( + "push %2\n" + "movq 0(%3), %%mm7\n" // colorMask + "0:\n" + "movq 0(%0), %%mm0\n" // src0 + "movq 0(%1), %%mm1\n" // src1 + "movq %%mm0, 0(%1)\n" // src1 = src0 + "pand %%mm7, %%mm0\n" // color & colorMask + "pand %%mm7, %%mm1\n" // src1 & colorMask + "psrld $1, %%mm0\n" // (color & colorMask) >> 1 (E) + "psrld $1, %%mm1\n" // (src & colorMask) >> 1 (F) + "paddd %%mm1, %%mm0\n" // E+F + + "movq %%mm0, 0(%0)\n" // src0 = res + + "addl $8, %0\n" + "addl $8, %1\n" + + "decl %2\n" + "jnz 0b\n" + "pop %2\n" + "emms\n" + : "+r" (src0), "+r" (src1) + : "r" (count), "r" (qRGB_COLOR_MASK) + ); +#else + __asm { + movq mm7, qword ptr [qRGB_COLOR_MASK]; + mov eax, src0; + mov ebx, src1; + mov edi, count; + label0: + movq mm0, qword ptr [eax]; // src0 + movq mm1, qword ptr [ebx]; // src1 + movq qword ptr [ebx], mm0; // src1 = src0 + pand mm0, mm7; // color & colorMask + pand mm1, mm7; // src1 & colorMask + psrld mm0, 1; // (color & colorMask) >> 1 (E) + psrld mm1, 1; // (src & colorMask) >> 1 (F) + paddd mm0, mm1; // E+F + + movq qword ptr [eax], mm0; // src0 = res + + add eax, 8; + add ebx, 8; + + dec edi; + jnz label0; + mov src0, eax; + mov src1, ebx; + emms; + } +#endif + src0++; + src1++; + } +} +#endif + +void MotionBlurIB32(u8 *srcPtr, u32 srcPitch, int width, int height) +{ + if(frm1 == NULL) { + Init(); + } + +#ifdef MMX + if(cpu_mmx) { + MotionBlurIB32_MMX(srcPtr, srcPitch, width, height); + return; + } +#endif + + u32 *src0 = (u32 *)srcPtr; + u32 *src1 = (u32 *)frm1; + + u32 colorMask = 0xfefefe; + + int sPitch = srcPitch >> 2; + int pos = 0; + + for (int j = 0; j < height; j++) + for (int i = 0; i < sPitch; i++) { + u32 color = src0[pos]; + src0[pos] = (((color & colorMask) >> 1) + + ((src1[pos] & colorMask) >> 1)); + src1[pos] = color; + pos++; + } +} diff --git a/source/vba/interp.h b/source/vba/interp.h index 569afe3..0fd2961 100644 --- a/source/vba/interp.h +++ b/source/vba/interp.h @@ -1,298 +1,302 @@ -/* - * This file is part of the Advance project. - * - * Copyright (C) 2003 Andrea Mazzoleni - * - * 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * In addition, as a special exception, Andrea Mazzoleni - * gives permission to link the code of this program with - * the MAME library (or with modified versions of MAME that use the - * same license as MAME), and distribute linked combinations including - * the two. You must obey the GNU General Public License in all - * respects for all of the code used other than MAME. If you modify - * this file, you may extend this exception to your version of the - * file, but you are not obligated to do so. If you do not wish to - * do so, delete this exception statement from your version. - */ - -#ifndef __INTERP_H -#define __INTERP_H - -/***************************************************************************/ -/* Basic types */ - -/***************************************************************************/ -/* interpolation */ - -static unsigned interp_mask[2]; -static unsigned interp_bits_per_pixel; - -#define INTERP_16_MASK_1(v) (v & interp_mask[0]) -#define INTERP_16_MASK_2(v) (v & interp_mask[1]) - -static inline u16 interp_16_521(u16 p1, u16 p2, u16 p3) -{ - return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*5 + INTERP_16_MASK_1(p2)*2 + INTERP_16_MASK_1(p3)*1) / 8) - | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*5 + INTERP_16_MASK_2(p2)*2 + INTERP_16_MASK_2(p3)*1) / 8); -} - -static inline u16 interp_16_332(u16 p1, u16 p2, u16 p3) -{ - return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*3 + INTERP_16_MASK_1(p2)*3 + INTERP_16_MASK_1(p3)*2) / 8) - | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*3 + INTERP_16_MASK_2(p2)*3 + INTERP_16_MASK_2(p3)*2) / 8); -} - -static inline u16 interp_16_611(u16 p1, u16 p2, u16 p3) -{ - return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*6 + INTERP_16_MASK_1(p2) + INTERP_16_MASK_1(p3)) / 8) - | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*6 + INTERP_16_MASK_2(p2) + INTERP_16_MASK_2(p3)) / 8); -} - -static inline u16 interp_16_71(u16 p1, u16 p2) -{ - return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*7 + INTERP_16_MASK_1(p2)) / 8) - | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*7 + INTERP_16_MASK_2(p2)) / 8); -} - -static inline u16 interp_16_211(u16 p1, u16 p2, u16 p3) -{ - return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*2 + INTERP_16_MASK_1(p2) + INTERP_16_MASK_1(p3)) / 4) - | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*2 + INTERP_16_MASK_2(p2) + INTERP_16_MASK_2(p3)) / 4); -} - -static inline u16 interp_16_772(u16 p1, u16 p2, u16 p3) -{ - return INTERP_16_MASK_1(((INTERP_16_MASK_1(p1) + INTERP_16_MASK_1(p2))*7 + INTERP_16_MASK_1(p3)*2) / 16) - | INTERP_16_MASK_2(((INTERP_16_MASK_2(p1) + INTERP_16_MASK_2(p2))*7 + INTERP_16_MASK_2(p3)*2) / 16); -} - -static inline u16 interp_16_11(u16 p1, u16 p2) -{ - return INTERP_16_MASK_1((INTERP_16_MASK_1(p1) + INTERP_16_MASK_1(p2)) / 2) - | INTERP_16_MASK_2((INTERP_16_MASK_2(p1) + INTERP_16_MASK_2(p2)) / 2); -} - -static inline u16 interp_16_31(u16 p1, u16 p2) -{ - return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*3 + INTERP_16_MASK_1(p2)) / 4) - | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*3 + INTERP_16_MASK_2(p2)) / 4); -} - -static inline u16 interp_16_1411(u16 p1, u16 p2, u16 p3) -{ - return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*14 + INTERP_16_MASK_1(p2) + INTERP_16_MASK_1(p3)) / 16) - | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*14 + INTERP_16_MASK_2(p2) + INTERP_16_MASK_2(p3)) / 16); -} - -static inline u16 interp_16_431(u16 p1, u16 p2, u16 p3) -{ - return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*4 + INTERP_16_MASK_1(p2)*3 + INTERP_16_MASK_1(p3)) / 8) - | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*4 + INTERP_16_MASK_2(p2)*3 + INTERP_16_MASK_2(p3)) / 8); -} - -static inline u16 interp_16_53(u16 p1, u16 p2) -{ - return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*5 + INTERP_16_MASK_1(p2)*3) / 8) - | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*5 + INTERP_16_MASK_2(p2)*3) / 8); -} - -static inline u16 interp_16_151(u16 p1, u16 p2) -{ - return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*15 + INTERP_16_MASK_1(p2)) / 16) - | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*15 + INTERP_16_MASK_2(p2)) / 16); -} - -static inline u16 interp_16_97(u16 p1, u16 p2) -{ - return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*9 + INTERP_16_MASK_1(p2)*7) / 16) - | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*9 + INTERP_16_MASK_2(p2)*7) / 16); -} - -#define INTERP_32_MASK_1(v) (v & 0xFF00FF) -#define INTERP_32_MASK_2(v) (v & 0x00FF00) - -static inline u32 interp_32_521(u32 p1, u32 p2, u32 p3) -{ - return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*5 + INTERP_32_MASK_1(p2)*2 + INTERP_32_MASK_1(p3)*1) / 8) - | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*5 + INTERP_32_MASK_2(p2)*2 + INTERP_32_MASK_2(p3)*1) / 8); -} - -static inline u32 interp_32_332(u32 p1, u32 p2, u32 p3) -{ - return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*3 + INTERP_32_MASK_1(p2)*3 + INTERP_32_MASK_1(p3)*2) / 8) - | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*3 + INTERP_32_MASK_2(p2)*3 + INTERP_32_MASK_2(p3)*2) / 8); -} - -static inline u32 interp_32_211(u32 p1, u32 p2, u32 p3) -{ - return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*2 + INTERP_32_MASK_1(p2) + INTERP_32_MASK_1(p3)) / 4) - | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*2 + INTERP_32_MASK_2(p2) + INTERP_32_MASK_2(p3)) / 4); -} - -static inline u32 interp_32_611(u32 p1, u32 p2, u32 p3) -{ - return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*6 + INTERP_32_MASK_1(p2) + INTERP_32_MASK_1(p3)) / 8) - | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*6 + INTERP_32_MASK_2(p2) + INTERP_32_MASK_2(p3)) / 8); -} - -static inline u32 interp_32_71(u32 p1, u32 p2) -{ - return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*7 + INTERP_32_MASK_1(p2)) / 8) - | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*7 + INTERP_32_MASK_2(p2)) / 8); -} - -static inline u32 interp_32_772(u32 p1, u32 p2, u32 p3) -{ - return INTERP_32_MASK_1(((INTERP_32_MASK_1(p1) + INTERP_32_MASK_1(p2))*7 + INTERP_32_MASK_1(p3)*2) / 16) - | INTERP_32_MASK_2(((INTERP_32_MASK_2(p1) + INTERP_32_MASK_2(p2))*7 + INTERP_32_MASK_2(p3)*2) / 16); -} - -static inline u32 interp_32_11(u32 p1, u32 p2) -{ - return INTERP_32_MASK_1((INTERP_32_MASK_1(p1) + INTERP_32_MASK_1(p2)) / 2) - | INTERP_32_MASK_2((INTERP_32_MASK_2(p1) + INTERP_32_MASK_2(p2)) / 2); -} - -static inline u32 interp_32_31(u32 p1, u32 p2) -{ - return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*3 + INTERP_32_MASK_1(p2)) / 4) - | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*3 + INTERP_32_MASK_2(p2)) / 4); -} - -static inline u32 interp_32_1411(u32 p1, u32 p2, u32 p3) -{ - return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*14 + INTERP_32_MASK_1(p2) + INTERP_32_MASK_1(p3)) / 16) - | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*14 + INTERP_32_MASK_2(p2) + INTERP_32_MASK_2(p3)) / 16); -} - -static inline u32 interp_32_431(u32 p1, u32 p2, u32 p3) -{ - return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*4 + INTERP_32_MASK_1(p2)*3 + INTERP_32_MASK_1(p3)) / 8) - | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*4 + INTERP_32_MASK_2(p2)*3 + INTERP_32_MASK_2(p3)) / 8); -} - -static inline u32 interp_32_53(u32 p1, u32 p2) -{ - return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*5 + INTERP_32_MASK_1(p2)*3) / 8) - | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*5 + INTERP_32_MASK_2(p2)*3) / 8); -} - -static inline u32 interp_32_151(u32 p1, u32 p2) -{ - return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*15 + INTERP_32_MASK_1(p2)) / 16) - | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*15 + INTERP_32_MASK_2(p2)) / 16); -} - -static inline u32 interp_32_97(u32 p1, u32 p2) -{ - return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*9 + INTERP_32_MASK_1(p2)*7) / 16) - | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*9 + INTERP_32_MASK_2(p2)*7) / 16); -} - -/***************************************************************************/ -/* diff */ - -#define INTERP_Y_LIMIT (0x30*4) -#define INTERP_U_LIMIT (0x07*4) -#define INTERP_V_LIMIT (0x06*8) - -static int interp_16_diff(u16 p1, u16 p2) -{ - int r, g, b; - int y, u, v; - - if (p1 == p2) - return 0; - - if (interp_bits_per_pixel == 16) - { - b = (int)((p1 & 0x1F) - (p2 & 0x1F)) << 3; - g = (int)((p1 & 0x7E0) - (p2 & 0x7E0)) >> 3; - r = (int)((p1 & 0xF800) - (p2 & 0xF800)) >> 8; - } - else - { - b = (int)((p1 & 0x1F) - (p2 & 0x1F)) << 3; - g = (int)((p1 & 0x3E0) - (p2 & 0x3E0)) >> 2; - r = (int)((p1 & 0x7C00) - (p2 & 0x7C00)) >> 7; - } - - y = r + g + b; - u = r - b; - v = -r + 2*g - b; - - if (y < -INTERP_Y_LIMIT || y > INTERP_Y_LIMIT) - return 1; - - if (u < -INTERP_U_LIMIT || u > INTERP_U_LIMIT) - return 1; - - if (v < -INTERP_V_LIMIT || v > INTERP_V_LIMIT) - return 1; - - return 0; -} - -static int interp_32_diff(u32 p1, u32 p2) -{ - int r, g, b; - int y, u, v; - - if ((p1 & 0xF8F8F8) == (p2 & 0xF8F8F8)) - return 0; - - b = (int)((p1 & 0xFF) - (p2 & 0xFF)); - g = (int)((p1 & 0xFF00) - (p2 & 0xFF00)) >> 8; - r = (int)((p1 & 0xFF0000) - (p2 & 0xFF0000)) >> 16; - - y = r + g + b; - u = r - b; - v = -r + 2*g - b; - - if (y < -INTERP_Y_LIMIT || y > INTERP_Y_LIMIT) - return 1; - - if (u < -INTERP_U_LIMIT || u > INTERP_U_LIMIT) - return 1; - - if (v < -INTERP_V_LIMIT || v > INTERP_V_LIMIT) - return 1; - - return 0; -} - -static void interp_set(unsigned bits_per_pixel) -{ - interp_bits_per_pixel = bits_per_pixel; - - switch (bits_per_pixel) - { - case 15 : - interp_mask[0] = 0x7C1F; - interp_mask[1] = 0x03E0; - break; - case 16 : - interp_mask[0] = 0xF81F; - interp_mask[1] = 0x07E0; - break; - case 32 : - interp_mask[0] = 0xFF00FF; - interp_mask[1] = 0x00FF00; - break; - } -} - -#endif +/* + * This file is part of the Advance project. + * + * Copyright (C) 2003 Andrea Mazzoleni + * + * 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * In addition, as a special exception, Andrea Mazzoleni + * gives permission to link the code of this program with + * the MAME library (or with modified versions of MAME that use the + * same license as MAME), and distribute linked combinations including + * the two. You must obey the GNU General Public License in all + * respects for all of the code used other than MAME. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +#ifndef __INTERP_H +#define __INTERP_H + +#define __STDC_CONSTANT_MACROS + +#include + + +typedef uint16_t interp_uint16; +typedef uint32_t interp_uint32; + +/***************************************************************************/ +/* Basic types */ + +/***************************************************************************/ +/* interpolation */ + +static unsigned interp_mask[2]; +static unsigned interp_bits_per_pixel; + +#define INTERP_16_MASK_1(v) (v & interp_mask[0]) +#define INTERP_16_MASK_2(v) (v & interp_mask[1]) + +static inline u16 interp_16_521(u16 p1, u16 p2, u16 p3) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*5 + INTERP_16_MASK_1(p2)*2 + INTERP_16_MASK_1(p3)*1) / 8) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*5 + INTERP_16_MASK_2(p2)*2 + INTERP_16_MASK_2(p3)*1) / 8); +} + +static inline u16 interp_16_332(u16 p1, u16 p2, u16 p3) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*3 + INTERP_16_MASK_1(p2)*3 + INTERP_16_MASK_1(p3)*2) / 8) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*3 + INTERP_16_MASK_2(p2)*3 + INTERP_16_MASK_2(p3)*2) / 8); +} + +static inline u16 interp_16_611(u16 p1, u16 p2, u16 p3) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*6 + INTERP_16_MASK_1(p2) + INTERP_16_MASK_1(p3)) / 8) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*6 + INTERP_16_MASK_2(p2) + INTERP_16_MASK_2(p3)) / 8); +} + +static inline u16 interp_16_71(u16 p1, u16 p2) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*7 + INTERP_16_MASK_1(p2)) / 8) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*7 + INTERP_16_MASK_2(p2)) / 8); +} + +static inline u16 interp_16_211(u16 p1, u16 p2, u16 p3) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*2 + INTERP_16_MASK_1(p2) + INTERP_16_MASK_1(p3)) / 4) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*2 + INTERP_16_MASK_2(p2) + INTERP_16_MASK_2(p3)) / 4); +} + +static inline u16 interp_16_772(u16 p1, u16 p2, u16 p3) +{ + return INTERP_16_MASK_1(((INTERP_16_MASK_1(p1) + INTERP_16_MASK_1(p2))*7 + INTERP_16_MASK_1(p3)*2) / 16) + | INTERP_16_MASK_2(((INTERP_16_MASK_2(p1) + INTERP_16_MASK_2(p2))*7 + INTERP_16_MASK_2(p3)*2) / 16); +} + +static inline u16 interp_16_11(u16 p1, u16 p2) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1) + INTERP_16_MASK_1(p2)) / 2) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1) + INTERP_16_MASK_2(p2)) / 2); +} + +static inline u16 interp_16_31(u16 p1, u16 p2) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*3 + INTERP_16_MASK_1(p2)) / 4) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*3 + INTERP_16_MASK_2(p2)) / 4); +} + +static inline u16 interp_16_1411(u16 p1, u16 p2, u16 p3) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*14 + INTERP_16_MASK_1(p2) + INTERP_16_MASK_1(p3)) / 16) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*14 + INTERP_16_MASK_2(p2) + INTERP_16_MASK_2(p3)) / 16); +} + +static inline u16 interp_16_431(u16 p1, u16 p2, u16 p3) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*4 + INTERP_16_MASK_1(p2)*3 + INTERP_16_MASK_1(p3)) / 8) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*4 + INTERP_16_MASK_2(p2)*3 + INTERP_16_MASK_2(p3)) / 8); +} + +static inline u16 interp_16_53(u16 p1, u16 p2) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*5 + INTERP_16_MASK_1(p2)*3) / 8) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*5 + INTERP_16_MASK_2(p2)*3) / 8); +} + +static inline u16 interp_16_151(u16 p1, u16 p2) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*15 + INTERP_16_MASK_1(p2)) / 16) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*15 + INTERP_16_MASK_2(p2)) / 16); +} + +static inline u16 interp_16_97(u16 p1, u16 p2) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*9 + INTERP_16_MASK_1(p2)*7) / 16) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*9 + INTERP_16_MASK_2(p2)*7) / 16); +} + +#define INTERP_32_MASK_1(v) (v & 0xFF00FF) +#define INTERP_32_MASK_2(v) (v & 0x00FF00) + +static inline u32 interp_32_521(u32 p1, u32 p2, u32 p3) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*5 + INTERP_32_MASK_1(p2)*2 + INTERP_32_MASK_1(p3)*1) / 8) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*5 + INTERP_32_MASK_2(p2)*2 + INTERP_32_MASK_2(p3)*1) / 8); +} + +static inline u32 interp_32_332(u32 p1, u32 p2, u32 p3) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*3 + INTERP_32_MASK_1(p2)*3 + INTERP_32_MASK_1(p3)*2) / 8) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*3 + INTERP_32_MASK_2(p2)*3 + INTERP_32_MASK_2(p3)*2) / 8); +} + +static inline u32 interp_32_211(u32 p1, u32 p2, u32 p3) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*2 + INTERP_32_MASK_1(p2) + INTERP_32_MASK_1(p3)) / 4) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*2 + INTERP_32_MASK_2(p2) + INTERP_32_MASK_2(p3)) / 4); +} + +static inline u32 interp_32_611(u32 p1, u32 p2, u32 p3) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*6 + INTERP_32_MASK_1(p2) + INTERP_32_MASK_1(p3)) / 8) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*6 + INTERP_32_MASK_2(p2) + INTERP_32_MASK_2(p3)) / 8); +} + +static inline u32 interp_32_71(u32 p1, u32 p2) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*7 + INTERP_32_MASK_1(p2)) / 8) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*7 + INTERP_32_MASK_2(p2)) / 8); +} + +static inline u32 interp_32_772(u32 p1, u32 p2, u32 p3) +{ + return INTERP_32_MASK_1(((INTERP_32_MASK_1(p1) + INTERP_32_MASK_1(p2))*7 + INTERP_32_MASK_1(p3)*2) / 16) + | INTERP_32_MASK_2(((INTERP_32_MASK_2(p1) + INTERP_32_MASK_2(p2))*7 + INTERP_32_MASK_2(p3)*2) / 16); +} + +static inline u32 interp_32_11(u32 p1, u32 p2) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1) + INTERP_32_MASK_1(p2)) / 2) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1) + INTERP_32_MASK_2(p2)) / 2); +} + +static inline u32 interp_32_31(u32 p1, u32 p2) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*3 + INTERP_32_MASK_1(p2)) / 4) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*3 + INTERP_32_MASK_2(p2)) / 4); +} + +static inline u32 interp_32_1411(u32 p1, u32 p2, u32 p3) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*14 + INTERP_32_MASK_1(p2) + INTERP_32_MASK_1(p3)) / 16) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*14 + INTERP_32_MASK_2(p2) + INTERP_32_MASK_2(p3)) / 16); +} + +static inline u32 interp_32_431(u32 p1, u32 p2, u32 p3) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*4 + INTERP_32_MASK_1(p2)*3 + INTERP_32_MASK_1(p3)) / 8) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*4 + INTERP_32_MASK_2(p2)*3 + INTERP_32_MASK_2(p3)) / 8); +} + +static inline u32 interp_32_53(u32 p1, u32 p2) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*5 + INTERP_32_MASK_1(p2)*3) / 8) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*5 + INTERP_32_MASK_2(p2)*3) / 8); +} + +static inline u32 interp_32_151(u32 p1, u32 p2) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*15 + INTERP_32_MASK_1(p2)) / 16) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*15 + INTERP_32_MASK_2(p2)) / 16); +} + +static inline u32 interp_32_97(u32 p1, u32 p2) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*9 + INTERP_32_MASK_1(p2)*7) / 16) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*9 + INTERP_32_MASK_2(p2)*7) / 16); +} + +/***************************************************************************/ +/* diff */ + +#define INTERP_Y_LIMIT (0x30*4) +#define INTERP_U_LIMIT (0x07*4) +#define INTERP_V_LIMIT (0x06*8) + +static int interp_16_diff(u16 p1, u16 p2) +{ + int r, g, b; + int y, u, v; + + if (p1 == p2) + return 0; + + if (interp_bits_per_pixel == 16) { + b = (int)((p1 & 0x1F) - (p2 & 0x1F)) << 3; + g = (int)((p1 & 0x7E0) - (p2 & 0x7E0)) >> 3; + r = (int)((p1 & 0xF800) - (p2 & 0xF800)) >> 8; + } else { + b = (int)((p1 & 0x1F) - (p2 & 0x1F)) << 3; + g = (int)((p1 & 0x3E0) - (p2 & 0x3E0)) >> 2; + r = (int)((p1 & 0x7C00) - (p2 & 0x7C00)) >> 7; + } + + y = r + g + b; + u = r - b; + v = -r + 2*g - b; + + if (y < -INTERP_Y_LIMIT || y > INTERP_Y_LIMIT) + return 1; + + if (u < -INTERP_U_LIMIT || u > INTERP_U_LIMIT) + return 1; + + if (v < -INTERP_V_LIMIT || v > INTERP_V_LIMIT) + return 1; + + return 0; +} + +static int interp_32_diff(u32 p1, u32 p2) +{ + int r, g, b; + int y, u, v; + + if ((p1 & 0xF8F8F8) == (p2 & 0xF8F8F8)) + return 0; + + b = (int)((p1 & 0xFF) - (p2 & 0xFF)); + g = (int)((p1 & 0xFF00) - (p2 & 0xFF00)) >> 8; + r = (int)((p1 & 0xFF0000) - (p2 & 0xFF0000)) >> 16; + + y = r + g + b; + u = r - b; + v = -r + 2*g - b; + + if (y < -INTERP_Y_LIMIT || y > INTERP_Y_LIMIT) + return 1; + + if (u < -INTERP_U_LIMIT || u > INTERP_U_LIMIT) + return 1; + + if (v < -INTERP_V_LIMIT || v > INTERP_V_LIMIT) + return 1; + + return 0; +} + +static void interp_set(unsigned bits_per_pixel) +{ + interp_bits_per_pixel = bits_per_pixel; + + switch (bits_per_pixel) { + case 15 : + interp_mask[0] = 0x7C1F; + interp_mask[1] = 0x03E0; + break; + case 16 : + interp_mask[0] = 0xF81F; + interp_mask[1] = 0x07E0; + break; + case 32 : + interp_mask[0] = 0xFF00FF; + interp_mask[1] = 0x00FF00; + break; + } +} + +#endif diff --git a/source/vba/pixel.cpp b/source/vba/pixel.cpp index cfa7c7c..21a55a3 100644 --- a/source/vba/pixel.cpp +++ b/source/vba/pixel.cpp @@ -1,157 +1,150 @@ -// 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. - -#include "System.h" - -extern int RGB_LOW_BITS_MASK; - -void Pixelate(u8 *srcPtr, u32 srcPitch, u8 *deltaPtr, - u8 *dstPtr, u32 dstPitch, int width, int height) -{ - u8 *nextLine, *finish; - u32 colorMask = ~(RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 16)); - - nextLine = dstPtr + dstPitch; - - do - { - u32 *bP = (u32 *) srcPtr; - u32 *xP = (u32 *) deltaPtr; - u32 *dP = (u32 *) dstPtr; - u32 *nL = (u32 *) nextLine; - u32 currentPixel; - u32 nextPixel; - u32 currentDelta; - u32 nextDelta; - - finish = (u8 *) bP + ((width+2) << 1); - nextPixel = *bP++; - nextDelta = *xP++; - - do - { - currentPixel = nextPixel; - currentDelta = nextDelta; - nextPixel = *bP++; - nextDelta = *xP++; - - if ((nextPixel != nextDelta) || (currentPixel != currentDelta)) - { - u32 colorA, colorB, product; - - *(xP - 2) = currentPixel; -#ifdef WORDS_BIGENDIAN - colorA = currentPixel >> 16; - colorB = currentPixel & 0xffff; -#else - colorA = currentPixel & 0xffff; - colorB = currentPixel >> 16; -#endif - product = (((colorA & colorMask) >> 1) & colorMask) >> 1; - -#ifdef WORDS_BIGENDIAN - *(nL) = (product << 16) | (product); - *(dP) = (colorA << 16) | product; -#else - *(nL) = product | (product << 16); - *(dP) = colorA | (product << 16); -#endif - -#ifdef WORDS_BIGENDIAN - colorA = nextPixel >> 16; -#else - colorA = nextPixel & 0xffff; -#endif - product = (((colorB & colorMask) >> 1) & colorMask) >> 1; -#ifdef WORDS_BIGENDIAN - *(nL + 1) = (product << 16) | (product); - *(dP + 1) = (colorB << 16) | (product); -#else - *(nL + 1) = (product) | (product << 16); - *(dP + 1) = (colorB) | (product << 16); -#endif - } - - dP += 2; - nL += 2; - } - while ((u8 *) bP < finish); - - deltaPtr += srcPitch; - srcPtr += srcPitch; - dstPtr += dstPitch << 1; - nextLine += dstPitch << 1; - } - while (--height); -} - -void Pixelate32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, - u8 *dstPtr, u32 dstPitch, int width, int height) -{ - u8 *nextLine, *finish; - u32 colorMask = ~RGB_LOW_BITS_MASK; - - nextLine = dstPtr + dstPitch; - - do - { - u32 *bP = (u32 *) srcPtr; - // u32 *xP = (u32 *) deltaPtr; - u32 *dP = (u32 *) dstPtr; - u32 *nL = (u32 *) nextLine; - u32 currentPixel; - u32 nextPixel; - - finish = (u8 *) bP + ((width+1) << 2); - nextPixel = *bP++; - - do - { - currentPixel = nextPixel; - nextPixel = *bP++; - - u32 colorA, colorB, product; - - colorA = currentPixel; - colorB = nextPixel; - - product = (((colorA & colorMask) >> 1) & colorMask) >> 1; - *(nL) = product; - *(nL+1) = product; - *(dP) = colorA; - *(dP+1) = product; - - nextPixel = *bP++; - colorA = nextPixel; - product = (((colorB & colorMask) >> 1) & colorMask) >> 1; - *(nL + 2) = product; - *(nL + 3) = product; - *(dP + 2) = colorB; - *(dP + 3) = product; - - dP += 4; - nL += 4; - } - while ((u8 *) bP < finish); - - srcPtr += srcPitch; - dstPtr += dstPitch << 1; - nextLine += dstPitch << 1; - } - while (--height); -} +// 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. + +#include "System.h" + +extern int RGB_LOW_BITS_MASK; + +void Pixelate(u8 *srcPtr, u32 srcPitch, u8 *deltaPtr, + u8 *dstPtr, u32 dstPitch, int width, int height) +{ + u8 *nextLine, *finish; + u32 colorMask = ~(RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 16)); + + nextLine = dstPtr + dstPitch; + + do { + u32 *bP = (u32 *) srcPtr; + u32 *xP = (u32 *) deltaPtr; + u32 *dP = (u32 *) dstPtr; + u32 *nL = (u32 *) nextLine; + u32 currentPixel; + u32 nextPixel; + u32 currentDelta; + u32 nextDelta; + + finish = (u8 *) bP + ((width+2) << 1); + nextPixel = *bP++; + nextDelta = *xP++; + + do { + currentPixel = nextPixel; + currentDelta = nextDelta; + nextPixel = *bP++; + nextDelta = *xP++; + + if ((nextPixel != nextDelta) || (currentPixel != currentDelta)) { + u32 colorA, colorB, product; + + *(xP - 2) = currentPixel; +#ifdef WORDS_BIGENDIAN + colorA = currentPixel >> 16; + colorB = currentPixel & 0xffff; +#else + colorA = currentPixel & 0xffff; + colorB = currentPixel >> 16; +#endif + product = (((colorA & colorMask) >> 1) & colorMask) >> 1; + +#ifdef WORDS_BIGENDIAN + *(nL) = (product << 16) | (product); + *(dP) = (colorA << 16) | product; +#else + *(nL) = product | (product << 16); + *(dP) = colorA | (product << 16); +#endif + +#ifdef WORDS_BIGENDIAN + colorA = nextPixel >> 16; +#else + colorA = nextPixel & 0xffff; +#endif + product = (((colorB & colorMask) >> 1) & colorMask) >> 1; +#ifdef WORDS_BIGENDIAN + *(nL + 1) = (product << 16) | (product); + *(dP + 1) = (colorB << 16) | (product); +#else + *(nL + 1) = (product) | (product << 16); + *(dP + 1) = (colorB) | (product << 16); +#endif + } + + dP += 2; + nL += 2; + } while ((u8 *) bP < finish); + + deltaPtr += srcPitch; + srcPtr += srcPitch; + dstPtr += dstPitch << 1; + nextLine += dstPitch << 1; + } + while (--height); +} + +void Pixelate32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, + u8 *dstPtr, u32 dstPitch, int width, int height) +{ + u8 *nextLine, *finish; + u32 colorMask = ~RGB_LOW_BITS_MASK; + + nextLine = dstPtr + dstPitch; + + do { + u32 *bP = (u32 *) srcPtr; + // u32 *xP = (u32 *) deltaPtr; + u32 *dP = (u32 *) dstPtr; + u32 *nL = (u32 *) nextLine; + u32 currentPixel; + u32 nextPixel; + + finish = (u8 *) bP + ((width+1) << 2); + nextPixel = *bP++; + + do { + currentPixel = nextPixel; + nextPixel = *bP++; + + u32 colorA, colorB, product; + + colorA = currentPixel; + colorB = nextPixel; + + product = (((colorA & colorMask) >> 1) & colorMask) >> 1; + *(nL) = product; + *(nL+1) = product; + *(dP) = colorA; + *(dP+1) = product; + + nextPixel = *bP++; + colorA = nextPixel; + product = (((colorB & colorMask) >> 1) & colorMask) >> 1; + *(nL + 2) = product; + *(nL + 3) = product; + *(dP + 2) = colorB; + *(dP + 3) = product; + + dP += 4; + nL += 4; + } while ((u8 *) bP < finish); + + srcPtr += srcPitch; + dstPtr += dstPitch << 1; + nextLine += dstPitch << 1; + } + while (--height); +} diff --git a/source/vba/simple2x.cpp b/source/vba/simple2x.cpp deleted file mode 100644 index 9297a5c..0000000 --- a/source/vba/simple2x.cpp +++ /dev/null @@ -1,112 +0,0 @@ -// 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. - -#include "System.h" - -void Simple2x(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, - u8 *dstPtr, u32 dstPitch, int width, int height) -{ - u8 *nextLine, *finish; - - nextLine = dstPtr + dstPitch; - - do - { - u32 *bP = (u32 *) srcPtr; - u32 *dP = (u32 *) dstPtr; - u32 *nL = (u32 *) nextLine; - u32 currentPixel; - - finish = (u8 *) bP + ((width+2) << 1); - currentPixel = *bP++; - - do - { -#ifdef WORDS_BIGENDIAN - u32 color = currentPixel >> 16; -#else - u32 color = currentPixel & 0xffff; -#endif - - color = color | (color << 16); - - *(dP) = color; - *(nL) = color; - -#ifdef WORDS_BIGENDIAN - color = currentPixel & 0xffff; -#else - color = currentPixel >> 16; -#endif - color = color| (color << 16); - *(dP + 1) = color; - *(nL + 1) = color; - - currentPixel = *bP++; - - dP += 2; - nL += 2; - } - while ((u8 *) bP < finish); - - srcPtr += srcPitch; - dstPtr += dstPitch << 1; - nextLine += dstPitch << 1; - } - while (--height); -} - -void Simple2x32(u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, - u8 *dstPtr, u32 dstPitch, int width, int height) -{ - u8 *nextLine, *finish; - - nextLine = dstPtr + dstPitch; - - do - { - u32 *bP = (u32 *) srcPtr; - u32 *dP = (u32 *) dstPtr; - u32 *nL = (u32 *) nextLine; - u32 currentPixel; - - finish = (u8 *) bP + ((width+1) << 2); - currentPixel = *bP++; - - do - { - u32 color = currentPixel; - - *(dP) = color; - *(dP+1) = color; - *(nL) = color; - *(nL + 1) = color; - - currentPixel = *bP++; - - dP += 2; - nL += 2; - } - while ((u8 *) bP < finish); - - srcPtr += srcPitch; - dstPtr += dstPitch << 1; - nextLine += dstPitch << 1; - } - while (--height); -} diff --git a/source/vba/thumb.h b/source/vba/thumb.h deleted file mode 100644 index d4b2830..0000000 --- a/source/vba/thumb.h +++ /dev/null @@ -1,2474 +0,0 @@ -// -*- 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. - -#ifdef C_CORE -#define NEG(i) ((i) >> 31) -#define POS(i) ((~(i)) >> 31) -#define ADDCARRY(a, b, c) \ - C_FLAG = ((NEG(a) & NEG(b)) |\ - (NEG(a) & POS(c)) |\ - (NEG(b) & POS(c))) ? true : false; -#define ADDOVERFLOW(a, b, c) \ - V_FLAG = ((NEG(a) & NEG(b) & POS(c)) |\ - (POS(a) & POS(b) & NEG(c))) ? true : false; -#define SUBCARRY(a, b, c) \ - C_FLAG = ((NEG(a) & POS(b)) |\ - (NEG(a) & POS(c)) |\ - (POS(b) & POS(c))) ? true : false; -#define SUBOVERFLOW(a, b, c)\ - V_FLAG = ((NEG(a) & POS(b) & POS(c)) |\ - (POS(a) & NEG(b) & NEG(c))) ? true : false; -#define ADD_RD_RS_RN \ - {\ - u32 lhs = reg[source].I;\ - u32 rhs = value;\ - u32 res = lhs + rhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } -#define ADD_RD_RS_O3 \ - {\ - u32 lhs = reg[source].I;\ - u32 rhs = value;\ - u32 res = lhs + rhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } -#define ADD_RN_O8(d) \ - {\ - u32 lhs = reg[(d)].I;\ - u32 rhs = (opcode & 255);\ - u32 res = lhs + rhs;\ - reg[(d)].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } -#define CMN_RD_RS \ - {\ - u32 lhs = reg[dest].I;\ - u32 rhs = value;\ - u32 res = lhs + rhs;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } -#define ADC_RD_RS \ - {\ - u32 lhs = reg[dest].I;\ - u32 rhs = value;\ - u32 res = lhs + rhs + (u32)C_FLAG;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - ADDCARRY(lhs, rhs, res);\ - ADDOVERFLOW(lhs, rhs, res);\ - } -#define SUB_RD_RS_RN \ - {\ - u32 lhs = reg[source].I;\ - u32 rhs = value;\ - u32 res = lhs - rhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#define SUB_RD_RS_O3 \ - {\ - u32 lhs = reg[source].I;\ - u32 rhs = value;\ - u32 res = lhs - rhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#define SUB_RN_O8(d) \ - {\ - u32 lhs = reg[(d)].I;\ - u32 rhs = (opcode & 255);\ - u32 res = lhs - rhs;\ - reg[(d)].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#define CMP_RN_O8(d) \ - {\ - u32 lhs = reg[(d)].I;\ - u32 rhs = (opcode & 255);\ - u32 res = lhs - rhs;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#define SBC_RD_RS \ - {\ - u32 lhs = reg[dest].I;\ - u32 rhs = value;\ - u32 res = lhs - rhs - !((u32)C_FLAG);\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#define LSL_RD_RM_I5 \ - {\ - C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false;\ - value = reg[source].I << shift;\ - } -#define LSL_RD_RS \ - {\ - C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false;\ - value = reg[dest].I << value;\ - } -#define LSR_RD_RM_I5 \ - {\ - C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false;\ - value = reg[source].I >> shift;\ - } -#define LSR_RD_RS \ - {\ - C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\ - value = reg[dest].I >> value;\ - } -#define ASR_RD_RM_I5 \ - {\ - C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false;\ - value = (s32)reg[source].I >> (int)shift;\ - } -#define ASR_RD_RS \ - {\ - C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false;\ - value = (s32)reg[dest].I >> (int)value;\ - } -#define ROR_RD_RS \ - {\ - C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\ - value = ((reg[dest].I << (32 - value)) |\ - (reg[dest].I >> value));\ - } -#define NEG_RD_RS \ - {\ - u32 lhs = reg[source].I;\ - u32 rhs = 0;\ - u32 res = rhs - lhs;\ - reg[dest].I = res;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(rhs, lhs, res);\ - SUBOVERFLOW(rhs, lhs, res);\ - } -#define CMP_RD_RS \ - {\ - u32 lhs = reg[dest].I;\ - u32 rhs = value;\ - u32 res = lhs - rhs;\ - Z_FLAG = (res == 0) ? true : false;\ - N_FLAG = NEG(res) ? true : false;\ - SUBCARRY(lhs, rhs, res);\ - SUBOVERFLOW(lhs, rhs, res);\ - } -#else -#ifdef __GNUC__ -#ifdef __POWERPC__ - #define ADD_RD_RS_RN \ - { \ - register int Flags; \ - register int Result; \ - asm volatile("addco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[source].I), \ - "r" (value) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define ADD_RD_RS_O3 ADD_RD_RS_RN - #define ADD_RN_O8(d) \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("addco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[(d)].I), \ - "r" (opcode & 255) \ - ); \ - reg[(d)].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define CMN_RD_RS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("addco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[dest].I), \ - "r" (value) \ - ); \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define ADC_RD_RS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("mtspr xer, %4\n" \ - "addeo. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[dest].I), \ - "r" (value), \ - "r" (C_FLAG << 29) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define SUB_RD_RS_RN \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[source].I), \ - "r" (value) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define SUB_RD_RS_O3 SUB_RD_RS_RN - #define SUB_RN_O8(d) \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[(d)].I), \ - "r" (opcode & 255) \ - ); \ - reg[(d)].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define CMP_RN_O8(d) \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[(d)].I), \ - "r" (opcode & 255) \ - ); \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define SBC_RD_RS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("mtspr xer, %4\n" \ - "subfeo. %0, %3, %2\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[dest].I), \ - "r" (value), \ - "r" (C_FLAG << 29) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define LSL_RD_RM_I5 \ - {\ - C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false;\ - value = reg[source].I << shift;\ - } - #define LSL_RD_RS \ - {\ - C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false;\ - value = reg[dest].I << value;\ - } - #define LSR_RD_RM_I5 \ - {\ - C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false;\ - value = reg[source].I >> shift;\ - } - #define LSR_RD_RS \ - {\ - C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\ - value = reg[dest].I >> value;\ - } - #define ASR_RD_RM_I5 \ - {\ - C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false;\ - value = (s32)reg[source].I >> (int)shift;\ - } - #define ASR_RD_RS \ - {\ - C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false;\ - value = (s32)reg[dest].I >> (int)value;\ - } - #define ROR_RD_RS \ - {\ - C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\ - value = ((reg[dest].I << (32 - value)) |\ - (reg[dest].I >> value));\ - } - #define NEG_RD_RS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subfco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[source].I), \ - "r" (0) \ - ); \ - reg[dest].I = Result; \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } - #define CMP_RD_RS \ - {\ - register int Flags; \ - register int Result; \ - asm volatile("subco. %0, %2, %3\n" \ - "mcrxr cr1\n" \ - "mfcr %1\n" \ - : "=r" (Result), \ - "=r" (Flags) \ - : "r" (reg[dest].I), \ - "r" (value) \ - ); \ - Z_FLAG = (Flags >> 29) & 1; \ - N_FLAG = (Flags >> 31) & 1; \ - C_FLAG = (Flags >> 25) & 1; \ - V_FLAG = (Flags >> 26) & 1; \ - } -#else -#define ADD_RD_RS_RN \ - asm ("add %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setcb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[source].I)); -#define ADD_RD_RS_O3 \ - asm ("add %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setcb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[source].I)); -#define ADD_RN_O8(d) \ - asm ("add %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setcb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[(d)].I)\ - : "r" (opcode & 255), "b" (reg[(d)].I)); -#define CMN_RD_RS \ - asm ("add %0, %1;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setcb C_FLAG;"\ - "setob V_FLAG;"\ - : \ - : "r" (value), "r" (reg[dest].I):"1"); -#define ADC_RD_RS \ - asm ("bt $0, C_FLAG;"\ - "adc %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setcb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[dest].I)); -#define SUB_RD_RS_RN \ - asm ("sub %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setncb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[source].I)); -#define SUB_RD_RS_O3 \ - asm ("sub %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setncb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[source].I)); -#define SUB_RN_O8(d) \ - asm ("sub %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setncb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[(d)].I)\ - : "r" (opcode & 255), "b" (reg[(d)].I)); -#define CMP_RN_O8(d) \ - asm ("sub %0, %1;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setncb C_FLAG;"\ - "setob V_FLAG;"\ - : \ - : "r" (opcode & 255), "r" (reg[(d)].I) : "1"); -#define SBC_RD_RS \ - asm volatile ("bt $0, C_FLAG;"\ - "cmc;"\ - "sbb %1, %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setncb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "r" (value), "b" (reg[dest].I) : "cc", "memory"); -#define LSL_RD_RM_I5 \ - asm ("shl %%cl, %%eax;"\ - "setcb C_FLAG;"\ - : "=a" (value)\ - : "a" (reg[source].I), "c" (shift)); -#define LSL_RD_RS \ - asm ("shl %%cl, %%eax;"\ - "setcb C_FLAG;"\ - : "=a" (value)\ - : "a" (reg[dest].I), "c" (value)); -#define LSR_RD_RM_I5 \ - asm ("shr %%cl, %%eax;"\ - "setcb C_FLAG;"\ - : "=a" (value)\ - : "a" (reg[source].I), "c" (shift)); -#define LSR_RD_RS \ - asm ("shr %%cl, %%eax;"\ - "setcb C_FLAG;"\ - : "=a" (value)\ - : "a" (reg[dest].I), "c" (value)); -#define ASR_RD_RM_I5 \ - asm ("sar %%cl, %%eax;"\ - "setcb C_FLAG;"\ - : "=a" (value)\ - : "a" (reg[source].I), "c" (shift)); -#define ASR_RD_RS \ - asm ("sar %%cl, %%eax;"\ - "setcb C_FLAG;"\ - : "=a" (value)\ - : "a" (reg[dest].I), "c" (value)); -#define ROR_RD_RS \ - asm ("ror %%cl, %%eax;"\ - "setcb C_FLAG;"\ - : "=a" (value)\ - : "a" (reg[dest].I), "c" (value)); -#define NEG_RD_RS \ - asm ("neg %%ebx;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setncb C_FLAG;"\ - "setob V_FLAG;"\ - : "=b" (reg[dest].I)\ - : "b" (reg[source].I)); -#define CMP_RD_RS \ - asm ("sub %0, %1;"\ - "setsb N_FLAG;"\ - "setzb Z_FLAG;"\ - "setncb C_FLAG;"\ - "setob V_FLAG;"\ - : \ - : "r" (value), "r" (reg[dest].I):"1"); -#endif -#else -#define ADD_RD_RS_RN \ - {\ - __asm mov eax, source\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm add ebx, value\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define ADD_RD_RS_O3 \ - {\ - __asm mov eax, source\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm add ebx, value\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define ADD_RN_O8(d) \ - {\ - __asm mov ebx, opcode\ - __asm and ebx, 255\ - __asm add dword ptr [OFFSET reg+4*(d)], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define CMN_RD_RS \ - {\ - __asm mov eax, dest\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm add ebx, value\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define ADC_RD_RS \ - {\ - __asm mov ebx, dest\ - __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ - __asm bt word ptr C_FLAG, 0\ - __asm adc ebx, value\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define SUB_RD_RS_RN \ - {\ - __asm mov eax, source\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm sub ebx, value\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define SUB_RD_RS_O3 \ - {\ - __asm mov eax, source\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm sub ebx, value\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define SUB_RN_O8(d) \ - {\ - __asm mov ebx, opcode\ - __asm and ebx, 255\ - __asm sub dword ptr [OFFSET reg + 4*(d)], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define CMP_RN_O8(d) \ - {\ - __asm mov eax, dword ptr [OFFSET reg+4*(d)]\ - __asm mov ebx, opcode\ - __asm and ebx, 255\ - __asm sub eax, ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define SBC_RD_RS \ - {\ - __asm mov ebx, dest\ - __asm mov ebx, dword ptr [OFFSET reg + 4*ebx]\ - __asm mov eax, value\ - __asm bt word ptr C_FLAG, 0\ - __asm cmc\ - __asm sbb ebx, eax\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg + 4*eax], ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define LSL_RD_RM_I5 \ - {\ - __asm mov eax, source\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr shift\ - __asm shl eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } -#define LSL_RD_RS \ - {\ - __asm mov eax, dest\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr value\ - __asm shl eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } -#define LSR_RD_RM_I5 \ - {\ - __asm mov eax, source\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr shift\ - __asm shr eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } -#define LSR_RD_RS \ - {\ - __asm mov eax, dest\ - __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\ - __asm mov cl, byte ptr value\ - __asm shr eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } -#define ASR_RD_RM_I5 \ - {\ - __asm mov eax, source\ - __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ - __asm mov cl, byte ptr shift\ - __asm sar eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } -#define ASR_RD_RS \ - {\ - __asm mov eax, dest\ - __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ - __asm mov cl, byte ptr value\ - __asm sar eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } -#define ROR_RD_RS \ - {\ - __asm mov eax, dest\ - __asm mov eax, dword ptr [OFFSET reg + 4*eax]\ - __asm mov cl, byte ptr value\ - __asm ror eax, cl\ - __asm mov value, eax\ - __asm setc byte ptr C_FLAG\ - } -#define NEG_RD_RS \ - {\ - __asm mov ebx, source\ - __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\ - __asm neg ebx\ - __asm mov eax, dest\ - __asm mov dword ptr [OFFSET reg+4*eax],ebx\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#define CMP_RD_RS \ - {\ - __asm mov eax, dest\ - __asm mov ebx, dword ptr [OFFSET reg+4*eax]\ - __asm sub ebx, value\ - __asm sets byte ptr N_FLAG\ - __asm setz byte ptr Z_FLAG\ - __asm setnc byte ptr C_FLAG\ - __asm seto byte ptr V_FLAG\ - } -#endif -#endif - -u32 opcode = CPUReadHalfWordQuick(armNextPC); -clockTicks = thumbCycles[opcode >> 8] + memoryWaitFetch[(armNextPC >> 24) & 15]; -#ifndef FINAL_VERSION -if(armNextPC == stop) { - armNextPC = armNextPC++; -} -#endif - -armNextPC = reg[15].I; -reg[15].I += 2; - -switch(opcode >> 8) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - { - // LSL Rd, Rm, #Imm 5 - int dest = opcode & 0x07; - int source = (opcode >> 3) & 0x07; - int shift = (opcode >> 6) & 0x1f; - u32 value; - - if(shift) { - LSL_RD_RM_I5; - } else { - value = reg[source].I; - } - reg[dest].I = value; - // C_FLAG set above - N_FLAG = (value & 0x80000000 ? true : false); - Z_FLAG = (value ? false : true); - } - break; - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - { - // LSR Rd, Rm, #Imm 5 - int dest = opcode & 0x07; - int source = (opcode >> 3) & 0x07; - int shift = (opcode >> 6) & 0x1f; - u32 value; - - if(shift) { - LSR_RD_RM_I5; - } else { - C_FLAG = reg[source].I & 0x80000000 ? true : false; - value = 0; - } - reg[dest].I = value; - // C_FLAG set above - N_FLAG = (value & 0x80000000 ? true : false); - Z_FLAG = (value ? false : true); - } - break; - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - { - // ASR Rd, Rm, #Imm 5 - int dest = opcode & 0x07; - int source = (opcode >> 3) & 0x07; - int shift = (opcode >> 6) & 0x1f; - u32 value; - - if(shift) { - ASR_RD_RM_I5; - } else { - if(reg[source].I & 0x80000000) { - value = 0xFFFFFFFF; - C_FLAG = true; - } else { - value = 0; - C_FLAG = false; - } - } - reg[dest].I = value; - // C_FLAG set above - N_FLAG = (value & 0x80000000 ? true : false); - Z_FLAG = (value ? false :true); - } - break; - case 0x18: - case 0x19: - { - // ADD Rd, Rs, Rn - int dest = opcode & 0x07; - int source = (opcode >> 3) & 0x07; - u32 value = reg[(opcode>>6)& 0x07].I; - ADD_RD_RS_RN; - } - break; - case 0x1a: - case 0x1b: - { - // SUB Rd, Rs, Rn - int dest = opcode & 0x07; - int source = (opcode >> 3) & 0x07; - u32 value = reg[(opcode>>6)& 0x07].I; - SUB_RD_RS_RN; - } - break; - case 0x1c: - case 0x1d: - { - // ADD Rd, Rs, #Offset3 - int dest = opcode & 0x07; - int source = (opcode >> 3) & 0x07; - u32 value = (opcode >> 6) & 7; - ADD_RD_RS_O3; - } - break; - case 0x1e: - case 0x1f: - { - // SUB Rd, Rs, #Offset3 - int dest = opcode & 0x07; - int source = (opcode >> 3) & 0x07; - u32 value = (opcode >> 6) & 7; - SUB_RD_RS_O3; - } - break; - case 0x20: - // MOV R0, #Offset8 - reg[0].I = opcode & 255; - N_FLAG = false; - Z_FLAG = (reg[0].I ? false : true); - break; - case 0x21: - // MOV R1, #Offset8 - reg[1].I = opcode & 255; - N_FLAG = false; - Z_FLAG = (reg[1].I ? false : true); - break; - case 0x22: - // MOV R2, #Offset8 - reg[2].I = opcode & 255; - N_FLAG = false; - Z_FLAG = (reg[2].I ? false : true); - break; - case 0x23: - // MOV R3, #Offset8 - reg[3].I = opcode & 255; - N_FLAG = false; - Z_FLAG = (reg[3].I ? false : true); - break; - case 0x24: - // MOV R4, #Offset8 - reg[4].I = opcode & 255; - N_FLAG = false; - Z_FLAG = (reg[4].I ? false : true); - break; - case 0x25: - // MOV R5, #Offset8 - reg[5].I = opcode & 255; - N_FLAG = false; - Z_FLAG = (reg[5].I ? false : true); - break; - case 0x26: - // MOV R6, #Offset8 - reg[6].I = opcode & 255; - N_FLAG = false; - Z_FLAG = (reg[6].I ? false : true); - break; - case 0x27: - // MOV R7, #Offset8 - reg[7].I = opcode & 255; - N_FLAG = false; - Z_FLAG = (reg[7].I ? false : true); - break; - case 0x28: - // CMP R0, #Offset8 - CMP_RN_O8(0); - break; - case 0x29: - // CMP R1, #Offset8 - CMP_RN_O8(1); - break; - case 0x2a: - // CMP R2, #Offset8 - CMP_RN_O8(2); - break; - case 0x2b: - // CMP R3, #Offset8 - CMP_RN_O8(3); - break; - case 0x2c: - // CMP R4, #Offset8 - CMP_RN_O8(4); - break; - case 0x2d: - // CMP R5, #Offset8 - CMP_RN_O8(5); - break; - case 0x2e: - // CMP R6, #Offset8 - CMP_RN_O8(6); - break; - case 0x2f: - // CMP R7, #Offset8 - CMP_RN_O8(7); - break; - case 0x30: - // ADD R0,#Offset8 - ADD_RN_O8(0); - break; - case 0x31: - // ADD R1,#Offset8 - ADD_RN_O8(1); - break; - case 0x32: - // ADD R2,#Offset8 - ADD_RN_O8(2); - break; - case 0x33: - // ADD R3,#Offset8 - ADD_RN_O8(3); - break; - case 0x34: - // ADD R4,#Offset8 - ADD_RN_O8(4); - break; - case 0x35: - // ADD R5,#Offset8 - ADD_RN_O8(5); - break; - case 0x36: - // ADD R6,#Offset8 - ADD_RN_O8(6); - break; - case 0x37: - // ADD R7,#Offset8 - ADD_RN_O8(7); - break; - case 0x38: - // SUB R0,#Offset8 - SUB_RN_O8(0); - break; - case 0x39: - // SUB R1,#Offset8 - SUB_RN_O8(1); - break; - case 0x3a: - // SUB R2,#Offset8 - SUB_RN_O8(2); - break; - case 0x3b: - // SUB R3,#Offset8 - SUB_RN_O8(3); - break; - case 0x3c: - // SUB R4,#Offset8 - SUB_RN_O8(4); - break; - case 0x3d: - // SUB R5,#Offset8 - SUB_RN_O8(5); - break; - case 0x3e: - // SUB R6,#Offset8 - SUB_RN_O8(6); - break; - case 0x3f: - // SUB R7,#Offset8 - SUB_RN_O8(7); - break; - case 0x40: - switch((opcode >> 6) & 3) { - case 0x00: - { - // AND Rd, Rs - int dest = opcode & 7; - reg[dest].I &= reg[(opcode >> 3)&7].I; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = reg[dest].I ? false : true; -#ifdef BKPT_SUPPORT -#define THUMB_CONSOLE_OUTPUT(a,b) \ - if((opcode == 0x4000) && (reg[0].I == 0xC0DED00D)) {\ - extern void (*dbgOutput)(char *, u32);\ - dbgOutput((a), (b));\ - } -#else -#define THUMB_CONSOLE_OUTPUT(a,b) -#endif - THUMB_CONSOLE_OUTPUT(NULL, reg[2].I); - } - break; - case 0x01: - // EOR Rd, Rs - { - int dest = opcode & 7; - reg[dest].I ^= reg[(opcode >> 3)&7].I; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = reg[dest].I ? false : true; - } - break; - case 0x02: - // LSL Rd, Rs - { - int dest = opcode & 7; - u32 value = reg[(opcode >> 3)&7].B.B0; - if(value) { - if(value == 32) { - value = 0; - C_FLAG = (reg[dest].I & 1 ? true : false); - } else if(value < 32) { - LSL_RD_RS; - } else { - value = 0; - C_FLAG = false; - } - reg[dest].I = value; - } - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = reg[dest].I ? false : true; - clockTicks++; - } - break; - case 0x03: - { - // LSR Rd, Rs - int dest = opcode & 7; - u32 value = reg[(opcode >> 3)&7].B.B0; - if(value) { - if(value == 32) { - value = 0; - C_FLAG = (reg[dest].I & 0x80000000 ? true : false); - } else if(value < 32) { - LSR_RD_RS; - } else { - value = 0; - C_FLAG = false; - } - reg[dest].I = value; - } - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = reg[dest].I ? false : true; - clockTicks++; - } - break; - } - break; - case 0x41: - switch((opcode >> 6) & 3) { - case 0x00: - { - // ASR Rd, Rs - int dest = opcode & 7; - u32 value = reg[(opcode >> 3)&7].B.B0; - // ASR - if(value) { - if(value < 32) { - ASR_RD_RS; - reg[dest].I = value; - } else { - if(reg[dest].I & 0x80000000){ - reg[dest].I = 0xFFFFFFFF; - C_FLAG = true; - } else { - reg[dest].I = 0x00000000; - C_FLAG = false; - } - } - } - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = reg[dest].I ? false : true; - clockTicks++; - } - break; - case 0x01: - { - // ADC Rd, Rs - int dest = opcode & 0x07; - u32 value = reg[(opcode >> 3)&7].I; - // ADC - ADC_RD_RS; - } - break; - case 0x02: - { - // SBC Rd, Rs - int dest = opcode & 0x07; - u32 value = reg[(opcode >> 3)&7].I; - - // SBC - SBC_RD_RS; - } - break; - case 0x03: - // ROR Rd, Rs - { - int dest = opcode & 7; - u32 value = reg[(opcode >> 3)&7].B.B0; - - if(value) { - value = value & 0x1f; - if(value == 0) { - C_FLAG = (reg[dest].I & 0x80000000 ? true : false); - } else { - ROR_RD_RS; - reg[dest].I = value; - } - } - clockTicks++; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - Z_FLAG = reg[dest].I ? false : true; - } - break; - } - break; - case 0x42: - switch((opcode >> 6) & 3) { - case 0x00: - { - // TST Rd, Rs - u32 value = reg[opcode & 7].I & reg[(opcode >> 3) & 7].I; - N_FLAG = value & 0x80000000 ? true : false; - Z_FLAG = value ? false : true; - } - break; - case 0x01: - { - // NEG Rd, Rs - int dest = opcode & 7; - int source = (opcode >> 3) & 7; - NEG_RD_RS; - } - break; - case 0x02: - { - // CMP Rd, Rs - int dest = opcode & 7; - u32 value = reg[(opcode >> 3)&7].I; - CMP_RD_RS; - } - break; - case 0x03: - { - // CMN Rd, Rs - int dest = opcode & 7; - u32 value = reg[(opcode >> 3)&7].I; - // CMN - CMN_RD_RS; - } - break; - } - break; - case 0x43: - switch((opcode >> 6) & 3) { - case 0x00: - { - // ORR Rd, Rs - int dest = opcode & 7; - reg[dest].I |= reg[(opcode >> 3) & 7].I; - Z_FLAG = reg[dest].I ? false : true; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - } - break; - case 0x01: - { - // MUL Rd, Rs - int dest = opcode & 7; - u32 rm = reg[(opcode >> 3) & 7].I; - reg[dest].I = reg[dest].I * rm; - if (((s32)rm) < 0) - rm = ~rm; - if ((rm & 0xFFFFFF00) == 0) - clockTicks += 1; - else if ((rm & 0xFFFF0000) == 0) - clockTicks += 2; - else if ((rm & 0xFF000000) == 0) - clockTicks += 3; - else - clockTicks += 4; - Z_FLAG = reg[dest].I ? false : true; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - } - break; - case 0x02: - { - // BIC Rd, Rs - int dest = opcode & 7; - reg[dest].I &= (~reg[(opcode >> 3) & 7].I); - Z_FLAG = reg[dest].I ? false : true; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - } - break; - case 0x03: - { - // MVN Rd, Rs - int dest = opcode & 7; - reg[dest].I = ~reg[(opcode >> 3) & 7].I; - Z_FLAG = reg[dest].I ? false : true; - N_FLAG = reg[dest].I & 0x80000000 ? true : false; - } - break; - } - break; - case 0x44: - { - int dest = opcode & 7; - int base = (opcode >> 3) & 7; - switch((opcode >> 6)& 3) { - default: - goto unknown_thumb; - case 1: - // ADD Rd, Hs - reg[dest].I += reg[base+8].I; - break; - case 2: - // ADD Hd, Rs - reg[dest+8].I += reg[base].I; - if(dest == 7) { - reg[15].I &= 0xFFFFFFFE; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks++; - } - break; - case 3: - // ADD Hd, Hs - reg[dest+8].I += reg[base+8].I; - if(dest == 7) { - reg[15].I &= 0xFFFFFFFE; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks++; - } - break; - } - } - break; - case 0x45: - { - int dest = opcode & 7; - int base = (opcode >> 3) & 7; - u32 value; - switch((opcode >> 6) & 3) { - case 0: - // CMP Rd, Hs - value = reg[base].I; - CMP_RD_RS; - break; - case 1: - // CMP Rd, Hs - value = reg[base+8].I; - CMP_RD_RS; - break; - case 2: - // CMP Hd, Rs - value = reg[base].I; - dest += 8; - CMP_RD_RS; - break; - case 3: - // CMP Hd, Hs - value = reg[base+8].I; - dest += 8; - CMP_RD_RS; - break; - } - } - break; - case 0x46: - { - int dest = opcode & 7; - int base = (opcode >> 3) & 7; - switch((opcode >> 6) & 3) { - case 0: - // this form should not be used... - // MOV Rd, Rs - reg[dest].I = reg[base].I; - break; - case 1: - // MOV Rd, Hs - reg[dest].I = reg[base+8].I; - break; - case 2: - // MOV Hd, Rs - reg[dest+8].I = reg[base].I; - if(dest == 7) { - reg[15].I &= 0xFFFFFFFE; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks++; - } - break; - case 3: - // MOV Hd, Hs - reg[dest+8].I = reg[base+8].I; - if(dest == 7) { - reg[15].I &= 0xFFFFFFFE; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks++; - } - break; - } - } - break; - case 0x47: - { - int base = (opcode >> 3) & 7; - switch((opcode >>6) & 3) { - case 0: - // BX Rs - reg[15].I = (reg[base].I) & 0xFFFFFFFE; - if(reg[base].I & 1) { - armState = false; - armNextPC = reg[15].I; - reg[15].I += 2; - } else { - armState = true; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - break; - case 1: - // BX Hs - reg[15].I = (reg[8+base].I) & 0xFFFFFFFE; - if(reg[8+base].I & 1) { - armState = false; - armNextPC = reg[15].I; - reg[15].I += 2; - } else { - armState = true; - reg[15].I &= 0xFFFFFFFC; - armNextPC = reg[15].I; - reg[15].I += 4; - } - break; - default: - goto unknown_thumb; - } - } - break; - case 0x48: - // LDR R0,[PC, #Imm] - { - u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); - reg[0].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x49: - // LDR R1,[PC, #Imm] - { - u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); - reg[1].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x4a: - // LDR R2,[PC, #Imm] - { - u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); - reg[2].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x4b: - // LDR R3,[PC, #Imm] - { - u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); - reg[3].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x4c: - // LDR R4,[PC, #Imm] - { - u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); - reg[4].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x4d: - // LDR R5,[PC, #Imm] - { - u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); - reg[5].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x4e: - // LDR R6,[PC, #Imm] - { - u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); - reg[6].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x4f: - // LDR R7,[PC, #Imm] - { - u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); - reg[7].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x50: - case 0x51: - // STR Rd, [Rs, Rn] - { - u32 - address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - CPUWriteMemory(address, - reg[opcode & 7].I); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x52: - case 0x53: - // STRH Rd, [Rs, Rn] - { - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - CPUWriteHalfWord(address, - reg[opcode&7].W.W0); - clockTicks += CPUUpdateTicksAccess16(address); - } - break; - case 0x54: - case 0x55: - // STRB Rd, [Rs, Rn] - { - u32 address = reg[(opcode>>3)&7].I + reg[(opcode >>6)&7].I; - CPUWriteByte(address, - reg[opcode & 7].B.B0); - clockTicks += CPUUpdateTicksAccess16(address); - } - break; - case 0x56: - case 0x57: - // LDSB Rd, [Rs, Rn] - { - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - reg[opcode&7].I = (s8)CPUReadByte(address); - clockTicks += CPUUpdateTicksAccess16(address); - } - break; - case 0x58: - case 0x59: - // LDR Rd, [Rs, Rn] - { - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - reg[opcode&7].I = CPUReadMemory(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x5a: - case 0x5b: - // LDRH Rd, [Rs, Rn] - { - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - reg[opcode&7].I = CPUReadHalfWord(address); - clockTicks += CPUUpdateTicksAccess16(address); - } - break; - case 0x5c: - case 0x5d: - // LDRB Rd, [Rs, Rn] - { - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - reg[opcode&7].I = CPUReadByte(address); - clockTicks += CPUUpdateTicksAccess16(address); - } - break; - case 0x5e: - case 0x5f: - // LDSH Rd, [Rs, Rn] - { - u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; - reg[opcode&7].I = (s16)CPUReadHalfWordSigned(address); - clockTicks += CPUUpdateTicksAccess16(address); - } - break; - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - // STR Rd, [Rs, #Imm] - { - u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2); - CPUWriteMemory(address, - reg[opcode&7].I); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x68: - case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: - // LDR Rd, [Rs, #Imm] - { - u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2); - reg[opcode&7].I = CPUReadMemory(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - // STRB Rd, [Rs, #Imm] - { - u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)); - CPUWriteByte(address, - reg[opcode&7].B.B0); - clockTicks += CPUUpdateTicksAccess16(address); - } - break; - case 0x78: - case 0x79: - case 0x7a: - case 0x7b: - case 0x7c: - case 0x7d: - case 0x7e: - case 0x7f: - // LDRB Rd, [Rs, #Imm] - { - u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)); - reg[opcode&7].I = CPUReadByte(address); - clockTicks += CPUUpdateTicksAccess16(address); - } - break; - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - // STRH Rd, [Rs, #Imm] - { - u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1); - CPUWriteHalfWord(address, - reg[opcode&7].W.W0); - clockTicks += CPUUpdateTicksAccess16(address); - } - break; - case 0x88: - case 0x89: - case 0x8a: - case 0x8b: - case 0x8c: - case 0x8d: - case 0x8e: - case 0x8f: - // LDRH Rd, [Rs, #Imm] - { - u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1); - reg[opcode&7].I = CPUReadHalfWord(address); - clockTicks += CPUUpdateTicksAccess16(address); - } - break; - case 0x90: - // STR R0, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - CPUWriteMemory(address, reg[0].I); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x91: - // STR R1, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - CPUWriteMemory(address, reg[1].I); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x92: - // STR R2, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - CPUWriteMemory(address, reg[2].I); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x93: - // STR R3, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - CPUWriteMemory(address, reg[3].I); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x94: - // STR R4, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - CPUWriteMemory(address, reg[4].I); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x95: - // STR R5, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - CPUWriteMemory(address, reg[5].I); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x96: - // STR R6, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - CPUWriteMemory(address, reg[6].I); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x97: - // STR R7, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - CPUWriteMemory(address, reg[7].I); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x98: - // LDR R0, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - reg[0].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x99: - // LDR R1, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - reg[1].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x9a: - // LDR R2, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - reg[2].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x9b: - // LDR R3, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - reg[3].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x9c: - // LDR R4, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - reg[4].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x9d: - // LDR R5, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - reg[5].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x9e: - // LDR R6, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - reg[6].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0x9f: - // LDR R7, [SP, #Imm] - { - u32 address = reg[13].I + ((opcode&255)<<2); - reg[7].I = CPUReadMemoryQuick(address); - clockTicks += CPUUpdateTicksAccess32(address); - } - break; - case 0xa0: - // ADD R0, PC, Imm - reg[0].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); - break; - case 0xa1: - // ADD R1, PC, Imm - reg[1].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); - break; - case 0xa2: - // ADD R2, PC, Imm - reg[2].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); - break; - case 0xa3: - // ADD R3, PC, Imm - reg[3].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); - break; - case 0xa4: - // ADD R4, PC, Imm - reg[4].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); - break; - case 0xa5: - // ADD R5, PC, Imm - reg[5].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); - break; - case 0xa6: - // ADD R6, PC, Imm - reg[6].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); - break; - case 0xa7: - // ADD R7, PC, Imm - reg[7].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); - break; - case 0xa8: - // ADD R0, SP, Imm - reg[0].I = reg[13].I + ((opcode&255)<<2); - break; - case 0xa9: - // ADD R1, SP, Imm - reg[1].I = reg[13].I + ((opcode&255)<<2); - break; - case 0xaa: - // ADD R2, SP, Imm - reg[2].I = reg[13].I + ((opcode&255)<<2); - break; - case 0xab: - // ADD R3, SP, Imm - reg[3].I = reg[13].I + ((opcode&255)<<2); - break; - case 0xac: - // ADD R4, SP, Imm - reg[4].I = reg[13].I + ((opcode&255)<<2); - break; - case 0xad: - // ADD R5, SP, Imm - reg[5].I = reg[13].I + ((opcode&255)<<2); - break; - case 0xae: - // ADD R6, SP, Imm - reg[6].I = reg[13].I + ((opcode&255)<<2); - break; - case 0xaf: - // ADD R7, SP, Imm - reg[7].I = reg[13].I + ((opcode&255)<<2); - break; - case 0xb0: - { - // ADD SP, Imm - int offset = (opcode & 127) << 2; - if(opcode & 0x80) - offset = -offset; - reg[13].I += offset; - } - break; -#define PUSH_REG(val, r) \ - if(opcode & (val)) {\ - CPUWriteMemory(address, reg[(r)].I);\ - if(offset)\ - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);\ - else\ - clockTicks += 1 + CPUUpdateTicksAccess32(address);\ - offset = 1;\ - address += 4;\ - } - case 0xb4: - // PUSH {Rlist} - { - int offset = 0; - u32 temp = reg[13].I - 4 * cpuBitsSet[opcode & 0xff]; - u32 address = temp & 0xFFFFFFFC; - PUSH_REG(1, 0); - PUSH_REG(2, 1); - PUSH_REG(4, 2); - PUSH_REG(8, 3); - PUSH_REG(16, 4); - PUSH_REG(32, 5); - PUSH_REG(64, 6); - PUSH_REG(128, 7); - reg[13].I = temp; - } - break; - case 0xb5: - // PUSH {Rlist, LR} - { - int offset = 0; - u32 temp = reg[13].I - 4 - 4 * cpuBitsSet[opcode & 0xff]; - u32 address = temp & 0xFFFFFFFC; - PUSH_REG(1, 0); - PUSH_REG(2, 1); - PUSH_REG(4, 2); - PUSH_REG(8, 3); - PUSH_REG(16, 4); - PUSH_REG(32, 5); - PUSH_REG(64, 6); - PUSH_REG(128, 7); - PUSH_REG(256, 14); - reg[13].I = temp; - } - break; -#define POP_REG(val, r) \ - if(opcode & (val)) {\ - reg[(r)].I = CPUReadMemory(address);\ - if(offset)\ - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);\ - else\ - clockTicks += 2 + CPUUpdateTicksAccess32(address);\ - offset = 1;\ - address += 4;\ - } - case 0xbc: - // POP {Rlist} - { - int offset = 0; - u32 address = reg[13].I & 0xFFFFFFFC; - u32 temp = reg[13].I + 4*cpuBitsSet[opcode & 0xFF]; - POP_REG(1, 0); - POP_REG(2, 1); - POP_REG(4, 2); - POP_REG(8, 3); - POP_REG(16, 4); - POP_REG(32, 5); - POP_REG(64, 6); - POP_REG(128, 7); - reg[13].I = temp; - } - break; - case 0xbd: - // POP {Rlist, PC} - { - int offset = 0; - u32 address = reg[13].I & 0xFFFFFFFC; - u32 temp = reg[13].I + 4 + 4*cpuBitsSet[opcode & 0xFF]; - POP_REG(1, 0); - POP_REG(2, 1); - POP_REG(4, 2); - POP_REG(8, 3); - POP_REG(16, 4); - POP_REG(32, 5); - POP_REG(64, 6); - POP_REG(128, 7); - reg[15].I = (CPUReadMemory(address) & 0xFFFFFFFE); - if(offset) - clockTicks += CPUUpdateTicksAccessSeq32(address); - else - clockTicks += CPUUpdateTicksAccess32(address); - armNextPC = reg[15].I; - reg[15].I += 2; - reg[13].I = temp; - } - break; -#define THUMB_STM_REG(val,r,b) \ - if(opcode & (val)) {\ - CPUWriteMemory(address, reg[(r)].I);\ - if(!offset) {\ - reg[(b)].I = temp;\ - clockTicks += 1 + CPUUpdateTicksAccess32(address);\ - } else \ - clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);\ - offset = 1;\ - address += 4;\ - } - case 0xc0: - { - // STM R0!, {Rlist} - u32 address = reg[0].I & 0xFFFFFFFC; - u32 temp = reg[0].I + 4*cpuBitsSet[opcode & 0xff]; - int offset = 0; - // store - THUMB_STM_REG(1, 0, 0); - THUMB_STM_REG(2, 1, 0); - THUMB_STM_REG(4, 2, 0); - THUMB_STM_REG(8, 3, 0); - THUMB_STM_REG(16, 4, 0); - THUMB_STM_REG(32, 5, 0); - THUMB_STM_REG(64, 6, 0); - THUMB_STM_REG(128, 7, 0); - } - break; - case 0xc1: - { - // STM R1!, {Rlist} - u32 address = reg[1].I & 0xFFFFFFFC; - u32 temp = reg[1].I + 4*cpuBitsSet[opcode & 0xff]; - int offset = 0; - // store - THUMB_STM_REG(1, 0, 1); - THUMB_STM_REG(2, 1, 1); - THUMB_STM_REG(4, 2, 1); - THUMB_STM_REG(8, 3, 1); - THUMB_STM_REG(16, 4, 1); - THUMB_STM_REG(32, 5, 1); - THUMB_STM_REG(64, 6, 1); - THUMB_STM_REG(128, 7, 1); - } - break; - case 0xc2: - { - // STM R2!, {Rlist} - u32 address = reg[2].I & 0xFFFFFFFC; - u32 temp = reg[2].I + 4*cpuBitsSet[opcode & 0xff]; - int offset = 0; - // store - THUMB_STM_REG(1, 0, 2); - THUMB_STM_REG(2, 1, 2); - THUMB_STM_REG(4, 2, 2); - THUMB_STM_REG(8, 3, 2); - THUMB_STM_REG(16, 4, 2); - THUMB_STM_REG(32, 5, 2); - THUMB_STM_REG(64, 6, 2); - THUMB_STM_REG(128, 7, 2); - } - break; - case 0xc3: - { - // STM R3!, {Rlist} - u32 address = reg[3].I & 0xFFFFFFFC; - u32 temp = reg[3].I + 4*cpuBitsSet[opcode & 0xff]; - int offset = 0; - // store - THUMB_STM_REG(1, 0, 3); - THUMB_STM_REG(2, 1, 3); - THUMB_STM_REG(4, 2, 3); - THUMB_STM_REG(8, 3, 3); - THUMB_STM_REG(16, 4, 3); - THUMB_STM_REG(32, 5, 3); - THUMB_STM_REG(64, 6, 3); - THUMB_STM_REG(128, 7, 3); - } - break; - case 0xc4: - { - // STM R4!, {Rlist} - u32 address = reg[4].I & 0xFFFFFFFC; - u32 temp = reg[4].I + 4*cpuBitsSet[opcode & 0xff]; - int offset = 0; - // store - THUMB_STM_REG(1, 0, 4); - THUMB_STM_REG(2, 1, 4); - THUMB_STM_REG(4, 2, 4); - THUMB_STM_REG(8, 3, 4); - THUMB_STM_REG(16, 4, 4); - THUMB_STM_REG(32, 5, 4); - THUMB_STM_REG(64, 6, 4); - THUMB_STM_REG(128, 7, 4); - } - break; - case 0xc5: - { - // STM R5!, {Rlist} - u32 address = reg[5].I & 0xFFFFFFFC; - u32 temp = reg[5].I + 4*cpuBitsSet[opcode & 0xff]; - int offset = 0; - // store - THUMB_STM_REG(1, 0, 5); - THUMB_STM_REG(2, 1, 5); - THUMB_STM_REG(4, 2, 5); - THUMB_STM_REG(8, 3, 5); - THUMB_STM_REG(16, 4, 5); - THUMB_STM_REG(32, 5, 5); - THUMB_STM_REG(64, 6, 5); - THUMB_STM_REG(128, 7, 5); - } - break; - case 0xc6: - { - // STM R6!, {Rlist} - u32 address = reg[6].I & 0xFFFFFFFC; - u32 temp = reg[6].I + 4*cpuBitsSet[opcode & 0xff]; - int offset = 0; - // store - THUMB_STM_REG(1, 0, 6); - THUMB_STM_REG(2, 1, 6); - THUMB_STM_REG(4, 2, 6); - THUMB_STM_REG(8, 3, 6); - THUMB_STM_REG(16, 4, 6); - THUMB_STM_REG(32, 5, 6); - THUMB_STM_REG(64, 6, 6); - THUMB_STM_REG(128, 7, 6); - } - break; - case 0xc7: - { - // STM R7!, {Rlist} - u32 address = reg[7].I & 0xFFFFFFFC; - u32 temp = reg[7].I + 4*cpuBitsSet[opcode & 0xff]; - int offset = 0; - // store - THUMB_STM_REG(1, 0, 7); - THUMB_STM_REG(2, 1, 7); - THUMB_STM_REG(4, 2, 7); - THUMB_STM_REG(8, 3, 7); - THUMB_STM_REG(16, 4, 7); - THUMB_STM_REG(32, 5, 7); - THUMB_STM_REG(64, 6, 7); - THUMB_STM_REG(128, 7, 7); - } - break; -#define THUMB_LDM_REG(val,r) \ - if(opcode & (val)) {\ - reg[(r)].I = CPUReadMemory(address);\ - if(offset)\ - clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);\ - else\ - clockTicks += 2 + CPUUpdateTicksAccess32(address);\ - offset = 1;\ - address += 4;\ - } - case 0xc8: - { - // LDM R0!, {Rlist} - u32 address = reg[0].I & 0xFFFFFFFC; - u32 temp = reg[0].I + 4*cpuBitsSet[opcode & 0xFF]; - int offset = 0; - // load - THUMB_LDM_REG(1, 0); - THUMB_LDM_REG(2, 1); - THUMB_LDM_REG(4, 2); - THUMB_LDM_REG(8, 3); - THUMB_LDM_REG(16, 4); - THUMB_LDM_REG(32, 5); - THUMB_LDM_REG(64, 6); - THUMB_LDM_REG(128, 7); - if(!(opcode & 1)) - reg[0].I = temp; - } - break; - case 0xc9: - { - // LDM R1!, {Rlist} - u32 address = reg[1].I & 0xFFFFFFFC; - u32 temp = reg[1].I + 4*cpuBitsSet[opcode & 0xFF]; - int offset = 0; - // load - THUMB_LDM_REG(1, 0); - THUMB_LDM_REG(2, 1); - THUMB_LDM_REG(4, 2); - THUMB_LDM_REG(8, 3); - THUMB_LDM_REG(16, 4); - THUMB_LDM_REG(32, 5); - THUMB_LDM_REG(64, 6); - THUMB_LDM_REG(128, 7); - if(!(opcode & 2)) - reg[1].I = temp; - } - break; - case 0xca: - { - // LDM R2!, {Rlist} - u32 address = reg[2].I & 0xFFFFFFFC; - u32 temp = reg[2].I + 4*cpuBitsSet[opcode & 0xFF]; - int offset = 0; - // load - THUMB_LDM_REG(1, 0); - THUMB_LDM_REG(2, 1); - THUMB_LDM_REG(4, 2); - THUMB_LDM_REG(8, 3); - THUMB_LDM_REG(16, 4); - THUMB_LDM_REG(32, 5); - THUMB_LDM_REG(64, 6); - THUMB_LDM_REG(128, 7); - if(!(opcode & 4)) - reg[2].I = temp; - } - break; - case 0xcb: - { - // LDM R3!, {Rlist} - u32 address = reg[3].I & 0xFFFFFFFC; - u32 temp = reg[3].I + 4*cpuBitsSet[opcode & 0xFF]; - int offset = 0; - // load - THUMB_LDM_REG(1, 0); - THUMB_LDM_REG(2, 1); - THUMB_LDM_REG(4, 2); - THUMB_LDM_REG(8, 3); - THUMB_LDM_REG(16, 4); - THUMB_LDM_REG(32, 5); - THUMB_LDM_REG(64, 6); - THUMB_LDM_REG(128, 7); - if(!(opcode & 8)) - reg[3].I = temp; - } - break; - case 0xcc: - { - // LDM R4!, {Rlist} - u32 address = reg[4].I & 0xFFFFFFFC; - u32 temp = reg[4].I + 4*cpuBitsSet[opcode & 0xFF]; - int offset = 0; - // load - THUMB_LDM_REG(1, 0); - THUMB_LDM_REG(2, 1); - THUMB_LDM_REG(4, 2); - THUMB_LDM_REG(8, 3); - THUMB_LDM_REG(16, 4); - THUMB_LDM_REG(32, 5); - THUMB_LDM_REG(64, 6); - THUMB_LDM_REG(128, 7); - if(!(opcode & 16)) - reg[4].I = temp; - } - break; - case 0xcd: - { - // LDM R5!, {Rlist} - u32 address = reg[5].I & 0xFFFFFFFC; - u32 temp = reg[5].I + 4*cpuBitsSet[opcode & 0xFF]; - int offset = 0; - // load - THUMB_LDM_REG(1, 0); - THUMB_LDM_REG(2, 1); - THUMB_LDM_REG(4, 2); - THUMB_LDM_REG(8, 3); - THUMB_LDM_REG(16, 4); - THUMB_LDM_REG(32, 5); - THUMB_LDM_REG(64, 6); - THUMB_LDM_REG(128, 7); - if(!(opcode & 32)) - reg[5].I = temp; - } - break; - case 0xce: - { - // LDM R6!, {Rlist} - u32 address = reg[6].I & 0xFFFFFFFC; - u32 temp = reg[6].I + 4*cpuBitsSet[opcode & 0xFF]; - int offset = 0; - // load - THUMB_LDM_REG(1, 0); - THUMB_LDM_REG(2, 1); - THUMB_LDM_REG(4, 2); - THUMB_LDM_REG(8, 3); - THUMB_LDM_REG(16, 4); - THUMB_LDM_REG(32, 5); - THUMB_LDM_REG(64, 6); - THUMB_LDM_REG(128, 7); - if(!(opcode & 64)) - reg[6].I = temp; - } - break; - case 0xcf: - { - // LDM R7!, {Rlist} - u32 address = reg[7].I & 0xFFFFFFFC; - u32 temp = reg[7].I + 4*cpuBitsSet[opcode & 0xFF]; - int offset = 0; - // load - THUMB_LDM_REG(1, 0); - THUMB_LDM_REG(2, 1); - THUMB_LDM_REG(4, 2); - THUMB_LDM_REG(8, 3); - THUMB_LDM_REG(16, 4); - THUMB_LDM_REG(32, 5); - THUMB_LDM_REG(64, 6); - THUMB_LDM_REG(128, 7); - if(!(opcode & 128)) - reg[7].I = temp; - } - break; - case 0xd0: - // BEQ offset - if(Z_FLAG) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xd1: - // BNE offset - if(!Z_FLAG) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xd2: - // BCS offset - if(C_FLAG) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xd3: - // BCC offset - if(!C_FLAG) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xd4: - // BMI offset - if(N_FLAG) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xd5: - // BPL offset - if(!N_FLAG) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xd6: - // BVS offset - if(V_FLAG) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xd7: - // BVC offset - if(!V_FLAG) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xd8: - // BHI offset - if(C_FLAG && !Z_FLAG) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xd9: - // BLS offset - if(!C_FLAG || Z_FLAG) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xda: - // BGE offset - if(N_FLAG == V_FLAG) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xdb: - // BLT offset - if(N_FLAG != V_FLAG) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xdc: - // BGT offset - if(!Z_FLAG && (N_FLAG == V_FLAG)) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xdd: - // BLE offset - if(Z_FLAG || (N_FLAG != V_FLAG)) { - reg[15].I += ((s8)(opcode & 0xFF)) << 1; - armNextPC = reg[15].I; - reg[15].I += 2; - clockTicks = 3; - } - break; - case 0xdf: - // SWI #comment - CPUSoftwareInterrupt(opcode & 0xFF); - break; - case 0xe0: - case 0xe1: - case 0xe2: - case 0xe3: - case 0xe4: - case 0xe5: - case 0xe6: - case 0xe7: - { - // B offset - int offset = (opcode & 0x3FF) << 1; - if(opcode & 0x0400) - offset |= 0xFFFFF800; - reg[15].I += offset; - armNextPC = reg[15].I; - reg[15].I += 2; - } - break; - case 0xf0: - case 0xf1: - case 0xf2: - case 0xf3: - { - // BLL #offset - int offset = (opcode & 0x7FF); - reg[14].I = reg[15].I + (offset << 12); - } - break; - case 0xf4: - case 0xf5: - case 0xf6: - case 0xf7: - { - // BLL #offset - int offset = (opcode & 0x7FF); - reg[14].I = reg[15].I + ((offset << 12) | 0xFF800000); - } - break; - case 0xf8: - case 0xf9: - case 0xfa: - case 0xfb: - case 0xfc: - case 0xfd: - case 0xfe: - case 0xff: - { - // BLH #offset - int offset = (opcode & 0x7FF); - u32 temp = reg[15].I-2; - reg[15].I = (reg[14].I + (offset<<1))&0xFFFFFFFE; - armNextPC = reg[15].I; - reg[15].I += 2; - reg[14].I = temp|1; - } - break; -#ifdef BKPT_SUPPORT - case 0xbe: - // BKPT #comment - extern void (*dbgSignal)(int,int); - reg[15].I -= 2; - armNextPC -= 2; - dbgSignal(5, opcode & 255); - return; -#endif - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb6: - case 0xb7: - case 0xb8: - case 0xb9: - case 0xba: - case 0xbb: -#ifndef BKPT_SUPPORT - case 0xbe: -#endif - case 0xbf: - case 0xde: - default: - unknown_thumb: -#ifdef DEV_VERSION - if(systemVerbose & VERBOSE_UNDEFINED) - log("Undefined THUMB instruction %04x at %08x\n", opcode, armNextPC-2); -#endif - CPUUndefinedException(); - break; -}