merging changes from Zopenko, libertyernie, Glitch, cebolleto, and

others
This commit is contained in:
Daryl Borth 2016-06-04 16:59:43 -06:00
parent 603431cbfd
commit 3ecc826354
92 changed files with 21903 additions and 11562 deletions

View File

@ -1,8 +1,8 @@
.PHONY = all wii gc wii-clean gc-clean wii-run gc-run .PHONY = all wii gc wii-clean gc-clean wii-run gc-run
all: wii gc all: wii
clean: wii-clean gc-clean clean: wii-clean
run: wii-run run: wii-run

View File

@ -21,7 +21,7 @@ BUILD := build_gc
SOURCES := source source/images source/sounds source/fonts source/lang \ SOURCES := source source/images source/sounds source/fonts source/lang \
source/gui source/utils source/utils/sz \ source/gui source/utils source/utils/sz \
source/vba source/vba/apu source/vba/common \ source/vba source/vba/apu source/vba/common \
source/vba/gb source/vba/gba source/vba/gb source/vba/gba source/goomba source/goomba/minilzo-2.06
INCLUDES := source source/vba INCLUDES := source source/vba
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
@ -29,7 +29,8 @@ INCLUDES := source source/vba
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
CFLAGS = -g -O3 -Wall $(MACHDEP) $(INCLUDE) \ CFLAGS = -g -O3 -Wall $(MACHDEP) $(INCLUDE) \
-DNO_SOUND -DUSE_VM -DWORDS_BIGENDIAN \ -DNO_SOUND -DUSE_VM -DWORDS_BIGENDIAN -DNO_LINK -DNO_FEX \
-DTILED_RENDERING \
-DC_CORE -D__ppc__ -D__POWERPC__ -DFINAL_VERSION \ -DC_CORE -D__ppc__ -D__POWERPC__ -DFINAL_VERSION \
-DSDL -DNO_PNG -DHAVE_ZUTIL_H \ -DSDL -DNO_PNG -DHAVE_ZUTIL_H \
-D_SZ_ONE_DIRECTORY -D_LZMA_IN_CB -D_LZMA_OUT_READ \ -D_SZ_ONE_DIRECTORY -D_LZMA_IN_CB -D_LZMA_OUT_READ \

View File

@ -21,7 +21,7 @@ BUILD := build_wii
SOURCES := source source/images source/sounds source/fonts source/lang \ SOURCES := source source/images source/sounds source/fonts source/lang \
source/gui source/utils source/utils/sz source/utils/unzip \ source/gui source/utils source/utils/sz source/utils/unzip \
source/vba source/vba/apu source/vba/common \ source/vba source/vba/apu source/vba/common \
source/vba/gb source/vba/gba source/vba/gb source/vba/gba source/goomba source/goomba/minilzo-2.06
INCLUDES := source source/vba INCLUDES := source source/vba
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
@ -29,19 +29,20 @@ INCLUDES := source source/vba
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
CFLAGS = -g -O3 -Wall $(MACHDEP) $(INCLUDE) \ CFLAGS = -g -O3 -Wall $(MACHDEP) $(INCLUDE) \
-DWORDS_BIGENDIAN \ -DWORDS_BIGENDIAN -DNO_LINK -DNO_FEX \
-DTILED_RENDERING \
-DC_CORE -D__ppc__ -D__POWERPC__ -DFINAL_VERSION \ -DC_CORE -D__ppc__ -D__POWERPC__ -DFINAL_VERSION \
-DSDL -DNO_PNG -DHAVE_ZUTIL_H \ -DSDL -DNO_PNG -DHAVE_ZUTIL_H \
-D_SZ_ONE_DIRECTORY -D_LZMA_IN_CB -D_LZMA_OUT_READ \ -D_SZ_ONE_DIRECTORY -D_LZMA_IN_CB -D_LZMA_OUT_READ \
-fomit-frame-pointer \ -fomit-frame-pointer \
-Wno-unused-parameter -Wno-strict-aliasing -Wno-parentheses -Wno-unused-parameter -Wno-strict-aliasing -Wno-parentheses
CXXFLAGS = $(CFLAGS) CXXFLAGS = $(CFLAGS)
LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map,-wrap,wiiuse_register
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# any extra libraries we wish to link with # any extra libraries we wish to link with
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
LIBS := -ldi -liso9660 -lpng -lmxml -lfat -lwiiuse -lz -lbte -lasnd -logc \ LIBS := -ldi -liso9660 -lpng -lmxml -lfat -lwiiuse -lwupc -lz -lbte -lasnd -logc \
-lvorbisidec -lfreetype -ltinysmb -lvorbisidec -lfreetype -ltinysmb
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------

View File

@ -1,8 +1,8 @@
¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤ ¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤
- Visual Boy Advance GX - - Visual Boy Advance GX -
http://code.google.com/p/vba-wii https://github.com/dborth/vba-wii
(Under GPL License) (Under GPL License)
¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤ ¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤
@ -18,15 +18,86 @@ With it you can play GBA/Game Boy Color/Game Boy games on your Wii/GameCube.
* IPS/UPS patch support * IPS/UPS patch support
* Custom controller configurations * Custom controller configurations
* SD, USB, DVD, SMB, Zip, and 7z support * SD, USB, DVD, SMB, Zip, and 7z support
* Compatibility based on VBA-M r927 * Compatibility based on VBA-M r1231
* MEM2 ROM Storage for fast access * MEM2 ROM Storage for fast access
* Auto frame skip for those core heavy games * Auto frame skip (optional) for those core heavy games
* Turbo speed, video zooming, widescreen, and unfiltered video options * Turbo speed, video zooming, widescreen, and unfiltered video options
* Native loading/saving of ROMS and SRAM from Goomba (a GB emulator for GBA)
* Improved video rendering from RetroArch
* Screenshots can be displayed on the main menu
* Fixed pixel ratio mode (1x, 2x, and 3x)
* Borders (from Super Game Boy games or custom from .png)
* Wii U Pro Controller support
* 240p support
×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ ×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬
|0O×øo· UPDATE HISTORY ·oø×O0| |0O×øo· UPDATE HISTORY ·oø×O0|
`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' `¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨'
[2.3.3] - Zopenko
* fixes the gc pad down on file browser
* added koston default green gb color screen
* added the screenshot/preview button
* added the wiiupro icon on the controller settings
* increased and centered the screenshot image
* added the screenshot white image background
[2.3.2 - March 4, 2015] - libertyernie
* Wii U: if widescreen is enabled in the Wii U setting, VBA GX will use a 16:9
aspect ratio, except while playing a game with fixed pixel mode turned on
* There are now three options for border in the emulation settings menu (see
"Super Game Boy borders" section for details)
* PNG borders now supported for GBA games
* Video mode "PAL (50Hz)" renamed to "PAL (576i)"
* Video mode "PAL (60Hz)" renamed to "European RGB (480i)"
* 240p support added (NTSC and European RGB modes)
* All video modes now use a width of 704 for the best pixel aspect ratio
[2.3.1b - November 8, 2014] - Glitch
* Added FIX94's libwupc for WiiU Pro Controllers
* Added tueidj's vWii Widescreen Fix
[2.3.1 - October 14, 2014] - libertyernie
* Super Game Boy border support
* Borders can be loaded from (and are automatically saved to) PNG files
* Any border loaded from the game itself will override the custom PNG border
* Custom palette support from 2.2.8 restored
* Option added to select Game Boy hardware (GB/SGB/GBC/auto)
* Fixed pixel ratio mode added
* Overrides zoom and aspect ratio settings
* To squish the picture so it appears correctly on a 16:9 TV, you can open
the settings.xml file and add 10 to the gbFixed/gbaFixed value. However,
setting your TV to 4:3 mode will yield a better picture.
* Real-time clock fixes for GB/GBC games, including Pokémon G/S/C
* RTC data in save file stored as little-endian
* Option added for UTC offset in the main menu (only required if you use the
same SRAM on other, time-zone-aware platforms)
* New option for selecting "sharp" or "soft" filtering settings
* "Sharp" was the default for 480p, "soft" was the default for 480i
[2.3.0 - September 10, 2014] - libertyernie
* VBA-M core updated to r1231
* Tiled rendering used for GBA games (new VBA-M feature, originally from
RetroArch) - provides a major speed boost!
* Changes from cebolleto's version
* Screenshots can be displayed for each game on the menu
* Nicer 7-Zip support
* When you leave a folder, the folder you just left will be selected
* New options available:
* Disable the " Auto" string being appended to save files
* Disable frameskip entirely on GBA
* Keyboard fixed (from libwiigui r56)
* GUI prompt is now purple instead of green (button colors more intuitive)
* Goomba and Goomba Color ROM support:
* Any Game Boy ROM stored within a Goomba ROM can be loaded "natively" in
the Game Boy (Color) emulator (or the Goomba ROM can be loaded as GBA)
* Game Boy SRAM stored within Goomba SRAM is loaded and saved correctly
[2.2.8 - July 29, 2012] [2.2.8 - July 29, 2012]
* Fixed lag with GameCube controllers * Fixed lag with GameCube controllers
@ -508,9 +579,8 @@ Z = Gameboy A Button
C = Gameboy B Button C = Gameboy B Button
Classic Controller: Classic Controller:
Use the buttons as labelled. B = Gameboy A Button
A = Gameboy A Button Y = Gameboy B Button
B = Gameboy B Button
R = Gameboy R Button R = Gameboy R Button
L = Gameboy L Button L = Gameboy L Button
@ -535,6 +605,43 @@ to the main menu and B again to return to the game.
A+B, Spacebar, or right analog stick: fast forward A+B, Spacebar, or right analog stick: fast forward
Right analog stick: zoom (if enabled) Right analog stick: zoom (if enabled)
-=[ Super Game Boy borders ]=-
VBA-GX has supported Super Game Boy borders since 2.3.1. You can enable this
feature in the Emulation settings on the main menu.
Borders can be loaded from two locations:
* PNG files in the borders folder (by default, /vbagx/borders)
* The game itself
Borders will only be loaded from the game itself when the emulator is running
in Super Game Boy mode, and the border setting in Emulation settings is set to
"From game (SGB only)". (You can also use the Emulation settings menu to
force SGB mode even for Game Boy Color games.) If the borders folder exists,
but no border for the game is present, the loaded Super Game Boy border will
be written to a .png file, which can be loaded later in "From .png file" mode.
In addition, if the borders folder exists but there is no border for the game,
the first border loaded from the game will be written to a PNG file so it can
be loaded in the future (even in Game Boy Color mode.) This means after you
run a game once in SGB mode, you can then use the same border in GBC mode.
If the border setting is set to "From .png file", borders will be loaded
from the borders folder. Borders can be up to 640x480 and will work for both
Game Boy (Color) and Game Boy Advance games.
For both loading and saving, the PNG filename is [TITLE].png, where [TITLE]
is the ROM title defined at 0x134 (for GB games) or 0xA0 (for GBA games). For
example, POKEMON_SFXAAXE.png will be loaded for Pokémon Silver. If no PNG file
by that name exists, VBA-GX will try loading default.png (for GB games) or
defaultgba.png (for GBA games) instead.
Since the borders are rendered along with the video output of the game, the
pixels in the border will be the same size as game pixels. This means that
a Game Boy game will appear in the middle 160x144 pixels of the border, and a
Game Boy Advance game will appear in the middle 240x160 pixels, regardless of
the resolution of the border PNG image.
-=[ Match Wii Controls ]=- -=[ Match Wii Controls ]=-
Special Wii controls exist for the following games: Special Wii controls exist for the following games:
@ -577,8 +684,8 @@ Medal Of Honour Underground, Medal Of Honour Infiltrator
One Piece can be played with One Piece Unlimited Adventure controls. One Piece can be played with One Piece Unlimited Adventure controls.
Boktai 1, Boktai 2, Boktai 3, Kirby's Tilt n Tumble, and WarioWare Twisted Boktai 1, Boktai 2, Boktai 3, and Kirby's Tilt n Tumble can be played with
can be played with controls I designed for them. controls designed for them.
-=[ Zelda, Match Wii Controls ]=- -=[ Zelda, Match Wii Controls ]=-
@ -740,8 +847,11 @@ A = spin attack
X/Y = shoot, run, hold on to things, yoshi's tongue, etc. X/Y = shoot, run, hold on to things, yoshi's tongue, etc.
ZL or sometimes L = crouch or lay egg. Press in the air to butt stomp. ZL or sometimes L = crouch or lay egg. Press in the air to butt stomp.
+ = pause + = pause
L/R sometimes look around L/R = look around (if the game supports it)
ZR = fast forward (8-bit Game Boy only)
In Super Mario World and Super Mario Land 2, you can use the A or R
buttons for a spin jump.
-=[ Yoshi's Universal Gravitation (Topsy Turvy), Match Wii Controls ]=- -=[ Yoshi's Universal Gravitation (Topsy Turvy), Match Wii Controls ]=-
@ -834,20 +944,9 @@ Z or 1 = change element, or change subscreen (L)
-=[ WarioWare Twisted, Match Wii Controls ]=- -=[ WarioWare Twisted, Match Wii Controls ]=-
Turn "Match Wii Controls" ON to use these controls. NOTE: For unknown reasons (but probably related to the update of the VBA-M
emulator code), WarioWare Twisted will no longer work on VBA-GX. For now, you
WarioWare Twisted uses similar controls to the Gameboy game. will need to go back to VBA-GX 2.2.8 to play it.
The Wii WarioWare Twisted controls are:
=======================================
Rotate the Wii Remote to rotate.
Hold Z to lock the current menu item.
A = Select
B = Cancel
+ = Start
-=[ Kirby's Tilt n Tumble, Match Wii Controls ]=- -=[ Kirby's Tilt n Tumble, Match Wii Controls ]=-
@ -987,11 +1086,51 @@ Z = grab
right analog stick = fast forward right analog stick = fast forward
1 = select (maybe does nothing) 1 = select (maybe does nothing)
-=[ Kid Dracula, Match Wii Controls ]=-
Turn "Match Wii Controls" ON to use these controls.
(There's no Kid Dracula game for the Wii, but this is a good opportunity to
show off some fancy memory-swapping tricks. -libertyernie)
The Kid Dracula Wii controls (remote + nunchuk) are:
====================================================
A = jump
B = use selected weapon
Z = use NOR weapon (fireball)
C = use BAT weapon (turn into bat for 5 sec)
+ = pause
- = switch item
1/2 = fast forward
The Kid Dracula Classic Controller controls are:
================================================
A/B = jump
Y = use selected weapon
X = use NOR weapon (fireball)
R/ZR = use BAT weapon (turn into bat for 5 sec)
+ = pause
- = switch item
1/2 = fast forward
In Kid Dracula, pressing the "fire" button will always shoot a small fireball,
but holding the button for a second or so to charge up the shoot lets you use
whichever item is selected.
Pressing B (nunchuk) or Y (classic) will switch back to whatever item was
selected before you pressed Z/C (nunchuk) or X/R/ZR (classic), unless you have
switched items since then.
¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤ ¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤
-=[ Credits ]=- -=[ Credits ]=-
Coding & menu design Tantric Coding & menu design Tantric
Codebase update & Goomba libertyernie
Menu screenshots cebolleto
GBA tiled rendering bgK (for RetroArch)
Additional coding Carl Kenner, dancinninjac Additional coding Carl Kenner, dancinninjac
Menu artwork the3seashells Menu artwork the3seashells
Menu sound Peter de Man Menu sound Peter de Man
@ -1009,6 +1148,6 @@ right analog stick = fast forward
¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤ ¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤
VBAGX Web Site VBAGX Web Site
http://code.google.com/p/vba-wii https://github.com/dborth/vba-wii
¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤ ¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤

View File

@ -35,6 +35,7 @@ BROWSERINFO browser;
BROWSERENTRY * browserList = NULL; // list of files/folders in browser BROWSERENTRY * browserList = NULL; // list of files/folders in browser
char szpath[MAXPATHLEN]; char szpath[MAXPATHLEN];
char szname[MAXPATHLEN];
bool inSz = false; bool inSz = false;
char ROMFilename[512]; char ROMFilename[512];
@ -211,6 +212,8 @@ int UpdateDirName()
/* remove last subdirectory name */ /* remove last subdirectory name */
size = strlen(browser.dir) - size - 1; size = strlen(browser.dir) - size - 1;
strncpy(GCSettings.LastFileLoaded, &browser.dir[size], strlen(browser.dir) - size - 1); //set as loaded file the previous dir
GCSettings.LastFileLoaded[strlen(browser.dir) - size - 1] = 0;
browser.dir[size] = 0; browser.dir[size] = 0;
} }
@ -255,6 +258,24 @@ bool MakeFilePath(char filepath[], int type, char * filename, int filenum)
sprintf(temppath, "%s%s",browser.dir,browserList[browser.selIndex].filename); sprintf(temppath, "%s%s",browser.dir,browserList[browser.selIndex].filename);
} }
} }
else if (type == FILE_BORDER_PNG)
{
const char* loadedpath = filename;
if (loadedpath == NULL) loadedpath = "default";
// Ensure that loadedname contains only the filename, not the path
const char* loadedname = strrchr(loadedpath, '/');
if (loadedname == NULL) loadedname = loadedpath;
// Check path length
if ((strlen(pathPrefix[GCSettings.LoadMethod]) + strlen(GCSettings.BorderFolder) + strlen(loadedname)) >= MAXPATHLEN) {
ErrorPrompt("Maximum filepath length reached!");
filepath[0] = 0;
return false;
}
StripExt(file, loadedname);
sprintf(temppath, "%s%s/%s.png", pathPrefix[GCSettings.LoadMethod], GCSettings.BorderFolder, file);
}
else else
{ {
if(GCSettings.SaveMethod == DEVICE_AUTO) if(GCSettings.SaveMethod == DEVICE_AUTO)
@ -277,7 +298,14 @@ bool MakeFilePath(char filepath[], int type, char * filename, int filenum)
if(filenum == -1) if(filenum == -1)
sprintf(file, "%s.%s", filename, ext); sprintf(file, "%s.%s", filename, ext);
else if(filenum == 0) else if(filenum == 0)
sprintf(file, "%s Auto.%s", filename, ext); if (GCSettings.AppendAuto <= 0)
{
sprintf(file, "%s.%s", filename, ext);
}
else
{
sprintf(file, "%s Auto.%s", filename, ext);
}
else else
sprintf(file, "%s %i.%s", filename, filenum, ext); sprintf(file, "%s %i.%s", filename, filenum, ext);
} }
@ -344,7 +372,7 @@ bool IsSz()
* *
* Strips an extension from a filename * Strips an extension from a filename
***************************************************************************/ ***************************************************************************/
void StripExt(char* returnstring, char * inputstring) void StripExt(char* returnstring, const char * inputstring)
{ {
char* loc_dot; char* loc_dot;
@ -436,12 +464,11 @@ void ShortenFilename(char * returnstring, char * inputstring)
***************************************************************************/ ***************************************************************************/
int BrowserLoadSz() int BrowserLoadSz()
{ {
char filepath[MAXPATHLEN]; memset(szpath, 0, MAXPATHLEN);
memset(filepath, 0, MAXPATHLEN); strncpy(szpath, browser.dir, strlen(browser.dir) - 1);
// we'll store the 7z filepath for extraction later strncpy(szname, strrchr(szpath, '/') + 1, strrchr(szpath, '.') - strrchr(szpath, '/'));
if(!MakeFilePath(szpath, FILE_ROM)) *strrchr(szname, '.') = '\0';
return 0;
int szfiles = SzParse(szpath); int szfiles = SzParse(szpath);
if(szfiles) if(szfiles)
@ -469,7 +496,7 @@ int BrowserLoadFile()
// store the filename (w/o ext) - used for sram/freeze naming // store the filename (w/o ext) - used for sram/freeze naming
StripExt(ROMFilename, browserList[browser.selIndex].filename); StripExt(ROMFilename, browserList[browser.selIndex].filename);
strcpy(loadedFile, browserList[browser.selIndex].filename); snprintf(GCSettings.LastFileLoaded, MAXPATHLEN, "%s", browserList[browser.selIndex].filename);
loadingFile = true; loadingFile = true;
ROMLoaded = LoadVBAROM(); ROMLoaded = LoadVBAROM();
@ -516,12 +543,22 @@ int BrowserChangeFolder()
if(!UpdateDirName()) if(!UpdateDirName())
return -1; return -1;
HaltParseThread(); // halt parsing HaltParseThread();
CleanupPath(browser.dir); CleanupPath(browser.dir);
ResetBrowser(); // reset browser ResetBrowser();
if(browser.dir[0] != 0) if(browser.dir[0] != 0)
ParseDirectory(); {
if(strstr(browser.dir, ".7z"))
{
BrowserLoadSz();
}
else
{
ParseDirectory(true, true);
}
FindAndSelectLastLoadedFile();
}
if(browser.numEntries == 0) if(browser.numEntries == 0)
{ {

View File

@ -47,6 +47,7 @@ extern bool ROMLoaded;
extern bool loadingFile; extern bool loadingFile;
extern char szpath[MAXPATHLEN]; extern char szpath[MAXPATHLEN];
extern bool inSz; extern bool inSz;
extern char szname[MAXPATHLEN];
enum enum
{ {
@ -64,7 +65,7 @@ int OpenGameList();
int autoLoadMethod(); int autoLoadMethod();
int autoSaveMethod(bool silent); int autoSaveMethod(bool silent);
int FileSortCallback(const void *f1, const void *f2); int FileSortCallback(const void *f1, const void *f2);
void StripExt(char* returnstring, char * inputstring); void StripExt(char* returnstring, const char* inputstring);
bool IsSz(); bool IsSz();
void ResetBrowser(); void ResetBrowser();
bool AddBrowserEntry(); bool AddBrowserEntry();

View File

@ -104,6 +104,8 @@ extern const u8 icon_settings_gamecube_png[];
extern const u32 icon_settings_gamecube_png_size; extern const u32 icon_settings_gamecube_png_size;
extern const u8 icon_settings_nunchuk_png[]; extern const u8 icon_settings_nunchuk_png[];
extern const u32 icon_settings_nunchuk_png_size; extern const u32 icon_settings_nunchuk_png_size;
extern const u8 icon_settings_wiiupro_png[];
extern const u32 icon_settings_wiiupro_png_size;
extern const u8 icon_settings_file_png[]; extern const u8 icon_settings_file_png[];
extern const u32 icon_settings_file_png_size; extern const u32 icon_settings_file_png_size;
@ -115,6 +117,8 @@ extern const u8 icon_settings_network_png[];
extern const u32 icon_settings_network_png_size; extern const u32 icon_settings_network_png_size;
extern const u8 icon_settings_video_png[]; extern const u8 icon_settings_video_png[];
extern const u32 icon_settings_video_png_size; extern const u32 icon_settings_video_png_size;
extern const u8 icon_settings_screenshot_png[];
extern const u32 icon_settings_screenshot_png_size;
extern const u8 button_png[]; extern const u8 button_png[];
extern const u32 button_png_size; extern const u32 button_png_size;
@ -242,6 +246,9 @@ extern const u32 bg_game_selection_png_size;
extern const u8 bg_game_selection_entry_png[]; extern const u8 bg_game_selection_entry_png[];
extern const u32 bg_game_selection_entry_png_size; extern const u32 bg_game_selection_entry_png_size;
extern const u8 bg_preview_png[];
extern const u32 bg_preview_png_size;
extern const u8 scrollbar_png[]; extern const u8 scrollbar_png[];
extern const u32 scrollbar_png_size; extern const u32 scrollbar_png_size;

View File

@ -53,7 +53,7 @@ bool isMounted[7] = { false, false, false, false, false, false, false };
// folder parsing thread // folder parsing thread
static lwp_t parsethread = LWP_THREAD_NULL; static lwp_t parsethread = LWP_THREAD_NULL;
static DIR * dir = NULL; static DIR *dir = NULL;
static bool parseHalt = true; static bool parseHalt = true;
static bool parseFilter = true; static bool parseFilter = true;
static bool ParseDirEntries(); static bool ParseDirEntries();
@ -490,6 +490,40 @@ bool GetFileSize(int i)
return true; return true;
} }
void FindAndSelectLastLoadedFile ()
{
int indexFound = -1;
for(int j=1; j < browser.numEntries; j++)
{
if(strcmp(browserList[j].filename, GCSettings.LastFileLoaded) == 0)
{
indexFound = j;
break;
}
}
// move to this file
if(indexFound > 0)
{
if(indexFound >= FILE_PAGESIZE)
{
int newIndex = (floor(indexFound/(float)FILE_PAGESIZE)) * FILE_PAGESIZE;
if(newIndex + FILE_PAGESIZE > browser.numEntries)
newIndex = browser.numEntries - FILE_PAGESIZE;
if(newIndex < 0)
newIndex = 0;
browser.pageIndex = newIndex;
}
browser.selIndex = indexFound;
}
selectLoadedFile = 2; // selecting done
}
static bool ParseDirEntries() static bool ParseDirEntries()
{ {
if(!dir) if(!dir)
@ -578,39 +612,6 @@ static bool ParseDirEntries()
closedir(dir); // close directory closedir(dir); // close directory
dir = NULL; dir = NULL;
// try to find and select the last loaded file
if(selectLoadedFile == 1 && !parseHalt && loadedFile[0] != 0 && browser.dir[0] != 0)
{
int indexFound = -1;
for(int j=1; j < browser.numEntries; j++)
{
if(strcmp(browserList[j].filename, loadedFile) == 0)
{
indexFound = j;
break;
}
}
// move to this file
if(indexFound > 0)
{
if(indexFound >= FILE_PAGESIZE)
{
int newIndex = (floor(indexFound/(float)FILE_PAGESIZE)) * FILE_PAGESIZE;
if(newIndex + FILE_PAGESIZE > browser.numEntries)
newIndex = browser.numEntries - FILE_PAGESIZE;
if(newIndex < 0)
newIndex = 0;
browser.pageIndex = newIndex;
}
browser.selIndex = indexFound;
}
selectLoadedFile = 2; // selecting done
}
return false; // no more entries return false; // no more entries
} }
return true; // more entries return true; // more entries
@ -824,6 +825,12 @@ LoadFile (char * rbuffer, char *filepath, size_t length, bool silent)
while(!feof(file)) while(!feof(file))
{ {
// If the size requested is *less* than the filesize, only read that much - we don't want to overrun the buffer
int toread = 4096;
if (length > 0 && offset+toread > length) {
toread = length - offset;
}
ShowProgress ("Loading...", offset, size); ShowProgress ("Loading...", offset, size);
readsize = fread (rbuffer + offset, 1, 4096, file); // read in next chunk readsize = fread (rbuffer + offset, 1, 4096, file); // read in next chunk
@ -831,6 +838,9 @@ LoadFile (char * rbuffer, char *filepath, size_t length, bool silent)
break; // reading finished (or failed) break; // reading finished (or failed)
offset += readsize; offset += readsize;
if (length > 0 && offset >= length) {
break;
}
} }
size = offset; size = offset;
CancelAction(); CancelAction();

View File

@ -18,7 +18,7 @@
#include <fat.h> #include <fat.h>
#include <unistd.h> #include <unistd.h>
#define SAVEBUFFERSIZE (1024 * 1024 * 2) #define SAVEBUFFERSIZE (1024 * 512)
void InitDeviceThread(); void InitDeviceThread();
void ResumeDeviceThread(); void ResumeDeviceThread();
@ -32,6 +32,7 @@ bool ChangeInterface(int device, bool silent);
bool ChangeInterface(char * filepath, bool silent); bool ChangeInterface(char * filepath, bool silent);
void CreateAppPath(char * origpath); void CreateAppPath(char * origpath);
bool GetFileSize(int i); bool GetFileSize(int i);
void FindAndSelectLastLoadedFile();
int ParseDirectory(bool waitParse = false, bool filter = true); int ParseDirectory(bool waitParse = false, bool filter = true);
void AllocSaveBuffer(); void AllocSaveBuffer();
void FreeSaveBuffer(); void FreeSaveBuffer();

View File

@ -1540,3 +1540,119 @@ u32 CastlevaniaCircleMoonInput(unsigned short pad) {
return J; return J;
} }
u8 KD_NOR[64] = {
0x7f, 0x00, 0x98, 0x67, 0x00, 0x99, 0x00, 0x89, 0x00, 0xa1, 0x00, 0xb1, 0x10, 0xa9, 0x18, 0x67,
0xff, 0x00, 0x81, 0x7e, 0x00, 0x81, 0x00, 0xb9, 0x10, 0xa9, 0x00, 0xb9, 0x00, 0x81, 0x81, 0x7e,
0xfe, 0x00, 0x03, 0xfc, 0x01, 0x82, 0x00, 0xb9, 0x00, 0xb9, 0x01, 0x82, 0x00, 0xb9, 0x10, 0xef,
0x00, 0x00, 0x00, 0x20, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 KD_BAT[64] = {
0x7f, 0x00, 0x83, 0x7c, 0x01, 0x82, 0x00, 0xb9, 0x01, 0x82, 0x00, 0xb9, 0x00, 0x81, 0x01, 0x7e,
0xff, 0x00, 0x81, 0x7e, 0x00, 0x81, 0x00, 0xb9, 0x00, 0xb9, 0x00, 0x81, 0x00, 0xb9, 0x10, 0xef,
0xfe, 0x00, 0x00, 0xff, 0x00, 0x81, 0x00, 0xe7, 0xc3, 0x24, 0xc3, 0x24, 0xc3, 0x24, 0xc2, 0x3c,
0x00, 0x00, 0x00, 0x20, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 KD_ACTUAL[64];
u8 KD_NOR_GRAPHICS[128] = {
0x00, 0x00, 0x00, 0x0f, 0x04, 0x07, 0x18, 0x1f, 0x0d, 0x0e, 0x40, 0x7f, 0x18, 0x1f, 0x70, 0x7f,
0xc0, 0xff, 0x70, 0x7f, 0x01, 0x3e, 0x0c, 0x0f, 0x3e, 0x3f, 0x10, 0x1f, 0x06, 0x07, 0x00, 0x00,
0x00, 0x00, 0x18, 0xe0, 0xe4, 0x18, 0x3a, 0xc4, 0xfc, 0x02, 0x3d, 0xc2, 0xfe, 0x01, 0x3e, 0xc1,
0x7e, 0x81, 0x3e, 0xc1, 0xfd, 0x02, 0x7c, 0x82, 0x1a, 0xe4, 0xe4, 0x18, 0x10, 0xe0, 0x00, 0x00,
0x04, 0x03, 0x13, 0x0c, 0x2f, 0x10, 0x5f, 0x20, 0x5f, 0x20, 0x3f, 0x40, 0x2a, 0x55, 0x2a, 0x55,
0x08, 0x77, 0x00, 0x7f, 0x28, 0x7f, 0x1a, 0x5f, 0x13, 0x17, 0x01, 0x05, 0x05, 0x05, 0x00, 0x00,
0x20, 0xc0, 0xc8, 0x30, 0xf4, 0x08, 0xf8, 0x04, 0xfa, 0x04, 0xf4, 0x0a, 0xb4, 0x4a, 0x24, 0xda,
0x20, 0xde, 0x0a, 0xfe, 0x1a, 0xfe, 0x18, 0xfc, 0x4c, 0xec, 0x48, 0xe8, 0xc0, 0xc0, 0x80, 0x80};
u8 KD_ACTUAL_GRAPHICS[128];
bool KD_WeaponPressed = false;
s8 KD_LastWeapon; // -1 for selected weapon, 0 for NOR, 4 for BAT
u8 KD_ActualItem; // Item selected by the player (byte in memory)
void KD_WeaponToMemory() {
// If the fourth 8x8 tile of the weapon indicator doesn't contain the "+" icon I made, the weapon has been changed in the game and has to be updated in memory.
bool hasPlusIcon = true;
for (int i=48; i<64; i++) {
if (gbReadMemory(0x9110+i) != KD_BAT[i]) {
hasPlusIcon = false;
break;
}
}
if (hasPlusIcon) return;
KD_ActualItem = gbReadMemory(0xC8CB);
for (int i=0; i<64; i++) {
KD_ACTUAL[i] = gbReadMemory(0x9110+i);
}
for (int i=0; i<128; i++) {
KD_ACTUAL_GRAPHICS[i] = gbReadMemory(0x8f40+i);
}
}
u32 KidDraculaInput(unsigned short pad) {
// Only Nunchuk and Classic controls available
// Wiimote and Gamecube controls depend on user configuration
u32 J = StandardMovement(pad) | DecodeGamecube(pad) | DecodeWiimote(pad) | DecodeClassic(pad);
bool JumpButton=0, ShootButton=0, PauseButton=0, SelectButton=0, SpeedButton=0, NorButton=0, BatButton=0;
#ifdef HW_RVL
WPADData * wp = WPAD_Data(pad);
if (wp->exp.type == WPAD_EXP_NUNCHUK) {
JumpButton = wp->btns_h & WPAD_BUTTON_A;
ShootButton = wp->btns_h & WPAD_BUTTON_B;
PauseButton = wp->btns_h & WPAD_BUTTON_PLUS;
SelectButton = wp->btns_h & WPAD_BUTTON_MINUS;
SpeedButton = wp->btns_h & WPAD_BUTTON_1 || wp->btns_h & WPAD_BUTTON_2;
NorButton = wp->btns_h & WPAD_NUNCHUK_BUTTON_Z;
BatButton = wp->btns_h & WPAD_NUNCHUK_BUTTON_C;
} else if (wp->exp.type == WPAD_EXP_CLASSIC) {
JumpButton = wp->btns_h & (WPAD_CLASSIC_BUTTON_B | WPAD_CLASSIC_BUTTON_A);
ShootButton = wp->btns_h & WPAD_CLASSIC_BUTTON_Y;
PauseButton = wp->btns_h & WPAD_CLASSIC_BUTTON_PLUS;
SelectButton = wp->btns_h & WPAD_CLASSIC_BUTTON_MINUS;
SpeedButton = wp->btns_h & (WPAD_CLASSIC_BUTTON_ZL | WPAD_CLASSIC_BUTTON_FULL_L);
NorButton = wp->btns_h & WPAD_CLASSIC_BUTTON_X;
BatButton = wp->btns_h & (WPAD_CLASSIC_BUTTON_ZR | WPAD_CLASSIC_BUTTON_FULL_R);
}
#endif
if (JumpButton) J |= VBA_BUTTON_A;
if (ShootButton && !(KD_WeaponPressed && KD_LastWeapon != -1)) {
J |= VBA_BUTTON_B;
KD_LastWeapon = -1;
// Insert original weapon and graphics
KD_WeaponToMemory();
gbWriteMemory(0xC8CB, KD_ActualItem);
for (int i=0; i<64; i++) {
gbWriteMemory(0x9110+i, KD_ACTUAL[i]);
}
for (int i=0; i<128; i++) {
gbWriteMemory(0x8f40+i, KD_ACTUAL_GRAPHICS[i]);
}
}
if (NorButton && !(KD_WeaponPressed && KD_LastWeapon != 0)) {
J |= VBA_BUTTON_B;
KD_LastWeapon = 0;
// Insert NOR weapon and graphics
KD_WeaponToMemory();
gbWriteMemory(0xC8CB, 0);
for (int i=0; i<64; i++) {
gbWriteMemory(0x9110+i, KD_NOR[i]);
}
for (int i=0; i<128; i++) {
gbWriteMemory(0x8f40+i, KD_NOR_GRAPHICS[i]);
}
}
if (BatButton && !(KD_WeaponPressed && KD_LastWeapon != 4)) {
J |= VBA_BUTTON_B;
KD_LastWeapon = 4;
// Insert BAT weapon and graphics
KD_WeaponToMemory();
gbWriteMemory(0xC8CB, 4);
for (int i=0; i<64; i++) {
gbWriteMemory(0x9110+i, KD_BAT[i]);
}
}
if (PauseButton) J |= VBA_BUTTON_START;
if (SelectButton) J |= VBA_BUTTON_SELECT;
if (SpeedButton) J |= VBA_SPEED;
KD_WeaponPressed = (ShootButton || NorButton || BatButton);
return J;
}

View File

@ -115,7 +115,7 @@
#define CVCLASSIC gid('F','A','D') #define CVCLASSIC gid('F','A','D')
#define CVDOUBLE gid('B','X','K') #define CVDOUBLE gid('B','X','K')
#define KIDDRACULA 0xFF0014
#define MARBLEMADNESS 0xFF000A #define MARBLEMADNESS 0xFF000A
@ -205,6 +205,7 @@ u32 CastlevaniaAdventureInput(unsigned short pad);
u32 CastlevaniaBelmontInput(unsigned short pad); u32 CastlevaniaBelmontInput(unsigned short pad);
u32 CastlevaniaLegendsInput(unsigned short pad); u32 CastlevaniaLegendsInput(unsigned short pad);
u32 CastlevaniaCircleMoonInput(unsigned short pad); u32 CastlevaniaCircleMoonInput(unsigned short pad);
u32 KidDraculaInput(unsigned short pad);
#endif #endif

View File

@ -13,6 +13,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <zlib.h> #include <zlib.h>
#include <sys/stat.h>
#include "vbagx.h" #include "vbagx.h"
#include "fileop.h" #include "fileop.h"
@ -367,14 +368,15 @@ int SzParse(char * filepath)
int device; int device;
if(!FindDevice(browser.dir, &device) || !GetFileSize(browser.selIndex)) struct stat filestat;
if(stat(filepath, &filestat) < 0)
return 0;
unsigned int filelen = filestat.st_size;
if(!FindDevice(filepath, &device) || !filelen)
return 0; return 0;
int nbfiles = 0; int nbfiles = 0;
// save the length/offset of this file
unsigned int filelen = browserList[browser.selIndex].length;
// setup archive stream // setup archive stream
SzArchiveStream.offset = 0; SzArchiveStream.offset = 0;
SzArchiveStream.len = filelen; SzArchiveStream.len = filelen;
@ -423,7 +425,7 @@ int SzParse(char * filepath)
// add '..' folder in case the user wants exit the 7z // add '..' folder in case the user wants exit the 7z
AddBrowserEntry(); AddBrowserEntry();
sprintf(browserList[0].filename, "..");
sprintf(browserList[0].displayname, "Up One Level"); sprintf(browserList[0].displayname, "Up One Level");
browserList[0].isdir = 1; browserList[0].isdir = 1;
browserList[0].length = filelen; browserList[0].length = filelen;
@ -452,6 +454,12 @@ int SzParse(char * filepath)
// parse information about this file to the file list structure // parse information about this file to the file list structure
snprintf(browserList[SzJ].filename, MAXJOLIET, "%s", SzF->Name); snprintf(browserList[SzJ].filename, MAXJOLIET, "%s", SzF->Name);
StripExt(browserList[SzJ].displayname, browserList[SzJ].filename); StripExt(browserList[SzJ].displayname, browserList[SzJ].filename);
char* strPos = strstr(browserList[SzJ].displayname, szname);
if(strPos)
{
snprintf(browserList[SzJ].displayname, MAXJOLIET, "%s", strPos + strlen(szname));
}
browserList[SzJ].length = SzF->Size; // filesize browserList[SzJ].length = SzF->Size; // filesize
browserList[SzJ].isdir = 0; // only files will be displayed (-> no flags) browserList[SzJ].isdir = 0; // only files will be displayed (-> no flags)
browserList[SzJ].filenum = SzI; // the extraction function identifies the file with this number browserList[SzJ].filenum = SzI; // the extraction function identifies the file with this number

6
source/goomba/README.txt Normal file
View File

@ -0,0 +1,6 @@
goombasav.c is designed to edit the compressed SRAM data of the Goomba and Goomba Color emulators. It can extract and replace the compressed Game Boy / Game Boy Color SRAM data. It can't edit savestate data or add new SRAM (yet).
goombarom.c can find uncompressed Game Boy ROMs within larger files (e.g. a Goomba Color .gba ROM, or a .tar archive.) It was written for my fork of TGB Dual.
https://github.com/libertyernie/goombasav
https://github.com/libertyernie/tgbdual

View File

@ -0,0 +1,84 @@
/* goombarom.c - functions to find uncompressed Game Boy ROM images
stored within a larger file (e.g. Goomba Color ROMs, TAR archives)
Copyright (C) 2014 libertyernie
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, see <http://www.gnu.org/licenses/>.
When compiling in Visual Studio, set all goombarom files to compile
as C++ code (Properties -> C/C++ -> Advanced -> Compile As.)
*/
#include <stdlib.h>
#include <string.h>
#include "goombarom.h"
const char NINTENDO_LOGO_GB[48] = { 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E };
char gb_title_buffer[16];
/* Finds the (expected) size of a Game Boy ROM, given a pointer to the start
of the ROM image. */
unsigned int gb_rom_size(const void* rom_start) {
const char* ptr = (const char*)rom_start;
return 0x8000 << ptr[0x148];
}
/* Finds the first Game Boy ROM in the given data block by looking for the
Nintendo logo that shows when you turn the Game Boy on. If no valid data is
found, this method will return NULL. */
const void* gb_first_rom(const void* data, size_t length) {
const char* ptr = (const char*)data;
const char* end = ptr + length;
int logo_pos = 0;
while (ptr < end) {
if (*ptr == NINTENDO_LOGO_GB[logo_pos]) {
// match
logo_pos++;
if (logo_pos == 48) { // matched all of GB logo - on last byte (0x133)
return ptr - 0x133;
}
} else {
// no match, try again
if (logo_pos > 0) {
ptr -= logo_pos;
logo_pos = 0;
}
}
ptr++;
}
return NULL;
}
/* Returns a pointer to the next Game Boy ROM in the data. If no valid Game
Boy ROM is found between *data and *data+length, starting at *rom, this method
will return NULL.*/
const void* gb_next_rom(const void* data, size_t length, const void* rom) {
size_t diff = (const char*)rom - (const char*)data;
if (diff > length) {
//fprintf(stderr, "*data and *rom are farther apart than length param\n");
return NULL;
}
size_t effective_length = length - diff;
if (effective_length <= 0x200) {
return NULL;
}
return gb_first_rom((const char*)rom + 0x134, effective_length - 0x134);
}
const char* gb_get_title(const void* rom, char* buffer) {
char* title = buffer != NULL ? buffer : gb_title_buffer;
title[15] = '\0';
memcpy(title, (char*)rom + 0x134, 15);
return title;
}

43
source/goomba/goombarom.h Normal file
View File

@ -0,0 +1,43 @@
/* goombarom.h - functions to find uncompressed Game Boy ROM images
stored within a larger file (e.g. Goomba Color ROMs, TAR archives)
Copyright (C) 2014 libertyernie
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, see <http://www.gnu.org/licenses/>.
When compiling in Visual Studio, set all goombarom files to compile
as C++ code (Properties -> C/C++ -> Advanced -> Compile As.)
*/
#include <stddef.h>
/* Finds the (expected) size of a Game Boy ROM, given a pointer to the start
of the ROM image. */
unsigned int gb_rom_size(const void* rom_start);
/* Finds the first Game Boy ROM in the given data block by looking for the
Nintendo logo that shows when you turn the Game Boy on. If no valid data is
found, this method will return NULL. */
const void* gb_first_rom(const void* data, size_t length);
/* Returns a pointer to the next Game Boy ROM in the data. If the location
where the next ROM would be does not contain a valid Nintendo logo at 0x104,
this method will return NULL. */
const void* gb_next_rom(const void* data, size_t length, const void* first_rom);
/* Returns a copy of the title from the ROM header. If buffer is NULL, the
string will be allocated in an internal 16-byte buffer which will be
overwritten later. If buffer is not NULL, the title will be copied to buffer,
and buffer will be returned. */
const char* gb_get_title(const void* rom, char* buffer);

445
source/goomba/goombasav.cpp Normal file
View File

@ -0,0 +1,445 @@
/* goombasav.c - functions to handle Goomba / Goomba Color SRAM
last updated September 8, 2014
Copyright (C) 2014 libertyernie
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, see <http://www.gnu.org/licenses/>.
https://github.com/libertyernie/goombasav
When compiling in Visual Studio, set all goombasav files to compile
as C++ code (Properties -> C/C++ -> Advanced -> Compile As.)
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "goombasav.h"
#include "minilzo-2.06/minilzo.h"
#define goomba_error(...) { sprintf(last_error, __VA_ARGS__); }
#define F16 little_endian_conv_16
#define F32 little_endian_conv_32
static const char* const sleeptxt[] = { "5min", "10min", "30min", "OFF" };
static const char* const brightxt[] = { "I", "II", "III", "IIII", "IIIII" };
static char last_error[256] = "No error has occured yet.";
static char goomba_strbuf[256];
const char* goomba_last_error() {
return (const char*)last_error;
}
size_t goomba_set_last_error(const char* msg) {
size_t len = strnlen(msg, sizeof(last_error)-1);
memcpy(last_error, msg, len);
last_error[sizeof(last_error)-1] = '\0';
return len;
}
// For making a checksum of the compressed data.
// output_bytes is limited to 8 at maximum
uint64_t checksum_slow(const void* ptr, size_t length, int output_bytes) {
const unsigned char* p = (const unsigned char*)ptr;
uint64_t sum=0;
char* sumptr = (char*)&sum;
size_t j;
for (j=0;j<length;j++) {
int index = j%output_bytes;
sumptr[index] += *p;
p++;
}
return sum;
}
uint16_t little_endian_conv_16(uint16_t value) {
if (*(uint16_t *)"\0\xff" < 0x100) {
uint16_t buffer;
((char*)&buffer)[0] = ((char*)&value)[1];
((char*)&buffer)[1] = ((char*)&value)[0];
return buffer;
} else {
return value;
}
}
uint32_t little_endian_conv_32(uint32_t value) {
if (*(uint16_t *)"\0\xff" < 0x100) {
uint32_t buffer;
((char*)&buffer)[0] = ((char*)&value)[3];
((char*)&buffer)[1] = ((char*)&value)[2];
((char*)&buffer)[2] = ((char*)&value)[1];
((char*)&buffer)[3] = ((char*)&value)[0];
return buffer;
} else {
return value;
}
}
configdata_misc_strings configdata_get_misc(char misc) {
configdata_misc_strings s;
s.sleep = sleeptxt[misc & 0x3];
s.autoload_state = ((misc & 0x10) >> 4) ? "ON" : "OFF";
s.gamma = brightxt[(misc & 0xE0) >> 5];
return s;
}
const char* stateheader_typestr(uint16_t type) {
switch (type) {
case GOOMBA_STATESAVE:
return "Savestate";
case GOOMBA_SRAMSAVE:
return "SRAM";
case GOOMBA_CONFIGSAVE:
return "Configuration";
case GOOMBA_PALETTE: // Used by Goomba Paletted
return "Palette";
default:
return "Unknown"; // Stateheaders with these types are rejected by stateheader_plausible
}
}
const char* stateheader_str(const stateheader* sh) {
int j = 0;
j += sprintf(goomba_strbuf + j, "size: %u\n", F16(sh->size));
j += sprintf(goomba_strbuf + j, "type: %s (%u)\n", stateheader_typestr(F16(sh->type)), F16(sh->type));
if (F16(sh->type) == GOOMBA_CONFIGSAVE) {
configdata* cd = (configdata*)sh;
j += sprintf(goomba_strbuf + j, "bordercolor: %u\n", cd->bordercolor);
j += sprintf(goomba_strbuf + j, "palettebank: %u\n", cd->palettebank);
configdata_misc_strings strs = configdata_get_misc(cd->misc);
j += sprintf(goomba_strbuf + j, "sleep: %s\n", strs.sleep);
j += sprintf(goomba_strbuf + j, "autoload state: %s\n", strs.autoload_state);
j += sprintf(goomba_strbuf + j, "gamma: %s\n", strs.gamma);
j += sprintf(goomba_strbuf + j, "rom checksum: %8X (0xE000-0xFFFF %s)\n", F32(cd->sram_checksum),
cd->sram_checksum != 0 ? "occupied" : "free");
} else {
j += sprintf(goomba_strbuf + j, "%scompressed_size: %u\n",
(F32(sh->uncompressed_size) < F16(sh->size) ? "" : "un"),
F32(sh->uncompressed_size));
j += sprintf(goomba_strbuf + j, "framecount: %u\n", F32(sh->framecount));
j += sprintf(goomba_strbuf + j, "rom checksum: %8X\n", F32(sh->checksum));
}
j += sprintf(goomba_strbuf + j, "title: %s", sh->title);
return goomba_strbuf;
}
const char* stateheader_summary_str(const stateheader* sh) {
sprintf(goomba_strbuf, "%s: %s (%u b / %u uncomp)", stateheader_typestr(
F16(sh->type)), sh->title, F16(sh->size), F32(sh->uncompressed_size));
return goomba_strbuf;
}
int stateheader_plausible(const stateheader* sh) {
uint16_t type = F16(sh->type);
if (type < 0 || type == 3 || type == 4 || type > 5) return 0;
return F16(sh->size) >= sizeof(stateheader) && // check size (at least 48)
(F16(sh->type) == GOOMBA_CONFIGSAVE || sh->uncompressed_size != 0); // check uncompressed_size, but not for configsave
// when checking for whether something equals 0, endian conversion is not necessary
}
stateheader* stateheader_advance(const stateheader* sh) {
if (!stateheader_plausible(sh)) return NULL;
uint16_t s = F16(sh->size);
char* c = (char*)sh;
c += s;
return (stateheader*)c;
}
stateheader** stateheader_scan(const void* gba_data) {
// Do not edit gba_data!
// We are casting to non-const pointers so the client gets non-const pointers back.
const goomba_size_t psize = sizeof(stateheader*);
stateheader** headers = (stateheader**)malloc(psize * 64);
memset(headers, 0, psize * 64);
uint32_t* check = (uint32_t*)gba_data;
if (F32(*check) == GOOMBA_STATEID) check++;
stateheader* sh = (stateheader*)check;
int i = 0;
while (stateheader_plausible(sh) && i < 63) {
headers[i] = sh;
i++;
sh = stateheader_advance(sh);
}
return headers;
}
stateheader* stateheader_for(const void* gba_data, const char* gbc_title) {
char title[0x10];
memcpy(title, gbc_title, 0x0F);
title[0x0F] = '\0';
stateheader* use_this = NULL;
stateheader** headers = stateheader_scan(gba_data);
int i;
for (i = 0; headers[i] != NULL; i++) {
if (strcmp(headers[i]->title, title) == 0 && F16(headers[i]->type) == GOOMBA_SRAMSAVE) {
use_this = headers[i];
break;
}
}
free(headers);
if (use_this == NULL) sprintf(last_error, "Could not find SRAM data for %s", title);
return use_this;
}
// Uses checksum_slow, and looks at the compressed data (not the header).
// output_bytes is limited to 8 at maximum
uint64_t goomba_compressed_data_checksum(const stateheader* sh, int output_bytes) {
return checksum_slow(sh+1, F16(sh->size) - sizeof(stateheader), output_bytes);
}
int goomba_is_sram(const void* data) {
return F32(*(uint32_t*)data) == GOOMBA_STATEID;
}
/**
* Returns the 32-bit checksum (unsigned) in the configdata header, or -1 if
* stateheader_scan returns NULL due to an error. When using this function,
* first check if the value is less than 0, then (if not) cast to uint32_t.
*/
int64_t goomba_get_configdata_checksum_field(const void* gba_data) {
// todo fix
stateheader** headers = stateheader_scan(gba_data);
if (headers == NULL) return -1;
int i;
for (i = 0; headers[i] != NULL; i++) {
if (F16(headers[i]->type) == GOOMBA_CONFIGSAVE) {
// found configdata
const configdata* cd = (configdata*)headers[i];
free(headers);
return F32(cd->sram_checksum); // 0 = clean, postitive = unclean
}
}
free(headers);
return -1; // not sure when this would happen
}
char* goomba_cleanup(const void* gba_data_param) {
char gba_data[GOOMBA_COLOR_SRAM_SIZE]; // on stack - do not need to free
memcpy(gba_data, gba_data_param, GOOMBA_COLOR_SRAM_SIZE);
stateheader** headers = stateheader_scan(gba_data);
if (headers == NULL) return NULL;
int i, j;
for (i = 0; headers[i] != NULL; i++) {
if (F16(headers[i]->type) == GOOMBA_CONFIGSAVE) {
// found configdata
configdata* cd = (configdata*)headers[i];
const uint32_t checksum = F32(cd->sram_checksum);
for (j = 0; headers[j] != NULL; j++) {
stateheader* sh = headers[j];
if (F16(sh->type) == GOOMBA_SRAMSAVE && F32(sh->checksum) == checksum) {
// found stateheader
free(headers); // so make sure we return something before the loop goes around again!!
cd->sram_checksum = 0; // because we do this here, goomba_new_sav should not complain about an unclean file
char gbc_data[GOOMBA_COLOR_SRAM_SIZE - GOOMBA_COLOR_AVAILABLE_SIZE];
memcpy(gbc_data,
gba_data + GOOMBA_COLOR_AVAILABLE_SIZE,
sizeof(gbc_data)); // Extract GBC data at 0xe000 to an array
char* new_gba_data = goomba_new_sav(gba_data, sh, gbc_data, sizeof(gbc_data));
if (new_gba_data != NULL) memset(new_gba_data + GOOMBA_COLOR_AVAILABLE_SIZE, 0, sizeof(gbc_data));
return new_gba_data;
}
}
}
}
free(headers);
return (char*)gba_data_param;
}
void* goomba_extract(const void* gba_data, const stateheader* header_ptr, goomba_size_t* size_output) {
const stateheader* sh = (const stateheader*)header_ptr;
if (F16(sh->type) != GOOMBA_SRAMSAVE) {
goomba_error("Error: this program can only extract SRAM data.\n");
return NULL;
}
const int64_t ck = goomba_get_configdata_checksum_field(gba_data);
if (ck < 0) {
return NULL;
} else if (ck == F32(sh->checksum)) {
goomba_error("File is unclean - run goomba_cleanup before trying to extract SRAM, or you might get old data\n");
return NULL;
} else if (ck != 0) {
fprintf(stderr, "File is unclean, but it shouldn't affect retrieval of the data you asked for\n");
}
lzo_uint compressed_size = F16(sh->size) - sizeof(stateheader);
lzo_uint output_size = 32768;
const unsigned char* compressed_data = (unsigned char*)header_ptr + sizeof(stateheader);
unsigned char* uncompressed_data = (unsigned char*)malloc(output_size);
int r = lzo1x_decompress_safe(compressed_data, compressed_size,
uncompressed_data, &output_size,
(void*)NULL);
//fprintf(stderr, "Actual uncompressed size: %lu\n", output_size);
if (r == LZO_E_INPUT_NOT_CONSUMED) {
//goomba_error("Warning: input not fully used. Double-check the result to make sure it works.\n");
} else if (r < 0) {
goomba_error("Cannot decompress data (lzoconf.h error code %d).\n", r);
free(uncompressed_data);
return NULL;
}
*size_output = output_size;
return uncompressed_data;
}
goomba_size_t copy_until_invalid_header(void* dest, const stateheader* src_param) {
const void* src = src_param;
goomba_size_t bytes_copied = 0;
while (1) {
const stateheader* sh = (const stateheader*)src;
if (!stateheader_plausible(sh)) break;
memcpy(dest, src, F16(sh->size));
src = (char*)src + F16(sh->size);
dest = (char*)dest + F16(sh->size);
bytes_copied += F16(sh->size);
}
memcpy(dest, src, sizeof(stateheader)); // copy "footer"
return bytes_copied + sizeof(stateheader);
}
char* goomba_new_sav(const void* gba_data, const void* gba_header, const void* gbc_sram, goomba_size_t gbc_length) {
unsigned char* gba_header_ptr = (unsigned char*)gba_header;
stateheader* sh = (stateheader*)gba_header_ptr;
int64_t ck = goomba_get_configdata_checksum_field(gba_data);
if (ck < 0) {
return NULL;
} else if (ck == F32(sh->checksum)) {
// have to clean file
goomba_error("File is unclean - run goomba_cleanup before trying to replace SRAM, or your new data might get overwritten");
return NULL;
} else if (ck != 0) {
fprintf(stderr, "File is unclean, but it shouldn't affect replacement of the data you asked for\n");
}
if (F16(sh->type) != GOOMBA_SRAMSAVE) {
goomba_error("Error - This program cannot replace non-SRAM data.\n");
return NULL;
}
// sh->uncompressed_size is valid for Goomba Color.
// For Goomba, it's actually compressed size (and will be less than sh->size).
goomba_size_t uncompressed_size;
if (F16(sh->size) > F32(sh->uncompressed_size)) {
// Uncompress to a temporary location, just so we can see how big it is
goomba_size_t output;
void* dump = goomba_extract(gba_data, sh, &output);
if (dump == NULL) {
return NULL;
}
free(dump);
uncompressed_size = output;
} else {
// Goomba Color header - use size from there
uncompressed_size = F32(sh->uncompressed_size);
}
if (gbc_length < uncompressed_size) {
goomba_error("Error: the length of the GBC data (%u) is too short - expected %u bytes.\n",
gbc_length, uncompressed_size);
return NULL;
} else if (gbc_length - 4 == uncompressed_size) {
goomba_error("Note: RTC data (TGB_Dual format) will not be copied\n");
} else if (gbc_length - 44 == uncompressed_size) {
goomba_error("Note: RTC data (old VBA format) will not be copied\n");
} else if (gbc_length - 48 == uncompressed_size) {
goomba_error("Note: RTC data (new VBA format) will not be copied\n");
} else if (gbc_length > uncompressed_size) {
goomba_error("Warning: unknown data at end of GBC save file - only first %u bytes will be used\n", uncompressed_size);
}
if (F16(sh->type) != GOOMBA_SRAMSAVE) {
goomba_error("The data at gba_header is not SRAM data.\n");
return NULL;
}
char* const goomba_new_sav = (char*)malloc(GOOMBA_COLOR_SRAM_SIZE);
memset(goomba_new_sav, 0, GOOMBA_COLOR_SRAM_SIZE);
char* working = goomba_new_sav; // will be incremented throughout
goomba_size_t before_header = (char*)gba_header - (char*)gba_data;
// copy anything before stateheader
memcpy(goomba_new_sav, gba_data, before_header);
working += before_header;
// copy stateheader
memcpy(working, sh, sizeof(stateheader));
stateheader* new_sh = (stateheader*)working;
working += sizeof(stateheader);
// backup data that comes after this header
unsigned char* backup = (unsigned char*)malloc(GOOMBA_COLOR_SRAM_SIZE);
goomba_size_t backup_len = copy_until_invalid_header(backup, (stateheader*)(gba_header_ptr + F16(sh->size)));
// compress gbc sram
lzo_uint compressed_size;
unsigned char* dest = (unsigned char*)working;
void* wrkmem = malloc(LZO1X_1_MEM_COMPRESS);
lzo1x_1_compress((const unsigned char*)gbc_sram, uncompressed_size,
dest, &compressed_size,
wrkmem);
free(wrkmem);
working += compressed_size;
//fprintf(stderr, "Compressed %u bytes (compressed size: %lu)\n", uncompressed_size, compressed_size);
if (F16(sh->size) > F32(sh->uncompressed_size)) {
// Goomba header (not Goomba Color)
new_sh->uncompressed_size = F32(compressed_size);
}
new_sh->size = F16((uint16_t)(compressed_size + sizeof(stateheader)));
// pad to 4 bytes!
// if I don't do this, goomba color might not load the palette settings, or seemingly 'forget' them later
// btw, the settings are stored in the configdata struct defined in goombasav.h
uint16_t s = F16(new_sh->size);
while (s % 4 != 0) {
*working = 0;
working++;
s++;
}
new_sh->size = F16(s);
goomba_size_t used = working - goomba_new_sav;
if (used + backup_len > GOOMBA_COLOR_AVAILABLE_SIZE) {
goomba_error("Not enough room in file for the new save data (0xe000-0xffff must be kept free, I think)\n");
free(backup);
free(goomba_new_sav);
return NULL;
}
// restore the backup - just assume we have enough space
memcpy(working, backup, backup_len);
free(backup);
// restore data from 0xe000 to 0xffff
memcpy(goomba_new_sav + GOOMBA_COLOR_AVAILABLE_SIZE,
(char*)gba_data + GOOMBA_COLOR_AVAILABLE_SIZE,
GOOMBA_COLOR_SRAM_SIZE - GOOMBA_COLOR_AVAILABLE_SIZE);
return goomba_new_sav;
}

184
source/goomba/goombasav.h Normal file
View File

@ -0,0 +1,184 @@
/* goombasav.h - functions to handle Goomba / Goomba Color SRAM
last updated July 3, 2014
Copyright (C) 2014 libertyernie
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, see <http://www.gnu.org/licenses/>.
https://github.com/libertyernie/goombasav
When compiling in Visual Studio, set all goombasav files to compile
as C++ code (Properties -> C/C++ -> Advanced -> Compile As.)
*/
#ifndef __GOOMBASAV_H
#define __GOOMBASAV_H
#include <stdint.h>
#define GOOMBA_COLOR_SRAM_SIZE 65536
#define GOOMBA_COLOR_AVAILABLE_SIZE 57344
#define GOOMBA_STATEID 0x57a731d8
#define GOOMBA_STATESAVE 0
#define GOOMBA_SRAMSAVE 1
#define GOOMBA_CONFIGSAVE 2
#define GOOMBA_PALETTE 5
typedef uint32_t goomba_size_t; // want a consistent size for printf. This is an alias for uint32_t, but this makes it clear that we're counting the size of something.
/* 16-bit and 32-bit values in the stateheader are stored as little endian
(native to the GBA's ARM chip as well as x86 processors.) Use this function
after getting or before setting a value if your code might run on a big-endian
processor (e.g. PowerPC.) */
uint16_t little_endian_conv_16(uint16_t value);
/* 16-bit and 32-bit values in the stateheader are stored as little endian
(native to the GBA's ARM chip as well as x86 processors.) Use this function
after getting or before setting a value if your code might run on a big-endian
processor (e.g. PowerPC.) */
uint32_t little_endian_conv_32(uint32_t value);
typedef struct { //(modified stateheader)
uint16_t size;
uint16_t type; //=CONFIGSAVE
char bordercolor;
char palettebank;
char misc;
char reserved3;
uint32_t sram_checksum; //checksum of rom using SRAM e000-ffff
uint32_t zero; //=0
char reserved4[32]; //="CFG"
} configdata;
typedef struct {
uint16_t size; //header+data
uint16_t type; //=STATESAVE or SRAMSAVE
uint32_t uncompressed_size;
uint32_t framecount;
uint32_t checksum;
char title[32];
} stateheader;
typedef struct {
const char* sleep;
const char* autoload_state;
const char* gamma;
} configdata_misc_strings;
/**
* Returns the last error encountered by goombasav (for functions that return
* NULL on error.) This string is stored statically by goombasav and its
* contents may change over time.
*/
const char* goomba_last_error();
/**
* Set the string buffer used by goomba_last_error to a custom value. If the
* input string is too long, the resulting goomba_last_error string will be
* truncated.
* Returns the number of bytes copied to the buffer (at present, the maximum
* is 255.)
*/
size_t goomba_set_last_error(const char* msg);
/**
* Gets a struct containing pointers to three static strings (which do not
* need to be deallocated.)
*/
configdata_misc_strings configdata_get_misc(char misc);
/**
* Returns a multi-line description string that includes all parameters of the
* given stateheader or configdata structure.
* This string is stored in a static character buffer, and subsequent calls to
* stateheader_str or stateheader_summary_str will overwrite this buffer.
*/
const char* stateheader_str(const stateheader* sh);
/**
* Returns a one-line summary string displaying the size and title of the
* stateheader or configdata structure.
* This string is stored in a static character buffer, and subsequent calls to
* stateheader_str or stateheader_summary_str will overwrite this buffer.
*/
const char* stateheader_summary_str(const stateheader* sh);
int stateheader_plausible(const stateheader* sh);
/**
* When given a pointer to a stateheader, returns a pointer to where the next
* stateheader will be located (if any). Use stateheader_plausible to
* determine if there really is a header at this location.
*
* If stateheader_plausible determines that the input is not a valid
* stateheader, NULL will be returned.
*/
stateheader* stateheader_advance(const stateheader* sh);
/**
* Scans for valid stateheaders and allocates an array to store them. The array
* will have a capacity of 64, and any difference between that
* and the number of headers found will be filled with NULL entries. The last
* entry (array[63]) is guaranteed to be NULL.
* NOTE: the gba_data parameter can point to a valid header, or to a sequence
* equal to GOOMBA_STATEID immediately before a valid header.
*/
stateheader** stateheader_scan(const void* gba_data);
/**
* Returns the stateheader in gba_data with the title field = gbc_title,
* or NULL if there is none. Only the first 15 bytes of gbc_title will be
* used in the comparison.
*/
stateheader* stateheader_for(const void* gba_data, const char* gbc_title_ptr);
/**
* Returns true if the given data starts with GOOMBA_STATEID (little endian.)
*/
int goomba_is_sram(const void* data);
/**
* Makes a hash of the compressed data that comes after the given header,
* using output_bytes bytes. A three-byte hash can be displayed as a color to
* give visual feedback of a change in the data. The maximum of output_bytes is
* sizeof(int).
*/
uint64_t goomba_compressed_data_checksum(const stateheader* sh, int output_bytes);
/**
* If there is save data in 0xe000-0xffff (as signaled by the configdata),
* this function compresses it to where it's supposed to go. In the event that
* the data passed in is already clean, the same pointer will be returned.
* NULL will be returned if an error occurs.
*
* The given pointer must be at least GOOMBA_COLOR_SRAM_SIZE bytes in length.
* If it is longer, any information after GOOMBA_COLOR_SRAM_SIZE bytes will be
* ignored.
*/
char* goomba_cleanup(const void* gba_data_param);
/**
* Allocates memory to store the uncompressed GB/GBC save file extracted from
* the Goomba Color save file stored in header_ptr, or returns NULL if the
* decompression failed.
*/
void* goomba_extract(const void* gba_data, const stateheader* header_ptr, goomba_size_t* size_output);
/**
* Copies data from the source (which must point to a valid stateheader or
* configdata) to dest, up to and including the first 48 bytes that do not
* constitute a valid header.
*/
char* goomba_new_sav(const void* gba_data, const void* gba_header, const void* gbc_sram, goomba_size_t gbc_length);
#endif

View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -0,0 +1,124 @@
============================================================================
miniLZO -- mini subset of the LZO real-time data compression library
============================================================================
Author : Markus Franz Xaver Johannes Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
Version : 2.06
Date : 12 Aug 2011
I've created miniLZO for projects where it is inconvenient to
include (or require) the full LZO source code just because you
want to add a little bit of data compression to your application.
miniLZO implements the LZO1X-1 compressor and both the standard and
safe LZO1X decompressor. Apart from fast compression it also useful
for situations where you want to use pre-compressed data files (which
must have been compressed with LZO1X-999).
miniLZO consists of one C source file and three header files:
minilzo.c
minilzo.h, lzoconf.h, lzodefs.h
To use miniLZO just copy these files into your source directory, add
minilzo.c to your Makefile and #include minilzo.h from your program.
Note: you also must distribute this file ('README.LZO') with your project.
minilzo.o compiles to about 6 KiB (using gcc or Visual C on an i386), and
the sources are about 30 KiB when packed with zip - so there's no more
excuse that your application doesn't support data compression :-)
For more information, documentation, example programs and other support
files (like Makefiles and build scripts) please download the full LZO
package from
http://www.oberhumer.com/opensource/lzo/
Have fun,
Markus
P.S. minilzo.c is generated automatically from the LZO sources and
therefore functionality is completely identical
Appendix A: building miniLZO
----------------------------
miniLZO is written such a way that it should compile and run
out-of-the-box on most machines.
If you are running on a very unusual architecture and lzo_init() fails then
you should first recompile with '-DLZO_DEBUG' to see what causes the failure.
The most probable case is something like 'sizeof(void *) != sizeof(size_t)'.
After identifying the problem you can compile by adding some defines
like '-DSIZEOF_VOID_P=8' to your Makefile.
The best solution is (of course) using Autoconf - if your project uses
Autoconf anyway just add '-DMINILZO_HAVE_CONFIG_H' to your compiler
flags when compiling minilzo.c. See the LZO distribution for an example
how to set up configure.ac.
Appendix B: list of public functions available in miniLZO
---------------------------------------------------------
Library initialization
lzo_init()
Compression
lzo1x_1_compress()
Decompression
lzo1x_decompress()
lzo1x_decompress_safe()
Checksum functions
lzo_adler32()
Version functions
lzo_version()
lzo_version_string()
lzo_version_date()
Portable (but slow) string functions
lzo_memcmp()
lzo_memcpy()
lzo_memmove()
lzo_memset()
Appendix C: suggested macros for 'configure.ac' when using Autoconf
-------------------------------------------------------------------
Checks for typedefs and structures
AC_CHECK_TYPE(ptrdiff_t,long)
AC_TYPE_SIZE_T
AC_CHECK_SIZEOF(short)
AC_CHECK_SIZEOF(int)
AC_CHECK_SIZEOF(long)
AC_CHECK_SIZEOF(long long)
AC_CHECK_SIZEOF(__int64)
AC_CHECK_SIZEOF(void *)
AC_CHECK_SIZEOF(size_t)
AC_CHECK_SIZEOF(ptrdiff_t)
Checks for compiler characteristics
AC_C_CONST
Checks for library functions
AC_CHECK_FUNCS(memcmp memcpy memmove memset)
Appendix D: Copyright
---------------------
LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001,
2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Markus Franz Xaver Oberhumer <markus@oberhumer.com>.
LZO and miniLZO are distributed under the terms of the GNU General
Public License (GPL). See the file COPYING.
Special licenses for commercial and other applications which
are not willing to accept the GNU General Public License
are available by contacting the author.

View File

@ -0,0 +1,446 @@
/* lzoconf.h -- configuration of the LZO data compression library
This file is part of the LZO real-time data compression library.
Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
The LZO library 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.
The LZO library 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 the LZO library; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
*/
#ifndef __LZOCONF_H_INCLUDED
#define __LZOCONF_H_INCLUDED 1
#define LZO_VERSION 0x2060
#define LZO_VERSION_STRING "2.06"
#define LZO_VERSION_DATE "Aug 12 2011"
/* internal Autoconf configuration file - only used when building LZO */
#if defined(LZO_HAVE_CONFIG_H)
# include <config.h>
#endif
#include <limits.h>
#include <stddef.h>
/***********************************************************************
// LZO requires a conforming <limits.h>
************************************************************************/
#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
# error "invalid CHAR_BIT"
#endif
#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
# error "check your compiler installation"
#endif
#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)
# error "your limits.h macros are broken"
#endif
/* get OS and architecture defines */
#ifndef __LZODEFS_H_INCLUDED
#include "lzodefs.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***********************************************************************
// some core defines
************************************************************************/
#if !defined(LZO_UINT32_C)
# if (UINT_MAX < LZO_0xffffffffL)
# define LZO_UINT32_C(c) c ## UL
# else
# define LZO_UINT32_C(c) ((c) + 0U)
# endif
#endif
/* memory checkers */
#if !defined(__LZO_CHECKER)
# if defined(__BOUNDS_CHECKING_ON)
# define __LZO_CHECKER 1
# elif defined(__CHECKER__)
# define __LZO_CHECKER 1
# elif defined(__INSURE__)
# define __LZO_CHECKER 1
# elif defined(__PURIFY__)
# define __LZO_CHECKER 1
# endif
#endif
/***********************************************************************
// integral and pointer types
************************************************************************/
/* lzo_uint should match size_t */
#if !defined(LZO_UINT_MAX)
# if defined(LZO_ABI_LLP64) /* WIN64 */
# if defined(LZO_OS_WIN64)
typedef unsigned __int64 lzo_uint;
typedef __int64 lzo_int;
# else
typedef unsigned long long lzo_uint;
typedef long long lzo_int;
# endif
# define LZO_UINT_MAX 0xffffffffffffffffull
# define LZO_INT_MAX 9223372036854775807LL
# define LZO_INT_MIN (-1LL - LZO_INT_MAX)
# elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */
typedef unsigned int lzo_uint;
typedef int lzo_int;
# define LZO_UINT_MAX UINT_MAX
# define LZO_INT_MAX INT_MAX
# define LZO_INT_MIN INT_MIN
# elif (ULONG_MAX >= LZO_0xffffffffL)
typedef unsigned long lzo_uint;
typedef long lzo_int;
# define LZO_UINT_MAX ULONG_MAX
# define LZO_INT_MAX LONG_MAX
# define LZO_INT_MIN LONG_MIN
# else
# error "lzo_uint"
# endif
#endif
/* Integral types with 32 bits or more. */
#if !defined(LZO_UINT32_MAX)
# if (UINT_MAX >= LZO_0xffffffffL)
typedef unsigned int lzo_uint32;
typedef int lzo_int32;
# define LZO_UINT32_MAX UINT_MAX
# define LZO_INT32_MAX INT_MAX
# define LZO_INT32_MIN INT_MIN
# elif (ULONG_MAX >= LZO_0xffffffffL)
typedef unsigned long lzo_uint32;
typedef long lzo_int32;
# define LZO_UINT32_MAX ULONG_MAX
# define LZO_INT32_MAX LONG_MAX
# define LZO_INT32_MIN LONG_MIN
# else
# error "lzo_uint32"
# endif
#endif
/* Integral types with exactly 64 bits. */
#if !defined(LZO_UINT64_MAX)
# if (LZO_UINT_MAX >= LZO_0xffffffffL)
# if ((((LZO_UINT_MAX) >> 31) >> 31) == 3)
# define lzo_uint64 lzo_uint
# define lzo_int64 lzo_int
# define LZO_UINT64_MAX LZO_UINT_MAX
# define LZO_INT64_MAX LZO_INT_MAX
# define LZO_INT64_MIN LZO_INT_MIN
# endif
# elif (ULONG_MAX >= LZO_0xffffffffL)
# if ((((ULONG_MAX) >> 31) >> 31) == 3)
typedef unsigned long lzo_uint64;
typedef long lzo_int64;
# define LZO_UINT64_MAX ULONG_MAX
# define LZO_INT64_MAX LONG_MAX
# define LZO_INT64_MIN LONG_MIN
# endif
# endif
#endif
/* The larger type of lzo_uint and lzo_uint32. */
#if (LZO_UINT_MAX >= LZO_UINT32_MAX)
# define lzo_xint lzo_uint
#else
# define lzo_xint lzo_uint32
#endif
/* Memory model that allows to access memory at offsets of lzo_uint. */
#if !defined(__LZO_MMODEL)
# if (LZO_UINT_MAX <= UINT_MAX)
# define __LZO_MMODEL /*empty*/
# elif defined(LZO_HAVE_MM_HUGE_PTR)
# define __LZO_MMODEL_HUGE 1
# define __LZO_MMODEL __huge
# else
# define __LZO_MMODEL /*empty*/
# endif
#endif
/* no typedef here because of const-pointer issues */
#define lzo_bytep unsigned char __LZO_MMODEL *
#define lzo_charp char __LZO_MMODEL *
#define lzo_voidp void __LZO_MMODEL *
#define lzo_shortp short __LZO_MMODEL *
#define lzo_ushortp unsigned short __LZO_MMODEL *
#define lzo_uint32p lzo_uint32 __LZO_MMODEL *
#define lzo_int32p lzo_int32 __LZO_MMODEL *
#if defined(LZO_UINT64_MAX)
#define lzo_uint64p lzo_uint64 __LZO_MMODEL *
#define lzo_int64p lzo_int64 __LZO_MMODEL *
#endif
#define lzo_uintp lzo_uint __LZO_MMODEL *
#define lzo_intp lzo_int __LZO_MMODEL *
#define lzo_xintp lzo_xint __LZO_MMODEL *
#define lzo_voidpp lzo_voidp __LZO_MMODEL *
#define lzo_bytepp lzo_bytep __LZO_MMODEL *
/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */
#define lzo_byte unsigned char __LZO_MMODEL
typedef int lzo_bool;
/***********************************************************************
// function types
************************************************************************/
/* name mangling */
#if !defined(__LZO_EXTERN_C)
# ifdef __cplusplus
# define __LZO_EXTERN_C extern "C"
# else
# define __LZO_EXTERN_C extern
# endif
#endif
/* calling convention */
#if !defined(__LZO_CDECL)
# define __LZO_CDECL __lzo_cdecl
#endif
/* DLL export information */
#if !defined(__LZO_EXPORT1)
# define __LZO_EXPORT1 /*empty*/
#endif
#if !defined(__LZO_EXPORT2)
# define __LZO_EXPORT2 /*empty*/
#endif
/* __cdecl calling convention for public C and assembly functions */
#if !defined(LZO_PUBLIC)
# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
#endif
#if !defined(LZO_EXTERN)
# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype)
#endif
#if !defined(LZO_PRIVATE)
# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL
#endif
/* function types */
typedef int
(__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem,
const lzo_bytep dict, lzo_uint dict_len );
typedef int
(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem,
const lzo_bytep dict, lzo_uint dict_len );
/* Callback interface. Currently only the progress indicator ("nprogress")
* is used, but this may change in a future release. */
struct lzo_callback_t;
typedef struct lzo_callback_t lzo_callback_t;
#define lzo_callback_p lzo_callback_t __LZO_MMODEL *
/* malloc & free function types */
typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t)
(lzo_callback_p self, lzo_uint items, lzo_uint size);
typedef void (__LZO_CDECL *lzo_free_func_t)
(lzo_callback_p self, lzo_voidp ptr);
/* a progress indicator callback function */
typedef void (__LZO_CDECL *lzo_progress_func_t)
(lzo_callback_p, lzo_uint, lzo_uint, int);
struct lzo_callback_t
{
/* custom allocators (set to 0 to disable) */
lzo_alloc_func_t nalloc; /* [not used right now] */
lzo_free_func_t nfree; /* [not used right now] */
/* a progress indicator callback function (set to 0 to disable) */
lzo_progress_func_t nprogress;
/* NOTE: the first parameter "self" of the nalloc/nfree/nprogress
* callbacks points back to this struct, so you are free to store
* some extra info in the following variables. */
lzo_voidp user1;
lzo_xint user2;
lzo_xint user3;
};
/***********************************************************************
// error codes and prototypes
************************************************************************/
/* Error codes for the compression/decompression functions. Negative
* values are errors, positive values will be used for special but
* normal events.
*/
#define LZO_E_OK 0
#define LZO_E_ERROR (-1)
#define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */
#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */
#define LZO_E_INPUT_OVERRUN (-4)
#define LZO_E_OUTPUT_OVERRUN (-5)
#define LZO_E_LOOKBEHIND_OVERRUN (-6)
#define LZO_E_EOF_NOT_FOUND (-7)
#define LZO_E_INPUT_NOT_CONSUMED (-8)
#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */
#define LZO_E_INVALID_ARGUMENT (-10)
#ifndef lzo_sizeof_dict_t
# define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep))
#endif
/* lzo_init() should be the first function you call.
* Check the return code !
*
* lzo_init() is a macro to allow checking that the library and the
* compiler's view of various types are consistent.
*/
#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
(int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\
(int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
(int)sizeof(lzo_callback_t))
LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int);
/* version functions (useful for shared libraries) */
LZO_EXTERN(unsigned) lzo_version(void);
LZO_EXTERN(const char *) lzo_version_string(void);
LZO_EXTERN(const char *) lzo_version_date(void);
LZO_EXTERN(const lzo_charp) _lzo_version_string(void);
LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
/* string functions */
LZO_EXTERN(int)
lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len);
LZO_EXTERN(lzo_voidp)
lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
LZO_EXTERN(lzo_voidp)
lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
LZO_EXTERN(lzo_voidp)
lzo_memset(lzo_voidp buf, int c, lzo_uint len);
/* checksum functions */
LZO_EXTERN(lzo_uint32)
lzo_adler32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
LZO_EXTERN(lzo_uint32)
lzo_crc32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
LZO_EXTERN(const lzo_uint32p)
lzo_get_crc32_table(void);
/* misc. */
LZO_EXTERN(int) _lzo_config_check(void);
typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
typedef union { void *vp; lzo_bytep bp; lzo_uint u; lzo_uint32 u32; unsigned long l; } lzo_align_t;
/* align a char pointer on a boundary that is a multiple of 'size' */
LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
#define LZO_PTR_ALIGN_UP(p,size) \
((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size)))
/***********************************************************************
// deprecated macros - only for backward compatibility with LZO v1.xx
************************************************************************/
#if defined(LZO_CFG_COMPAT)
#define __LZOCONF_H 1
#if defined(LZO_ARCH_I086)
# define __LZO_i386 1
#elif defined(LZO_ARCH_I386)
# define __LZO_i386 1
#endif
#if defined(LZO_OS_DOS16)
# define __LZO_DOS 1
# define __LZO_DOS16 1
#elif defined(LZO_OS_DOS32)
# define __LZO_DOS 1
#elif defined(LZO_OS_WIN16)
# define __LZO_WIN 1
# define __LZO_WIN16 1
#elif defined(LZO_OS_WIN32)
# define __LZO_WIN 1
#endif
#define __LZO_CMODEL /*empty*/
#define __LZO_DMODEL /*empty*/
#define __LZO_ENTRY __LZO_CDECL
#define LZO_EXTERN_CDECL LZO_EXTERN
#define LZO_ALIGN LZO_PTR_ALIGN_UP
#define lzo_compress_asm_t lzo_compress_t
#define lzo_decompress_asm_t lzo_decompress_t
#endif /* LZO_CFG_COMPAT */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* already included */
/* vim:set ts=4 et: */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
/* minilzo.h -- mini subset of the LZO real-time data compression library
This file is part of the LZO real-time data compression library.
Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
The LZO library 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.
The LZO library 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 the LZO library; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
*/
/*
* NOTE:
* the full LZO package can be found at
* http://www.oberhumer.com/opensource/lzo/
*/
#ifndef __MINILZO_H
#define __MINILZO_H 1
#define MINILZO_VERSION 0x2060
#ifdef __LZOCONF_H
# error "you cannot use both LZO and miniLZO"
#endif
#undef LZO_HAVE_CONFIG_H
#include "lzoconf.h"
#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
# error "version mismatch in header files"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***********************************************************************
//
************************************************************************/
/* Memory required for the wrkmem parameter.
* When the required size is 0, you can also pass a NULL pointer.
*/
#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
#define LZO1X_MEM_DECOMPRESS (0)
/* compression */
LZO_EXTERN(int)
lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
/* decompression */
LZO_EXTERN(int)
lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem /* NOT USED */ );
/* safe decompression with overrun testing */
LZO_EXTERN(int)
lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem /* NOT USED */ );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* already included */

View File

@ -123,6 +123,16 @@ typedef struct _paddata {
u8 triggerR; u8 triggerR;
} PADData; } PADData;
typedef struct _wupcfulldata {
u32 btns_d;
u32 btns_u;
u32 btns_h;
s16 stickX;
s16 stickY;
s16 substickX;
s16 substickY;
} WUPCFullData;
#define EFFECT_SLIDE_TOP 1 #define EFFECT_SLIDE_TOP 1
#define EFFECT_SLIDE_BOTTOM 2 #define EFFECT_SLIDE_BOTTOM 2
#define EFFECT_SLIDE_RIGHT 4 #define EFFECT_SLIDE_RIGHT 4
@ -226,6 +236,7 @@ class GuiTrigger
WPADData wpaddata; //!< Wii controller trigger data WPADData wpaddata; //!< Wii controller trigger data
PADData pad; //!< GameCube controller trigger data PADData pad; //!< GameCube controller trigger data
WUPCFullData wupcdata; //!< WiiU Pro controller trigger data
WPADData * wpad; //!< Wii controller trigger WPADData * wpad; //!< Wii controller trigger
s32 chan; //!< Trigger controller channel (0-3, -1 for all) s32 chan; //!< Trigger controller channel (0-3, -1 for all)
u8 type; //!< trigger type (TRIGGER_SIMPLE, TRIGGER_HELD, TRIGGER_BUTTON_ONLY, TRIGGER_BUTTON_ONLY_IN_FOCUS) u8 type; //!< trigger type (TRIGGER_SIMPLE, TRIGGER_HELD, TRIGGER_BUTTON_ONLY, TRIGGER_BUTTON_ONLY_IN_FOCUS)
@ -240,7 +251,7 @@ class GuiElement
//!Constructor //!Constructor
GuiElement(); GuiElement();
//!Destructor //!Destructor
~GuiElement(); virtual ~GuiElement();
//!Set the element's parent //!Set the element's parent
//!\param e Pointer to parent element //!\param e Pointer to parent element
void SetParent(GuiElement * e); void SetParent(GuiElement * e);

View File

@ -254,7 +254,7 @@ void GuiButton::Update(GuiTrigger * t)
// button triggers // button triggers
if(this->IsClickable()) if(this->IsClickable())
{ {
s32 wm_btns, wm_btns_trig, cc_btns, cc_btns_trig; s32 wm_btns, wm_btns_trig, cc_btns, cc_btns_trig, wupc_btns, wupc_btns_trig;
for(int i=0; i<3; i++) for(int i=0; i<3; i++)
{ {
if(trigger[i] && (trigger[i]->chan == -1 || trigger[i]->chan == t->chan)) if(trigger[i] && (trigger[i]->chan == -1 || trigger[i]->chan == t->chan))
@ -267,11 +267,16 @@ void GuiButton::Update(GuiTrigger * t)
cc_btns = t->wpad->btns_d >> 16; cc_btns = t->wpad->btns_d >> 16;
cc_btns_trig = trigger[i]->wpad->btns_d >> 16; cc_btns_trig = trigger[i]->wpad->btns_d >> 16;
// lower 16 bits only (WiiU Pro controller)
wupc_btns = t->wupcdata.btns_d >> 16;
wupc_btns_trig = trigger[i]->wupcdata.btns_d >> 16;
if( if(
(t->wpad->btns_d > 0 && (t->wpad->btns_d > 0 &&
(wm_btns == wm_btns_trig || (wm_btns == wm_btns_trig ||
(cc_btns == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) || (cc_btns == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) ||
(t->pad.btns_d == trigger[i]->pad.btns_d && t->pad.btns_d > 0)) (t->pad.btns_d == trigger[i]->pad.btns_d && t->pad.btns_d > 0) ||
(wupc_btns == wupc_btns_trig && wupc_btns_trig > 0))
{ {
if(t->chan == stateChan || stateChan == -1) if(t->chan == stateChan || stateChan == -1)
{ {
@ -303,7 +308,7 @@ void GuiButton::Update(GuiTrigger * t)
if(this->IsHoldable()) if(this->IsHoldable())
{ {
bool held = false; bool held = false;
s32 wm_btns, wm_btns_h, wm_btns_trig, cc_btns, cc_btns_h, cc_btns_trig; s32 wm_btns, wm_btns_h, wm_btns_trig, cc_btns, cc_btns_h, cc_btns_trig, wupc_btns, wupc_btns_h, wupc_btns_trig;
for(int i=0; i<3; i++) for(int i=0; i<3; i++)
{ {
@ -319,11 +324,17 @@ void GuiButton::Update(GuiTrigger * t)
cc_btns_h = t->wpad->btns_h >> 16; cc_btns_h = t->wpad->btns_h >> 16;
cc_btns_trig = trigger[i]->wpad->btns_h >> 16; cc_btns_trig = trigger[i]->wpad->btns_h >> 16;
// lower 16 bits only (WiiU Pro controller)
wupc_btns = t->wpad->btns_d >> 16;
wupc_btns_h = t->wpad->btns_h >> 16;
wupc_btns_trig = trigger[i]->wpad->btns_h >> 16;
if( if(
(t->wpad->btns_d > 0 && (t->wpad->btns_d > 0 &&
(wm_btns == wm_btns_trig || (wm_btns == wm_btns_trig ||
(cc_btns == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) || (cc_btns == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) ||
(t->pad.btns_d == trigger[i]->pad.btns_h && t->pad.btns_d > 0)) (t->pad.btns_d == trigger[i]->pad.btns_h && t->pad.btns_d > 0) ||
(wupc_btns == wupc_btns_trig && wupc_btns > 0))
{ {
if(trigger[i]->type == TRIGGER_HELD && state == STATE_SELECTED && if(trigger[i]->type == TRIGGER_HELD && state == STATE_SELECTED &&
(t->chan == stateChan || stateChan == -1)) (t->chan == stateChan || stateChan == -1))
@ -334,7 +345,8 @@ void GuiButton::Update(GuiTrigger * t)
(t->wpad->btns_h > 0 && (t->wpad->btns_h > 0 &&
(wm_btns_h == wm_btns_trig || (wm_btns_h == wm_btns_trig ||
(cc_btns_h == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) || (cc_btns_h == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) ||
(t->pad.btns_h == trigger[i]->pad.btns_h && t->pad.btns_h > 0)) (t->pad.btns_h == trigger[i]->pad.btns_h && t->pad.btns_h > 0) ||
(wupc_btns_h == wupc_btns_trig && wupc_btns_h > 0))
{ {
if(trigger[i]->type == TRIGGER_HELD) if(trigger[i]->type == TRIGGER_HELD)
held = true; held = true;

View File

@ -108,12 +108,12 @@ GuiFileBrowser::GuiFileBrowser(int w, int h)
fileListText[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff}); fileListText[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff});
fileListText[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); fileListText[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
fileListText[i]->SetPosition(5,0); fileListText[i]->SetPosition(5,0);
fileListText[i]->SetMaxWidth(380); fileListText[i]->SetMaxWidth(295);
fileListBg[i] = new GuiImage(bgFileSelectionEntry); fileListBg[i] = new GuiImage(bgFileSelectionEntry);
fileListIcon[i] = NULL; fileListIcon[i] = NULL;
fileList[i] = new GuiButton(380, 26); fileList[i] = new GuiButton(295, 26);
fileList[i]->SetParent(this); fileList[i]->SetParent(this);
fileList[i]->SetLabel(fileListText[i]); fileList[i]->SetLabel(fileListText[i]);
fileList[i]->SetImageOver(fileListBg[i]); fileList[i]->SetImageOver(fileListBg[i]);

View File

@ -22,7 +22,8 @@ static char * GetDisplayText(char * t)
if(len < MAX_KEYBOARD_DISPLAY) if(len < MAX_KEYBOARD_DISPLAY)
return t; return t;
snprintf(tmptxt, MAX_KEYBOARD_DISPLAY, "%s", &t[len-MAX_KEYBOARD_DISPLAY]); strncpy(tmptxt, &t[len-MAX_KEYBOARD_DISPLAY], MAX_KEYBOARD_DISPLAY);
tmptxt[MAX_KEYBOARD_DISPLAY-1] = 0;
return &tmptxt[0]; return &tmptxt[0];
} }
@ -40,7 +41,8 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max)
focus = 0; // allow focus focus = 0; // allow focus
alignmentHor = ALIGN_CENTRE; alignmentHor = ALIGN_CENTRE;
alignmentVert = ALIGN_MIDDLE; alignmentVert = ALIGN_MIDDLE;
snprintf(kbtextstr, 255, "%s", t); strncpy(kbtextstr, t, max);
kbtextstr[max] = 0;
kbtextmaxlen = max; kbtextmaxlen = max;
Key thekeys[4][11] = { Key thekeys[4][11] = {
@ -106,7 +108,7 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max)
keyTextboxImg->SetPosition(0, 0); keyTextboxImg->SetPosition(0, 0);
this->Append(keyTextboxImg); this->Append(keyTextboxImg);
kbText = new GuiText(GetDisplayText(kbtextstr), 22, (GXColor){0, 0, 0, 0xff}); kbText = new GuiText(GetDisplayText(kbtextstr), 20, (GXColor){0, 0, 0, 0xff});
kbText->SetAlignment(ALIGN_CENTRE, ALIGN_TOP); kbText->SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
kbText->SetPosition(0, 13); kbText->SetPosition(0, 13);
this->Append(kbText); this->Append(kbText);
@ -128,7 +130,7 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max)
keyBackImg = new GuiImage(keyMedium); keyBackImg = new GuiImage(keyMedium);
keyBackOverImg = new GuiImage(keyMediumOver); keyBackOverImg = new GuiImage(keyMediumOver);
keyBackText = new GuiText("Back", 22, (GXColor){0, 0, 0, 0xff}); keyBackText = new GuiText("Back", 20, (GXColor){0, 0, 0, 0xff});
keyBack = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight()); keyBack = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight());
keyBack->SetImage(keyBackImg); keyBack->SetImage(keyBackImg);
keyBack->SetImageOver(keyBackOverImg); keyBack->SetImageOver(keyBackOverImg);
@ -143,7 +145,7 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max)
keyCapsImg = new GuiImage(keyMedium); keyCapsImg = new GuiImage(keyMedium);
keyCapsOverImg = new GuiImage(keyMediumOver); keyCapsOverImg = new GuiImage(keyMediumOver);
keyCapsText = new GuiText("Caps", 22, (GXColor){0, 0, 0, 0xff}); keyCapsText = new GuiText("Caps", 20, (GXColor){0, 0, 0, 0xff});
keyCaps = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight()); keyCaps = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight());
keyCaps->SetImage(keyCapsImg); keyCaps->SetImage(keyCapsImg);
keyCaps->SetImageOver(keyCapsOverImg); keyCaps->SetImageOver(keyCapsOverImg);
@ -158,7 +160,7 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max)
keyShiftImg = new GuiImage(keyMedium); keyShiftImg = new GuiImage(keyMedium);
keyShiftOverImg = new GuiImage(keyMediumOver); keyShiftOverImg = new GuiImage(keyMediumOver);
keyShiftText = new GuiText("Shift", 22, (GXColor){0, 0, 0, 0xff}); keyShiftText = new GuiText("Shift", 20, (GXColor){0, 0, 0, 0xff});
keyShift = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight()); keyShift = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight());
keyShift->SetImage(keyShiftImg); keyShift->SetImage(keyShiftImg);
keyShift->SetImageOver(keyShiftOverImg); keyShift->SetImageOver(keyShiftOverImg);
@ -196,9 +198,9 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max)
txt[0] = keys[i][j].ch; txt[0] = keys[i][j].ch;
keyImg[i][j] = new GuiImage(key); keyImg[i][j] = new GuiImage(key);
keyImgOver[i][j] = new GuiImage(keyOver); keyImgOver[i][j] = new GuiImage(keyOver);
keyTxt[i][j] = new GuiText(txt, 22, (GXColor){0, 0, 0, 0xff}); keyTxt[i][j] = new GuiText(txt, 20, (GXColor){0, 0, 0, 0xff});
keyTxt[i][j]->SetAlignment(ALIGN_CENTRE, ALIGN_BOTTOM); keyTxt[i][j]->SetAlignment(ALIGN_CENTRE, ALIGN_BOTTOM);
keyTxt[i][j]->SetPosition(0, -8); keyTxt[i][j]->SetPosition(0, -10);
keyBtn[i][j] = new GuiButton(key->GetWidth(), key->GetHeight()); keyBtn[i][j] = new GuiButton(key->GetWidth(), key->GetHeight());
keyBtn[i][j]->SetImage(keyImg[i][j]); keyBtn[i][j]->SetImage(keyImg[i][j]);
keyBtn[i][j]->SetImageOver(keyImgOver[i][j]); keyBtn[i][j]->SetImageOver(keyImgOver[i][j]);

View File

@ -22,6 +22,7 @@ static u32 delay[4];
GuiTrigger::GuiTrigger() GuiTrigger::GuiTrigger()
{ {
chan = -1; chan = -1;
memset(&wupcdata, 0, sizeof(WUPCFullData));
memset(&wpaddata, 0, sizeof(WPADData)); memset(&wpaddata, 0, sizeof(WPADData));
memset(&pad, 0, sizeof(PADData)); memset(&pad, 0, sizeof(PADData));
wpad = &wpaddata; wpad = &wpaddata;
@ -43,6 +44,7 @@ void GuiTrigger::SetSimpleTrigger(s32 ch, u32 wiibtns, u16 gcbtns)
{ {
type = TRIGGER_SIMPLE; type = TRIGGER_SIMPLE;
chan = ch; chan = ch;
wupcdata.btns_d = wiibtns;
wpaddata.btns_d = wiibtns; wpaddata.btns_d = wiibtns;
pad.btns_d = gcbtns; pad.btns_d = gcbtns;
} }
@ -56,6 +58,7 @@ void GuiTrigger::SetHeldTrigger(s32 ch, u32 wiibtns, u16 gcbtns)
{ {
type = TRIGGER_HELD; type = TRIGGER_HELD;
chan = ch; chan = ch;
wupcdata.btns_h = wiibtns;
wpaddata.btns_h = wiibtns; wpaddata.btns_h = wiibtns;
pad.btns_h = gcbtns; pad.btns_h = gcbtns;
} }
@ -68,6 +71,7 @@ void GuiTrigger::SetButtonOnlyTrigger(s32 ch, u32 wiibtns, u16 gcbtns)
{ {
type = TRIGGER_BUTTON_ONLY; type = TRIGGER_BUTTON_ONLY;
chan = ch; chan = ch;
wupcdata.btns_d = wiibtns;
wpaddata.btns_d = wiibtns; wpaddata.btns_d = wiibtns;
pad.btns_d = gcbtns; pad.btns_d = gcbtns;
} }
@ -81,6 +85,7 @@ void GuiTrigger::SetButtonOnlyInFocusTrigger(s32 ch, u32 wiibtns, u16 gcbtns)
{ {
type = TRIGGER_BUTTON_ONLY_IN_FOCUS; type = TRIGGER_BUTTON_ONLY_IN_FOCUS;
chan = ch; chan = ch;
wupcdata.btns_d = wiibtns;
wpaddata.btns_d = wiibtns; wpaddata.btns_d = wiibtns;
pad.btns_d = gcbtns; pad.btns_d = gcbtns;
} }
@ -158,12 +163,15 @@ bool GuiTrigger::Left()
u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_UP : WPAD_BUTTON_LEFT; u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_UP : WPAD_BUTTON_LEFT;
if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT) if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT)
|| (wupcdata.btns_d | wupcdata.btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT)
|| (pad.btns_d | pad.btns_h) & PAD_BUTTON_LEFT || (pad.btns_d | pad.btns_h) & PAD_BUTTON_LEFT
|| pad.stickX < -PADCAL || pad.stickX < -PADCAL
|| WPAD_StickX(0) < -PADCAL) || WPAD_StickX(0) < -PADCAL
|| wupcdata.stickX < -WUPCCAL)
{ {
if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT) if((wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT))
|| pad.btns_d & PAD_BUTTON_LEFT) || (wupcdata.btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT))
|| pad.btns_d & PAD_BUTTON_LEFT)
{ {
prev[chan] = gettime(); prev[chan] = gettime();
delay[chan] = SCROLL_DELAY_INITIAL; // reset scroll delay delay[chan] = SCROLL_DELAY_INITIAL; // reset scroll delay
@ -191,11 +199,14 @@ bool GuiTrigger::Right()
u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_DOWN : WPAD_BUTTON_RIGHT; u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_DOWN : WPAD_BUTTON_RIGHT;
if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT) if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT)
|| ((wupcdata.btns_d | wupcdata.btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT))
|| (pad.btns_d | pad.btns_h) & PAD_BUTTON_RIGHT || (pad.btns_d | pad.btns_h) & PAD_BUTTON_RIGHT
|| pad.stickX > PADCAL || pad.stickX > PADCAL
|| WPAD_StickX(0) > PADCAL) || WPAD_StickX(0) > PADCAL
|| wupcdata.stickX > WUPCCAL)
{ {
if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT) if((wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT))
|| (wupcdata.btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT))
|| pad.btns_d & PAD_BUTTON_RIGHT) || pad.btns_d & PAD_BUTTON_RIGHT)
{ {
prev[chan] = gettime(); prev[chan] = gettime();
@ -223,12 +234,15 @@ bool GuiTrigger::Up()
{ {
u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_RIGHT : WPAD_BUTTON_UP; u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_RIGHT : WPAD_BUTTON_UP;
if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_UP) if(((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_UP))
|| ((wupcdata.btns_d | wupcdata.btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_UP))
|| (pad.btns_d | pad.btns_h) & PAD_BUTTON_UP || (pad.btns_d | pad.btns_h) & PAD_BUTTON_UP
|| pad.stickY > PADCAL || pad.stickY > PADCAL
|| WPAD_StickY(0) > PADCAL) || WPAD_StickY(0) > PADCAL
|| wupcdata.stickY > WUPCCAL)
{ {
if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_UP) if((wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_UP))
|| (wupcdata.btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_UP))
|| pad.btns_d & PAD_BUTTON_UP) || pad.btns_d & PAD_BUTTON_UP)
{ {
prev[chan] = gettime(); prev[chan] = gettime();
@ -256,12 +270,15 @@ bool GuiTrigger::Down()
{ {
u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_LEFT : WPAD_BUTTON_DOWN; u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_LEFT : WPAD_BUTTON_DOWN;
if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN) if(((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN))
|| ((wupcdata.btns_d | wupcdata.btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN))
|| (pad.btns_d | pad.btns_h) & PAD_BUTTON_DOWN || (pad.btns_d | pad.btns_h) & PAD_BUTTON_DOWN
|| pad.stickY < -PADCAL || pad.stickY < -PADCAL
|| WPAD_StickY(0) < -PADCAL) || WPAD_StickY(0) < -PADCAL
|| wupcdata.stickY < -WUPCCAL)
{ {
if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN) if((wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN))
|| wupcdata.btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN)
|| pad.btns_d & PAD_BUTTON_DOWN) || pad.btns_d & PAD_BUTTON_DOWN)
{ {
prev[chan] = gettime(); prev[chan] = gettime();

View File

@ -228,8 +228,8 @@ void GuiWindow::ToggleFocus(GuiTrigger * t)
} }
} }
// change focus // change focus
else if(t->wpad->btns_d & (WPAD_BUTTON_1 | WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B) else if((t->wpad->btns_d & (WPAD_BUTTON_1 | WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B))
|| t->pad.btns_d & PAD_BUTTON_B) || (t->pad.btns_d & PAD_BUTTON_B) || (t->wupcdata.btns_d & WPAD_CLASSIC_BUTTON_B))
{ {
for (i = found; i < elemSize; ++i) for (i = found; i < elemSize; ++i)
{ {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -16,6 +16,7 @@
#include <ogcsys.h> #include <ogcsys.h>
#include <unistd.h> #include <unistd.h>
#include <wiiuse/wpad.h> #include <wiiuse/wpad.h>
#include <wupc/wupc.h>
#include <ogc/lwp_watchdog.h> #include <ogc/lwp_watchdog.h>
#include "vbagx.h" #include "vbagx.h"
@ -138,6 +139,7 @@ void
UpdatePads() UpdatePads()
{ {
#ifdef HW_RVL #ifdef HW_RVL
WUPC_UpdateButtonStats();
WPAD_ScanPads(); WPAD_ScanPads();
#endif #endif
@ -154,6 +156,15 @@ UpdatePads()
userInput[i].pad.substickY = PAD_SubStickY(i); userInput[i].pad.substickY = PAD_SubStickY(i);
userInput[i].pad.triggerL = PAD_TriggerL(i); userInput[i].pad.triggerL = PAD_TriggerL(i);
userInput[i].pad.triggerR = PAD_TriggerR(i); userInput[i].pad.triggerR = PAD_TriggerR(i);
#ifdef HW_RVL
userInput[i].wupcdata.btns_d = WUPC_ButtonsDown(i);
userInput[i].wupcdata.btns_u = WUPC_ButtonsUp(i);
userInput[i].wupcdata.btns_h = WUPC_ButtonsHeld(i);
userInput[i].wupcdata.stickX = WUPC_lStickX(i);
userInput[i].wupcdata.stickY = WUPC_lStickY(i);
userInput[i].wupcdata.substickX = WUPC_rStickX(i);
userInput[i].wupcdata.substickY = WUPC_rStickY(i);
#endif
--i; --i;
} while(i >= 0); } while(i >= 0);
} }
@ -311,6 +322,9 @@ u32 StandardMovement(unsigned short chan)
#ifdef HW_RVL #ifdef HW_RVL
s8 wm_ax = userInput[0].WPAD_StickX(0); s8 wm_ax = userInput[0].WPAD_StickX(0);
s8 wm_ay = userInput[0].WPAD_StickY(0); s8 wm_ay = userInput[0].WPAD_StickY(0);
s16 wupc_ax = userInput[chan].wupcdata.stickX;
s16 wupc_ay = userInput[chan].wupcdata.stickY;
#endif #endif
/*** /***
@ -338,7 +352,19 @@ u32 StandardMovement(unsigned short chan)
if (wm_ax * wm_ax + wm_ay * wm_ay > PADCAL * PADCAL) if (wm_ax * wm_ax + wm_ay * wm_ay > PADCAL * PADCAL)
{ {
angle = atan2(wm_ay, wm_ax); angle = atan2(wm_ay, wm_ax);
if(cos(angle) > THRES)
J |= VBA_RIGHT;
else if(cos(angle) < -THRES)
J |= VBA_LEFT;
if(sin(angle) > THRES)
J |= VBA_UP;
else if(sin(angle) < -THRES)
J |= VBA_DOWN;
}
/* WiiU Pro Controller */
if (wupc_ax * wupc_ax + wupc_ay * wupc_ay > WUPCCAL * WUPCCAL)
{
angle = atan2(wupc_ay, wupc_ax);
if(cos(angle) > THRES) if(cos(angle) > THRES)
J |= VBA_RIGHT; J |= VBA_RIGHT;
else if(cos(angle) < -THRES) else if(cos(angle) < -THRES)
@ -380,7 +406,19 @@ u32 StandardDPad(unsigned short pad)
if (wp & WPAD_CLASSIC_BUTTON_RIGHT) if (wp & WPAD_CLASSIC_BUTTON_RIGHT)
J |= VBA_RIGHT; J |= VBA_RIGHT;
} }
/* WiiU Pro Controller */
u32 wupcp = userInput[pad].wupcdata.btns_h;
if (wupcp & WPAD_CLASSIC_BUTTON_UP)
J |= VBA_UP;
if (wupcp & WPAD_CLASSIC_BUTTON_DOWN)
J |= VBA_DOWN;
if (wupcp & WPAD_CLASSIC_BUTTON_LEFT)
J |= VBA_LEFT;
if (wupcp & WPAD_CLASSIC_BUTTON_RIGHT)
J |= VBA_RIGHT;
#endif #endif
if (jp & PAD_BUTTON_UP) if (jp & PAD_BUTTON_UP)
J |= VBA_UP; J |= VBA_UP;
if (jp & PAD_BUTTON_DOWN) if (jp & PAD_BUTTON_DOWN)
@ -436,7 +474,8 @@ u32 StandardClassic(unsigned short pad)
{ {
u32 J = 0; u32 J = 0;
#ifdef HW_RVL #ifdef HW_RVL
u32 wp = userInput[pad].wpad->btns_h; u32 wp = userInput[pad].wpad->btns_h
| userInput[pad].wupcdata.btns_h; /* just add pro controller */
if (wp & WPAD_CLASSIC_BUTTON_RIGHT) if (wp & WPAD_CLASSIC_BUTTON_RIGHT)
J |= VBA_RIGHT; J |= VBA_RIGHT;
@ -536,6 +575,14 @@ u32 DecodeClassic(unsigned short pad)
WPADData * wp = WPAD_Data(pad); WPADData * wp = WPAD_Data(pad);
u32 wpad_btns_h = wp->btns_h; u32 wpad_btns_h = wp->btns_h;
/* WiiU Pro Controller */
u32 wupc_btns_h = userInput[pad].wupcdata.btns_h;
for (u32 i = 0; i < MAXJP; ++i)
{
if(wupc_btns_h & btnmap[CTRLR_CLASSIC][i])
J |= vbapadmap[i];
}
if(wp->exp.type == WPAD_EXP_CLASSIC){ if(wp->exp.type == WPAD_EXP_CLASSIC){
for (u32 i = 0; i < MAXJP; ++i){ for (u32 i = 0; i < MAXJP; ++i){
if (wpad_btns_h & btnmap[CTRLR_CLASSIC][i] ) if (wpad_btns_h & btnmap[CTRLR_CLASSIC][i] )
@ -811,13 +858,16 @@ static u32 DecodeJoy(unsigned short pad)
case CVHARMONY: case CVHARMONY:
case CVARIA: case CVARIA:
return CastlevaniaCircleMoonInput(pad); return CastlevaniaCircleMoonInput(pad);
case KIDDRACULA:
return KidDraculaInput(pad);
} }
// the function result, J, is a combination of flags for all the VBA buttons that are down // the function result, J, is a combination of flags for all the VBA buttons that are down
u32 J = StandardMovement(pad); u32 J = StandardMovement(pad);
// Turbo feature // Turbo feature
if(userInput[0].pad.substickX > 70 || userInput[0].WPAD_Stick(1,0) > 70) if(userInput[0].pad.substickX > 70 || userInput[0].WPAD_Stick(1,0) > 70 || userInput[0].wupcdata.substickX > 560)
J |= VBA_SPEED; J |= VBA_SPEED;
// Report pressed buttons (gamepads) // Report pressed buttons (gamepads)
@ -849,6 +899,7 @@ static u32 DecodeJoy(unsigned short pad)
} }
} }
else if(wpad_exp_type == WPAD_EXP_NUNCHUK) else if(wpad_exp_type == WPAD_EXP_NUNCHUK)
{ // nunchuk + wiimote { // nunchuk + wiimote
@ -858,8 +909,8 @@ static u32 DecodeJoy(unsigned short pad)
|| ( (wpad_btns_h & btnmap[CTRLR_NUNCHUK][i]) )) || ( (wpad_btns_h & btnmap[CTRLR_NUNCHUK][i]) ))
J |= vbapadmap[i]; J |= vbapadmap[i];
} }
} }
else else
// Check out this trickery! // Check out this trickery!
// If all else fails OR if HW_RVL is undefined, the result is the same // If all else fails OR if HW_RVL is undefined, the result is the same
@ -871,32 +922,38 @@ static u32 DecodeJoy(unsigned short pad)
J |= vbapadmap[i]; J |= vbapadmap[i];
} }
} }
#ifdef HW_RVL
/* WiiU Pro Controller */
u32 wupc_btns_h = userInput[pad].wupcdata.btns_h;
for (u32 i =0; i < MAXJP; ++i)
{
if(wupc_btns_h & btnmap[CTRLR_CLASSIC][i])
J |= vbapadmap[i];
}
#endif
return J; return J;
} }
bool MenuRequested() bool MenuRequested()
{ {
if( (userInput[0].pad.substickX < -70) || for(int i=0; i<4; i++)
(userInput[0].wpad->btns_h & WPAD_BUTTON_HOME) || {
(userInput[0].wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME) if (
|| (userInput[i].pad.substickX < -70)
(userInput[1].pad.substickX < -70) || #ifdef HW_RVL
(userInput[1].wpad->btns_h & WPAD_BUTTON_HOME) || || (userInput[i].wpad->btns_h & WPAD_BUTTON_HOME) ||
(userInput[1].wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME) (userInput[i].wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME) ||
|| (userInput[i].wupcdata.btns_h & WPAD_CLASSIC_BUTTON_HOME)
(userInput[2].pad.substickX < -70) || #endif
(userInput[2].wpad->btns_h & WPAD_BUTTON_HOME) ||
(userInput[2].wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME)
||
(userInput[3].pad.substickX < -70) ||
(userInput[3].wpad->btns_h & WPAD_BUTTON_HOME) ||
(userInput[3].wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME)
) )
{ {
return true; return true;
} }
return false; return false;
} }
}
u32 GetJoy(int pad) u32 GetJoy(int pad)
{ {
@ -915,5 +972,6 @@ u32 GetJoy(int pad)
if ((J & 192) == 192) if ((J & 192) == 192)
J &= ~128; J &= ~128;
updateRumbleFrame(); updateRumbleFrame();
return J; return J;
} }

View File

@ -16,6 +16,7 @@
#define PI 3.14159265f #define PI 3.14159265f
#define PADCAL 50 #define PADCAL 50
#define WUPCCAL 400
#define MAXJP 10 // # of mappable controller buttons #define MAXJP 10 // # of mappable controller buttons
#define VBA_BUTTON_A 1 #define VBA_BUTTON_A 1

View File

@ -396,13 +396,8 @@ u32 MarioLand2Input(unsigned short pad) {
if (wp->btns_h & WPAD_CLASSIC_BUTTON_X || wp->btns_h & WPAD_CLASSIC_BUTTON_Y || run) if (wp->btns_h & WPAD_CLASSIC_BUTTON_X || wp->btns_h & WPAD_CLASSIC_BUTTON_Y || run)
J |= VBA_BUTTON_B; J |= VBA_BUTTON_B;
// Spin attack // Spin attack
if (wp->btns_h & WPAD_CLASSIC_BUTTON_A) if (wp->btns_h & WPAD_CLASSIC_BUTTON_A || wp->btns_h & WPAD_CLASSIC_BUTTON_FULL_R)
J |= VBA_DOWN | VBA_BUTTON_A; J |= VBA_DOWN | VBA_BUTTON_A;
// Camera
if (wp->btns_h & WPAD_CLASSIC_BUTTON_FULL_L)
J |= VBA_DOWN | VBA_BUTTON_B;
if (wp->btns_h & WPAD_CLASSIC_BUTTON_FULL_R)
J |= VBA_UP | VBA_BUTTON_B;
// Crouch // Crouch
if (wp->btns_h & WPAD_CLASSIC_BUTTON_ZL && (!(wp->btns_h & WPAD_CLASSIC_BUTTON_A))) { if (wp->btns_h & WPAD_CLASSIC_BUTTON_ZL && (!(wp->btns_h & WPAD_CLASSIC_BUTTON_A))) {
J |= VBA_DOWN; J |= VBA_DOWN;

View File

@ -241,6 +241,18 @@ msgstr "Presione un bot
msgid "Press any button on the Wiimote or Nunchuk now. Press Home to clear the existing mapping." msgid "Press any button on the Wiimote or Nunchuk now. Press Home to clear the existing mapping."
msgstr "Presione un botón en el Wiimote o Nunchuck. Presione HOME para eliminar la configuración actual." msgstr "Presione un botón en el Wiimote o Nunchuck. Presione HOME para eliminar la configuración actual."
msgid "Press any button on the Wii U Pro Controller now. Press Home to clear the existing mapping."
msgstr "Presione un botón en el Mando Wii U Pro. Presione HOME para eliminar la configuración actual."
msgid "ScreenShot"
msgstr "Pantalla"
msgid "Preview Screenshot"
msgstr "Imagen de Pantalla"
msgid "Save a new Preview Screenshot? Current Screenshot image will be overwritten."
msgstr "¿Grabar una nueva imagen de pantalla? La imagen actual será sobre-escrita."
msgid "Progressive (480p)" msgid "Progressive (480p)"
msgstr "Progresivo (480p)" msgstr "Progresivo (480p)"

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@ void MainMenu (int menuitem);
void ErrorPrompt(const char * msg); void ErrorPrompt(const char * msg);
int ErrorPromptRetry(const char * msg); int ErrorPromptRetry(const char * msg);
void InfoPrompt(const char * msg); void InfoPrompt(const char * msg);
int YesNoPrompt(const char *msg, bool yesDefault);
void ShowAction (const char *msg); void ShowAction (const char *msg);
void CancelAction(); void CancelAction();
void ShowProgress (const char *msg, int done, int total); void ShowProgress (const char *msg, int done, int total);
@ -43,7 +44,8 @@ enum
MENU_GAMESETTINGS_MAPPINGS_MAP, MENU_GAMESETTINGS_MAPPINGS_MAP,
MENU_GAMESETTINGS_VIDEO, MENU_GAMESETTINGS_VIDEO,
MENU_GAMESETTINGS_CHEATS, MENU_GAMESETTINGS_CHEATS,
MENU_GAMESETTINGS_PALETTE MENU_GAMESETTINGS_PALETTE,
MENU_SETTINGS_EMULATION
}; };
#endif #endif

View File

@ -3,7 +3,7 @@
* PNGU * PNGU
* *
* Original author: frontier (http://frontier-dev.net) * Original author: frontier (http://frontier-dev.net)
* Modified by Tantric, 2009-2010 * This is Tantric's modified/condensed version + RGB565 decoder from original
* *
***************************************************************************/ ***************************************************************************/
@ -16,18 +16,6 @@
#define PNGU_SOURCE_BUFFER 1 #define PNGU_SOURCE_BUFFER 1
#define PNGU_SOURCE_DEVICE 2 #define PNGU_SOURCE_DEVICE 2
// Return codes
#define PNGU_OK 0
#define PNGU_ODD_WIDTH 1
#define PNGU_ODD_STRIDE 2
#define PNGU_INVALID_WIDTH_OR_HEIGHT 3
#define PNGU_FILE_IS_NOT_PNG 4
#define PNGU_UNSUPPORTED_COLOR_TYPE 5
#define PNGU_NO_FILE_SELECTED 6
#define PNGU_CANT_OPEN_FILE 7
#define PNGU_CANT_READ_FILE 8
#define PNGU_LIB_ERROR 9
// Color types // Color types
#define PNGU_COLOR_TYPE_GRAY 1 #define PNGU_COLOR_TYPE_GRAY 1
#define PNGU_COLOR_TYPE_GRAY_ALPHA 2 #define PNGU_COLOR_TYPE_GRAY_ALPHA 2
@ -311,7 +299,7 @@ static int pngu_decode (IMGCTX ctx, u32 width, u32 height, u32 stripAlpha)
return PNGU_INVALID_WIDTH_OR_HEIGHT; return PNGU_INVALID_WIDTH_OR_HEIGHT;
// Check if color type is supported by PNGU // Check if color type is supported by PNGU
if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_PALETTE) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_UNKNOWN) ) if (ctx->prop.imgColorType == PNGU_COLOR_TYPE_UNKNOWN)
return PNGU_UNSUPPORTED_COLOR_TYPE; return PNGU_UNSUPPORTED_COLOR_TYPE;
// Scale 16 bit samples to 8 bit // Scale 16 bit samples to 8 bit
@ -330,6 +318,10 @@ static int pngu_decode (IMGCTX ctx, u32 width, u32 height, u32 stripAlpha)
if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA) ) if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA) )
png_set_gray_to_rgb (ctx->png_ptr); png_set_gray_to_rgb (ctx->png_ptr);
// Transform palette images to RGB
if (ctx->prop.imgColorType == PNGU_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(ctx->png_ptr);
// Flush transformations // Flush transformations
png_read_update_info (ctx->png_ptr, ctx->info_ptr); png_read_update_info (ctx->png_ptr, ctx->info_ptr);
@ -479,6 +471,70 @@ static u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, u32 width, u32 height, int * dstW
return dst; return dst;
} }
int PNGU_DecodeTo4x4RGB565 (IMGCTX ctx, u32 width, u32 height, void *buffer)
{
int result;
u32 x, y, qwidth, qheight;
// width and height need to be divisible by four
if ((width % 4) || (height % 4))
return PNGU_INVALID_WIDTH_OR_HEIGHT;
result = pngu_decode (ctx, width, height, 1);
if (result != PNGU_OK)
return result;
// Copy image to the output buffer
qwidth = width / 4;
qheight = height / 4;
for (y = 0; y < qheight; y++)
for (x = 0; x < qwidth; x++)
{
int blockbase = (y * qwidth + x) * 4;
u64 field64 = *((u64 *)(ctx->row_pointers[y*4]+x*12));
u64 field32 = (u64) *((u32 *)(ctx->row_pointers[y*4]+x*12+8));
((u64 *) buffer)[blockbase] =
(((field64 & 0xF800000000000000ULL) | ((field64 & 0xFC000000000000ULL) << 3) | ((field64 & 0xF80000000000ULL) << 5)) |
(((field64 & 0xF800000000ULL) << 8) | ((field64 & 0xFC000000ULL) << 11) | ((field64 & 0xF80000ULL) << 13)) |
(((field64 & 0xF800ULL) << 16) | ((field64 & 0xFCULL) << 19) | ((field32 & 0xF8000000ULL) >> 11)) |
(((field32 & 0xF80000ULL) >> 8) | ((field32 & 0xFC00ULL) >> 5) | ((field32 & 0xF8ULL) >> 3)));
field64 = *((u64 *)(ctx->row_pointers[y*4+1]+x*12));
field32 = (u64) *((u32 *)(ctx->row_pointers[y*4+1]+x*12+8));
((u64 *) buffer)[blockbase+1] =
(((field64 & 0xF800000000000000ULL) | ((field64 & 0xFC000000000000ULL) << 3) | ((field64 & 0xF80000000000ULL) << 5)) |
(((field64 & 0xF800000000ULL) << 8) | ((field64 & 0xFC000000ULL) << 11) | ((field64 & 0xF80000ULL) << 13)) |
(((field64 & 0xF800ULL) << 16) | ((field64 & 0xFCULL) << 19) | ((field32 & 0xF8000000ULL) >> 11)) |
(((field32 & 0xF80000ULL) >> 8) | ((field32 & 0xFC00ULL) >> 5) | ((field32 & 0xF8ULL) >> 3)));
field64 = *((u64 *)(ctx->row_pointers[y*4+2]+x*12));
field32 = (u64) *((u32 *)(ctx->row_pointers[y*4+2]+x*12+8));
((u64 *) buffer)[blockbase+2] =
(((field64 & 0xF800000000000000ULL) | ((field64 & 0xFC000000000000ULL) << 3) | ((field64 & 0xF80000000000ULL) << 5)) |
(((field64 & 0xF800000000ULL) << 8) | ((field64 & 0xFC000000ULL) << 11) | ((field64 & 0xF80000ULL) << 13)) |
(((field64 & 0xF800ULL) << 16) | ((field64 & 0xFCULL) << 19) | ((field32 & 0xF8000000ULL) >> 11)) |
(((field32 & 0xF80000ULL) >> 8) | ((field32 & 0xFC00ULL) >> 5) | ((field32 & 0xF8ULL) >> 3)));
field64 = *((u64 *)(ctx->row_pointers[y*4+3]+x*12));
field32 = (u64) *((u32 *)(ctx->row_pointers[y*4+3]+x*12+8));
((u64 *) buffer)[blockbase+3] =
(((field64 & 0xF800000000000000ULL) | ((field64 & 0xFC000000000000ULL) << 3) | ((field64 & 0xF80000000000ULL) << 5)) |
(((field64 & 0xF800000000ULL) << 8) | ((field64 & 0xFC000000ULL) << 11) | ((field64 & 0xF80000ULL) << 13)) |
(((field64 & 0xF800ULL) << 16) | ((field64 & 0xFCULL) << 19) | ((field32 & 0xF8000000ULL) >> 11)) |
(((field32 & 0xF80000ULL) >> 8) | ((field32 & 0xFC00ULL) >> 5) | ((field32 & 0xF8ULL) >> 3)));
}
// Free resources
free (ctx->img_data);
free (ctx->row_pointers);
// Success
return PNGU_OK;
}
IMGCTX PNGU_SelectImageFromBuffer (const void *buffer) IMGCTX PNGU_SelectImageFromBuffer (const void *buffer)
{ {
IMGCTX ctx = NULL; IMGCTX ctx = NULL;
@ -749,3 +805,38 @@ int PNGU_EncodeFromEFB (IMGCTX ctx, u32 width, u32 height)
free(tmpbuffer); free(tmpbuffer);
return res; return res;
} }
// Added by libertyernie
int PNGU_EncodeFromLinearRGB565 (IMGCTX ctx, u32 width, u32 height, const void* buffer, int rowlength)
{
int res;
u32 x, y, tmpy1, tmpxy;
u16 * src = (u16 *)buffer;
unsigned char * tmpbuffer = malloc(width*height*3);
if(!tmpbuffer)
return PNGU_LIB_ERROR;
for(y=0; y < height; y++)
{
tmpy1 = y * width * 3;
for(x=0; x < width; x++)
{
tmpxy = x * 3 + tmpy1;
u16 color = *src++;
tmpbuffer[tmpxy ] = (color >> 11) << 3; // R
tmpbuffer[tmpxy+1] = ((color >> 6) & 31) << 3; // G - discard least significant byte
tmpbuffer[tmpxy+2] = (color & 31) << 3; // B
}
if (rowlength > width) {
src += (rowlength - width);
}
}
res = PNGU_EncodeFromRGB (ctx, width, height, tmpbuffer, 0);
free(tmpbuffer);
return res;
}

View File

@ -3,7 +3,7 @@
* PNGU * PNGU
* *
* Original author: frontier (http://frontier-dev.net) * Original author: frontier (http://frontier-dev.net)
* Modified by Tantric, 2009-2010 * This is Tantric's modified/condensed version + RGB565 decoder from original
* *
********************************************************************************************/ ********************************************************************************************/
@ -16,6 +16,18 @@
extern "C" { extern "C" {
#endif #endif
// Return codes
#define PNGU_OK 0
#define PNGU_ODD_WIDTH 1
#define PNGU_ODD_STRIDE 2
#define PNGU_INVALID_WIDTH_OR_HEIGHT 3
#define PNGU_FILE_IS_NOT_PNG 4
#define PNGU_UNSUPPORTED_COLOR_TYPE 5
#define PNGU_NO_FILE_SELECTED 6
#define PNGU_CANT_OPEN_FILE 7
#define PNGU_CANT_READ_FILE 8
#define PNGU_LIB_ERROR 9
typedef struct typedef struct
{ {
u8 r; u8 r;
@ -68,6 +80,9 @@ int PNGU_EncodeFromRGB (IMGCTX ctx, u32 width, u32 height, void *buffer, u32 str
int PNGU_EncodeFromGXTexture (IMGCTX ctx, u32 width, u32 height, void *buffer, u32 stride); int PNGU_EncodeFromGXTexture (IMGCTX ctx, u32 width, u32 height, void *buffer, u32 stride);
int PNGU_EncodeFromEFB (IMGCTX ctx, u32 width, u32 height); int PNGU_EncodeFromEFB (IMGCTX ctx, u32 width, u32 height);
int PNGU_DecodeTo4x4RGB565 (IMGCTX ctx, u32 width, u32 height, void *buffer);
int PNGU_EncodeFromLinearRGB565 (IMGCTX ctx, u32 width, u32 height, const void* buffer, int rowlength);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,58 +1,57 @@
#ifndef SYSTEM_H #ifndef SYSTEM_H
#define SYSTEM_H #define SYSTEM_H
#include "common/Types.h" #include "common/Types.h"
#include <zlib.h> #include <zlib.h>
class SoundDriver; class SoundDriver;
struct EmulatedSystem { struct EmulatedSystem {
// main emulation function // main emulation function
void (*emuMain)(int); void (*emuMain)(int);
// reset emulator // reset emulator
void (*emuReset)(); void (*emuReset)();
// clean up memory // clean up memory
void (*emuCleanUp)(); void (*emuCleanUp)();
// load battery file // load battery file
bool (*emuReadBattery)(const char *); bool (*emuReadBattery)(const char *);
// write battery file // write battery file
bool (*emuWriteBattery)(const char *); bool (*emuWriteBattery)(const char *);
// load state #ifdef __LIBRETRO__
bool (*emuReadState)(const char *); // load state
// save state bool (*emuReadState)(const u8*, unsigned);
bool (*emuWriteState)(const char *); // load state
// load memory state (rewind) unsigned (*emuWriteState)(u8*, unsigned);
bool (*emuReadMemState)(char *, int); #else
// write memory state (rewind) // load state
bool (*emuWriteMemState)(char *, int); bool (*emuReadState)(const char *);
// write PNG file // save state
bool (*emuWritePNG)(const char *); bool (*emuWriteState)(const char *);
// write BMP file #endif
bool (*emuWriteBMP)(const char *); // load memory state (rewind)
// emulator update CPSR (ARM only) bool (*emuReadMemState)(char *, int);
void (*emuUpdateCPSR)(); // write memory state (rewind)
// emulator has debugger bool (*emuWriteMemState)(char *, int);
bool emuHasDebugger; // write PNG file
// clock ticks to emulate bool (*emuWritePNG)(const char *);
int emuCount; // 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 void log(const char *,...);
extern bool systemPauseOnFrame(); extern bool systemPauseOnFrame();
extern void systemGbPrint(u8 *,int,int,int,int); extern void systemGbPrint(u8 *,int,int,int,int,int);
extern void systemScreenCapture(int); extern void systemScreenCapture(int);
extern void systemDrawScreen(); extern void systemDrawScreen();
// updates the joystick data // updates the joystick data
extern bool systemReadJoypads(); extern bool systemReadJoypads();
// return information about the given joystick, -1 for default joystick // return information about the given joystick, -1 for default joystick
extern u32 systemReadJoypad(int); extern u32 systemReadJoypad(int);
// this function should turn on or off rumble on the gamepad
extern void systemCartridgeRumble(bool);
extern void systemPossibleCartridgeRumble(bool);
// This should be called once per frame
extern void updateRumbleFrame();
extern u32 systemGetClock(); extern u32 systemGetClock();
extern void systemMessage(int, const char *, ...); extern void systemMessage(int, const char *, ...);
extern void systemSetTitle(const char *); extern void systemSetTitle(const char *);
@ -61,26 +60,26 @@ extern void systemOnWriteDataToSoundBuffer(const u16 * finalWave, int length);
extern void systemOnSoundShutdown(); extern void systemOnSoundShutdown();
extern void systemScreenMessage(const char *); extern void systemScreenMessage(const char *);
extern void systemUpdateMotionSensor(); extern void systemUpdateMotionSensor();
extern int systemGetSensorX(); extern int systemGetSensorX();
extern int systemGetSensorY(); extern int systemGetSensorY();
extern bool systemCanChangeSoundQuality(); extern bool systemCanChangeSoundQuality();
extern void systemShowSpeed(int); extern void systemShowSpeed(int);
extern void system10Frames(int); extern void system10Frames(int);
extern void systemFrame(); extern void systemFrame();
extern void systemGbBorderOn(); extern void systemGbBorderOn();
extern void Sm60FPS_Init(); extern void Sm60FPS_Init();
extern bool Sm60FPS_CanSkipFrame(); extern bool Sm60FPS_CanSkipFrame();
extern void Sm60FPS_Sleep(); extern void Sm60FPS_Sleep();
extern void DbgMsg(const char *msg, ...); extern void DbgMsg(const char *msg, ...);
#ifdef SDL
#define winlog log
#else
extern void winlog(const char *,...); extern void winlog(const char *,...);
#endif
extern void (*dbgOutput)(const char *s, u32 addr); extern void (*dbgOutput)(const char *s, u32 addr);
extern void (*dbgSignal)(int sig,int number); extern void (*dbgSignal)(int sig,int number);
extern u16 systemColorMap16[0x10000]; extern u16 systemColorMap16[0x10000];
//extern u32 systemColorMap32[0x10000]; extern u32 systemColorMap32[0x10000];
extern u32 *systemColorMap32;
extern u16 systemGbPalette[24]; extern u16 systemGbPalette[24];
extern int systemRedShift; extern int systemRedShift;
extern int systemGreenShift; extern int systemGreenShift;
@ -91,8 +90,6 @@ extern int systemVerbose;
extern int systemFrameSkip; extern int systemFrameSkip;
extern int systemSaveUpdateCounter; extern int systemSaveUpdateCounter;
extern int systemSpeed; extern int systemSpeed;
#define SYSTEM_SAVE_UPDATED 30 #define SYSTEM_SAVE_UPDATED 30
#define SYSTEM_SAVE_NOT_UPDATED 0 #define SYSTEM_SAVE_NOT_UPDATED 0
#endif // SYSTEM_H #endif // SYSTEM_H

View File

@ -1,26 +1,14 @@
// 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 <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <zlib.h> #include <zlib.h>
#ifndef NO_PNG
extern "C" {
#include <png.h>
}
#endif
#include "System.h" #include "System.h"
#include "NLS.h" #include "NLS.h"
#include "Util.h" #include "Util.h"
@ -29,12 +17,18 @@
#include "gba/Globals.h" #include "gba/Globals.h"
#include "gba/RTC.h" #include "gba/RTC.h"
#include "common/Port.h" #include "common/Port.h"
#include "../utils/unzip/unzip.h"
#ifndef NO_FEX
#include "fex/fex.h"
#endif
extern "C" { extern "C" {
#include "common/memgzio.h" #include "common/memgzio.h"
} }
#include "gba/gbafilter.h"
#include "gb/gbGlobals.h"
#ifndef _MSC_VER #ifndef _MSC_VER
#define _stricmp strcasecmp #define _stricmp strcasecmp
#endif // ! _MSC_VER #endif // ! _MSC_VER
@ -45,13 +39,283 @@ extern int systemGreenShift;
extern int systemBlueShift; extern int systemBlueShift;
extern u16 systemColorMap16[0x10000]; extern u16 systemColorMap16[0x10000];
//extern u32 systemColorMap32[0x10000]; extern u32 systemColorMap32[0x10000];
extern u32 *systemColorMap32;
static int (*utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL; static int (ZEXPORT *utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL;
static int (*utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL; static int (ZEXPORT *utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL;
static int (*utilGzCloseFunc)(gzFile) = NULL; static int (ZEXPORT *utilGzCloseFunc)(gzFile) = NULL;
static z_off_t (*utilGzSeekFunc)(gzFile, z_off_t, int) = NULL; static z_off_t (ZEXPORT *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) {
fclose(fp);
return false;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr) {
png_destroy_write_struct(&png_ptr,NULL);
fclose(fp);
return false;
}
if(setjmp(png_jmpbuf(png_ptr))) {
png_destroy_write_struct(&png_ptr,NULL);
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);
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 = 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);
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);
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;
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);
fwrite(writeBuffer, 1, 3*w, fp);
b = writeBuffer;
}
}
break;
}
fclose(fp);
return true;
}
extern bool cpuIsMultiBoot; extern bool cpuIsMultiBoot;
@ -95,34 +359,221 @@ bool utilIsGBImage(const char * file)
return false; return false;
} }
bool utilIsZipFile(const char *file) bool utilIsGzipFile(const char *file)
{ {
if(strlen(file) > 4) if(strlen(file) > 3) {
{ const char * p = strrchr(file,'.');
char * p = strrchr(file,'.');
if(p != NULL) if(p != NULL) {
{ if(_stricmp(p, ".gz") == 0)
if(_stricmp(p, ".zip") == 0) return true;
return true; if(_stricmp(p, ".z") == 0)
} return true;
} }
}
return false; return false;
} }
void utilPutDword(u8 *p, u32 value) // strip .gz or .z off end
void utilStripDoubleExtension(const char *file, char *buffer)
{ {
*p++ = value & 255; if(buffer != file) // allows conversion in place
*p++ = (value >> 8) & 255; strcpy(buffer, file);
*p++ = (value >> 16) & 255;
*p = (value >> 24) & 255; if(utilIsGzipFile(file)) {
char *p = strrchr(buffer, '.');
if(p)
*p = 0;
}
} }
void utilPutWord(u8 *p, u16 value) #ifndef NO_FEX
// Opens and scans archive using accept(). Returns fex_t if found.
// If error or not found, displays message and returns NULL.
static fex_t* scan_arc(const char *file, bool (*accept)(const char *),
char (&buffer) [2048] )
{ {
*p++ = value & 255; fex_t* fe;
*p = (value >> 8) & 255; fex_err_t err = fex_open( &fe, file );
if(!fe)
{
systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s: %s"), file, err);
return NULL;
}
// Scan filenames
bool found=false;
while(!fex_done(fe)) {
strncpy(buffer,fex_name(fe),sizeof buffer);
buffer [sizeof buffer-1] = '\0';
utilStripDoubleExtension(buffer, buffer);
if(accept(buffer)) {
found = true;
break;
}
fex_err_t err = fex_next(fe);
if(err) {
systemMessage(MSG_BAD_ZIP_FILE, N_("Cannot read archive %s: %s"), file, err);
fex_close(fe);
return NULL;
}
}
if(!found) {
systemMessage(MSG_NO_IMAGE_ON_ZIP,
N_("No image found in file %s"), file);
fex_close(fe);
return NULL;
}
return fe;
}
#endif
static bool utilIsImage(const char *file)
{
return utilIsGBAImage(file) || utilIsGBImage(file);
}
#ifdef WIN32
#include <Windows.h>
#endif
IMAGE_TYPE utilFindType(const char *file, char (&buffer)[2048]);
IMAGE_TYPE utilFindType(const char *file)
{
char buffer [2048];
return utilFindType(file, buffer);
}
IMAGE_TYPE utilFindType(const char *file, char (&buffer)[2048])
{
#ifndef NO_FEX
#ifdef WIN32
DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, file, -1, NULL, 0);
wchar_t *pwText;
pwText = new wchar_t[dwNum];
if(!pwText)
{
return IMAGE_UNKNOWN;
}
MultiByteToWideChar (CP_ACP, 0, file, -1, pwText, dwNum );
char* file_conv = fex_wide_to_path( pwText);
// if ( !utilIsImage( file_conv ) ) // TODO: utilIsArchive() instead?
// {
fex_t* fe = scan_arc(file_conv,utilIsImage,buffer);
if(!fe)
return IMAGE_UNKNOWN;
fex_close(fe);
file = buffer;
// }
free(file_conv);
#else
// if ( !utilIsImage( file ) ) // TODO: utilIsArchive() instead?
// {
fex_t* fe = scan_arc(file,utilIsImage,buffer);
if(!fe)
return IMAGE_UNKNOWN;
fex_close(fe);
file = buffer;
// }
#endif
#endif
return utilIsGBAImage(file) ? IMAGE_GBA : IMAGE_GB;
}
static int utilGetSize(int size)
{
int res = 1;
while(res < size)
res <<= 1;
return res;
}
u8 *utilLoad(const char *file,
bool (*accept)(const char *),
u8 *data,
int &size)
{
// find image file
char buffer [2048];
#ifdef NO_FEX
FILE* f = fopen(file, "rb");
fseek(f, 0, SEEK_END);
int fileSize = ftell(f);
fseek(f, 0, SEEK_SET);
#else
#ifdef WIN32
DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, file, -1, NULL, 0);
wchar_t *pwText;
pwText = new wchar_t[dwNum];
if(!pwText)
{
return NULL;
}
MultiByteToWideChar (CP_ACP, 0, file, -1, pwText, dwNum );
char* file_conv = fex_wide_to_path( pwText);
delete []pwText;
fex_t *fe = scan_arc(file_conv,accept,buffer);
if(!fe)
return NULL;
free(file_conv);
#else
fex_t *fe = scan_arc(file,accept,buffer);
if(!fe)
return NULL;
#endif
// Allocate space for image
fex_err_t err = fex_stat(fe);
int fileSize = fex_size(fe);
if(size == 0)
size = fileSize;
#endif
u8 *image = data;
if(image == NULL) {
// allocate buffer memory if none was passed to the function
image = (u8 *)malloc(utilGetSize(size));
if(image == NULL) {
#ifdef NO_FEX
fclose(f);
#else
fex_close(fe);
#endif
systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
"data");
return NULL;
}
size = fileSize;
}
// Read image
int read = fileSize <= size ? fileSize : size; // do not read beyond file
#ifdef NO_FEX
int br = fread(image, 1, read, f);
const char* err = (br < read) ? "too few bytes from fread" : NULL;
fclose(f);
#else
err = fex_read(fe, image, read);
fex_close(fe);
#endif
if(err) {
systemMessage(MSG_ERROR_READING_IMAGE,
N_("Error reading image from %s: %s"), buffer, err);
if(data == NULL)
free(image);
return NULL;
}
size = fileSize;
return image;
} }
void utilWriteInt(gzFile gzFile, int i) void utilWriteInt(gzFile gzFile, int i)
@ -163,7 +614,7 @@ void utilWriteData(gzFile gzFile, variable_desc *data)
gzFile utilGzOpen(const char *file, const char *mode) gzFile utilGzOpen(const char *file, const char *mode)
{ {
utilGzWriteFunc = (int (ZEXPORT *)(void *,void * const, unsigned int))gzwrite; utilGzWriteFunc = (int (ZEXPORT *)(gzFile, void * const, unsigned int))gzwrite;
utilGzReadFunc = gzread; utilGzReadFunc = gzread;
utilGzCloseFunc = gzclose; utilGzCloseFunc = gzclose;
utilGzSeekFunc = gzseek; utilGzSeekFunc = gzseek;
@ -176,6 +627,7 @@ gzFile utilMemGzOpen(char *memory, int available, const char *mode)
utilGzWriteFunc = memgzwrite; utilGzWriteFunc = memgzwrite;
utilGzReadFunc = memgzread; utilGzReadFunc = memgzread;
utilGzCloseFunc = memgzclose; utilGzCloseFunc = memgzclose;
utilGzSeekFunc = memgzseek;
return memgzopen(memory, available, mode); return memgzopen(memory, available, mode);
} }
@ -204,3 +656,90 @@ long utilGzMemTell(gzFile file)
{ {
return memtell(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(bool lcd)
{
switch(systemColorDepth) {
case 16:
{
for(int i = 0; i < 0x10000; i++) {
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
(((i & 0x3e0) >> 5) << systemGreenShift) |
(((i & 0x7c00) >> 10) << systemBlueShift);
}
if (lcd) gbafilter_pal(systemColorMap16, 0x10000);
}
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);
}
if (lcd) gbafilter_pal32(systemColorMap32, 0x10000);
}
break;
}
}
// Check for existence of file.
bool utilFileExists( const char *filename )
{
FILE *f = fopen( filename, "r" );
if( f == NULL ) {
return false;
} else {
fclose( f );
return true;
}
}

View File

@ -1,24 +1,5 @@
// -*- C++ -*- #ifndef UTIL_H
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. #define UTIL_H
// 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_UTIL_H
#define VBA_UTIL_H
#include "System.h" #include "System.h"
@ -29,28 +10,47 @@ enum IMAGE_TYPE {
}; };
// save game // save game
typedef struct { typedef struct {
void *address; void *address;
int size; int size;
} variable_desc; } variable_desc;
bool utilWritePNGFile(const char *, int, int, u8 *);
bool utilWriteBMPFile(const char *, int, int, u8 *);
void utilApplyIPS(const char *ips, uint8_t **rom, int *size);
bool utilIsGBAImage(const char *);
bool utilIsGBImage(const char *);
bool utilIsGzipFile(const char *);
void utilStripDoubleExtension(const char *, char *);
IMAGE_TYPE utilFindType(const char *);
uint8_t *utilLoad(const char *, bool (*)(const char*), uint8_t *, int &);
extern bool utilIsGBAImage(const char *); void utilPutDword(uint8_t *, uint32_t);
extern bool utilIsGBImage(const char *); void utilPutWord(uint8_t *, uint16_t);
extern bool utilIsZipFile(const char *); void utilWriteData(gzFile, variable_desc *);
void utilReadData(gzFile, variable_desc *);
void utilReadDataSkip(gzFile, variable_desc *);
int utilReadInt(gzFile);
void utilWriteInt(gzFile, int);
gzFile utilGzOpen(const char *file, const char *mode);
gzFile utilMemGzOpen(char *memory, int available, const char *mode);
int utilGzWrite(gzFile file, const voidp buffer, unsigned int len);
int utilGzRead(gzFile file, voidp buffer, unsigned int len);
int utilGzClose(gzFile file);
z_off_t utilGzSeek(gzFile file, z_off_t offset, int whence);
long utilGzMemTell(gzFile file);
void utilGBAFindSave(const u8 *, const int);
void utilUpdateSystemColorMaps(bool lcd = false);
bool utilFileExists( const char *filename );
extern void utilPutDword(u8 *, u32);
extern void utilPutWord(u8 *, u16); #ifdef __LIBRETRO__
extern void utilWriteData(gzFile, variable_desc *); void utilWriteIntMem(uint8_t *& data, int);
extern void utilReadData(gzFile, variable_desc *); void utilWriteMem(uint8_t *& data, const void *in_data, unsigned size);
extern void utilReadDataSkip(gzFile, variable_desc *); void utilWriteDataMem(uint8_t *& data, variable_desc *);
extern int utilReadInt(gzFile);
extern void utilWriteInt(gzFile, int); int utilReadIntMem(const uint8_t *& data);
extern gzFile utilGzOpen(const char *file, const char *mode); void utilReadMem(void *buf, const uint8_t *& data, unsigned size);
extern gzFile utilMemGzOpen(char *memory, int available, const char *mode); void utilReadDataMem(const uint8_t *& data, variable_desc *);
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);
#endif #endif
#endif // UTIL_H

View File

@ -29,7 +29,7 @@ int const silent_buf_size = 1; // size used for Silent_Blip_Buffer
Blip_Buffer::Blip_Buffer() Blip_Buffer::Blip_Buffer()
{ {
factor_ = LONG_MAX; factor_ = (blip_ulong)LONG_MAX;
buffer_ = 0; buffer_ = 0;
buffer_size_ = 0; buffer_size_ = 0;
sample_rate_ = 0; sample_rate_ = 0;
@ -126,7 +126,7 @@ Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec
blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const
{ {
double ratio = (double)(sample_rate_) / double(rate); double ratio = (double) sample_rate_ / rate;
blip_long factor = (blip_long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 ); blip_long factor = (blip_long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 );
assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large
return (blip_resampled_time_t) factor; return (blip_resampled_time_t) factor;
@ -226,17 +226,15 @@ static void gen_sinc( float* out, int count, double oversample, double treble, d
treble = 5.0; treble = 5.0;
double const maxh = 4096.0; double const maxh = 4096.0;
double const rolloff = pow( 10.0, treble / (maxh * 20.0 * (1.0 - cutoff)) ); double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) );
double const pow_a_n = pow( rolloff, maxh - maxh * cutoff ); double const pow_a_n = pow( rolloff, maxh - maxh * cutoff );
double const to_angle = PI / (2.0 * maxh * oversample); double const to_angle = PI / 2 / maxh / oversample;
for ( int i = 0; i < count; i++ ) for ( int i = 0; i < count; i++ )
{ {
double angle = double(((i - count)<<1) + 1) * to_angle; double angle = ((i - count) * 2 + 1) * to_angle;
double maxhAngle = maxh * angle; double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle );
double c = rolloff * cos( maxhAngle - angle ) - cos( maxhAngle ); double cos_nc_angle = cos( maxh * cutoff * angle );
double cos_nc_angle = cos( maxhAngle * cutoff ); double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle );
double cos_nc1_angle = cos( maxhAngle * cutoff - angle );
double cos_angle = cos( angle ); double cos_angle = cos( angle );
c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle; c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
@ -252,7 +250,7 @@ void blip_eq_t::generate( float* out, int count ) const
{ {
// lower cutoff freq for narrow kernels with their wider transition band // lower cutoff freq for narrow kernels with their wider transition band
// (8 points->1.49, 16 points->1.15) // (8 points->1.49, 16 points->1.15)
double oversample = blip_res * 2.25 / double(count) + 0.85; double oversample = blip_res * 2.25 / count + 0.85;
double half_rate = sample_rate * 0.5; double half_rate = sample_rate * 0.5;
if ( cutoff_freq ) if ( cutoff_freq )
oversample = half_rate / cutoff_freq; oversample = half_rate / cutoff_freq;
@ -270,9 +268,7 @@ void Blip_Synth_::adjust_impulse()
{ {
// sum pairs for each phase and add error correction to end of first half // sum pairs for each phase and add error correction to end of first half
int const size = impulses_size(); int const size = impulses_size();
for ( int p = blip_res; p-- >= blip_res / 2; )
int blipRes2 = blip_res >> 1;
for ( int p = blip_res; p-- >= blipRes2; )
{ {
int p2 = blip_res - 2 - p; int p2 = blip_res - 2 - p;
long error = kernel_unit; long error = kernel_unit;
@ -294,11 +290,9 @@ void Blip_Synth_::adjust_impulse()
void Blip_Synth_::treble_eq( blip_eq_t const& eq ) void Blip_Synth_::treble_eq( blip_eq_t const& eq )
{ {
int blipRes2 = blip_res >> 1; float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2];
float fimpulse [blipRes2 * (blip_widest_impulse_ - 1) + blip_res * 2]; int const half_size = blip_res / 2 * (width - 1);
int const half_size = blipRes2 * (width - 1);
eq.generate( &fimpulse [blip_res], half_size ); eq.generate( &fimpulse [blip_res], half_size );
int i; int i;
@ -308,25 +302,25 @@ void Blip_Synth_::treble_eq( blip_eq_t const& eq )
fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i]; fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i];
// starts at 0 // starts at 0
for ( i = 0; i < blip_res; ++i ) for ( i = 0; i < blip_res; i++ )
fimpulse [i] = 0.0f; fimpulse [i] = 0.0f;
// find rescale factor // find rescale factor
double total = 0.0; double total = 0.0;
for ( i = 0; i < half_size; ++i ) for ( i = 0; i < half_size; i++ )
total += fimpulse [blip_res + i]; total += fimpulse [blip_res + i];
//double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB //double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB
//double const base_unit = 37888.0; // allows treble to +5 dB //double const base_unit = 37888.0; // allows treble to +5 dB
double const base_unit = 32768.0; // necessary for blip_unscaled to work double const base_unit = 32768.0; // necessary for blip_unscaled to work
double rescale = base_unit / (2 * total); double rescale = base_unit / 2 / total;
kernel_unit = (long) base_unit; kernel_unit = (long) base_unit;
// integrate, first difference, rescale, convert to int // integrate, first difference, rescale, convert to int
double sum = 0.0; double sum = 0.0;
double next = 0.0; double next = 0.0;
int const size = this->impulses_size(); int const size = this->impulses_size();
for ( i = 0; i < size; ++i ) for ( i = 0; i < size; i++ )
{ {
impulses [i] = (short) (int) floor( (next - sum) * rescale + 0.5 ); impulses [i] = (short) (int) floor( (next - sum) * rescale + 0.5 );
sum += fimpulse [i]; sum += fimpulse [i];
@ -361,7 +355,7 @@ void Blip_Synth_::volume_unit( double new_unit )
// if unit is really small, might need to attenuate kernel // if unit is really small, might need to attenuate kernel
while ( factor < 2.0 ) while ( factor < 2.0 )
{ {
++shift; shift++;
factor *= 2.0; factor *= 2.0;
} }
@ -417,7 +411,7 @@ long Blip_Buffer::read_samples( blip_sample_t* out_, long max_samples, int stere
blip_long s = BLIP_READER_READ( reader ); blip_long s = BLIP_READER_READ( reader );
BLIP_READER_NEXT_IDX_( reader, bass, offset ); BLIP_READER_NEXT_IDX_( reader, bass, offset );
BLIP_CLAMP( s, s ); BLIP_CLAMP( s, s );
out [offset << 1] = (blip_sample_t) s; out [offset * 2] = (blip_sample_t) s;
} }
while ( ++offset ); while ( ++offset );
} }

View File

@ -505,7 +505,7 @@ void Effects_Buffer::mix_effects( blip_sample_t* out_, int pair_count )
int bufs_remain = bufs_size; int bufs_remain = bufs_size;
do do
{ {
if ( buf->non_silent() && ( buf->echo == (bool)echo_phase ) ) if ( buf->non_silent() && ( buf->echo == !!echo_phase ) )
{ {
stereo_fixed_t* BLIP_RESTRICT out = (stereo_fixed_t*) &echo [echo_pos]; stereo_fixed_t* BLIP_RESTRICT out = (stereo_fixed_t*) &echo [echo_pos];
int const bass = BLIP_READER_BASS( *buf ); int const bass = BLIP_READER_BASS( *buf );

View File

@ -50,6 +50,7 @@ public:
class Gb_Env : public Gb_Osc { class Gb_Env : public Gb_Osc {
public: public:
Gb_Env() : env_enabled(false), env_delay(0) {}
int env_delay; int env_delay;
int volume; int volume;
bool env_enabled; bool env_enabled;

View File

@ -1,471 +1,445 @@
// 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 <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <zlib.h> #include <zlib.h>
#include "../System.h" #include "Patch.h"
#include "memfile.h"
/*
#ifdef __GNUC__
typedef off64_t __off64_t;
#endif
*/
#ifndef _MSC_VER #ifndef _MSC_VER
#define _stricmp strcasecmp #define _stricmp strcasecmp
#endif // ! _MSC_VER #endif // ! _MSC_VER
#ifdef _MSC_VER static int readInt2(MFILE *f)
#define fseeko64 _fseeki64 {
#define ftello64 _ftelli64 int res = 0;
typedef __int64 __off64_t; int c = memfgetc(f);
#endif if(c == MEOF)
return -1;
#if defined(__APPLE__) || defined (MACOSX) res = c;
#define fseeko64 fseeko c = memfgetc(f);
#define ftello64 ftello if(c == MEOF)
typedef off_t __off64_t; return -1;
#endif /* __APPLE__ || MACOSX */ return c + (res<<8);
static int readInt2(MFILE *f) {
int res = 0;
int c = memfgetc(f);
if (c == MEOF)
return -1;
res = c;
c = memfgetc(f);
if (c == MEOF)
return -1;
return c + (res << 8);
} }
static int readInt3(MFILE *f) { static int readInt3(MFILE *f)
int res = 0; {
int c = memfgetc(f); int res = 0;
if (c == MEOF) int c = memfgetc(f);
return -1; if(c == MEOF)
res = c; return -1;
c = memfgetc(f); res = c;
if (c == MEOF) c = memfgetc(f);
return -1; if(c == MEOF)
res = c + (res << 8); return -1;
c = memfgetc(f); res = c + (res<<8);
if (c == MEOF) c = memfgetc(f);
return -1; if(c == MEOF)
return c + (res << 8); return -1;
return c + (res<<8);
} }
static s64 readInt4(MFILE *f) { static s64 readInt4(MFILE *f)
s64 tmp, res = 0; {
int c; s64 tmp, res = 0;
int c;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
c = memfgetc(f); c = memfgetc(f);
if (c == MEOF) if (c == MEOF)
return -1; return -1;
tmp = c; tmp = c;
res = res + (tmp << (i * 8)); res = res + (tmp << (i*8));
} }
return res; return res;
} }
static s64 readInt8(MFILE *f) { static s64 readInt8(MFILE *f)
s64 tmp, res = 0; {
int c; s64 tmp, res = 0;
int c;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
c = memfgetc(f); c = memfgetc(f);
if (c == MEOF) if (c == MEOF)
return -1; return -1;
tmp = c; tmp = c;
res = res + (tmp << (i * 8)); res = res + (tmp << (i*8));
} }
return res; return res;
} }
static s64 readVarPtr(MFILE *f) { static s64 readVarPtr(MFILE *f)
s64 offset = 0, shift = 1; {
for (;;) { s64 offset = 0, shift = 1;
int c = memfgetc(f); for (;;) {
if (c == MEOF) int c = memfgetc(f);
return 0; if (c == MEOF) return 0;
offset += (c & 0x7F) * shift; offset += (c & 0x7F) * shift;
if (c & 0x80) if (c & 0x80) break;
break; shift <<= 7;
shift <<= 7; offset += shift;
offset += shift; }
} return offset;
return offset;
} }
#ifndef MIN #ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b)) #define MIN(a,b) (((a)<(b))?(a):(b))
#endif #endif
static uLong computePatchCRC(MFILE *f, unsigned int size) { static uLong computePatchCRC(MFILE *f, unsigned int size)
Bytef buf[4096]; {
long readed; Bytef buf[4096];
long readed;
uLong crc = crc32(0L, Z_NULL, 0); uLong crc = crc32(0L, Z_NULL, 0);
do { do {
readed = memfread(buf, 1, MIN(size, sizeof(buf)), f); readed = memfread(buf, 1, MIN(size, sizeof(buf)), f);
crc = crc32(crc, buf, readed); crc = crc32(crc, buf, readed);
size -= readed; size -= readed;
} while (readed > 0); } while (readed > 0);
return crc;
return crc;
} }
bool patchApplyIPS(MFILE * f, u8 **r, int *s) { bool patchApplyIPS(MFILE *f, u8 **r, int *s)
// from the IPS spec at http://zerosoft.zophar.net/ips.htm {
// from the IPS spec at http://zerosoft.zophar.net/ips.htm
bool result = false; bool result = false;
u8 *rom = *r; u8 *rom = *r;
int size = *s; int size = *s;
if (memfgetc(f) == 'P' && memfgetc(f) == 'A' && memfgetc(f) == 'T' if(memfgetc(f) == 'P' &&
&& memfgetc(f) == 'C' && memfgetc(f) == 'H') { memfgetc(f) == 'A' &&
int b; memfgetc(f) == 'T' &&
int offset; memfgetc(f) == 'C' &&
int len; memfgetc(f) == 'H') {
int b;
int offset;
int len;
result = true; result = true;
for (;;) { for(;;) {
// read offset // read offset
offset = readInt3(f); offset = readInt3(f);
// if offset == MEOF, end of patch // if offset == MEOF, end of patch
if (offset == 0x454f46 || offset == -1) if(offset == 0x454f46 || offset == -1)
break; break;
// read length // read length
len = readInt2(f); len = readInt2(f);
if (!len) { if(!len) {
// len == 0, RLE block // len == 0, RLE block
len = readInt2(f); len = readInt2(f);
// byte to fill // byte to fill
int c = memfgetc(f); int c = memfgetc(f);
if (c == -1) if(c == -1)
break; break;
b = (u8) c; b = (u8)c;
} else } else
b = -1; b= -1;
// check if we need to reallocate our ROM // check if we need to reallocate our ROM
if ((offset + len) >= size) { if((offset + len) >= size) {
#ifdef GEKKO #ifdef GEKKO
size = offset + len; size = offset + len;
#else #else
size *= 2; size *= 2;
rom = (u8 *) realloc(rom, size); rom = (u8 *)realloc(rom, size);
#endif #endif
*r = rom; *r = rom;
*s = size; *s = size;
} }
if (b == -1) { if(b == -1) {
// normal block, just read the data // normal block, just read the data
if (memfread(&rom[offset], 1, len, f) != (size_t) len) if(memfread(&rom[offset], 1, len, f) != (size_t)len)
break; break;
} else { } else {
// fill the region with the given byte // fill the region with the given byte
while (len--) { while(len--) {
rom[offset++] = b; rom[offset++] = b;
} }
} }
} }
} }
return result;
return result;
} }
bool patchApplyUPS(MFILE * f, u8 **rom, int *size) { bool patchApplyUPS(MFILE *f, u8 **rom, int *size)
{
s64 srcCRC, dstCRC, patchCRC;
s64 srcCRC, dstCRC, patchCRC; memfseek(f, 0, MSEEK_END);
long int patchSize = memftell(f);
if (patchSize < 20) {
return false;
}
memfseek(f, 0, MSEEK_END); memfseek(f, 0, MSEEK_SET);
long int patchSize = memftell(f); if(memfgetc(f) != 'U' || memfgetc(f) != 'P' || memfgetc(f) != 'S' || memfgetc(f) != '1') {
if (patchSize < 20) { return false;
return false; }
}
memfseek(f, 0, MSEEK_SET); memfseek(f, -12, MSEEK_END);
srcCRC = readInt4(f);
dstCRC = readInt4(f);
patchCRC = readInt4(f);
if (srcCRC == -1 || dstCRC == -1 || patchCRC == -1) {
return false;
}
if (memfgetc(f) != 'U' || memfgetc(f) != 'P' || memfgetc(f) != 'S' memfseek(f, 0, MSEEK_SET);
|| memfgetc(f) != '1') { u32 crc = computePatchCRC(f, patchSize-4);
return false;
}
memfseek(f, -12, MSEEK_END); if (crc != patchCRC) {
srcCRC = readInt4(f); return false;
dstCRC = readInt4(f); }
patchCRC = readInt4(f);
if (srcCRC == -1 || dstCRC == -1 || patchCRC == -1) {
return false;
}
memfseek(f, 0, MSEEK_SET); crc = crc32(0L, Z_NULL, 0);
u32 crc = computePatchCRC(f, patchSize - 4); crc = crc32(crc, *rom, *size);
if (crc != patchCRC) { memfseek(f, 4, MSEEK_SET);
return false; s64 dataSize;
} s64 srcSize = readVarPtr(f);
s64 dstSize = readVarPtr(f);
crc = crc32(0L, Z_NULL, 0); if (crc == srcCRC) {
crc = crc32(crc, *rom, *size); if (srcSize != *size) {
return false;
}
dataSize = dstSize;
} else if (crc == dstCRC) {
if (dstSize != *size) {
return false;
}
dataSize = srcSize;
} else {
return false;
}
if (dataSize > *size) {
*rom = (u8*)realloc(*rom, dataSize);
memset(*rom + *size, 0, dataSize - *size);
*size = dataSize;
}
memfseek(f, 4, MSEEK_SET); s64 relative = 0;
s64 dataSize; u8 *mem;
s64 srcSize = readVarPtr(f); while(memftell(f) < patchSize - 12) {
s64 dstSize = readVarPtr(f); relative += readVarPtr(f);
if (relative > dataSize) continue;
mem = *rom + relative;
for(s64 i = relative; i < dataSize; i++) {
int x = memfgetc(f);
relative++;
if (!x) break;
if (i < dataSize) {
*mem++ ^= x;
}
}
}
if (crc == srcCRC) { return true;
dataSize = srcSize;
} else if (crc == dstCRC) {
dataSize = dstSize;
} else {
return false;
}
if (dataSize != *size) {
return false;
}
s64 relative = 0;
u8 *mem;
while (memftell(f) < patchSize - 12) {
relative += readVarPtr(f);
if (relative > dataSize)
continue;
mem = *rom + relative;
for (s64 i = relative; i < dataSize; i++) {
int x = memfgetc(f);
relative++;
if (!x)
break;
if (i < dataSize) {
*mem++ ^= x;
}
}
}
return true;
} }
static int ppfVersion(MFILE *f) { static int ppfVersion(MFILE *f)
memfseek(f, 0, MSEEK_SET); {
if (memfgetc(f) != 'P' || memfgetc(f) != 'P' || memfgetc(f) != 'F') memfseek(f, 0, MSEEK_SET);
return 0; if (memfgetc(f) != 'P' || memfgetc(f) != 'P' || memfgetc(f) != 'F') //-V501
switch (memfgetc(f)) { return 0;
case '1': switch(memfgetc(f)){
return 1; case '1': return 1;
case '2': case '2': return 2;
return 2; case '3': return 3;
case '3': default: return 0;
return 3; }
default:
return 0;
}
} }
int ppfFileIdLen(MFILE *f, int version) { static int ppfFileIdLen(MFILE *f, int version)
if (version == 2) { {
memfseek(f, -8, MSEEK_END); if (version == 2) {
} else { memfseek(f, -8, MSEEK_END);
memfseek(f, -6, MSEEK_END); } else {
} memfseek(f, -6, MSEEK_END);
}
if (memfgetc(f) != '.' || memfgetc(f) != 'D' || memfgetc(f) != 'I' if (memfgetc(f) != '.' || memfgetc(f) != 'D' || memfgetc(f) != 'I' || memfgetc(f) != 'Z')
|| memfgetc(f) != 'Z') return 0;
return 0;
return (version == 2) ? readInt4(f) : readInt2(f); return (version == 2) ? readInt4(f) : readInt2(f);
} }
static bool patchApplyPPF1(MFILE *f, u8 **rom, int *size) { static bool patchApplyPPF1(MFILE *f, u8 **rom, int *size)
memfseek(f, 0, MSEEK_END); {
int count = memftell(f); memfseek(f, 0, MSEEK_END);
if (count < 56) int count = memftell(f);
return false; if (count < 56)
count -= 56; return false;
count -= 56;
memfseek(f, 56, MSEEK_SET); memfseek(f, 56, MSEEK_SET);
u8 *mem = *rom; u8 *mem = *rom;
while (count > 0) { while (count > 0) {
int offset = readInt4(f); int offset = readInt4(f);
if (offset == -1) if (offset == -1)
break; break;
int len = memfgetc(f); int len = memfgetc(f);
if (len == MEOF) if (len == MEOF)
break; break;
if (offset + len > *size) if (offset+len > *size)
break; break;
if (memfread(&mem[offset], 1, len, f) != (size_t) len) if (memfread(&mem[offset], 1, len, f) != (size_t)len)
break; break;
count -= 4 + 1 + len; count -= 4 + 1 + len;
} }
return (count == 0); return (count == 0);
} }
static bool patchApplyPPF2(MFILE *f, u8 **rom, int *size) { static bool patchApplyPPF2(MFILE *f, u8 **rom, int *size)
memfseek(f, 0, MSEEK_END); {
int count = memftell(f); memfseek(f, 0, MSEEK_END);
if (count < 56 + 4 + 1024) int count = memftell(f);
return false; if (count < 56+4+1024)
count -= 56 + 4 + 1024; return false;
count -= 56+4+1024;
memfseek(f, 56, MSEEK_SET); memfseek(f, 56, MSEEK_SET);
int datalen = readInt4(f); int datalen = readInt4(f);
if (datalen != *size) if (datalen != *size)
return false; return false;
u8 *mem = *rom; u8 *mem = *rom;
u8 block[1024]; u8 block[1024];
memfread(&block, 1, 1024, f); memfread(&block, 1, 1024, f);
if (memcmp(&mem[0x9320], &block, 1024) != 0) if (memcmp(&mem[0x9320], &block, 1024) != 0)
return false; return false;
int idlen = ppfFileIdLen(f, 2); int idlen = ppfFileIdLen(f, 2);
if (idlen > 0) if (idlen > 0)
count -= 16 + 16 + idlen; count -= 16 + 16 + idlen;
memfseek(f, 56 + 4 + 1024, MSEEK_SET); memfseek(f, 56+4+1024, MSEEK_SET);
while (count > 0) { while (count > 0) {
int offset = readInt4(f); int offset = readInt4(f);
if (offset == -1) if (offset == -1)
break; break;
int len = memfgetc(f); int len = memfgetc(f);
if (len == MEOF) if (len == MEOF)
break; break;
if (offset + len > *size) if (offset+len > *size)
break; break;
if (memfread(&mem[offset], 1, len, f) != (size_t) len) if (memfread(&mem[offset], 1, len, f) != (size_t)len)
break; break;
count -= 4 + 1 + len; count -= 4 + 1 + len;
} }
return (count == 0); return (count == 0);
} }
static bool patchApplyPPF3(MFILE *f, u8 **rom, int *size) { static bool patchApplyPPF3(MFILE *f, u8 **rom, int *size)
memfseek(f, 0, MSEEK_END); {
int count = memftell(f); memfseek(f, 0, MSEEK_END);
if (count < 56 + 4 + 1024) int count = memftell(f);
return false; if (count < 56+4+1024)
count -= 56 + 4; return false;
count -= 56+4;
memfseek(f, 56, MSEEK_SET); memfseek(f, 56, MSEEK_SET);
int imagetype = memfgetc(f); int imagetype = memfgetc(f);
int blockcheck = memfgetc(f); int blockcheck = memfgetc(f);
int undo = memfgetc(f); int undo = memfgetc(f);
memfgetc(f); memfgetc(f);
u8 *mem = *rom; u8 *mem = *rom;
if (blockcheck) { if (blockcheck) {
u8 block[1024]; u8 block[1024];
memfread(&block, 1, 1024, f); memfread(&block, 1, 1024, f);
if (memcmp(&mem[(imagetype == 0) ? 0x9320 : 0x80A0], &block, 1024) != 0) if (memcmp(&mem[(imagetype == 0) ? 0x9320 : 0x80A0], &block, 1024) != 0)
return false; return false;
count -= 1024; count -= 1024;
} }
int idlen = ppfFileIdLen(f, 2); int idlen = ppfFileIdLen(f, 2);
if (idlen > 0) if (idlen > 0)
count -= 16 + 16 + idlen; count -= 16 + 16 + idlen;
memfseek(f, 56 + 4 + (blockcheck ? 1024 : 0), MSEEK_SET); memfseek(f, 56+4+(blockcheck ? 1024 : 0), MSEEK_SET);
while (count > 0) { while (count > 0) {
s64 offset = readInt8(f); s64 offset = readInt8(f);
if (offset == -1) if (offset == -1)
break; break;
int len = memfgetc(f); int len = memfgetc(f);
if (len == MEOF) if (len == MEOF)
break; break;
if (offset + len > *size) if (offset+len > *size)
break; break;
if (memfread(&mem[offset], 1, len, f) != (size_t) len) if (memfread(&mem[offset], 1, len, f) != (size_t)len)
break; break;
if (undo) if (undo) memfseek(f, len, MSEEK_CUR);
memfseek(f, len, MSEEK_CUR); count -= 8 + 1 + len;
count -= 8 + 1 + len; if (undo) count -= len;
if (undo) }
count -= len;
}
return (count == 0); return (count == 0);
} }
bool patchApplyPPF(MFILE *f, u8 **rom, int *size) bool patchApplyPPF(MFILE *f, u8 **rom, int *size)
{ {
bool res = false; bool res = false;
int version = ppfVersion(f); int version = ppfVersion(f);
switch (version) switch (version) {
{ case 1: res = patchApplyPPF1(f, rom, size); break;
case 1: res = patchApplyPPF1(f, rom, size); break; case 2: res = patchApplyPPF2(f, rom, size); break;
case 2: res = patchApplyPPF2(f, rom, size); break; case 3: res = patchApplyPPF3(f, rom, size); break;
case 3: res = patchApplyPPF3(f, rom, size); break; }
}
return res; return res;
} }
bool applyPatch(const char *patchname, u8 **rom, int *size) bool applyPatch(const char *patchname, u8 **rom, int *size)
{ {
bool result = false; bool result = false;
if (strlen(patchname) < 5) if (strlen(patchname) < 5)
return false; return false;
const char * p = strrchr(patchname, '.'); const char * p = strrchr(patchname, '.');
if (p == NULL) if (p == NULL)
return false; return false;
FILE *f = fopen(patchname, "rb"); FILE *f = fopen(patchname, "rb");
if (!f) if (!f)
return false; return false;
// read in file // read in file
fseek(f, 0, SEEK_END); // go to end of file fseek(f, 0, SEEK_END); // go to end of file
int filesize = ftell(f); // get filesize int filesize = ftell(f); // get filesize
fseek(f, 0, SEEK_SET); // go to start of file fseek(f, 0, SEEK_SET); // go to start of file
char * pbuffer = (char *) malloc(filesize); char * pbuffer = (char *) malloc(filesize);
fread (pbuffer, 1, filesize, f); fread (pbuffer, 1, filesize, f);
fclose(f); fclose(f);
MFILE * mf = memfopen(pbuffer, filesize); // create memory file MFILE * mf = memfopen(pbuffer, filesize); // create memory file
if (_stricmp(p, ".ips") == 0) if (_stricmp(p, ".ips") == 0)
result = patchApplyIPS(mf, rom, size); result = patchApplyIPS(mf, rom, size);
else if (_stricmp(p, ".ups") == 0) else if (_stricmp(p, ".ups") == 0)
result = patchApplyUPS(mf, rom, size); result = patchApplyUPS(mf, rom, size);
else if (_stricmp(p, ".ppf") == 0) else if (_stricmp(p, ".ppf") == 0)
result = patchApplyPPF(mf, rom, size); result = patchApplyPPF(mf, rom, size);
memfclose(mf); // close memory file memfclose(mf); // close memory file
free(pbuffer); // free buffer free(pbuffer); // free buffer
return result; return result;
} }

View File

@ -1,31 +1,12 @@
// -*- C++ -*- #ifndef PATCH_H
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. #define PATCH_H
// 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_PATCH_H
#define VBA_PATCH_H
#include "memfile.h" #include "memfile.h"
#include "System.h" #include "Types.h"
bool applyPatch(const char *patchname, u8 **rom, int *size); bool applyPatch(const char *patchname, u8 **rom, int *size);
bool patchApplyIPS(MFILE * f, u8 **r, int *s); bool patchApplyIPS(MFILE * f, u8 **r, int *s);
bool patchApplyUPS(MFILE * f, u8 **rom, int *size); bool patchApplyUPS(MFILE * f, u8 **rom, int *size);
bool patchApplyPPF(MFILE *f, u8 **rom, int *size); bool patchApplyPPF(MFILE *f, u8 **rom, int *size);
#endif #endif // PATCH_H

View File

@ -1,24 +1,17 @@
// -*- C++ -*- #ifndef PORT_H
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. #define PORT_H
// 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 #ifdef __CELLOS_LV2__
// it under the terms of the GNU General Public License as published by /* PlayStation3 */
// the Free Software Foundation; either version 2, or(at your option) #include <ppu_intrinsics.h>
// any later version. #endif
//
// 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 #ifdef _XBOX360
#define VBA_PORT_H /* XBox 360 */
#include <ppcintrinsics.h>
#endif
#include "Types.h"
// swaps a 16-bit value // swaps a 16-bit value
static inline u16 swap16(u16 v) static inline u16 swap16(u16 v)
@ -72,4 +65,4 @@ static inline u32 swap32(u32 v)
*((u32 *)x) = (v) *((u32 *)x) = (v)
#endif #endif
#endif #endif // PORT_H

View File

@ -13,7 +13,7 @@
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation, // along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef __VBA_SOUND_DRIVER_H__ #ifndef __VBA_SOUND_DRIVER_H__
#define __VBA_SOUND_DRIVER_H__ #define __VBA_SOUND_DRIVER_H__

View File

@ -13,7 +13,7 @@
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation, // along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef __VBA_TYPES_H__ #ifndef __VBA_TYPES_H__
#define __VBA_TYPES_H__ #define __VBA_TYPES_H__

View File

@ -9,7 +9,7 @@
* Adapted from original gzio.c from zlib library by Forgotten * Adapted from original gzio.c from zlib library by Forgotten
*/ */
/* @(#) $Id: memgzio.c,v 1.5 2006/06/06 21:04:20 spacy51 Exp $ */ /* @(#) $Id: memgzio.c 1213 2013-09-21 13:57:40Z kode54 $ */
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
@ -697,3 +697,23 @@ long ZEXPORT memtell(file)
return memTell(s->file); return memTell(s->file);
} }
z_off_t ZEXPORT memgzseek(gzFile file, z_off_t off, int whence)
{
char buf[80];
if(whence != SEEK_CUR) {
fputs("FIXME: memgzio does not support seeking\n", stderr);
exit(1);
}
// this is inefficient, but the best I can do without actually reading
// the above code
while(off > 0) {
int r = memgzread(file, buf, off > 80 ? 80 : off);
if(r <= 0)
return -1;
off -= r;
}
return memtell(file);
}

View File

@ -19,5 +19,6 @@ int ZEXPORT memgzread(gzFile file, voidp buf, unsigned len);
int ZEXPORT memgzwrite(gzFile file, const voidp buf, unsigned len); int ZEXPORT memgzwrite(gzFile file, const voidp buf, unsigned len);
int ZEXPORT memgzclose(gzFile file); int ZEXPORT memgzclose(gzFile file);
long ZEXPORT memtell(gzFile file); long ZEXPORT memtell(gzFile file);
z_off_t ZEXPORT memgzseek(gzFile file, z_off_t off, int whence);
#endif // MEMGZIO_H #endif // MEMGZIO_H

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,12 @@ typedef union {
u16 W; u16 W;
} gbRegister; } gbRegister;
extern gbRegister AF, BC, DE, HL, SP, PC;
extern u16 IFF;
int gbDis(char *, u16);
bool gbLoadRom(const char *); bool gbLoadRom(const char *);
bool gbUpdateSizes();
void gbEmulate(int); void gbEmulate(int);
void gbWriteMemory(register u16, register u8); void gbWriteMemory(register u16, register u8);
void gbDrawLine(); void gbDrawLine();
@ -38,8 +43,11 @@ bool gbWritePNGFile(const char *);
bool gbWriteBMPFile(const char *); bool gbWriteBMPFile(const char *);
bool gbReadGSASnapshot(const char *); bool gbReadGSASnapshot(const char *);
extern int gbHardware;
extern struct EmulatedSystem GBSystem; extern struct EmulatedSystem GBSystem;
// For VBA-GX
bool MemgbReadBatteryFile(char * membuffer, int read); bool MemgbReadBatteryFile(char * membuffer, int read);
int MemgbWriteBatteryFile(char * membuffer); int MemgbWriteBatteryFile(char * membuffer);

View File

@ -1,4 +1,4 @@
#include <string.h> #include <cstdlib>
#include "../common/Types.h" #include "../common/Types.h"
u8 *gbMemoryMap[16]; u8 *gbMemoryMap[16];
@ -30,7 +30,7 @@ u16 gbColorFilter[32768];
int gbColorOption = 0; int gbColorOption = 0;
int gbPaletteOption = 0; int gbPaletteOption = 0;
int gbEmulatorType = 0; int gbEmulatorType = 0;
int gbBorderOn = 1; int gbBorderOn = 0;
int gbBorderAutomatic = 0; int gbBorderAutomatic = 0;
int gbBorderLineSkip = 160; int gbBorderLineSkip = 160;
int gbBorderRowSkip = 0; int gbBorderRowSkip = 0;
@ -38,3 +38,4 @@ int gbBorderColumnSkip = 0;
int gbDmaTicks = 0; int gbDmaTicks = 0;
u8 (*gbSerialFunction)(u8) = NULL; u8 (*gbSerialFunction)(u8) = NULL;
void (*sgbBorderListener)(bool) = NULL;

View File

@ -5,10 +5,12 @@
#include "gb.h" #include "gb.h"
u8 gbDaysinMonth [12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; u8 gbDaysinMonth [12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const u8 gbDisabledRam [8] = {0x80, 0xff, 0xf0, 0x00, 0x30, 0xbf, 0xbf, 0xbf}; const u8 gbDisabledRam [8] = {0x80, 0xff, 0xf0, 0x00, 0x30, 0xbf, 0xbf, 0xbf};
extern int gbHardware;
extern int gbGBCColorType; extern int gbGBCColorType;
extern gbRegister PC; extern gbRegister PC;
// for UTC offset
#include "../../vbagx.h"
mapperMBC1 gbDataMBC1 = { mapperMBC1 gbDataMBC1 = {
0, // RAM enable 0, // RAM enable
1, // ROM bank 1, // ROM bank
@ -327,7 +329,7 @@ mapperMBC3 gbDataMBC3 = {
void memoryUpdateMBC3Clock() void memoryUpdateMBC3Clock()
{ {
time_t now = time(NULL); time_t now = time(NULL) - (GCSettings.OffsetMinutesUTC*60);
time_t diff = now - gbDataMBC3.mapperLastTime; time_t diff = now - gbDataMBC3.mapperLastTime;
if(diff > 0) { if(diff > 0) {
// update the clock according to the last update time // update the clock according to the last update time
@ -437,6 +439,7 @@ void mapperMBC3RAM(u16 address, u8 value)
} }
} else { } else {
time(&gbDataMBC3.mapperLastTime); time(&gbDataMBC3.mapperLastTime);
gbDataMBC3.mapperLastTime -= (GCSettings.OffsetMinutesUTC*60);
switch(gbDataMBC3.mapperClockRegister) { switch(gbDataMBC3.mapperClockRegister) {
case 0x08: case 0x08:
gbDataMBC3.mapperSeconds = value; gbDataMBC3.mapperSeconds = value;
@ -540,7 +543,6 @@ mapperMBC5 gbDataMBC5 = {
0 // is rumble cartridge? 0 // is rumble cartridge?
}; };
extern int ConfigRequested;
// MBC5 ROM write registers // MBC5 ROM write registers
void mapperMBC5ROM(u16 address, u8 value) void mapperMBC5ROM(u16 address, u8 value)
{ {
@ -581,18 +583,10 @@ void mapperMBC5ROM(u16 address, u8 value)
gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
} }
break; break;
case 0x4000: // RAM bank select, plus rumble case 0x4000: // RAM bank select
// Some games support rumble, such as Disney Tarzan, but aren't on a if(gbDataMBC5.isRumbleCartridge)
// rumble cartridge. As long as the RAM is less than or equal to 256Kbit
// we know that the last address line is not used for real RAM addresses,
// so it must be a rumble signal instead.
if(gbDataMBC5.isRumbleCartridge) {
systemCartridgeRumble(value & 0x08);
value &= 0x07; value &= 0x07;
} else if (gbRamSizeMask <= 0x7FFF) { else
systemPossibleCartridgeRumble(value & 0x08);
value &= 0x07;
} else
value &= 0x0f; value &= 0x0f;
if(value == gbDataMBC5.mapperRAMBank) if(value == gbDataMBC5.mapperRAMBank)
break; break;
@ -1231,7 +1225,7 @@ void memoryUpdateTAMA5Clock()
else else
gbDaysinMonth[1] = 28; gbDaysinMonth[1] = 28;
time_t now = time(NULL); time_t now = time(NULL) - (GCSettings.OffsetMinutesUTC*60);
time_t diff = now - gbDataTAMA5.mapperLastTime; time_t diff = now - gbDataTAMA5.mapperLastTime;
if(diff > 0) { if(diff > 0) {
// update the clock according to the last update time // update the clock according to the last update time
@ -1428,6 +1422,7 @@ void mapperTAMA5RAM(u16 address, u8 value)
gbTAMA5ram[0x94] = MonthsH*16+MonthsL; // incorrect ? (not used by the game) ? gbTAMA5ram[0x94] = MonthsH*16+MonthsL; // incorrect ? (not used by the game) ?
time(&gbDataTAMA5.mapperLastTime); time(&gbDataTAMA5.mapperLastTime);
gbDataMBC3.mapperLastTime -= (GCSettings.OffsetMinutesUTC*60);
gbMemoryMap[0xa][0] = 1; gbMemoryMap[0xa][0] = 1;
} }

View File

@ -38,6 +38,7 @@ void gbPrinterReset()
void gbPrinterShowData() void gbPrinterShowData()
{ {
systemGbPrint(gbPrinterData, systemGbPrint(gbPrinterData,
gbPrinterDataCount,
gbPrinterPacket[6], gbPrinterPacket[6],
gbPrinterPacket[7], gbPrinterPacket[7],
gbPrinterPacket[8], gbPrinterPacket[8],
@ -87,6 +88,7 @@ void gbPrinterShowData()
void gbPrinterReceiveData() void gbPrinterReceiveData()
{ {
int i = gbPrinterDataCount;
if(gbPrinterPacket[3]) { // compressed if(gbPrinterPacket[3]) { // compressed
u8 *data = &gbPrinterPacket[6]; u8 *data = &gbPrinterPacket[6];
u8 *dest = &gbPrinterData[gbPrinterDataCount]; u8 *dest = &gbPrinterData[gbPrinterDataCount];
@ -97,16 +99,17 @@ void gbPrinterReceiveData()
control &= 0x7f; control &= 0x7f;
control += 2; control += 2;
memset(dest, *data++, control); memset(dest, *data++, control);
len += control; len += 2;
dest += control; dest += control;
} else { // raw data } else { // raw data
control++; control++;
memcpy(dest, data, control); memcpy(dest, data, control);
dest += control; dest += control;
data += control; data += control;
len += control; len += control + 1;
} }
} }
gbPrinterDataCount = (int)(dest - gbPrinterData);
} else { } else {
memcpy(&gbPrinterData[gbPrinterDataCount], memcpy(&gbPrinterData[gbPrinterDataCount],
&gbPrinterPacket[6], &gbPrinterPacket[6],

View File

@ -40,7 +40,7 @@ u8 gbSgbScreenBuffer[4160];
inline void gbSgbDraw24Bit(u8 *p, u16 v) inline void gbSgbDraw24Bit(u8 *p, u16 v)
{ {
*((u32*) p) = systemColorMap32[v]; memcpy(p, &systemColorMap32[v], 3);
} }
inline void gbSgbDraw32Bit(u32 *p, u16 v) inline void gbSgbDraw32Bit(u32 *p, u16 v)
@ -188,9 +188,9 @@ void gbSgbRenderScreenToBuffer()
void gbSgbDrawBorderTile(int x, int y, int tile, int attr) void gbSgbDrawBorderTile(int x, int y, int tile, int attr)
{ {
u16 *dest = (u16*)pix + ((y+1) * (256+2)) + x; u16 *dest = (u16*)pix + (y * (256+2)) + x;
u8 *dest8 = (u8*)pix + ((y*256)+x)*3; u8 *dest8 = (u8*)pix + ((y*256)+x)*3;
u32 *dest32 = (u32*)pix + ((y+1)*257) + x; u32 *dest32 = (u32*)pix + (y*257) + x;
u8 *tileAddress = &gbSgbBorderChar[tile * 32]; u8 *tileAddress = &gbSgbBorderChar[tile * 32];
u8 *tileAddress2 = &gbSgbBorderChar[tile * 32 + 16]; u8 *tileAddress2 = &gbSgbBorderChar[tile * 32 + 16];

View File

@ -4,11 +4,11 @@
#include "../Util.h" #include "../Util.h"
#include "gbGlobals.h" #include "gbGlobals.h"
#include "gbSound.h" #include "gbSound.h"
#include "gb.h"
#include "../apu/Gb_Apu.h" #include "../apu/Gb_Apu.h"
#include "../apu/Effects_Buffer.h" #include "../apu/Effects_Buffer.h"
extern int gbHardware;
extern long soundSampleRate; // current sound quality extern long soundSampleRate; // current sound quality
gb_effects_config_t gb_effects_config = { false, 0.20f, 0.15f, false }; gb_effects_config_t gb_effects_config = { false, 0.20f, 0.15f, false };
@ -121,6 +121,13 @@ static void reset_apu()
static void remake_stereo_buffer() static void remake_stereo_buffer()
{ {
// APU
if ( !gb_apu )
{
gb_apu = new Gb_Apu; // TODO: handle errors
reset_apu();
}
// Stereo_Buffer // Stereo_Buffer
delete stereo_buffer; delete stereo_buffer;
stereo_buffer = 0; stereo_buffer = 0;
@ -129,19 +136,14 @@ static void remake_stereo_buffer()
if ( stereo_buffer->set_sample_rate( soundSampleRate ) ) { } // TODO: handle out of memory if ( stereo_buffer->set_sample_rate( soundSampleRate ) ) { } // TODO: handle out of memory
stereo_buffer->clock_rate( gb_apu->clock_rate ); stereo_buffer->clock_rate( gb_apu->clock_rate );
// APU // Multi_Buffer
static int const chan_types [chan_count] = { static int const chan_types [chan_count] = {
Multi_Buffer::wave_type+1, Multi_Buffer::wave_type+2, Multi_Buffer::wave_type+1, Multi_Buffer::wave_type+2,
Multi_Buffer::wave_type+3, Multi_Buffer::mixed_type+1 Multi_Buffer::wave_type+3, Multi_Buffer::mixed_type+1
}; };
if ( stereo_buffer->set_channel_count( chan_count, chan_types ) ) { } // TODO: handle errors if ( stereo_buffer->set_channel_count( chan_count, chan_types ) ) { } // TODO: handle errors
if ( !gb_apu ) // Volume Level
{
gb_apu = new Gb_Apu; // TODO: handle errors
reset_apu();
}
apply_effects(); apply_effects();
apply_volume(); apply_volume();
} }

View File

@ -1,4 +1,4 @@
#include <string.h> #ifndef __LIBRETRO__
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
@ -910,24 +910,24 @@ int cheatsCheckKeys(u32 keys, u32 extended)
} }
break; break;
case GSA_8_BIT_POINTER : case GSA_8_BIT_POINTER :
if ((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000) || if (((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000)) ||
(CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000)) ((CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000)))
{ {
CPUWriteByte(CPUReadMemory(cheatsList[i].address)+((cheatsList[i].value & 0xFFFFFF00) >> 8), CPUWriteByte(CPUReadMemory(cheatsList[i].address)+((cheatsList[i].value & 0xFFFFFF00) >> 8),
cheatsList[i].value & 0xFF); cheatsList[i].value & 0xFF);
} }
break; break;
case GSA_16_BIT_POINTER : case GSA_16_BIT_POINTER :
if ((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000) || if (((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000)) ||
(CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000)) ((CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000)))
{ {
CPUWriteHalfWord(CPUReadMemory(cheatsList[i].address)+((cheatsList[i].value & 0xFFFF0000) >> 15), CPUWriteHalfWord(CPUReadMemory(cheatsList[i].address)+((cheatsList[i].value & 0xFFFF0000) >> 15),
cheatsList[i].value & 0xFFFF); cheatsList[i].value & 0xFFFF);
} }
break; break;
case GSA_32_BIT_POINTER : case GSA_32_BIT_POINTER :
if ((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000) || if (((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000)) ||
(CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000)) ((CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000)))
{ {
CPUWriteMemory(CPUReadMemory(cheatsList[i].address), CPUWriteMemory(CPUReadMemory(cheatsList[i].address),
cheatsList[i].value); cheatsList[i].value);
@ -935,15 +935,15 @@ int cheatsCheckKeys(u32 keys, u32 extended)
break; break;
case GSA_8_BIT_ADD : case GSA_8_BIT_ADD :
CPUWriteByte(cheatsList[i].address, CPUWriteByte(cheatsList[i].address,
(cheatsList[i].value & 0xFF) + CPUReadMemory(cheatsList[i].address) & 0xFF); ((cheatsList[i].value & 0xFF) + CPUReadMemory(cheatsList[i].address)) & 0xFF);
break; break;
case GSA_16_BIT_ADD : case GSA_16_BIT_ADD :
CPUWriteHalfWord(cheatsList[i].address, CPUWriteHalfWord(cheatsList[i].address,
(cheatsList[i].value & 0xFFFF) + CPUReadMemory(cheatsList[i].address) & 0xFFFF); ((cheatsList[i].value & 0xFFFF) + CPUReadMemory(cheatsList[i].address)) & 0xFFFF);
break; break;
case GSA_32_BIT_ADD : case GSA_32_BIT_ADD :
CPUWriteMemory(cheatsList[i].address , CPUWriteMemory(cheatsList[i].address ,
cheatsList[i].value + CPUReadMemory(cheatsList[i].address) & 0xFFFFFFFF); (cheatsList[i].value + CPUReadMemory(cheatsList[i].address)) & 0xFFFFFFFF);
break; break;
case GSA_8_BIT_IF_LOWER_U: case GSA_8_BIT_IF_LOWER_U:
if (!(CPUReadByte(cheatsList[i].address) < (cheatsList[i].value & 0xFF))) { if (!(CPUReadByte(cheatsList[i].address) < (cheatsList[i].value & 0xFF))) {
@ -2678,8 +2678,6 @@ void cheatsReadGameSkip( gzFile file, int version )
utilGzSeek( file, sizeof( cheatsList ), SEEK_CUR ); utilGzSeek( file, sizeof( cheatsList ), SEEK_CUR );
} }
bool firstCodeBreaker = true;
for( int i = 0; i < nCheats; i++ ) { for( int i = 0; i < nCheats; i++ ) {
if( version < 9 ) { if( version < 9 ) {
utilGzSeek( file, ( 7 * sizeof(int) ) + ( 52 * sizeof(char) ), SEEK_CUR ); utilGzSeek( file, ( 7 * sizeof(int) ) + ( 52 * sizeof(char) ), SEEK_CUR );
@ -2898,3 +2896,4 @@ void cheatsWriteByte(u32, u8)
#endif #endif
#endif #endif
} }
#endif

View File

@ -9,7 +9,15 @@ int eepromMode = EEPROM_IDLE;
int eepromByte = 0; int eepromByte = 0;
int eepromBits = 0; int eepromBits = 0;
int eepromAddress = 0; int eepromAddress = 0;
#ifdef __LIBRETRO__
// Workaround for broken-by-design GBA save semantics
extern u8 libretro_save_buf[0x20000 + 0x2000];
u8 *eepromData = libretro_save_buf + 0x20000;
#else
u8 eepromData[0x2000]; u8 eepromData[0x2000];
#endif
u8 eepromBuffer[16]; u8 eepromBuffer[16];
bool eepromInUse = false; bool eepromInUse = false;
int eepromSize = 512; int eepromSize = 512;
@ -27,7 +35,11 @@ variable_desc eepromSaveData[] = {
void eepromInit() void eepromInit()
{ {
memset(eepromData, 255, sizeof(eepromData)); #ifdef __LIBRETRO__
memset(eepromData, 255, 0x2000);
#else
memset(eepromData, 255, sizeof(eepromData));
#endif
} }
void eepromReset() void eepromReset()
@ -40,6 +52,26 @@ void eepromReset()
eepromSize = 512; eepromSize = 512;
} }
#ifdef __LIBRETRO__
void eepromSaveGame(uint8_t *& data)
{
utilWriteDataMem(data, eepromSaveData);
utilWriteIntMem(data, eepromSize);
utilWriteMem(data, eepromData, 0x2000);
}
void eepromReadGame(const uint8_t *& data, int version)
{
utilReadDataMem(data, eepromSaveData);
if (version >= SAVE_GAME_VERSION_3) {
eepromSize = utilReadIntMem(data);
utilReadMem(eepromData, data, 0x2000);
} else {
// prior to 0.7.1, only 4K EEPROM was supported
eepromSize = 512;
}
}
#else
void eepromSaveGame(gzFile gzFile) void eepromSaveGame(gzFile gzFile)
{ {
utilWriteData(gzFile, eepromSaveData); utilWriteData(gzFile, eepromSaveData);
@ -68,6 +100,7 @@ void eepromReadGameSkip(gzFile gzFile, int version)
utilGzSeek(gzFile, 0x2000, SEEK_CUR); utilGzSeek(gzFile, 0x2000, SEEK_CUR);
} }
} }
#endif
int eepromRead(u32 /* address */) int eepromRead(u32 /* address */)
{ {

View File

@ -1,14 +1,23 @@
#ifndef EEPROM_H #ifndef EEPROM_H
#define EEPROM_H #define EEPROM_H
#ifdef __LIBRETRO__
extern void eepromSaveGame(u8* &data);
extern void eepromReadGame(const u8 *&data, int version);
#else
extern void eepromSaveGame(gzFile _gzFile); extern void eepromSaveGame(gzFile _gzFile);
extern void eepromReadGame(gzFile _gzFile, int version); extern void eepromReadGame(gzFile _gzFile, int version);
#endif
extern void eepromReadGameSkip(gzFile _gzFile, int version); extern void eepromReadGameSkip(gzFile _gzFile, int version);
extern int eepromRead(u32 address); extern int eepromRead(u32 address);
extern void eepromWrite(u32 address, u8 value); extern void eepromWrite(u32 address, u8 value);
extern void eepromInit(); extern void eepromInit();
extern void eepromReset(); extern void eepromReset();
#ifdef __LIBRETRO__
extern u8 *eepromData;
#else
extern u8 eepromData[0x2000]; extern u8 eepromData[0x2000];
#endif
extern bool eepromInUse; extern bool eepromInUse;
extern int eepromSize; extern int eepromSize;

View File

@ -17,7 +17,13 @@
#define FLASH_PROGRAM 8 #define FLASH_PROGRAM 8
#define FLASH_SETBANK 9 #define FLASH_SETBANK 9
u8 flashSaveMemory[0x20000]; #ifdef __LIBRETRO__
extern uint8_t libretro_save_buf[0x20000 + 0x2000];
uint8_t *flashSaveMemory = libretro_save_buf;
#else
uint8_t flashSaveMemory[FLASH_128K_SZ];
#endif
int flashState = FLASH_READ_ARRAY; int flashState = FLASH_READ_ARRAY;
int flashReadState = FLASH_READ_ARRAY; int flashReadState = FLASH_READ_ARRAY;
int flashSize = 0x10000; int flashSize = 0x10000;
@ -51,7 +57,11 @@ static variable_desc flashSaveData3[] = {
void flashInit() void flashInit()
{ {
memset(flashSaveMemory, 0xff, sizeof(flashSaveMemory)); #ifdef __LIBRETRO__
memset(flashSaveMemory, 0xff, 0x20000);
#else
memset(flashSaveMemory, 0xff, sizeof(flashSaveMemory));
#endif
} }
void flashReset() void flashReset()
@ -61,6 +71,17 @@ void flashReset()
flashBank = 0; flashBank = 0;
} }
#ifdef __LIBRETRO__
void flashSaveGame(uint8_t *& data)
{
utilWriteDataMem(data, flashSaveData3);
}
void flashReadGame(const uint8_t *& data, int)
{
utilReadDataMem(data, flashSaveData3);
}
#else
void flashSaveGame(gzFile gzFile) void flashSaveGame(gzFile gzFile)
{ {
utilWriteData(gzFile, flashSaveData3); utilWriteData(gzFile, flashSaveData3);
@ -90,6 +111,8 @@ void flashReadGameSkip(gzFile gzFile, int version)
utilReadDataSkip(gzFile, flashSaveData3); utilReadDataSkip(gzFile, flashSaveData3);
} }
} }
#endif
void flashSetSize(int size) void flashSetSize(int size)
{ {

View File

@ -1,13 +1,24 @@
#ifndef FLASH_H #ifndef FLASH_H
#define FLASH_H #define FLASH_H
#define FLASH_128K_SZ 0x20000
#ifdef __LIBRETRO__
extern void flashSaveGame(u8 *& data);
extern void flashReadGame(const u8 *& data, int);
#else
extern void flashSaveGame(gzFile _gzFile); extern void flashSaveGame(gzFile _gzFile);
extern void flashReadGame(gzFile _gzFile, int version); extern void flashReadGame(gzFile _gzFile, int version);
#endif
extern void flashReadGameSkip(gzFile _gzFile, int version); extern void flashReadGameSkip(gzFile _gzFile, int version);
extern u8 flashRead(u32 address); extern u8 flashRead(u32 address);
extern void flashWrite(u32 address, u8 byte); extern void flashWrite(u32 address, u8 byte);
extern void flashDelayedWrite(u32 address, u8 byte); extern void flashDelayedWrite(u32 address, u8 byte);
extern u8 flashSaveMemory[0x20000]; #ifdef __LIBRETRO__
extern uint8_t *flashSaveMemory;
#else
extern u8 flashSaveMemory[FLASH_128K_SZ];
#endif
extern void flashSaveDecide(u32 address, u8 byte); extern void flashSaveDecide(u32 address, u8 byte);
extern void flashReset(); extern void flashReset();
extern void flashSetSize(int size); extern void flashSetSize(int size);

View File

@ -297,7 +297,7 @@ static void count(u32 opcode, int cond_res)
#define EMIT0(op) #op"; " #define EMIT0(op) #op"; "
#define EMIT1(op,arg) #op" "arg"; " #define EMIT1(op,arg) #op" "arg"; "
#define EMIT2(op,src,dest) #op" "src", "dest"; " #define EMIT2(op,src,dest) #op" "src", "dest"; "
#define CONST(val) "$"#val #define KONST(val) "$"#val
#define ASMVAR(cvar) ASMVAR2 (__USER_LABEL_PREFIX__, cvar) #define ASMVAR(cvar) ASMVAR2 (__USER_LABEL_PREFIX__, cvar)
#define ASMVAR2(prefix,cvar) STRING (prefix) cvar #define ASMVAR2(prefix,cvar) STRING (prefix) cvar
#define STRING(x) #x #define STRING(x) #x
@ -330,7 +330,7 @@ static void count(u32 opcode, int cond_res)
#define EMIT0(op) __asm op #define EMIT0(op) __asm op
#define EMIT1(op,arg) __asm op arg #define EMIT1(op,arg) __asm op arg
#define EMIT2(op,src,dest) __asm op dest, src #define EMIT2(op,src,dest) __asm op dest, src
#define CONST(val) val #define KONST(val) val
#define VAR(var) var #define VAR(var) var
#define VARL(var) dword ptr var #define VARL(var) dword ptr var
#define REGREF1(index) reg[index] #define REGREF1(index) reg[index]
@ -349,15 +349,19 @@ static void count(u32 opcode, int cond_res)
// Helper macros for loading value / shift count // Helper macros for loading value / shift count
#define VALUE_LOAD_IMM \ #define VALUE_LOAD_IMM \
EMIT2(and, CONST(0x0F), eax) \ EMIT2(and, KONST(0x0F), eax) \
EMIT2(mov, REGREF2(eax,4), eax) \ EMIT2(mov, REGREF2(eax,4), eax) \
EMIT2(shr, CONST(7), ecx) \ EMIT2(shr, KONST(7), ecx) \
EMIT2(and, CONST(0x1F), ecx) EMIT2(and, KONST(0x1F), ecx)
#define VALUE_LOAD_REG \ #define VALUE_LOAD_REG \
EMIT2(and, CONST(0x0F), eax) \ EMIT2(and, KONST(0x0F), eax) \
EMIT2(mov, REGREF2(eax,4), eax) \ EMIT2(cmp, KONST(0x0F), eax) \
EMIT2(mov, REGREF2(eax,4), eax) \
EMIT1(jne, LABELREF(3,f)) \
EMIT2(add, KONST(4), eax) \
LABEL(3) \
EMIT2(movzx, ch, ecx) \ EMIT2(movzx, ch, ecx) \
EMIT2(and, CONST(0x0F), ecx) \ EMIT2(and, KONST(0x0F), ecx) \
EMIT2(mov, REGREF2(ecx,4), ecx) EMIT2(mov, REGREF2(ecx,4), ecx)
// Helper macros for setting flags // Helper macros for setting flags
@ -381,13 +385,13 @@ static void count(u32 opcode, int cond_res)
ALU_HEADER \ ALU_HEADER \
LOAD_C_FLAG \ LOAD_C_FLAG \
EMIT2(mov, ecx, edx) \ EMIT2(mov, ecx, edx) \
EMIT2(shr, CONST(14), edx) \ EMIT2(shr, KONST(14), edx) \
EMIT2(mov, ecx, eax) \ EMIT2(mov, ecx, eax) \
EMIT2(mov, ecx, esi) \ EMIT2(mov, ecx, esi) \
EMIT2(shr, CONST(10), esi) \ EMIT2(shr, KONST(10), esi) \
EMIT2(and, CONST(0x3C), edx) \ EMIT2(and, KONST(0x3C), edx) \
EMIT2(mov, REGREF1(edx), edx) \ EMIT2(mov, REGREF1(edx), edx) \
EMIT2(and, CONST(0x3C), esi) EMIT2(and, KONST(0x3C), esi)
#define LOAD_C_FLAG_YES EMIT2(mov, VAR(C_FLAG), bl) #define LOAD_C_FLAG_YES EMIT2(mov, VAR(C_FLAG), bl)
#define LOAD_C_FLAG_NO /*nothing*/ #define LOAD_C_FLAG_NO /*nothing*/
@ -415,14 +419,14 @@ static void count(u32 opcode, int cond_res)
VALUE_LOAD_REG \ VALUE_LOAD_REG \
EMIT2(test, cl, cl) \ EMIT2(test, cl, cl) \
EMIT1(jz, LABELREF(0,f)) \ EMIT1(jz, LABELREF(0,f)) \
EMIT2(cmp, CONST(0x20), cl) \ EMIT2(cmp, KONST(0x20), cl) \
EMIT1(je, LABELREF(1,f)) \ EMIT1(je, LABELREF(1,f)) \
EMIT1(ja, LABELREF(2,f)) \ EMIT1(ja, LABELREF(2,f)) \
EMIT2(shl, cl, eax) \ EMIT2(shl, cl, eax) \
EMIT1(setc, bl) \ EMIT1(setc, bl) \
EMIT1(jmp, LABELREF(0,f)) \ EMIT1(jmp, LABELREF(0,f)) \
LABEL(1) \ LABEL(1) \
EMIT2(test, CONST(1), al) \ EMIT2(test, KONST(1), al) \
EMIT1(setnz, bl) \ EMIT1(setnz, bl) \
EMIT2(xor, eax, eax) \ EMIT2(xor, eax, eax) \
EMIT1(jmp, LABELREF(0,f)) \ EMIT1(jmp, LABELREF(0,f)) \
@ -432,7 +436,7 @@ static void count(u32 opcode, int cond_res)
LABEL(0) LABEL(0)
#define VALUE_LSL_REG_NC \ #define VALUE_LSL_REG_NC \
VALUE_LOAD_REG \ VALUE_LOAD_REG \
EMIT2(cmp, CONST(0x20), cl) \ EMIT2(cmp, KONST(0x20), cl) \
EMIT1(jae, LABELREF(1,f)) \ EMIT1(jae, LABELREF(1,f)) \
EMIT2(shl, cl, eax) \ EMIT2(shl, cl, eax) \
EMIT1(jmp, LABELREF(0,f)) \ EMIT1(jmp, LABELREF(0,f)) \
@ -466,7 +470,7 @@ static void count(u32 opcode, int cond_res)
VALUE_LOAD_REG \ VALUE_LOAD_REG \
EMIT2(test, cl, cl) \ EMIT2(test, cl, cl) \
EMIT1(jz, LABELREF(0,f)) \ EMIT1(jz, LABELREF(0,f)) \
EMIT2(cmp, CONST(0x20), cl) \ EMIT2(cmp, KONST(0x20), cl) \
EMIT1(je, LABELREF(1,f)) \ EMIT1(je, LABELREF(1,f)) \
EMIT1(ja, LABELREF(2,f)) \ EMIT1(ja, LABELREF(2,f)) \
EMIT2(shr, cl, eax) \ EMIT2(shr, cl, eax) \
@ -483,7 +487,7 @@ static void count(u32 opcode, int cond_res)
LABEL(0) LABEL(0)
#define VALUE_LSR_REG_NC \ #define VALUE_LSR_REG_NC \
VALUE_LOAD_REG \ VALUE_LOAD_REG \
EMIT2(cmp, CONST(0x20), cl) \ EMIT2(cmp, KONST(0x20), cl) \
EMIT1(jae, LABELREF(1,f)) \ EMIT1(jae, LABELREF(1,f)) \
EMIT2(shr, cl, eax) \ EMIT2(shr, cl, eax) \
EMIT1(jmp, LABELREF(0,f)) \ EMIT1(jmp, LABELREF(0,f)) \
@ -499,7 +503,7 @@ static void count(u32 opcode, int cond_res)
EMIT1(setc, bl) \ EMIT1(setc, bl) \
EMIT1(jmp, LABELREF(0,f)) \ EMIT1(jmp, LABELREF(0,f)) \
LABEL(1) \ LABEL(1) \
EMIT2(sar, CONST(31), eax) \ EMIT2(sar, KONST(31), eax) \
EMIT1(sets, bl) \ EMIT1(sets, bl) \
LABEL(0) LABEL(0)
#define VALUE_ASR_IMM_NC \ #define VALUE_ASR_IMM_NC \
@ -508,7 +512,7 @@ static void count(u32 opcode, int cond_res)
EMIT2(sar, cl, eax) \ EMIT2(sar, cl, eax) \
EMIT1(jmp, LABELREF(0,f)) \ EMIT1(jmp, LABELREF(0,f)) \
LABEL(1) \ LABEL(1) \
EMIT2(sar, CONST(31), eax) \ EMIT2(sar, KONST(31), eax) \
LABEL(0) LABEL(0)
// OP Rd,Rb,Rm ASR Rs // OP Rd,Rb,Rm ASR Rs
@ -516,23 +520,23 @@ static void count(u32 opcode, int cond_res)
VALUE_LOAD_REG \ VALUE_LOAD_REG \
EMIT2(test, cl, cl) \ EMIT2(test, cl, cl) \
EMIT1(jz, LABELREF(0,f)) \ EMIT1(jz, LABELREF(0,f)) \
EMIT2(cmp, CONST(0x20), cl) \ EMIT2(cmp, KONST(0x20), cl) \
EMIT1(jae, LABELREF(1,f)) \ EMIT1(jae, LABELREF(1,f)) \
EMIT2(sar, cl, eax) \ EMIT2(sar, cl, eax) \
EMIT1(setc, bl) \ EMIT1(setc, bl) \
EMIT1(jmp, LABELREF(0,f)) \ EMIT1(jmp, LABELREF(0,f)) \
LABEL(1) \ LABEL(1) \
EMIT2(sar, CONST(31), eax) \ EMIT2(sar, KONST(31), eax) \
EMIT1(sets, bl) \ EMIT1(sets, bl) \
LABEL(0) LABEL(0)
#define VALUE_ASR_REG_NC \ #define VALUE_ASR_REG_NC \
VALUE_LOAD_REG \ VALUE_LOAD_REG \
EMIT2(cmp, CONST(0x20), cl) \ EMIT2(cmp, KONST(0x20), cl) \
EMIT1(jae, LABELREF(1,f)) \ EMIT1(jae, LABELREF(1,f)) \
EMIT2(sar, cl, eax) \ EMIT2(sar, cl, eax) \
EMIT1(jmp, LABELREF(0,f)) \ EMIT1(jmp, LABELREF(0,f)) \
LABEL(1) \ LABEL(1) \
EMIT2(sar, CONST(31), eax) \ EMIT2(sar, KONST(31), eax) \
LABEL(0) LABEL(0)
// OP Rd,Rb,Rm ROR # // OP Rd,Rb,Rm ROR #
@ -542,8 +546,8 @@ static void count(u32 opcode, int cond_res)
EMIT2(ror, cl, eax) \ EMIT2(ror, cl, eax) \
EMIT1(jmp, LABELREF(0,f)) \ EMIT1(jmp, LABELREF(0,f)) \
LABEL(1) \ LABEL(1) \
EMIT2(bt, CONST(0), ebx) \ EMIT2(bt, KONST(0), ebx) \
EMIT2(rcr, CONST(1), eax) \ EMIT2(rcr, KONST(1), eax) \
LABEL(0) \ LABEL(0) \
EMIT1(setc, bl) EMIT1(setc, bl)
#define VALUE_ROR_IMM_NC \ #define VALUE_ROR_IMM_NC \
@ -552,14 +556,14 @@ static void count(u32 opcode, int cond_res)
EMIT2(ror, cl, eax) \ EMIT2(ror, cl, eax) \
EMIT1(jmp, LABELREF(0,f)) \ EMIT1(jmp, LABELREF(0,f)) \
LABEL(1) \ LABEL(1) \
EMIT2(bt, CONST(0), VARL(C_FLAG)) \ EMIT2(bt, KONST(0), VARL(C_FLAG)) \
EMIT2(rcr, CONST(1), eax) \ EMIT2(rcr, KONST(1), eax) \
LABEL(0) LABEL(0)
// OP Rd,Rb,Rm ROR Rs // OP Rd,Rb,Rm ROR Rs
#define VALUE_ROR_REG_C \ #define VALUE_ROR_REG_C \
VALUE_LOAD_REG \ VALUE_LOAD_REG \
EMIT2(bt, CONST(0), ebx) \ EMIT2(bt, KONST(0), ebx) \
EMIT2(ror, cl, eax) \ EMIT2(ror, cl, eax) \
EMIT1(setc, bl) EMIT1(setc, bl)
#define VALUE_ROR_REG_NC \ #define VALUE_ROR_REG_NC \
@ -571,7 +575,7 @@ static void count(u32 opcode, int cond_res)
EMIT2(movzx, ch, ecx) \ EMIT2(movzx, ch, ecx) \
EMIT2(add, ecx, ecx) \ EMIT2(add, ecx, ecx) \
EMIT2(movzx, al, eax) \ EMIT2(movzx, al, eax) \
EMIT2(bt, CONST(0), ebx) \ EMIT2(bt, KONST(0), ebx) \
EMIT2(ror, cl, eax) \ EMIT2(ror, cl, eax) \
EMIT1(setc, bl) EMIT1(setc, bl)
#define VALUE_IMM_NC \ #define VALUE_IMM_NC \
@ -584,7 +588,7 @@ static void count(u32 opcode, int cond_res)
// Set condition codes iff the destination register is not R15 (PC) // Set condition codes iff the destination register is not R15 (PC)
#define CHECK_PC(OP, SETCOND) \ #define CHECK_PC(OP, SETCOND) \
EMIT2(cmp, CONST(0x3C), esi) \ EMIT2(cmp, KONST(0x3C), esi) \
EMIT1(je, LABELREF(8,f)) \ EMIT1(je, LABELREF(8,f)) \
OP SETCOND \ OP SETCOND \
EMIT1(jmp, LABELREF(9,f)) \ EMIT1(jmp, LABELREF(9,f)) \
@ -613,18 +617,18 @@ static void count(u32 opcode, int cond_res)
EMIT2(mov, edx, REGREF1(esi)) EMIT2(mov, edx, REGREF1(esi))
#define OP_ADDS CHECK_PC(OP_ADD, SETCOND_ADD) #define OP_ADDS CHECK_PC(OP_ADD, SETCOND_ADD)
#define OP_ADC \ #define OP_ADC \
EMIT2(bt, CONST(0), VARL(C_FLAG)) \ EMIT2(bt, KONST(0), VARL(C_FLAG)) \
EMIT2(adc, eax, edx) \ EMIT2(adc, eax, edx) \
EMIT2(mov, edx, REGREF1(esi)) EMIT2(mov, edx, REGREF1(esi))
#define OP_ADCS CHECK_PC(OP_ADC, SETCOND_ADD) #define OP_ADCS CHECK_PC(OP_ADC, SETCOND_ADD)
#define OP_SBC \ #define OP_SBC \
EMIT2(bt, CONST(0), VARL(C_FLAG)) \ EMIT2(bt, KONST(0), VARL(C_FLAG)) \
EMIT0(cmc) \ EMIT0(cmc) \
EMIT2(sbb, eax, edx) \ EMIT2(sbb, eax, edx) \
EMIT2(mov, edx, REGREF1(esi)) EMIT2(mov, edx, REGREF1(esi))
#define OP_SBCS CHECK_PC(OP_SBC, SETCOND_SUB) #define OP_SBCS CHECK_PC(OP_SBC, SETCOND_SUB)
#define OP_RSC \ #define OP_RSC \
EMIT2(bt, CONST(0), VARL(C_FLAG)) \ EMIT2(bt, KONST(0), VARL(C_FLAG)) \
EMIT0(cmc) \ EMIT0(cmc) \
EMIT2(sbb, edx, eax) \ EMIT2(sbb, edx, eax) \
EMIT2(mov, eax, REGREF1(esi)) EMIT2(mov, eax, REGREF1(esi))
@ -656,7 +660,7 @@ static void count(u32 opcode, int cond_res)
#define OP_MVN \ #define OP_MVN \
EMIT1(not, eax) \ EMIT1(not, eax) \
EMIT2(mov, eax, REGREF1(esi)) EMIT2(mov, eax, REGREF1(esi))
#define OP_MVNS CHECK_PC(OP_MVN, SETCOND_LOGICAL) #define OP_MVNS CHECK_PC(OP_MVN EMIT2(test,eax,eax), SETCOND_LOGICAL)
// ALU cleanup macro // ALU cleanup macro
#define ALU_FINISH ALU_TRAILER #define ALU_FINISH ALU_TRAILER
@ -677,7 +681,7 @@ static void count(u32 opcode, int cond_res)
: "0" (offset), "c" (shift)); : "0" (offset), "c" (shift));
#define RRX_OFFSET \ #define RRX_OFFSET \
asm(EMIT2(btl,CONST(0),VAR(C_FLAG)) \ asm(EMIT2(btl,KONST(0),VAR(C_FLAG)) \
"rcr $1, %0" \ "rcr $1, %0" \
: "=r" (offset) \ : "=r" (offset) \
: "0" (offset)); : "0" (offset));
@ -752,27 +756,31 @@ static void count(u32 opcode, int cond_res)
// OP Rd,Rb,Rm LSL Rs // OP Rd,Rb,Rm LSL Rs
#ifndef VALUE_LSL_REG_C #ifndef VALUE_LSL_REG_C
#define VALUE_LSL_REG_C \ #define VALUE_LSL_REG_C \
unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ u32 shift = reg[(opcode >> 8)&15].B.B0; \
if (LIKELY(shift)) { \ u32 rm = reg[opcode & 0x0F].I; \
if (shift == 32) { \ if((opcode & 0x0F) == 15) { \
value = 0; \ rm += 4; \
C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false);\ } \
} else if (LIKELY(shift < 32)) { \ if (LIKELY(shift)) { \
u32 v = reg[opcode & 0x0F].I; \ if (shift == 32) { \
C_OUT = (v >> (32 - shift)) & 1 ? true : false;\ value = 0; \
value = v << shift; \ C_OUT = (rm & 1 ? true : false); \
} else { \ } else if (LIKELY(shift < 32)) { \
value = 0; \ u32 v = rm; \
C_OUT = false; \ C_OUT = (v >> (32 - shift)) & 1 ? true : false; \
} \ value = v << shift; \
} else { \ } else { \
value = reg[opcode & 0x0F].I; \ value = 0; \
C_OUT = false; \
} \
} else { \
value = rm; \
} }
#endif #endif
// OP Rd,Rb,Rm LSR # // OP Rd,Rb,Rm LSR #
#ifndef VALUE_LSR_IMM_C #ifndef VALUE_LSR_IMM_C
#define VALUE_LSR_IMM_C \ #define VALUE_LSR_IMM_C \
unsigned int shift = (opcode >> 7) & 0x1F; \ u32 shift = (opcode >> 7) & 0x1F; \
if (LIKELY(shift)) { \ if (LIKELY(shift)) { \
u32 v = reg[opcode & 0x0F].I; \ u32 v = reg[opcode & 0x0F].I; \
C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
@ -786,12 +794,16 @@ static void count(u32 opcode, int cond_res)
#ifndef VALUE_LSR_REG_C #ifndef VALUE_LSR_REG_C
#define VALUE_LSR_REG_C \ #define VALUE_LSR_REG_C \
unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
u32 rm = reg[opcode & 0x0F].I; \
if((opcode & 0x0F) == 15) { \
rm += 4; \
} \
if (LIKELY(shift)) { \ if (LIKELY(shift)) { \
if (shift == 32) { \ if (shift == 32) { \
value = 0; \ value = 0; \
C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false);\ C_OUT = (rm & 0x80000000 ? true : false);\
} else if (LIKELY(shift < 32)) { \ } else if (LIKELY(shift < 32)) { \
u32 v = reg[opcode & 0x0F].I; \ u32 v = rm; \
C_OUT = (v >> (shift - 1)) & 1 ? true : false;\ C_OUT = (v >> (shift - 1)) & 1 ? true : false;\
value = v >> shift; \ value = v >> shift; \
} else { \ } else { \
@ -799,7 +811,7 @@ static void count(u32 opcode, int cond_res)
C_OUT = false; \ C_OUT = false; \
} \ } \
} else { \ } else { \
value = reg[opcode & 0x0F].I; \ value = rm; \
} }
#endif #endif
// OP Rd,Rb,Rm ASR # // OP Rd,Rb,Rm ASR #
@ -825,13 +837,17 @@ static void count(u32 opcode, int cond_res)
#ifndef VALUE_ASR_REG_C #ifndef VALUE_ASR_REG_C
#define VALUE_ASR_REG_C \ #define VALUE_ASR_REG_C \
unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
u32 rm = reg[opcode & 0x0F].I; \
if((opcode & 0x0F) == 15) { \
rm += 4; \
} \
if (LIKELY(shift < 32)) { \ if (LIKELY(shift < 32)) { \
if (LIKELY(shift)) { \ if (LIKELY(shift)) { \
s32 v = reg[opcode & 0x0F].I; \ s32 v = rm; \
C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\ C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\
value = v >> (int)shift; \ value = v >> (int)shift; \
} else { \ } else { \
value = reg[opcode & 0x0F].I; \ value = rm; \
} \ } \
} else { \ } else { \
if (reg[opcode & 0x0F].I & 0x80000000) { \ if (reg[opcode & 0x0F].I & 0x80000000) { \
@ -863,13 +879,17 @@ static void count(u32 opcode, int cond_res)
#ifndef VALUE_ROR_REG_C #ifndef VALUE_ROR_REG_C
#define VALUE_ROR_REG_C \ #define VALUE_ROR_REG_C \
unsigned int shift = reg[(opcode >> 8)&15].B.B0; \ unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
u32 rm = reg[opcode & 0x0F].I; \
if((opcode & 0x0F) == 15) { \
rm += 4; \
} \
if (LIKELY(shift & 0x1F)) { \ if (LIKELY(shift & 0x1F)) { \
u32 v = reg[opcode & 0x0F].I; \ u32 v = rm; \
C_OUT = (v >> (shift - 1)) & 1 ? true : false; \ C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
value = ((v << (32 - shift)) | \ value = ((v << (32 - shift)) | \
(v >> shift)); \ (v >> shift)); \
} else { \ } else { \
value = reg[opcode & 0x0F].I; \ value = rm; \
if (shift) \ if (shift) \
C_OUT = (value & 0x80000000 ? true : false);\ C_OUT = (value & 0x80000000 ? true : false);\
} }
@ -950,9 +970,9 @@ static void count(u32 opcode, int cond_res)
#endif #endif
#ifndef OP_RSB #ifndef OP_RSB
#define OP_RSB \ #define OP_RSB \
u32 lhs = reg[(opcode>>16)&15].I; \ u32 lhs = value; \
u32 rhs = value; \ u32 rhs = reg[(opcode>>16)&15].I; \
u32 res = rhs - lhs; \ u32 res = lhs - rhs; \
reg[dest].I = res; reg[dest].I = res;
#endif #endif
#ifndef OP_RSBS #ifndef OP_RSBS
@ -990,9 +1010,9 @@ static void count(u32 opcode, int cond_res)
#endif #endif
#ifndef OP_RSC #ifndef OP_RSC
#define OP_RSC \ #define OP_RSC \
u32 lhs = reg[(opcode>>16)&15].I; \ u32 lhs = value; \
u32 rhs = value; \ u32 rhs = reg[(opcode>>16)&15].I; \
u32 res = rhs - lhs - !((u32)C_FLAG); \ u32 res = lhs - rhs - !((u32)C_FLAG); \
reg[dest].I = res; reg[dest].I = res;
#endif #endif
#ifndef OP_RSCS #ifndef OP_RSCS
@ -1516,7 +1536,7 @@ static INSN_REGPARM void arm121(u32 opcode)
#define OP_LDR reg[dest].I = CPUReadMemory(address) #define OP_LDR reg[dest].I = CPUReadMemory(address)
#define OP_LDRH reg[dest].I = CPUReadHalfWord(address) #define OP_LDRH reg[dest].I = CPUReadHalfWord(address)
#define OP_LDRB reg[dest].I = CPUReadByte(address) #define OP_LDRB reg[dest].I = CPUReadByte(address)
#define OP_LDRSH reg[dest].I = (s16)CPUReadHalfWordSigned(address) #define OP_LDRSH reg[dest].I = (u32)CPUReadHalfWordSigned(address)
#define OP_LDRSB reg[dest].I = (s8)CPUReadByte(address) #define OP_LDRSB reg[dest].I = (s8)CPUReadByte(address)
#define WRITEBACK_NONE /*nothing*/ #define WRITEBACK_NONE /*nothing*/
@ -2591,8 +2611,7 @@ static INSN_REGPARM void armA00(u32 opcode)
reg[15].I += 4; reg[15].I += 4;
ARM_PREFETCH; ARM_PREFETCH;
clockTicks = codeTicksAccessSeq32(armNextPC) + 1; clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
clockTicks += 2 + codeTicksAccess32(armNextPC) clockTicks = (clockTicks * 2) + codeTicksAccess32(armNextPC) + 1;
+ codeTicksAccessSeq32(armNextPC);
busPrefetchCount = 0; busPrefetchCount = 0;
} }
@ -2608,8 +2627,7 @@ static INSN_REGPARM void armB00(u32 opcode)
reg[15].I += 4; reg[15].I += 4;
ARM_PREFETCH; ARM_PREFETCH;
clockTicks = codeTicksAccessSeq32(armNextPC) + 1; clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
clockTicks += 2 + codeTicksAccess32(armNextPC) clockTicks = (clockTicks * 2) + codeTicksAccess32(armNextPC) + 1;
+ codeTicksAccessSeq32(armNextPC);
busPrefetchCount = 0; busPrefetchCount = 0;
} }
@ -2627,9 +2645,8 @@ static INSN_REGPARM void armE01(u32 opcode)
// SWI <comment> // SWI <comment>
static INSN_REGPARM void armF00(u32 opcode) static INSN_REGPARM void armF00(u32 opcode)
{ {
clockTicks = codeTicksAccessSeq32(armNextPC) + 1; clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
clockTicks += 2 + codeTicksAccess32(armNextPC) clockTicks = (clockTicks * 2) + codeTicksAccess32(armNextPC) + 1;
+ codeTicksAccessSeq32(armNextPC);
busPrefetchCount = 0; busPrefetchCount = 0;
CPUSoftwareInterrupt(opcode & 0x00FFFFFF); CPUSoftwareInterrupt(opcode & 0x00FFFFFF);
} }
@ -2681,9 +2698,9 @@ static insnfunc_t armInsnTable[4096] = {
arm0D0,arm0D1,arm0D2,arm0D3,arm0D4,arm0D5,arm0D6,arm0D7, // 0D0 arm0D0,arm0D1,arm0D2,arm0D3,arm0D4,arm0D5,arm0D6,arm0D7, // 0D0
arm0D0,arm0D9,arm0D2,arm0DB,arm0D4,arm0DD,arm0D6,arm0DF, // 0D8 arm0D0,arm0D9,arm0D2,arm0DB,arm0D4,arm0DD,arm0D6,arm0DF, // 0D8
arm0E0,arm0E1,arm0E2,arm0E3,arm0E4,arm0E5,arm0E6,arm0E7, // 0E0 arm0E0,arm0E1,arm0E2,arm0E3,arm0E4,arm0E5,arm0E6,arm0E7, // 0E0
arm0E0,arm0E9,arm0E2,arm_UI,arm0E4,arm_UI,arm0E6,arm_UI, // 0E8 arm0E0,arm0E9,arm0E2,arm0CB,arm0E4,arm_UI,arm0E6,arm_UI, // 0E8
arm0F0,arm0F1,arm0F2,arm0F3,arm0F4,arm0F5,arm0F6,arm0F7, // 0F0 arm0F0,arm0F1,arm0F2,arm0F3,arm0F4,arm0F5,arm0F6,arm0F7, // 0F0
arm0F0,arm0F9,arm0F2,arm_UI,arm0F4,arm0DD,arm0F6,arm0DF, // 0F8 arm0F0,arm0F9,arm0F2,arm0DB,arm0F4,arm0DD,arm0F6,arm0DF, // 0F8
arm100,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 100 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 arm_UI,arm109,arm_UI,arm10B,arm_UI,arm_UI,arm_UI,arm_UI, // 108

View File

@ -300,7 +300,7 @@ static INSN_REGPARM void thumbBreakpoint(u32 opcode)
#else #else
#define EMIT1(op,arg) #op" "arg"; " #define EMIT1(op,arg) #op" "arg"; "
#define EMIT2(op,src,dest) #op" "src", "dest"; " #define EMIT2(op,src,dest) #op" "src", "dest"; "
#define CONST(val) "$"#val #define KONST(val) "$"#val
#define ASMVAR(cvar) ASMVAR2 (__USER_LABEL_PREFIX__, cvar) #define ASMVAR(cvar) ASMVAR2 (__USER_LABEL_PREFIX__, cvar)
#define ASMVAR2(prefix,cvar) STRING (prefix) cvar #define ASMVAR2(prefix,cvar) STRING (prefix) cvar
#define STRING(x) #x #define STRING(x) #x
@ -327,7 +327,7 @@ static INSN_REGPARM void thumbBreakpoint(u32 opcode)
: \ : \
: "r" (value), "r" (reg[dest].I):"1"); : "r" (value), "r" (reg[dest].I):"1");
#define ADC_RD_RS \ #define ADC_RD_RS \
asm (EMIT2(bt,CONST(0),VAR(C_FLAG)) \ asm (EMIT2(bt,KONST(0),VAR(C_FLAG)) \
"adc %1, %%ebx;"\ "adc %1, %%ebx;"\
EMIT1(setsb, VAR(N_FLAG)) \ EMIT1(setsb, VAR(N_FLAG)) \
EMIT1(setzb, VAR(Z_FLAG)) \ EMIT1(setzb, VAR(Z_FLAG)) \
@ -345,7 +345,7 @@ static INSN_REGPARM void thumbBreakpoint(u32 opcode)
: "=m" (reg[(d)].I)); : "=m" (reg[(d)].I));
#define MOV_RN_O8(d) \ #define MOV_RN_O8(d) \
asm ("andl $0xFF, %%eax;"\ asm ("andl $0xFF, %%eax;"\
EMIT2(movb,CONST(0),VAR(N_FLAG)) \ EMIT2(movb,KONST(0),VAR(N_FLAG)) \
"movl %%eax, %0;"\ "movl %%eax, %0;"\
EMIT1(setzb, VAR(Z_FLAG)) \ EMIT1(setzb, VAR(Z_FLAG)) \
: "=m" (reg[(d)].I)); : "=m" (reg[(d)].I));
@ -359,7 +359,7 @@ static INSN_REGPARM void thumbBreakpoint(u32 opcode)
: \ : \
: "m" (reg[(d)].I)); : "m" (reg[(d)].I));
#define SBC_RD_RS \ #define SBC_RD_RS \
asm volatile (EMIT2(bt,CONST(0),VAR(C_FLAG)) \ asm volatile (EMIT2(bt,KONST(0),VAR(C_FLAG)) \
"cmc;"\ "cmc;"\
"sbb %1, %%ebx;"\ "sbb %1, %%ebx;"\
EMIT1(setsb, VAR(N_FLAG)) \ EMIT1(setsb, VAR(N_FLAG)) \
@ -464,9 +464,9 @@ static INSN_REGPARM void thumbBreakpoint(u32 opcode)
EMIT1(setcb, VAR(C_FLAG)) \ EMIT1(setcb, VAR(C_FLAG)) \
EMIT1(setob, VAR(V_FLAG)) EMIT1(setob, VAR(V_FLAG))
#define ADD_RD_RS_O3_0(N) \ #define ADD_RD_RS_O3_0(N) \
EMIT2(movb,CONST(0),VAR(C_FLAG)) \ EMIT2(movb,KONST(0),VAR(C_FLAG)) \
"add $0,%%ecx;" \ "add $0,%%ecx;" \
EMIT2(movb,CONST(0),VAR(V_FLAG)) EMIT2(movb,KONST(0),VAR(V_FLAG))
#define SUB_RD_RS_RN(N) \ #define SUB_RD_RS_RN(N) \
EMIT2(sub,VAR(reg)"+"#N"*4",ecx) \ EMIT2(sub,VAR(reg)"+"#N"*4",ecx) \
EMIT1(setncb, VAR(C_FLAG)) \ EMIT1(setncb, VAR(C_FLAG)) \
@ -476,9 +476,9 @@ static INSN_REGPARM void thumbBreakpoint(u32 opcode)
EMIT1(setncb, VAR(C_FLAG)) \ EMIT1(setncb, VAR(C_FLAG)) \
EMIT1(setob, VAR(V_FLAG)) EMIT1(setob, VAR(V_FLAG))
#define SUB_RD_RS_O3_0(N) \ #define SUB_RD_RS_O3_0(N) \
EMIT2(movb,CONST(1),VAR(C_FLAG)) \ EMIT2(movb,KONST(1),VAR(C_FLAG)) \
"sub $0,%%ecx;" \ "sub $0,%%ecx;" \
EMIT2(movb,CONST(0),VAR(V_FLAG)) EMIT2(movb,KONST(0),VAR(V_FLAG))
#endif #endif
#else // !__GNUC__ #else // !__GNUC__
#define ADD_RD_RS_RN(N) \ #define ADD_RD_RS_RN(N) \
@ -1416,10 +1416,18 @@ static INSN_REGPARM void thumb45_3(u32 opcode)
CMP_RD_RS; CMP_RD_RS;
} }
// MOV Rd, Rs
static INSN_REGPARM void thumb46_0(u32 opcode)
{
reg[opcode&7].I = reg[((opcode>>3)&7)].I;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
}
// MOV Rd, Hs // MOV Rd, Hs
static INSN_REGPARM void thumb46_1(u32 opcode) static INSN_REGPARM void thumb46_1(u32 opcode)
{ {
reg[opcode&7].I = reg[((opcode>>3)&7)+8].I; reg[opcode&7].I = reg[((opcode>>3)&7)+8].I;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
} }
// MOV Hd, Rs // MOV Hd, Rs
@ -1466,16 +1474,14 @@ static INSN_REGPARM void thumb47(u32 opcode)
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) clockTicks = codeTicksAccessSeq16(armNextPC)*2 + codeTicksAccess16(armNextPC) + 3;
+ codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 3;
} else { } else {
armState = true; armState = true;
reg[15].I &= 0xFFFFFFFC; reg[15].I &= 0xFFFFFFFC;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 4; reg[15].I += 4;
ARM_PREFETCH; ARM_PREFETCH;
clockTicks = codeTicksAccessSeq32(armNextPC) clockTicks = codeTicksAccessSeq32(armNextPC)*2 + codeTicksAccess32(armNextPC) + 3;
+ codeTicksAccessSeq32(armNextPC) + codeTicksAccess32(armNextPC) + 3;
} }
} }
@ -1569,7 +1575,7 @@ static INSN_REGPARM void thumb5E(u32 opcode)
if (busPrefetchCount == 0) if (busPrefetchCount == 0)
busPrefetch = busPrefetchEnable; busPrefetch = busPrefetchEnable;
u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I; u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
reg[opcode&7].I = (s16)CPUReadHalfWordSigned(address); reg[opcode&7].I = (u32)CPUReadHalfWordSigned(address);
clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC); clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC);
} }
@ -1662,6 +1668,7 @@ static INSN_REGPARM void thumbA0(u32 opcode)
{ {
u8 regist = (opcode >> 8) & 7; u8 regist = (opcode >> 8) & 7;
reg[regist].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2); reg[regist].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2);
clockTicks = 1 + codeTicksAccess16(armNextPC);
} }
// ADD R0~R7, SP, Imm // ADD R0~R7, SP, Imm
@ -1669,6 +1676,7 @@ static INSN_REGPARM void thumbA8(u32 opcode)
{ {
u8 regist = (opcode >> 8) & 7; u8 regist = (opcode >> 8) & 7;
reg[regist].I = reg[13].I + ((opcode&255)<<2); reg[regist].I = reg[13].I + ((opcode&255)<<2);
clockTicks = 1 + codeTicksAccess16(armNextPC);
} }
// ADD SP, Imm // ADD SP, Imm
@ -1678,6 +1686,7 @@ static INSN_REGPARM void thumbB0(u32 opcode)
if(opcode & 0x80) if(opcode & 0x80)
offset = -offset; offset = -offset;
reg[13].I += offset; reg[13].I += offset;
clockTicks = 1 + codeTicksAccess16(armNextPC);
} }
// Push and pop /////////////////////////////////////////////////////////// // Push and pop ///////////////////////////////////////////////////////////
@ -1875,13 +1884,13 @@ static INSN_REGPARM void thumbC8(u32 opcode)
static INSN_REGPARM void thumbD0(u32 opcode) static INSN_REGPARM void thumbD0(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(Z_FLAG) { if(Z_FLAG) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -1890,13 +1899,13 @@ static INSN_REGPARM void thumbD0(u32 opcode)
static INSN_REGPARM void thumbD1(u32 opcode) static INSN_REGPARM void thumbD1(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(!Z_FLAG) { if(!Z_FLAG) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -1905,13 +1914,13 @@ static INSN_REGPARM void thumbD1(u32 opcode)
static INSN_REGPARM void thumbD2(u32 opcode) static INSN_REGPARM void thumbD2(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(C_FLAG) { if(C_FLAG) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -1920,13 +1929,13 @@ static INSN_REGPARM void thumbD2(u32 opcode)
static INSN_REGPARM void thumbD3(u32 opcode) static INSN_REGPARM void thumbD3(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(!C_FLAG) { if(!C_FLAG) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -1935,13 +1944,13 @@ static INSN_REGPARM void thumbD3(u32 opcode)
static INSN_REGPARM void thumbD4(u32 opcode) static INSN_REGPARM void thumbD4(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(N_FLAG) { if(N_FLAG) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -1950,13 +1959,13 @@ static INSN_REGPARM void thumbD4(u32 opcode)
static INSN_REGPARM void thumbD5(u32 opcode) static INSN_REGPARM void thumbD5(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(!N_FLAG) { if(!N_FLAG) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -1965,13 +1974,13 @@ static INSN_REGPARM void thumbD5(u32 opcode)
static INSN_REGPARM void thumbD6(u32 opcode) static INSN_REGPARM void thumbD6(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(V_FLAG) { if(V_FLAG) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -1980,13 +1989,13 @@ static INSN_REGPARM void thumbD6(u32 opcode)
static INSN_REGPARM void thumbD7(u32 opcode) static INSN_REGPARM void thumbD7(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(!V_FLAG) { if(!V_FLAG) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -1995,13 +2004,13 @@ static INSN_REGPARM void thumbD7(u32 opcode)
static INSN_REGPARM void thumbD8(u32 opcode) static INSN_REGPARM void thumbD8(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(C_FLAG && !Z_FLAG) { if(C_FLAG && !Z_FLAG) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -2010,13 +2019,13 @@ static INSN_REGPARM void thumbD8(u32 opcode)
static INSN_REGPARM void thumbD9(u32 opcode) static INSN_REGPARM void thumbD9(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(!C_FLAG || Z_FLAG) { if(!C_FLAG || Z_FLAG) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -2025,13 +2034,13 @@ static INSN_REGPARM void thumbD9(u32 opcode)
static INSN_REGPARM void thumbDA(u32 opcode) static INSN_REGPARM void thumbDA(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(N_FLAG == V_FLAG) { if(N_FLAG == V_FLAG) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -2040,13 +2049,13 @@ static INSN_REGPARM void thumbDA(u32 opcode)
static INSN_REGPARM void thumbDB(u32 opcode) static INSN_REGPARM void thumbDB(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(N_FLAG != V_FLAG) { if(N_FLAG != V_FLAG) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -2055,13 +2064,13 @@ static INSN_REGPARM void thumbDB(u32 opcode)
static INSN_REGPARM void thumbDC(u32 opcode) static INSN_REGPARM void thumbDC(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
if(!Z_FLAG && (N_FLAG == V_FLAG)) { if(!Z_FLAG && (N_FLAG == V_FLAG)) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -2070,13 +2079,13 @@ static INSN_REGPARM void thumbDC(u32 opcode)
static INSN_REGPARM void thumbDD(u32 opcode) static INSN_REGPARM void thumbDD(u32 opcode)
{ {
UPDATE_OLDREG; UPDATE_OLDREG;
clockTicks = codeTicksAccessSeq16(armNextPC);
if(Z_FLAG || (N_FLAG != V_FLAG)) { if(Z_FLAG || (N_FLAG != V_FLAG)) {
reg[15].I += ((s8)(opcode & 0xFF)) << 1; reg[15].I += ((s8)(opcode & 0xFF)) << 1;
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
codeTicksAccess16(armNextPC)+3;
busPrefetchCount=0; busPrefetchCount=0;
} }
} }
@ -2087,8 +2096,8 @@ static INSN_REGPARM void thumbDD(u32 opcode)
static INSN_REGPARM void thumbDF(u32 opcode) static INSN_REGPARM void thumbDF(u32 opcode)
{ {
u32 address = 0; u32 address = 0;
clockTicks = codeTicksAccessSeq16(address) + codeTicksAccessSeq16(address) + //clockTicks = codeTicksAccessSeq16(address)*2 + codeTicksAccess16(address)+3;
codeTicksAccess16(address)+3; clockTicks = 3;
busPrefetchCount=0; busPrefetchCount=0;
CPUSoftwareInterrupt(opcode & 0xFF); CPUSoftwareInterrupt(opcode & 0xFF);
} }
@ -2103,8 +2112,7 @@ static INSN_REGPARM void thumbE0(u32 opcode)
armNextPC = reg[15].I; armNextPC = reg[15].I;
reg[15].I += 2; reg[15].I += 2;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) + clockTicks = codeTicksAccessSeq16(armNextPC)*2 + codeTicksAccess16(armNextPC)+3;
codeTicksAccess16(armNextPC) + 3;
busPrefetchCount=0; busPrefetchCount=0;
} }
@ -2134,8 +2142,7 @@ static INSN_REGPARM void thumbF8(u32 opcode)
reg[15].I += 2; reg[15].I += 2;
reg[14].I = temp|1; reg[14].I = temp|1;
THUMB_PREFETCH; THUMB_PREFETCH;
clockTicks = codeTicksAccessSeq16(armNextPC) + clockTicks = codeTicksAccessSeq16(armNextPC)*2 + codeTicksAccess16(armNextPC) + 3;
codeTicksAccess16(armNextPC) + codeTicksAccessSeq16(armNextPC) + 3;
busPrefetchCount = 0; busPrefetchCount = 0;
} }
@ -2184,7 +2191,7 @@ static insnfunc_t thumbInsnTable[1024] = {
thumb40_0,thumb40_1,thumb40_2,thumb40_3,thumb41_0,thumb41_1,thumb41_2,thumb41_3, // 40 thumb40_0,thumb40_1,thumb40_2,thumb40_3,thumb41_0,thumb41_1,thumb41_2,thumb41_3, // 40
thumb42_0,thumb42_1,thumb42_2,thumb42_3,thumb43_0,thumb43_1,thumb43_2,thumb43_3, thumb42_0,thumb42_1,thumb42_2,thumb42_3,thumb43_0,thumb43_1,thumb43_2,thumb43_3,
thumbUI,thumb44_1,thumb44_2,thumb44_3,thumbUI,thumb45_1,thumb45_2,thumb45_3, thumbUI,thumb44_1,thumb44_2,thumb44_3,thumbUI,thumb45_1,thumb45_2,thumb45_3,
thumbUI,thumb46_1,thumb46_2,thumb46_3,thumb47,thumb47,thumbUI,thumbUI, thumb46_0,thumb46_1,thumb46_2,thumb46_3,thumb47,thumb47,thumbUI,thumbUI,
thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48, // 48 thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48, // 48
thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48, thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,
thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48, thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,

File diff suppressed because it is too large Load Diff

View File

@ -78,6 +78,7 @@ extern char oldbuffer[10];
#endif #endif
extern bool CPUReadGSASnapshot(const char *); extern bool CPUReadGSASnapshot(const char *);
extern bool CPUReadGSASPSnapshot(const char *);
extern bool CPUWriteGSASnapshot(const char *, const char *, const char *, const char *); extern bool CPUWriteGSASnapshot(const char *, const char *, const char *, const char *);
extern bool CPUWriteBatteryFile(const char *); extern bool CPUWriteBatteryFile(const char *);
extern bool CPUReadBatteryFile(const char *); extern bool CPUReadBatteryFile(const char *);
@ -89,9 +90,14 @@ extern void CPUCleanUp();
extern void CPUUpdateRender(); extern void CPUUpdateRender();
extern void CPUUpdateRenderBuffers(bool); extern void CPUUpdateRenderBuffers(bool);
extern bool CPUReadMemState(char *, int); extern bool CPUReadMemState(char *, int);
extern bool CPUReadState(const char *);
extern bool CPUWriteMemState(char *, int); extern bool CPUWriteMemState(char *, int);
#ifdef __LIBRETRO__
extern bool CPUReadState(const u8*, unsigned);
extern unsigned int CPUWriteState(u8 *data, unsigned int size);
#else
extern bool CPUReadState(const char *);
extern bool CPUWriteState(const char *); extern bool CPUWriteState(const char *);
#endif
extern int CPULoadRom(const char *); extern int CPULoadRom(const char *);
extern void doMirroring(bool); extern void doMirroring(bool);
extern void CPUUpdateRegister(u32, u16); extern void CPUUpdateRegister(u32, u16);

View File

@ -8,7 +8,11 @@
//#define SPRITE_DEBUG //#define SPRITE_DEBUG
#ifdef TILED_RENDERING
extern void gfxDrawTextScreen(u16, u16, u16, u32 *);
#else
static void gfxDrawTextScreen(u16, u16, u16, u32 *); static void gfxDrawTextScreen(u16, u16, u16, u32 *);
#endif
static void gfxDrawRotScreen(u16, static void gfxDrawRotScreen(u16,
u16, u16, u16, u16,
u16, u16, u16, u16,
@ -98,6 +102,7 @@ static inline void gfxClearArray(u32 *array)
} }
} }
#ifndef TILED_RENDERING
static inline void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs, static inline void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs,
u32 *line) u32 *line)
{ {
@ -238,6 +243,7 @@ static inline void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs,
} }
} }
} }
#endif
static inline void gfxDrawRotScreen(u16 control, static inline void gfxDrawRotScreen(u16 control,
u16 x_l, u16 x_h, u16 x_l, u16 x_h,

View File

@ -5,8 +5,11 @@ extern int armExecute();
extern int thumbExecute(); extern int thumbExecute();
#ifdef __GNUC__ #ifdef __GNUC__
#ifndef __APPLE__
# define INSN_REGPARM __attribute__((regparm(1)))
#else
# define INSN_REGPARM /*nothing*/ # define INSN_REGPARM /*nothing*/
//# define INSN_REGPARM __attribute__((regparm(1))) #endif
# define LIKELY(x) __builtin_expect(!!(x),1) # define LIKELY(x) __builtin_expect(!!(x),1)
# define UNLIKELY(x) __builtin_expect(!!(x),0) # define UNLIKELY(x) __builtin_expect(!!(x),0)
#else #else

View File

@ -6,7 +6,8 @@
#include "RTC.h" #include "RTC.h"
#include "Sound.h" #include "Sound.h"
#include "agbprint.h" #include "agbprint.h"
#include "vmmem.h" // Nintendo GC Virtual Memory #include "GBAcpu.h"
#include "GBALink.h"
extern const u32 objTilesAddress[3]; extern const u32 objTilesAddress[3];
@ -33,103 +34,33 @@ extern bool timer3On;
extern int timer3Ticks; extern int timer3Ticks;
extern int timer3ClockReload; extern int timer3ClockReload;
extern int cpuTotalTicks; extern int cpuTotalTicks;
extern u32 RomIdCode;
#define gid(a,b,c) (a|(b<<8)|(c<<16)) #define CPUReadByteQuick(addr) \
#define CORVETTE gid('A','V','C')
/*****************************************************************************
* Nintendo GC Virtual Memory function override
* Tantric September 2008
****************************************************************************/
#define CPUReadByteQuickDef(addr) \
map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
#define CPUReadHalfWordQuickDef(addr) \ #define CPUReadHalfWordQuick(addr) \
READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
#define CPUReadMemoryQuickDef(addr) \ #define CPUReadMemoryQuick(addr) \
READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
u8 inline CPUReadByteQuick( u32 addr )
{
switch(addr >> 24 )
{
case 0x08:
case 0x09:
case 0x0A:
case 0x0C:
#ifdef USE_VM
return VMRead8( addr & 0x1FFFFFF );
#endif
default:
return CPUReadByteQuickDef(addr);
}
return 0;
}
u16 inline CPUReadHalfWordQuick( u32 addr )
{
switch(addr >> 24)
{
case 0x08:
case 0x09:
case 0x0A:
case 0x0C:
#ifdef USE_VM
return VMRead16( addr & 0x1FFFFFF );
#endif
default:
return CPUReadHalfWordQuickDef(addr);
}
return 0;
}
u32 inline CPUReadMemoryQuick( u32 addr )
{
switch(addr >> 24)
{
case 0x08:
case 0x09:
case 0x0A:
case 0x0C:
#ifdef USE_VM
return VMRead32( addr & 0x1FFFFFF );
#endif
default:
return CPUReadMemoryQuickDef(addr);
}
return 0;
}
/*****************************************************************************
* End of VM override
****************************************************************************/
static inline u32 CPUReadMemory(u32 address) 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; u32 value;
u32 oldAddress = address;
if(address & 3) {
address &= ~0x03;
}
switch(address >> 24) { switch(address >> 24) {
case 0x00: case 0:
if(reg[15].I >> 24) { if(reg[15].I >> 24) {
if(address < 0x4000) { if(address < 0x4000) {
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_READ) { if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal word read: %08x at %08x\n", address, armMode ? log("Illegal word read from bios: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2); armNextPC - 4 : armNextPC - 2);
} }
#endif #endif
@ -139,117 +70,92 @@ static inline u32 CPUReadMemory(u32 address)
} else } else
value = READ32LE(((u32 *)&bios[address & 0x3FFC])); value = READ32LE(((u32 *)&bios[address & 0x3FFC]));
break; break;
case 0x02: case 2:
value = READ32LE(((u32 *)&workRAM[address & 0x3FFFC])); value = READ32LE(((u32 *)&workRAM[address & 0x3FFFC]));
break; break;
case 0x03: case 3:
value = READ32LE(((u32 *)&internalRAM[address & 0x7ffC])); value = READ32LE(((u32 *)&internalRAM[address & 0x7ffC]));
break; break;
case 0x04: case 4:
if((address < 0x4000400) && ioReadable[address & 0x3fc]) { if((address < 0x4000400) && ioReadable[address & 0x3fc]) {
if(ioReadable[(address & 0x3fc) + 2]) if(ioReadable[(address & 0x3fc) + 2]) {
value = READ32LE(((u32 *)&ioMem[address & 0x3fC])); value = READ32LE(((u32 *)&ioMem[address & 0x3fC]));
else if ((address & 0x3fc) == COMM_JOY_RECV_L)
UPDATE_REG(COMM_JOYSTAT, READ16LE(&ioMem[COMM_JOYSTAT]) & ~JOYSTAT_RECV);
} else {
value = READ16LE(((u16 *)&ioMem[address & 0x3fc])); value = READ16LE(((u16 *)&ioMem[address & 0x3fc]));
} else goto unreadable; }
break; }
case 0x05: else
goto unreadable;
break;
case 5:
value = READ32LE(((u32 *)&paletteRAM[address & 0x3fC])); value = READ32LE(((u32 *)&paletteRAM[address & 0x3fC]));
break; break;
case 0x06: case 6:
address = (address & 0x1fffc); address = (address & 0x1fffc);
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
{ {
value = 0; value = 0;
break; break;
} }
if ((address & 0x18000) == 0x18000) if ((address & 0x18000) == 0x18000)
address &= 0x17fff; address &= 0x17fff;
value = READ32LE(((u32 *)&vram[address])); value = READ32LE(((u32 *)&vram[address]));
break; break;
case 0x07: case 7:
value = READ32LE(((u32 *)&oam[address & 0x3FC])); value = READ32LE(((u32 *)&oam[address & 0x3FC]));
break; break;
case 0x08: case 8:
// Must be cartridge ROM, reading other sensors doesn't allow 32-bit access. case 9:
case 0x09: case 10:
case 0x0A: case 11:
case 0x0B: case 12:
case 0x0C: value = READ32LE(((u32 *)&rom[address&0x1FFFFFC]));
#ifdef USE_VM // Nintendo GC Virtual Memory
value = VMRead32( address & 0x1FFFFFC );
#else
value = READ32LE(((u32 *)&rom[address&0x1FFFFFC]));
#endif
break; break;
case 0x0D: case 13:
if(cpuEEPROMEnabled) value = eepromRead(address);
// no need to swap this break;
return eepromRead(address); case 14:
goto unreadable; case 15:
case 0x0E: value = flashRead(address) * 0x01010101;
// Yoshi's Universal Gravitation (Topsy Turvy) break;
// Koro Koro
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;
}
}
if(cpuFlashEnabled | cpuSramEnabled)
// no need to swap this
return flashRead(address);
// default // default
default: default:
unreadable: unreadable:
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_READ) { if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal word read: %08x at %08x\n", address, armMode ? log("Illegal word read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2); armNextPC - 4 : armNextPC - 2);
} }
#endif #endif
if(cpuDmaHack) {
if(cpuDmaHack) { value = cpuDmaLast;
value = cpuDmaLast; } else {
} else {
if(armState) { if(armState) {
#ifdef USE_VM // Nintendo GC Virtual Memory return CPUReadMemoryQuick(reg[15].I);
value = CPUReadMemoryQuick(reg[15].I);
#else
value = CPUReadMemoryQuickDef(reg[15].I);
#endif
} else { } else {
#ifdef USE_VM // Nintendo GC Virtual Memory return CPUReadHalfWordQuick(reg[15].I) |
value = CPUReadHalfWordQuick(reg[15].I) | CPUReadHalfWordQuick(reg[15].I) << 16;
CPUReadHalfWordQuick(reg[15].I) << 16;
#else
value = CPUReadHalfWordQuickDef(reg[15].I) |
CPUReadHalfWordQuickDef(reg[15].I) << 16;
#endif
} }
} }
break;
} }
if(address & 3) { if(oldAddress & 3) {
#ifdef C_CORE #ifdef C_CORE
int shift = (address & 3) << 3; int shift = (oldAddress & 3) << 3;
value = (value >> shift) | (value << (32 - shift)); value = (value >> shift) | (value << (32 - shift));
#else #else
#ifdef __GNUC__ #ifdef __GNUC__
asm("and $3, %%ecx;" asm("and $3, %%ecx;"
"shl $3 ,%%ecx;" "shl $3 ,%%ecx;"
"ror %%cl, %0" "ror %%cl, %0"
: "=r" (value) : "=r" (value)
: "r" (value), "c" (address)); : "r" (value), "c" (oldAddress));
#else #else
__asm { __asm {
mov ecx, address; mov ecx, oldAddress;
and ecx, 3; and ecx, 3;
shl ecx, 3; shl ecx, 3;
ror [dword ptr value], cl; ror [dword ptr value], cl;
@ -257,6 +163,15 @@ static inline u32 CPUReadMemory(u32 address)
#endif #endif
#endif #endif
} }
#ifdef GBA_LOGGING
if(oldAddress & 3) {
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
log("Unaligned word read from: %08x at %08x (%08x)\n", oldAddress, armMode ?
armNextPC - 4 : armNextPC - 2, value);
}
}
#endif
return value; return value;
} }
@ -264,25 +179,21 @@ extern u32 myROM[];
static inline u32 CPUReadHalfWord(u32 address) 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; u32 value;
u32 oldAddress = address;
if(address & 1) {
address &= ~0x01;
}
switch(address >> 24) { switch(address >> 24) {
case 0x00: case 0:
if (reg[15].I >> 24) { if (reg[15].I >> 24) {
if(address < 0x4000) { if(address < 0x4000) {
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_READ) { if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal halfword read: %08x at %08x\n", address, armMode ? log("Illegal halfword read from bios: %08x at %08x\n", oldAddress, armMode ?
armNextPC - 4 : armNextPC - 2); armNextPC - 4 : armNextPC - 2);
} }
#endif #endif
value = READ16LE(((u16 *)&biosProtected[address&2])); value = READ16LE(((u16 *)&biosProtected[address&2]));
@ -290,13 +201,13 @@ static inline u32 CPUReadHalfWord(u32 address)
} else } else
value = READ16LE(((u16 *)&bios[address & 0x3FFE])); value = READ16LE(((u16 *)&bios[address & 0x3FFE]));
break; break;
case 0x02: case 2:
value = READ16LE(((u16 *)&workRAM[address & 0x3FFFE])); value = READ16LE(((u16 *)&workRAM[address & 0x3FFFE]));
break; break;
case 0x03: case 3:
value = READ16LE(((u16 *)&internalRAM[address & 0x7ffe])); value = READ16LE(((u16 *)&internalRAM[address & 0x7ffe]));
break; break;
case 0x04: case 4:
if((address < 0x4000400) && ioReadable[address & 0x3fe]) if((address < 0x4000400) && ioReadable[address & 0x3fe])
{ {
value = READ16LE(((u16 *)&ioMem[address & 0x3fe])); value = READ16LE(((u16 *)&ioMem[address & 0x3fe]));
@ -305,216 +216,182 @@ static inline u32 CPUReadHalfWord(u32 address)
if (((address & 0x3fe) == 0x100) && timer0On) if (((address & 0x3fe) == 0x100) && timer0On)
value = 0xFFFF - ((timer0Ticks-cpuTotalTicks) >> timer0ClockReload); value = 0xFFFF - ((timer0Ticks-cpuTotalTicks) >> timer0ClockReload);
else else
if (((address & 0x3fe) == 0x104) && timer1On && !(TM1CNT & 4)) if (((address & 0x3fe) == 0x104) && timer1On && !(TM1CNT & 4))
value = 0xFFFF - ((timer1Ticks-cpuTotalTicks) >> timer1ClockReload); value = 0xFFFF - ((timer1Ticks-cpuTotalTicks) >> timer1ClockReload);
else else
if (((address & 0x3fe) == 0x108) && timer2On && !(TM2CNT & 4)) if (((address & 0x3fe) == 0x108) && timer2On && !(TM2CNT & 4))
value = 0xFFFF - ((timer2Ticks-cpuTotalTicks) >> timer2ClockReload); value = 0xFFFF - ((timer2Ticks-cpuTotalTicks) >> timer2ClockReload);
else else
if (((address & 0x3fe) == 0x10C) && timer3On && !(TM3CNT & 4)) if (((address & 0x3fe) == 0x10C) && timer3On && !(TM3CNT & 4))
value = 0xFFFF - ((timer3Ticks-cpuTotalTicks) >> timer3ClockReload); value = 0xFFFF - ((timer3Ticks-cpuTotalTicks) >> timer3ClockReload);
} }
} }
else if((address < 0x4000400) && ioReadable[address & 0x3fc])
{
value = 0;
}
else goto unreadable; else goto unreadable;
break; break;
case 0x05: case 5:
value = READ16LE(((u16 *)&paletteRAM[address & 0x3fe])); value = READ16LE(((u16 *)&paletteRAM[address & 0x3fe]));
break; break;
case 0x06: case 6:
address = (address & 0x1fffe); address = (address & 0x1fffe);
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
{ {
value = 0; value = 0;
break; break;
} }
if ((address & 0x18000) == 0x18000) if ((address & 0x18000) == 0x18000)
address &= 0x17fff; address &= 0x17fff;
value = READ16LE(((u16 *)&vram[address])); value = READ16LE(((u16 *)&vram[address]));
break; break;
case 0x07: case 7:
value = READ16LE(((u16 *)&oam[address & 0x3fe])); value = READ16LE(((u16 *)&oam[address & 0x3fe]));
break; break;
case 0x08: case 8:
// Use existing case statement and faster test for potential speed improvement case 9:
// This is possibly the GPIO port that controls the real time clock, case 10:
// WarioWare Twisted! tilt sensors, rumble, and solar sensors. case 11:
if(address >= 0x80000c4 && address <= 0x80000c8) { case 12:
// this function still works if there is no real time clock if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8)
// and does a normal memory read in that case. value = rtcRead(address);
value = rtcRead(address & 0xFFFFFFE); else
break; value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE]));
}
case 0x09:
case 0x0A:
case 0x0B:
case 0x0C:
#ifdef USE_VM // Nintendo GC Virtual Memory
value = VMRead16( address & 0x1FFFFFE );
#else
value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE]));
#endif
break; break;
case 0x0D: case 13:
if(cpuEEPROMEnabled) value = eepromRead(address);
// no need to swap this break;
return eepromRead(address); case 14:
goto unreadable; case 15:
case 0x0E: value = flashRead(address) * 0x0101;
// Yoshi's Universal Gravitation (Topsy Turvy) break;
// Koro Koro
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;
}
}
if(cpuFlashEnabled | cpuSramEnabled)
// no need to swap this
return flashRead(address);
// default // default
default: default:
unreadable: unreadable:
if(cpuDmaHack) {
value = cpuDmaLast & 0xFFFF;
} else {
if(armState) {
value = CPUReadHalfWordQuick(reg[15].I + (address & 2));
} else {
value = CPUReadHalfWordQuick(reg[15].I);
}
}
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_READ) { if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal halfword read: %08x at %08x\n", address, armMode ? log("Illegal halfword read: %08x at %08x (%08x)\n", oldAddress, reg[15].I, value);
armNextPC - 4 : armNextPC - 2); }
}
#endif #endif
if(cpuDmaHack) { return value;
value = cpuDmaLast & 0xFFFF;
} else {
if(armState) {
#ifdef USE_VM // Nintendo GC Virtual Memory
value = CPUReadHalfWordQuick(reg[15].I + (address & 2));
#else
value = CPUReadHalfWordQuickDef(reg[15].I + (address & 2));
#endif
} else {
#ifdef USE_VM // Nintendo GC Virtual Memory
value = CPUReadHalfWordQuick(reg[15].I);
#else
value = CPUReadHalfWordQuickDef(reg[15].I);
#endif
}
}
break;
} }
if(address & 1) { if(oldAddress & 1) {
value = (value >> 8) | (value << 24); value = (value >> 8) | (value << 24);
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
log("Unaligned halfword read from: %08x at %08x (%08x)\n", oldAddress, armMode ?
armNextPC - 4 : armNextPC - 2, value);
}
#endif
} }
return value; return value;
} }
static inline u16 CPUReadHalfWordSigned(u32 address) static inline s16 CPUReadHalfWordSigned(u32 address)
{ {
u16 value = CPUReadHalfWord(address); s32 value = (s32)CPUReadHalfWord(address);
if((address & 1)) if((address & 1))
value = (s8)value; {
return value; #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
log("Unaligned signed halfword read from: %08x at %08x (%08x)\n", address, armMode ?
armNextPC - 4 : armNextPC - 2, value);
}
#endif
}
return (s16)value;
} }
static inline u8 CPUReadByte(u32 address) static inline u8 CPUReadByte(u32 address)
{ {
switch(address >> 24) { switch(address >> 24) {
case 0x00: case 0:
if (reg[15].I >> 24) { if (reg[15].I >> 24) {
if(address < 0x4000) { if(address < 0x4000) {
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_READ) { if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal byte read: %08x at %08x\n", address, armMode ? log("Illegal byte read from bios: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2); armNextPC - 4 : armNextPC - 2);
} }
#endif #endif
return biosProtected[address & 3]; return biosProtected[address & 3];
} else goto unreadable; } else goto unreadable;
} }
return bios[address & 0x3FFF]; return bios[address & 0x3FFF];
case 0x02: case 2:
return workRAM[address & 0x3FFFF]; return workRAM[address & 0x3FFFF];
case 0x03: case 3:
return internalRAM[address & 0x7fff]; return internalRAM[address & 0x7fff];
case 0x04: case 4:
if((address < 0x4000400) && ioReadable[address & 0x3ff]) if((address < 0x4000400) && ioReadable[address & 0x3ff])
return ioMem[address & 0x3ff]; return ioMem[address & 0x3ff];
else goto unreadable; else goto unreadable;
case 0x05: case 5:
return paletteRAM[address & 0x3ff]; return paletteRAM[address & 0x3ff];
case 0x06: case 6:
address = (address & 0x1ffff); address = (address & 0x1ffff);
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
return 0; return 0;
if ((address & 0x18000) == 0x18000) if ((address & 0x18000) == 0x18000)
address &= 0x17fff; address &= 0x17fff;
return vram[address]; return vram[address];
case 0x07: case 7:
return oam[address & 0x3ff]; return oam[address & 0x3ff];
case 0x08: case 8:
// the real time clock doesn't support byte reads, so don't bother checking for it. case 9:
case 0x09: case 10:
case 0x0A: case 11:
case 0x0B: case 12:
case 0x0C:
#ifdef USE_VM // Nintendo GC Virtual Memory
return VMRead8( address & 0x1FFFFFF );
#else
return rom[address & 0x1FFFFFF]; return rom[address & 0x1FFFFFF];
#endif case 13:
case 0x0D: return eepromRead(address);
if(cpuEEPROMEnabled) case 14:
return eepromRead(address); case 15:
goto unreadable; {
case 0x0E: if (cpuEEPROMSensorEnabled) {
// Yoshi's Universal Gravitation (Topsy Turvy) switch (address & 0x00008f00) {
// Koro Koro case 0x8200:
if(cpuEEPROMSensorEnabled) { return systemGetSensorX() & 255;
switch(address & 0x00008f00) { case 0x8300:
case 0x8200: return (systemGetSensorX() >> 8) | 0x80;
return systemGetSensorX() & 255; case 0x8400:
case 0x8300: return systemGetSensorY() & 255;
return (systemGetSensorX() >> 8)|0x80; case 0x8500:
case 0x8400: return systemGetSensorY() >> 8;
return systemGetSensorY() & 255; }
case 0x8500: }
return systemGetSensorY() >> 8; return flashRead(address);
} }
}
if(cpuSramEnabled | cpuFlashEnabled)
return flashRead(address);
// default // default
default: default:
unreadable: unreadable:
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_READ) { if(systemVerbose & VERBOSE_ILLEGAL_READ) {
log("Illegal byte read: %08x at %08x\n", address, armMode ? log("Illegal byte read: %08x at %08x\n", address, armMode ?
armNextPC - 4 : armNextPC - 2); armNextPC - 4 : armNextPC - 2);
} }
#endif #endif
if(cpuDmaHack) { if(cpuDmaHack) {
return cpuDmaLast & 0xFF; return cpuDmaLast & 0xFF;
} else { } else {
if(armState) { if(armState) {
#ifdef USE_VM // Nintendo GC Virtual Memory return CPUReadByteQuick(reg[15].I + (address & 3));
return CPUReadByteQuick(reg[15].I+(address & 3)); } else {
#else return CPUReadByteQuick(reg[15].I + (address & 1));
return CPUReadByteQuickDef(reg[15].I+(address & 3)); }
#endif }
} else {
#ifdef USE_VM // Nintendo GC Virtual Memory
return CPUReadByteQuick(reg[15].I+(address & 1));
#else
return CPUReadByteQuickDef(reg[15].I+(address & 1));
#endif
}
}
break;
} }
} }
@ -525,19 +402,21 @@ static inline void CPUWriteMemory(u32 address, u32 value)
if(address & 3) { if(address & 3) {
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) { if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
log("Unaligned word write: %08x to %08x from %08x\n", log("Unaligned word write: %08x to %08x from %08x\n",
value, value,
address, address,
armMode ? armNextPC - 4 : armNextPC - 2); armMode ? armNextPC - 4 : armNextPC - 2);
} }
} }
#endif #endif
address &= 0xFFFFFFFC;
switch(address >> 24) { switch(address >> 24) {
case 0x02: case 0x02:
#ifdef BKPT_SUPPORT #ifdef BKPT_SUPPORT
if(*((u32 *)&freezeWorkRAM[address & 0x3FFFC])) if(*((u32 *)&freezeWorkRAM[address & 0x3FFFC]))
cheatsWriteMemory(address & 0x203FFFC, cheatsWriteMemory(address & 0x203FFFC,
value); value);
else else
#endif #endif
WRITE32LE(((u32 *)&workRAM[address & 0x3FFFC]), value); WRITE32LE(((u32 *)&workRAM[address & 0x3FFFC]), value);
@ -546,7 +425,7 @@ static inline void CPUWriteMemory(u32 address, u32 value)
#ifdef BKPT_SUPPORT #ifdef BKPT_SUPPORT
if(*((u32 *)&freezeInternalRAM[address & 0x7ffc])) if(*((u32 *)&freezeInternalRAM[address & 0x7ffc]))
cheatsWriteMemory(address & 0x3007FFC, cheatsWriteMemory(address & 0x3007FFC,
value); value);
else else
#endif #endif
WRITE32LE(((u32 *)&internalRAM[address & 0x7ffC]), value); WRITE32LE(((u32 *)&internalRAM[address & 0x7ffC]), value);
@ -561,16 +440,15 @@ static inline void CPUWriteMemory(u32 address, u32 value)
#ifdef BKPT_SUPPORT #ifdef BKPT_SUPPORT
if(*((u32 *)&freezePRAM[address & 0x3fc])) if(*((u32 *)&freezePRAM[address & 0x3fc]))
cheatsWriteMemory(address & 0x70003FC, cheatsWriteMemory(address & 0x70003FC,
value); value);
else else
#endif #endif
if(address < 0x5000400 || (RomIdCode & 0xFFFFFF) != CORVETTE) WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value);
WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value);
break; break;
case 0x06: case 0x06:
address = (address & 0x1fffc); address = (address & 0x1fffc);
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
return; return;
if ((address & 0x18000) == 0x18000) if ((address & 0x18000) == 0x18000)
address &= 0x17fff; address &= 0x17fff;
@ -580,16 +458,16 @@ static inline void CPUWriteMemory(u32 address, u32 value)
else else
#endif #endif
WRITE32LE(((u32 *)&vram[address]), value); WRITE32LE(((u32 *)&vram[address]), value);
break; break;
case 0x07: case 0x07:
#ifdef BKPT_SUPPORT #ifdef BKPT_SUPPORT
if(*((u32 *)&freezeOAM[address & 0x3fc])) if(*((u32 *)&freezeOAM[address & 0x3fc]))
cheatsWriteMemory(address & 0x70003FC, cheatsWriteMemory(address & 0x70003FC,
value); value);
else else
#endif #endif
WRITE32LE(((u32 *)&oam[address & 0x3fc]), value); WRITE32LE(((u32 *)&oam[address & 0x3fc]), value);
break; break;
case 0x0D: case 0x0D:
if(cpuEEPROMEnabled) { if(cpuEEPROMEnabled) {
@ -598,19 +476,20 @@ static inline void CPUWriteMemory(u32 address, u32 value)
} }
goto unwritable; goto unwritable;
case 0x0E: case 0x0E:
if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) { case 0x0F:
if((!eepromInUse) | cpuSramEnabled | cpuFlashEnabled) {
(*cpuSaveGameFunc)(address, (u8)value); (*cpuSaveGameFunc)(address, (u8)value);
break; break;
} }
// default // default
default: default:
unwritable: unwritable:
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_WRITE) { if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
log("Illegal word write: %08x to %08x from %08x\n", log("Illegal word write: %08x to %08x from %08x\n",
value, value,
address, address,
armMode ? armNextPC - 4 : armNextPC - 2); armMode ? armNextPC - 4 : armNextPC - 2);
} }
#endif #endif
break; break;
@ -623,19 +502,21 @@ static inline void CPUWriteHalfWord(u32 address, u16 value)
if(address & 1) { if(address & 1) {
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) { if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
log("Unaligned halfword write: %04x to %08x from %08x\n", log("Unaligned halfword write: %04x to %08x from %08x\n",
value, value,
address, address,
armMode ? armNextPC - 4 : armNextPC - 2); armMode ? armNextPC - 4 : armNextPC - 2);
} }
} }
#endif #endif
address &= 0xFFFFFFFE;
switch(address >> 24) { switch(address >> 24) {
case 2: case 2:
#ifdef BKPT_SUPPORT #ifdef BKPT_SUPPORT
if(*((u16 *)&freezeWorkRAM[address & 0x3FFFE])) if(*((u16 *)&freezeWorkRAM[address & 0x3FFFE]))
cheatsWriteHalfWord(address & 0x203FFFE, cheatsWriteHalfWord(address & 0x203FFFE,
value); value);
else else
#endif #endif
WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]),value); WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]),value);
@ -644,7 +525,7 @@ static inline void CPUWriteHalfWord(u32 address, u16 value)
#ifdef BKPT_SUPPORT #ifdef BKPT_SUPPORT
if(*((u16 *)&freezeInternalRAM[address & 0x7ffe])) if(*((u16 *)&freezeInternalRAM[address & 0x7ffe]))
cheatsWriteHalfWord(address & 0x3007ffe, cheatsWriteHalfWord(address & 0x3007ffe,
value); value);
else else
#endif #endif
WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value); WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value);
@ -658,34 +539,33 @@ static inline void CPUWriteHalfWord(u32 address, u16 value)
#ifdef BKPT_SUPPORT #ifdef BKPT_SUPPORT
if(*((u16 *)&freezePRAM[address & 0x03fe])) if(*((u16 *)&freezePRAM[address & 0x03fe]))
cheatsWriteHalfWord(address & 0x70003fe, cheatsWriteHalfWord(address & 0x70003fe,
value); value);
else else
#endif #endif
if(address < 0x5000400 || (RomIdCode & 0xFFFFFF) != CORVETTE) WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
break; break;
case 6: case 6:
address = (address & 0x1fffe); address = (address & 0x1fffe);
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000)) if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
return; return;
if ((address & 0x18000) == 0x18000) if ((address & 0x18000) == 0x18000)
address &= 0x17fff; address &= 0x17fff;
#ifdef BKPT_SUPPORT #ifdef BKPT_SUPPORT
if(*((u16 *)&freezeVRAM[address])) if(*((u16 *)&freezeVRAM[address]))
cheatsWriteHalfWord(address + 0x06000000, cheatsWriteHalfWord(address + 0x06000000,
value); value);
else else
#endif #endif
WRITE16LE(((u16 *)&vram[address]), value); WRITE16LE(((u16 *)&vram[address]), value);
break; break;
case 7: case 7:
#ifdef BKPT_SUPPORT #ifdef BKPT_SUPPORT
if(*((u16 *)&freezeOAM[address & 0x03fe])) if(*((u16 *)&freezeOAM[address & 0x03fe]))
cheatsWriteHalfWord(address & 0x70003fe, cheatsWriteHalfWord(address & 0x70003fe,
value); value);
else else
#endif #endif
WRITE16LE(((u16 *)&oam[address & 0x3fe]), value); WRITE16LE(((u16 *)&oam[address & 0x3fe]), value);
break; break;
case 8: case 8:
case 9: case 9:
@ -701,19 +581,20 @@ static inline void CPUWriteHalfWord(u32 address, u16 value)
} }
goto unwritable; goto unwritable;
case 14: case 14:
if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) { case 15:
if((!eepromInUse) | cpuSramEnabled | cpuFlashEnabled) {
(*cpuSaveGameFunc)(address, (u8)value); (*cpuSaveGameFunc)(address, (u8)value);
break; break;
} }
goto unwritable; goto unwritable;
default: default:
unwritable: unwritable:
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_ILLEGAL_WRITE) { if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
log("Illegal halfword write: %04x to %08x from %08x\n", log("Illegal halfword write: %04x to %08x from %08x\n",
value, value,
address, address,
armMode ? armNextPC - 4 : armNextPC - 2); armMode ? armNextPC - 4 : armNextPC - 2);
} }
#endif #endif
break; break;
@ -837,7 +718,8 @@ static inline void CPUWriteByte(u32 address, u8 b)
} }
goto unwritable; goto unwritable;
case 14: case 14:
if (!(saveType == 5) && (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)) { case 15:
if ((saveType != 5) && ((!eepromInUse) | cpuSramEnabled | cpuFlashEnabled)) {
//if(!cpuEEPROMEnabled && (cpuSramEnabled | cpuFlashEnabled)) { //if(!cpuEEPROMEnabled && (cpuSramEnabled | cpuFlashEnabled)) {

View File

@ -1,11 +1,3 @@
/*
Mode 0 is the tiled graphics mode, with all the layers available.
There is no rotation or scaling in this mode.
It can be either 16 colours (with 16 different palettes) or 256 colors.
There are 1024 tiles available.
These routines only render a single line at a time, because of the way the GBA does events.
*/
#include "GBA.h" #include "GBA.h"
#include "Globals.h" #include "Globals.h"
#include "GBAGfx.h" #include "GBAGfx.h"
@ -15,18 +7,9 @@ void mode0RenderLine()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
int x = 232; //240 - 8 for(int x = 0; x < 240; x++) {
do{ lineMix[x] = 0x7fff;
lineMix[x ] = }
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
return; return;
} }
@ -55,55 +38,11 @@ void mode0RenderLine()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(u32 x = 0; x < 240u; ++x) { for(int x = 0; x < 240; x++) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
//--DCN
//
// !NON-PORTABLE!!NON-PORTABLE!
//
// This takes advantage of the fact that the Wii has far more registers
// (32 vs 8) than IA-32 based processors processors (Intel, AMD).
// This actually runs SLOWER on those. This code will only show
// improvements on a PowerPC machine! (19.5% improvement: isolated tests)
//*
u8 li1 = (u8)(line1[x]>>24);
u8 li2 = (u8)(line2[x]>>24);
u8 li3 = (u8)(line3[x]>>24);
u8 li4 = (u8)(lineOBJ[x]>>24);
u8 r = (li2 < li1) ? (li2) : (li1); if(line0[x] < color) {
if(li3 < r) {
r = (li4 < li3) ? (li4) : (li3);
}else if(li4 < r){
r = (li4);
}
if(line0[x] < backdrop) {
color = line0[x];
top = 0x01;
}
if(r < (u8)(color >> 24)) {
if(r == li1){
color = line1[x];
top = 0x02;
}else if(r == li2){
color = line2[x];
top = 0x04;
}else if(r == li3){
color = line3[x];
top = 0x08;
}else if(r == li4){
color = lineOBJ[x];
top = 0x10;
}
}
//Original
/*
if(line0[x] < color) {
color = line0[x]; color = line0[x];
top = 0x01; top = 0x01;
} }
@ -117,49 +56,41 @@ void mode0RenderLine()
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
if((u8)(line3[x]>>24) < (u8)(color >> 24)) {
if((u8)(line3[x]>>24) < (u8)(color >> 24)) {
color = line3[x]; color = line3[x];
top = 0x08; top = 0x08;
} }
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) { if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
color = lineOBJ[x]; color = lineOBJ[x];
top = 0x10; top = 0x10;
} }
//*/
if((top & 0x10) && (color & 0x00010000)) { if((top & 0x10) && (color & 0x00010000)) {
// semi-transparent OBJ // semi-transparent OBJ
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
u8 li0 = (u8)(line0[x]>>24); if((u8)(line0[x]>>24) < (u8)(back >> 24)) {
u8 li1 = (u8)(line1[x]>>24); back = line0[x];
u8 li2 = (u8)(line2[x]>>24); top2 = 0x01;
u8 li3 = (u8)(line3[x]>>24); }
u8 r = (li1 < li0) ? (li1) : (li0); if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
back = line1[x];
top2 = 0x02;
}
if(li2 < r) { if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
r = (li3 < li2) ? (li3) : (li2); back = line2[x];
}else if(li3 < r){ top2 = 0x04;
r = (li3); }
}
if(r < (u8)(color >> 24)) { if((u8)(line3[x]>>24) < (u8)(back >> 24)) {
if(r == li0){ back = line3[x];
back = line0[x]; top2 = 0x08;
top2 = 0x01; }
}else if(r == li1){
back = line1[x];
top2 = 0x02;
}else if(r == li2){
back = line2[x];
top2 = 0x04;
}else if(r == li3){
back = line3[x];
top2 = 0x08;
}
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -188,20 +119,9 @@ void mode0RenderLineNoWindow()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
return; return;
} }
@ -234,41 +154,32 @@ void mode0RenderLineNoWindow()
for(int x = 0; x < 240; x++) { for(int x = 0; x < 240; x++) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
u8 li1 = (u8)(line1[x]>>24); if(line0[x] < color) {
u8 li2 = (u8)(line2[x]>>24); color = line0[x];
u8 li3 = (u8)(line3[x]>>24); top = 0x01;
u8 li4 = (u8)(lineOBJ[x]>>24); }
u8 r = (li2 < li1) ? (li2) : (li1); if(line1[x] < (color & 0xFF000000)) {
color = line1[x];
top = 0x02;
}
if(li3 < r) { if(line2[x] < (color & 0xFF000000)) {
r = (li4 < li3) ? (li4) : (li3); color = line2[x];
}else if(li4 < r){ top = 0x04;
r = (li4); }
}
if(line0[x] < backdrop) { if(line3[x] < (color & 0xFF000000)) {
color = line0[x]; color = line3[x];
top = 0x01; top = 0x08;
} }
if(r < (u8)(color >> 24)) { if(lineOBJ[x] < (color & 0xFF000000)) {
if(r == li1){ color = lineOBJ[x];
color = line1[x]; top = 0x10;
top = 0x02; }
}else if(r == li2){
color = line2[x];
top = 0x04;
}else if(r == li3){
color = line3[x];
top = 0x08;
}else if(r == li4){
color = lineOBJ[x];
top = 0x10;
}
}
if(!(color & 0x00010000)) { if(!(color & 0x00010000)) {
switch(effect) { switch(effect) {
@ -278,30 +189,40 @@ void mode0RenderLineNoWindow()
{ {
if(top & BLDMOD) { if(top & BLDMOD) {
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if(line0[x] < back) {
if((top != 0x01) && line0[x] < back) { if(top != 0x01) {
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
}
} }
if((top != 0x02) && line1[x] < (back & 0xFF000000)) {
if(line1[x] < (back & 0xFF000000)) {
if(top != 0x02) {
back = line1[x]; back = line1[x];
top2 = 0x02; top2 = 0x02;
}
} }
if((top != 0x04) && line2[x] < (back & 0xFF000000)) { if(line2[x] < (back & 0xFF000000)) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
}
} }
if((top != 0x08) && line3[x] < (back & 0xFF000000)) { if(line3[x] < (back & 0xFF000000)) {
if(top != 0x08) {
back = line3[x]; back = line3[x];
top2 = 0x08; top2 = 0x08;
}
} }
if((top != 0x10) && lineOBJ[x] < (back & 0xFF000000)) { if(lineOBJ[x] < (back & 0xFF000000)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
}
} }
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
@ -326,43 +247,25 @@ void mode0RenderLineNoWindow()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
//--DCN if(line0[x] < back) {
// This is pretty much the exact same result: back = line0[x];
// line1[x] < (back & 0xFF000000) top2 = 0x01;
// }
// (u8)(line0[x]>>24) < (u8)(back >> 24)
//
// The only difference is that the first is stored in a u32,
// and the second is stored in a u8
//*
u8 li0 = (u8)(line0[x]>>24);
u8 li1 = (u8)(line1[x]>>24);
u8 li2 = (u8)(line2[x]>>24);
u8 li3 = (u8)(line3[x]>>24);
u8 r = (li1 < li0) ? (li1) : (li0); if(line1[x] < (back & 0xFF000000)) {
back = line1[x];
top2 = 0x02;
}
if(li2 < r) { if(line2[x] < (back & 0xFF000000)) {
r = (li3 < li2) ? (li3) : (li2); back = line2[x];
}else if(li3 < r){ top2 = 0x04;
r = (li3); }
}
if(r < (u8)(color >> 24)) { if(line3[x] < (back & 0xFF000000)) {
if(r == li0){ back = line3[x];
back = line0[x]; top2 = 0x08;
top2 = 0x01; }
}else if(r == li1){
back = line1[x];
top2 = 0x02;
}else if(r == li2){
back = line2[x];
top2 = 0x04;
}else if(r == li3){
back = line3[x];
top2 = 0x08;
}
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -391,20 +294,9 @@ void mode0RenderLineAll()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
return; return;
} }
@ -480,7 +372,7 @@ void mode0RenderLineAll()
} }
} }
if((mask & 1) && (line0[x] < color)) { if((mask & 1) && (line0[x] < color)) {
color = line0[x]; color = line0[x];
top = 0x01; top = 0x01;
} }
@ -556,30 +448,39 @@ void mode0RenderLineAll()
if(top & BLDMOD) { if(top & BLDMOD) {
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
if((mask & 1) && (top != 0x01) && (u8)(line0[x]>>24) < (u8)(back >> 24)) { if(top != 0x01) {
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
}
} }
if((mask & 2) && (top != 0x02) && (u8)(line1[x]>>24) < (u8)(back >> 24)) { if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
if(top != 0x02) {
back = line1[x]; back = line1[x];
top2 = 0x02; top2 = 0x02;
}
} }
if((mask & 4) && (top != 0x04) && (u8)(line2[x]>>24) < (u8)(back >> 24)) { if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
}
} }
if((mask & 8) && (top != 0x08) && (u8)(line3[x]>>24) < (u8)(back >> 24)) { if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) {
if(top != 0x08) {
back = line3[x]; back = line3[x];
top2 = 0x08; top2 = 0x08;
}
} }
if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
}
} }
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))

View File

@ -1,12 +1,3 @@
/*
Mode 1 is a tiled graphics mode, but with background layer 2 supporting scaling and rotation.
There is no layer 3 in this mode.
Layers 0 and 1 can be either 16 colours (with 16 different palettes) or 256 colours.
There are 1024 tiles available.
Layer 2 is 256 colours and allows only 256 tiles.
These routines only render a single line at a time, because of the way the GBA does events.
*/
#include "GBA.h" #include "GBA.h"
#include "Globals.h" #include "Globals.h"
#include "GBAGfx.h" #include "GBAGfx.h"
@ -16,20 +7,9 @@ void mode1RenderLine()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -60,64 +40,49 @@ void mode1RenderLine()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(u32 x = 0; x < 240u; ++x) { for(int x = 0; x < 240; x++) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
u8 li1 = (u8)(line1[x]>>24); if(line0[x] < color) {
u8 li2 = (u8)(line2[x]>>24); color = line0[x];
u8 li4 = (u8)(lineOBJ[x]>>24); top = 0x01;
}
u8 r = (li2 < li1) ? (li2) : (li1); if((u8)(line1[x]>>24) < (u8)(color >> 24)) {
color = line1[x];
top = 0x02;
}
if(li4 < r){ if((u8)(line2[x]>>24) < (u8)(color >> 24)) {
r = (li4); color = line2[x];
} top = 0x04;
}
if(line0[x] < backdrop) { if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
color = line0[x]; color = lineOBJ[x];
top = 0x01; top = 0x10;
} }
if(r < (u8)(color >> 24)) {
if(r == li1){
color = line1[x];
top = 0x02;
}else if(r == li2){
color = line2[x];
top = 0x04;
}else if(r == li4){
color = lineOBJ[x];
top = 0x10;
}
}
if((top & 0x10) && (color & 0x00010000)) { if((top & 0x10) && (color & 0x00010000)) {
// semi-transparent OBJ // semi-transparent OBJ
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
u8 li0 = (u8)(line0[x]>>24); if((u8)(line0[x]>>24) < (u8)(back >> 24)) {
u8 li1 = (u8)(line1[x]>>24); back = line0[x];
u8 li2 = (u8)(line2[x]>>24); top2 = 0x01;
u8 r = (li1 < li0) ? (li1) : (li0); }
if(li2 < r) { if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
r = (li2); back = line1[x];
} top2 = 0x02;
}
if(r < (u8)(back >> 24)) { if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
if(r == li0){ back = line2[x];
back = line0[x]; top2 = 0x04;
top2 = 0x01; }
}else if(r == li1){
back = line1[x];
top2 = 0x02;
}else if(r == li2){
back = line2[x];
top2 = 0x04;
}
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -148,20 +113,9 @@ void mode1RenderLineNoWindow()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -193,37 +147,29 @@ void mode1RenderLineNoWindow()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
u8 li1 = (u8)(line1[x]>>24); if(line0[x] < color) {
u8 li2 = (u8)(line2[x]>>24); color = line0[x];
u8 li4 = (u8)(lineOBJ[x]>>24); top = 0x01;
}
u8 r = (li2 < li1) ? (li2) : (li1); if((u8)(line1[x]>>24) < (u8)(color >> 24)) {
color = line1[x];
top = 0x02;
}
if(li4 < r){ if((u8)(line2[x]>>24) < (u8)(color >> 24)) {
r = (li4); color = line2[x];
} top = 0x04;
}
if(line0[x] < backdrop) { if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
color = line0[x]; color = lineOBJ[x];
top = 0x01; top = 0x10;
} }
if(r < (u8)(color >> 24)) {
if(r == li1){
color = line1[x];
top = 0x02;
}else if(r == li2){
color = line2[x];
top = 0x04;
}else if(r == li4){
color = lineOBJ[x];
top = 0x10;
}
}
if(!(color & 0x00010000)) { if(!(color & 0x00010000)) {
switch((BLDMOD >> 6) & 3) { switch((BLDMOD >> 6) & 3) {
@ -234,26 +180,33 @@ void mode1RenderLineNoWindow()
if(top & BLDMOD) { if(top & BLDMOD) {
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((u8)(line0[x]>>24) < (u8)(back >> 24)) {
if(top != 0x01) {
back = line0[x];
top2 = 0x01;
}
}
if((top != 0x01) && (u8)(line0[x]>>24) < (u8)(back >> 24)) { if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
back = line0[x]; if(top != 0x02) {
top2 = 0x01; back = line1[x];
} top2 = 0x02;
}
}
if((top != 0x02) && (u8)(line1[x]>>24) < (u8)(back >> 24)) { if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
back = line1[x]; if(top != 0x04) {
top2 = 0x02; back = line2[x];
} top2 = 0x04;
}
}
if((top != 0x04) && (u8)(line2[x]>>24) < (u8)(back >> 24)) { if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
back = line2[x]; if(top != 0x10) {
top2 = 0x04; back = lineOBJ[x];
} top2 = 0x10;
}
if((top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { }
back = lineOBJ[x];
top2 = 0x10;
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -272,32 +225,24 @@ void mode1RenderLineNoWindow()
break; break;
} }
} else { } else {
// semi-transparent OBJ // semi-transparent OBJ
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
u8 li0 = (u8)(line0[x]>>24); if((u8)(line0[x]>>24) < (u8)(back >> 24)) {
u8 li1 = (u8)(line1[x]>>24); back = line0[x];
u8 li2 = (u8)(line2[x]>>24); top2 = 0x01;
}
u8 r = (li1 < li0) ? (li1) : (li0); if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
back = line1[x];
top2 = 0x02;
}
if(li2 < r) { if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
r = (li2); back = line2[x];
} top2 = 0x04;
}
if(r < (u8)(back >> 24)) {
if(r == li0){
back = line0[x];
top2 = 0x01;
}else if(r == li1){
back = line1[x];
top2 = 0x02;
}else if(r == li2){
back = line2[x];
top2 = 0x04;
}
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -328,20 +273,9 @@ void mode1RenderLineAll()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -399,7 +333,7 @@ void mode1RenderLineAll()
u8 inWin1Mask = WININ >> 8; u8 inWin1Mask = WININ >> 8;
u8 outMask = WINOUT & 0xFF; u8 outMask = WINOUT & 0xFF;
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
u8 mask = outMask; u8 mask = outMask;
@ -419,23 +353,22 @@ void mode1RenderLineAll()
} }
} }
// At the very least, move the inexpensive 'mask' operation up front if(line0[x] < color && (mask & 1)) {
if((mask & 1) && line0[x] < backdrop) {
color = line0[x]; color = line0[x];
top = 0x01; top = 0x01;
} }
if((mask & 2) && (u8)(line1[x]>>24) < (u8)(color >> 24)) { if((u8)(line1[x]>>24) < (u8)(color >> 24) && (mask & 2)) {
color = line1[x]; color = line1[x];
top = 0x02; top = 0x02;
} }
if((mask & 4) && (u8)(line2[x]>>24) < (u8)(color >> 24)) { if((u8)(line2[x]>>24) < (u8)(color >> 24) && (mask & 4)) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) { if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16)) {
color = lineOBJ[x]; color = lineOBJ[x];
top = 0x10; top = 0x10;
} }
@ -445,7 +378,7 @@ void mode1RenderLineAll()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 1) && (u8)(line0[x]>>24) < (u8)(backdrop >> 24)) { if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
} }
@ -487,24 +420,32 @@ void mode1RenderLineAll()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 1) && (top != 0x01) && (u8)(line0[x]>>24) < (u8)(backdrop >> 24)) { if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
if(top != 0x01) {
back = line0[x]; back = line0[x];
top2 = 0x01; top2 = 0x01;
}
} }
if((mask & 2) && (top != 0x02) && (u8)(line1[x]>>24) < (u8)(back >> 24)) { if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
if(top != 0x02) {
back = line1[x]; back = line1[x];
top2 = 0x02; top2 = 0x02;
}
} }
if((mask & 4) && (top != 0x04) && (u8)(line2[x]>>24) < (u8)(back >> 24)) { if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
}
} }
if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
}
} }
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))

View File

@ -1,11 +1,3 @@
/*
Mode 2 is a 256 colour tiled graphics mode which supports scaling and rotation.
There is no background layer 0 or 1 in this mode. Only background layers 2 and 3.
There are 256 tiles available.
It does not support flipping.
These routines only render a single line at a time, because of the way the GBA does events.
*/
#include "GBA.h" #include "GBA.h"
#include "Globals.h" #include "Globals.h"
#include "GBAGfx.h" #include "GBAGfx.h"
@ -15,20 +7,9 @@ void mode2RenderLine()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -62,51 +43,40 @@ void mode2RenderLine()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
u8 li2 = (u8)(line2[x]>>24);
u8 li3 = (u8)(line3[x]>>24);
u8 li4 = (u8)(lineOBJ[x]>>24);
u8 r = (li3 < li2) ? (li3) : (li2); if((u8)(line2[x]>>24) < (u8)(color >> 24)) {
color = line2[x];
top = 0x04;
}
if(li4 < r){ if((u8)(line3[x]>>24) < (u8)(color >> 24)) {
r = (li4); color = line3[x];
} top = 0x08;
}
if(r < (u8)(color >> 24)) { if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
if(r == li2){ color = lineOBJ[x];
color = line2[x]; top = 0x10;
top = 0x04; }
}else if(r == li3){
color = line3[x];
top = 0x08;
}else if(r == li4){
color = lineOBJ[x];
top = 0x10;
}
}
if((top & 0x10) && (color & 0x00010000)) { if((top & 0x10) && (color & 0x00010000)) {
// semi-transparent OBJ // semi-transparent OBJ
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
u8 li2 = (u8)(line2[x]>>24); if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
u8 li3 = (u8)(line3[x]>>24); back = line2[x];
u8 r = (li3 < li2) ? (li3) : (li2); top2 = 0x04;
}
if(r < (u8)(back >> 24)) { if((u8)(line3[x]>>24) < (u8)(back >> 24)) {
if(r == li2){ back = line3[x];
back = line2[x]; top2 = 0x08;
top2 = 0x04; }
}else if(r == li3){
back = line3[x];
top2 = 0x08;
}
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -138,20 +108,9 @@ void mode2RenderLineNoWindow()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -185,32 +144,25 @@ void mode2RenderLineNoWindow()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
u8 li2 = (u8)(line2[x]>>24);
u8 li3 = (u8)(line3[x]>>24);
u8 li4 = (u8)(lineOBJ[x]>>24);
u8 r = (li3 < li2) ? (li3) : (li2); if((u8)(line2[x]>>24) < (u8)(color >> 24)) {
color = line2[x];
top = 0x04;
}
if(li4 < r){ if((u8)(line3[x]>>24) < (u8)(color >> 24)) {
r = (li4); color = line3[x];
} top = 0x08;
}
if(r < (u8)(color >> 24)) { if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
if(r == li2){ color = lineOBJ[x];
color = line2[x]; top = 0x10;
top = 0x04; }
}else if(r == li3){
color = line3[x];
top = 0x08;
}else if(r == li4){
color = lineOBJ[x];
top = 0x10;
}
}
if(!(color & 0x00010000)) { if(!(color & 0x00010000)) {
switch((BLDMOD >> 6) & 3) { switch((BLDMOD >> 6) & 3) {
@ -222,20 +174,26 @@ void mode2RenderLineNoWindow()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((top != 0x04) && (u8)(line2[x]>>24) < (u8)(back >> 24)) { if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
back = line2[x]; if(top != 0x04) {
top2 = 0x04; back = line2[x];
top2 = 0x04;
}
} }
if((top != 0x08) && (u8)(line3[x]>>24) < (u8)(back >> 24)) { if((u8)(line3[x]>>24) < (u8)(back >> 24)) {
back = line3[x]; if(top != 0x08) {
top2 = 0x08; back = line3[x];
} top2 = 0x08;
}
}
if((top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
back = lineOBJ[x]; if(top != 0x10) {
top2 = 0x10; back = lineOBJ[x];
} top2 = 0x10;
}
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -258,19 +216,15 @@ void mode2RenderLineNoWindow()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
u8 li2 = (u8)(line2[x]>>24); if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
u8 li3 = (u8)(line3[x]>>24); back = line2[x];
u8 r = (li3 < li2) ? (li3) : (li2); top2 = 0x04;
}
if(r < (u8)(back >> 24)) { if((u8)(line3[x]>>24) < (u8)(back >> 24)) {
if(r == li2){ back = line3[x];
back = line2[x]; top2 = 0x08;
top2 = 0x04; }
}else if(r == li3){
back = line3[x];
top2 = 0x08;
}
}
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
@ -302,20 +256,9 @@ void mode2RenderLineAll()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -396,17 +339,17 @@ void mode2RenderLineAll()
} }
} }
if((mask & 4) && line2[x] < color) { if(line2[x] < color && (mask & 4)) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
if((mask & 8) && (u8)(line3[x]>>24) < (u8)(color >> 24)) { if((u8)(line3[x]>>24) < (u8)(color >> 24) && (mask & 8)) {
color = line3[x]; color = line3[x];
top = 0x08; top = 0x08;
} }
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) { if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16)) {
color = lineOBJ[x]; color = lineOBJ[x];
top = 0x10; top = 0x10;
} }
@ -453,19 +396,25 @@ void mode2RenderLineAll()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 4) && (top != 0x04) && line2[x] < back) { if((mask & 4) && line2[x] < back) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
}
} }
if((mask & 8) && (top != 0x08) && (u8)(line3[x]>>24) < (u8)(back >> 24)) { if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) {
if(top != 0x08) {
back = line3[x]; back = line3[x];
top2 = 0x08; top2 = 0x08;
}
} }
if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
}
} }
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))

View File

@ -1,10 +1,3 @@
/*
Mode 3 is a 15-bit (32768) colour bitmap graphics mode.
It has a single layer, background layer 2, the same size as the screen.
It doesn't support paging, scrolling, flipping, rotation or tiles.
These routines only render a single line at a time, because of the way the GBA does events.
*/
#include "GBA.h" #include "GBA.h"
#include "Globals.h" #include "Globals.h"
#include "GBAGfx.h" #include "GBAGfx.h"
@ -14,20 +7,9 @@ void mode3RenderLine()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -54,7 +36,7 @@ void mode3RenderLine()
background = ((customBackdropColor & 0x7FFF) | 0x30000000); background = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = background; u32 color = background;
u8 top = 0x20; u8 top = 0x20;
@ -73,7 +55,7 @@ void mode3RenderLine()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if(line2[x] < background) { if(line2[x] < back) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
@ -107,20 +89,9 @@ void mode3RenderLineNoWindow()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -147,11 +118,11 @@ void mode3RenderLineNoWindow()
background = ((customBackdropColor & 0x7FFF) | 0x30000000); background = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = background; u32 color = background;
u8 top = 0x20; u8 top = 0x20;
if(line2[x] < background) { if(line2[x] < color) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -171,14 +142,18 @@ void mode3RenderLineNoWindow()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if(top != 0x04 && (line2[x] < background) ) { if(line2[x] < back) {
back = line2[x]; if(top != 0x04) {
top2 = 0x04; back = line2[x];
top2 = 0x04;
}
} }
if(top != 0x10 && ((u8)(lineOBJ[x]>>24) < (u8)(back >> 24))) { if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
back = lineOBJ[x]; if(top != 0x10) {
top2 = 0x10; back = lineOBJ[x];
top2 = 0x10;
}
} }
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
@ -203,7 +178,7 @@ void mode3RenderLineNoWindow()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if(line2[x] < background) { if(line2[x] < back) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
@ -237,20 +212,9 @@ void mode3RenderLineAll()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x80) { if(DISPCNT & 0x80) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -304,7 +268,7 @@ void mode3RenderLineAll()
background = ((customBackdropColor & 0x7FFF) | 0x30000000); background = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = background; u32 color = background;
u8 top = 0x20; u8 top = 0x20;
u8 mask = outMask; u8 mask = outMask;
@ -324,7 +288,7 @@ void mode3RenderLineAll()
} }
} }
if((mask & 4) && line2[x] < background) { if((mask & 4) && (line2[x] < color)) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -339,7 +303,7 @@ void mode3RenderLineAll()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 4) && line2[x] < background) { if((mask & 4) && line2[x] < back) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
@ -370,20 +334,25 @@ void mode3RenderLineAll()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 4) && (top != 0x04) && line2[x] < back) { if((mask & 4) && line2[x] < back) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
}
} }
if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
}
} }
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
coeff[COLEV & 0x1F], coeff[COLEV & 0x1F],
coeff[(COLEV >> 8) & 0x1F]); coeff[(COLEV >> 8) & 0x1F]);
} }
} }
break; break;

View File

@ -1,10 +1,3 @@
/*
Mode 4 is a 256 colour bitmap graphics mode with 2 swappable pages.
It has a single layer, background layer 2, the same size as the screen.
It doesn't support scrolling, flipping, rotation or tiles.
These routines only render a single line at a time, because of the way the GBA does events.
*/
#include "GBA.h" #include "GBA.h"
#include "GBAGfx.h" #include "GBAGfx.h"
#include "Globals.h" #include "Globals.h"
@ -14,20 +7,9 @@ void mode4RenderLine()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x0080) { if(DISPCNT & 0x0080) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -53,11 +35,11 @@ void mode4RenderLine()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
if(line2[x] < backdrop) { if(line2[x] < color) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -72,7 +54,7 @@ void mode4RenderLine()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if(line2[x] < backdrop) { if(line2[x] < back) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
} }
@ -106,20 +88,9 @@ void mode4RenderLineNoWindow()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x0080) { if(DISPCNT & 0x0080) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -145,11 +116,11 @@ void mode4RenderLineNoWindow()
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000); backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
if(line2[x] < backdrop) { if(line2[x] < color) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -169,14 +140,18 @@ void mode4RenderLineNoWindow()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((top != 0x04) && line2[x] < backdrop) { if(line2[x] < back) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
}
} }
if((top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
}
} }
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
@ -235,20 +210,9 @@ void mode4RenderLineAll()
u16 *palette = (u16 *)paletteRAM; u16 *palette = (u16 *)paletteRAM;
if(DISPCNT & 0x0080) { if(DISPCNT & 0x0080) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -301,7 +265,7 @@ void mode4RenderLineAll()
u8 inWin1Mask = WININ >> 8; u8 inWin1Mask = WININ >> 8;
u8 outMask = WINOUT & 0xFF; u8 outMask = WINOUT & 0xFF;
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = backdrop; u32 color = backdrop;
u8 top = 0x20; u8 top = 0x20;
u8 mask = outMask; u8 mask = outMask;
@ -321,7 +285,7 @@ void mode4RenderLineAll()
} }
} }
if((mask & 4) && (line2[x] < backdrop)) { if((mask & 4) && (line2[x] < color)) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -367,20 +331,25 @@ void mode4RenderLineAll()
u32 back = backdrop; u32 back = backdrop;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 4) && (top != 0x04) && (line2[x] < backdrop)) { if((mask & 4) && line2[x] < back) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
}
} }
if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
}
} }
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
color = gfxAlphaBlend(color, back, color = gfxAlphaBlend(color, back,
coeff[COLEV & 0x1F], coeff[COLEV & 0x1F],
coeff[(COLEV >> 8) & 0x1F]); coeff[(COLEV >> 8) & 0x1F]);
} }
} }
break; break;

View File

@ -1,11 +1,3 @@
/*
Mode 5 is a low resolution (160x128) 15-bit colour bitmap graphics mode
with 2 swappable pages!
It has a single layer, background layer 2, lower resolution than the screen.
It doesn't support scrolling, flipping, rotation or tiles.
These routines only render a single line at a time, because of the way the GBA does events.
*/
#include "GBA.h" #include "GBA.h"
#include "Globals.h" #include "Globals.h"
#include "GBAGfx.h" #include "GBAGfx.h"
@ -13,20 +5,9 @@ These routines only render a single line at a time, because of the way the GBA d
void mode5RenderLine() void mode5RenderLine()
{ {
if(DISPCNT & 0x0080) { if(DISPCNT & 0x0080) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -55,11 +36,11 @@ void mode5RenderLine()
background = ((customBackdropColor & 0x7FFF) | 0x30000000); background = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = background; u32 color = background;
u8 top = 0x20; u8 top = 0x20;
if(line2[x] < background) { if(line2[x] < color) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -106,20 +87,9 @@ void mode5RenderLine()
void mode5RenderLineNoWindow() void mode5RenderLineNoWindow()
{ {
if(DISPCNT & 0x0080) { if(DISPCNT & 0x0080) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -148,11 +118,11 @@ void mode5RenderLineNoWindow()
background = ((customBackdropColor & 0x7FFF) | 0x30000000); background = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = background; u32 color = background;
u8 top = 0x20; u8 top = 0x20;
if(line2[x] < background) { if(line2[x] < color) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -172,14 +142,18 @@ void mode5RenderLineNoWindow()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if((top != 0x04) && line2[x] < background) { if(line2[x] < back) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
}
} }
if((top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
}
} }
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))
@ -236,19 +210,9 @@ void mode5RenderLineNoWindow()
void mode5RenderLineAll() void mode5RenderLineAll()
{ {
if(DISPCNT & 0x0080) { if(DISPCNT & 0x0080) {
for(int x = 0; x < 240; x++) {
int x = 232; //240 - 8 lineMix[x] = 0x7fff;
do{ }
lineMix[x ] =
lineMix[x+1] =
lineMix[x+2] =
lineMix[x+3] =
lineMix[x+4] =
lineMix[x+5] =
lineMix[x+6] =
lineMix[x+7] = 0x7fff;
x-=8;
}while(x>=0);
gfxLastVCOUNT = VCOUNT; gfxLastVCOUNT = VCOUNT;
return; return;
} }
@ -304,7 +268,7 @@ void mode5RenderLineAll()
background = ((customBackdropColor & 0x7FFF) | 0x30000000); background = ((customBackdropColor & 0x7FFF) | 0x30000000);
} }
for(int x = 0; x < 240; ++x) { for(int x = 0; x < 240; x++) {
u32 color = background; u32 color = background;
u8 top = 0x20; u8 top = 0x20;
u8 mask = outMask; u8 mask = outMask;
@ -324,7 +288,7 @@ void mode5RenderLineAll()
} }
} }
if((mask & 4) && (line2[x] < background)) { if((mask & 4) && (line2[x] < color)) {
color = line2[x]; color = line2[x];
top = 0x04; top = 0x04;
} }
@ -370,14 +334,18 @@ void mode5RenderLineAll()
u32 back = background; u32 back = background;
u8 top2 = 0x20; u8 top2 = 0x20;
if((mask & 4) && (top != 0x04) && (line2[x] < background)) { if((mask & 4) && line2[x] < back) {
if(top != 0x04) {
back = line2[x]; back = line2[x];
top2 = 0x04; top2 = 0x04;
}
} }
if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) { if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
if(top != 0x10) {
back = lineOBJ[x]; back = lineOBJ[x];
top2 = 0x10; top2 = 0x10;
}
} }
if(top2 & (BLDMOD>>8)) if(top2 & (BLDMOD>>8))

View File

@ -8,13 +8,21 @@
#include <time.h> #include <time.h>
#include <string.h> #include <string.h>
#include <stdio.h>
// Defined in VGA-GX input.cpp
void systemCartridgeRumble(bool);
enum RTCSTATE
{
IDLE = 0,
COMMAND,
DATA,
READDATA
};
u8 systemGetSensorDarkness(); u8 systemGetSensorDarkness();
int systemGetSensorZ(); int systemGetSensorZ();
enum RTCSTATE { IDLE, COMMAND, DATA, READDATA };
typedef struct { typedef struct {
u8 byte0; u8 byte0;
u8 byte1; u8 byte1;
@ -271,6 +279,17 @@ void rtcReset()
rtcClockData.reserved[11] = 0; rtcClockData.reserved[11] = 0;
} }
#ifdef __LIBRETRO__
void rtcSaveGame(u8 *&data)
{
utilWriteMem(data, &rtcClockData, sizeof(rtcClockData));
}
void rtcReadGame(const u8 *&data)
{
utilReadMem(&rtcClockData, data, sizeof(rtcClockData));
}
#else
void rtcSaveGame(gzFile gzFile) void rtcSaveGame(gzFile gzFile)
{ {
utilGzWrite(gzFile, &rtcClockData, sizeof(rtcClockData)); utilGzWrite(gzFile, &rtcClockData, sizeof(rtcClockData));
@ -280,3 +299,4 @@ void rtcReadGame(gzFile gzFile)
{ {
utilGzRead(gzFile, &rtcClockData, sizeof(rtcClockData)); utilGzRead(gzFile, &rtcClockData, sizeof(rtcClockData));
} }
#endif

View File

@ -8,7 +8,12 @@ void rtcEnableWarioRumble(bool);
bool rtcIsEnabled(); bool rtcIsEnabled();
void rtcReset(); void rtcReset();
#ifdef __LIBRETRO__
void rtcReadGame(const u8 *&data);
void rtcSaveGame(u8 *&data);
#else
void rtcReadGame(gzFile gzFile); void rtcReadGame(gzFile gzFile);
void rtcSaveGame(gzFile gzFile); void rtcSaveGame(gzFile gzFile);
#endif
#endif // RTC_H #endif // RTC_H

View File

@ -50,8 +50,8 @@ int soundTicks = SOUND_CLOCK_TICKS_;
static float soundVolume = 1.0f; static float soundVolume = 1.0f;
static int soundEnableFlag = 0x3ff; // emulator channels enabled static int soundEnableFlag = 0x3ff; // emulator channels enabled
static float soundFiltering_ = -1.0f; static float soundFiltering_ = -1;
static float soundVolume_ = -1.0f; static float soundVolume_ = -1;
void interp_rate() { /* empty for now */ } void interp_rate() { /* empty for now */ }
@ -82,8 +82,8 @@ public:
int readIndex; int readIndex;
int count; int count;
int writeIndex; int writeIndex;
int dac;
u8 fifo [32]; u8 fifo [32];
int dac;
private: private:
int timer; int timer;
@ -115,7 +115,7 @@ void Gba_Pcm::apply_control( int idx )
int ch = 0; int ch = 0;
if ( (soundEnableFlag >> idx & 0x100) && (ioMem [NR52] & 0x80) ) if ( (soundEnableFlag >> idx & 0x100) && (ioMem [NR52] & 0x80) )
ch = ioMem [SGCNT0_H+1] >> (idx <<2) & 3; ch = ioMem [SGCNT0_H+1] >> (idx * 4) & 3;
Blip_Buffer* out = 0; Blip_Buffer* out = 0;
switch ( ch ) switch ( ch )
@ -162,10 +162,11 @@ void Gba_Pcm::update( int dac )
int filter = 0; int filter = 0;
if ( soundInterpolation ) if ( soundInterpolation )
{ {
unsigned period = unsigned(time - last_time); // base filtering on how long since last sample was output
unsigned idx = period >> 9; int period = time - last_time;
if ( idx > 3 ) int idx = (unsigned) period / 512;
if ( idx >= 3 )
idx = 3; idx = 3;
static int const filters [4] = { 0, 0, 1, 2 }; static int const filters [4] = { 0, 0, 1, 2 };
@ -182,32 +183,28 @@ void Gba_Pcm_Fifo::timer_overflowed( int which_timer )
{ {
if ( which_timer == timer && enabled ) if ( which_timer == timer && enabled )
{ {
if ( count <= 16 ) /* Mother 3 fix, refined to not break Metroid Fusion */
if ( count == 16 || count == 0 )
{ {
// Need to fill FIFO // Need to fill FIFO
int saved_count = count;
CPUCheckDMA( 3, which ? 4 : 2 ); CPUCheckDMA( 3, which ? 4 : 2 );
if ( count <= 16 ) if ( saved_count == 0 && count == 16 )
CPUCheckDMA( 3, which ? 4 : 2 );
if ( count == 0 )
{ {
// Not filled by DMA, so fill with 16 bytes of silence // Not filled by DMA, so fill with 16 bytes of silence
int reg = which ? FIFOB_L : FIFOA_L; int reg = which ? FIFOB_L : FIFOA_L;
for ( int n = 8; n--; )
// No loops, yay! {
soundEvent(reg , (u16)0); soundEvent(reg , (u16)0);
soundEvent(reg+2, (u16)0); soundEvent(reg+2, (u16)0);
// }
soundEvent(reg , (u16)0);
soundEvent(reg+2, (u16)0);
//
soundEvent(reg , (u16)0);
soundEvent(reg+2, (u16)0);
//
soundEvent(reg , (u16)0);
soundEvent(reg+2, (u16)0);
} }
} }
// Read next sample from FIFO // Read next sample from FIFO
--count; count--;
dac = fifo [readIndex]; dac = fifo [readIndex];
readIndex = (readIndex + 1) & 31; readIndex = (readIndex + 1) & 31;
pcm.update( dac ); pcm.update( dac );
@ -287,17 +284,14 @@ static void apply_volume( bool apu_only = false )
if ( gb_apu ) if ( gb_apu )
{ {
static float const apu_vols [4] = { 0.25f, 0.5f, 1.0f, 0.25f }; static float const apu_vols [4] = { 0.25, 0.5, 1, 0.25 };
gb_apu->volume( soundVolume_ * apu_vols [ioMem [SGCNT0_H] & 3] ); gb_apu->volume( soundVolume_ * apu_vols [ioMem [SGCNT0_H] & 3] );
} }
if ( !apu_only ) if ( !apu_only )
{ {
double tmpVol = 0.002578125 * soundVolume_; // 0.66 / 256 * soundVolume_ for ( int i = 0; i < 3; i++ )
pcm_synth [i].volume( 0.66 / 256 * soundVolume_ );
pcm_synth[0].volume( tmpVol );
pcm_synth[1].volume( tmpVol );
pcm_synth[2].volume( tmpVol );
} }
} }
@ -358,14 +352,19 @@ static void end_frame( blip_time_t time )
void flush_samples(Multi_Buffer * buffer) void flush_samples(Multi_Buffer * buffer)
{ {
#ifdef __LIBRETRO__
int numSamples = buffer->read_samples( (blip_sample_t*) soundFinalWave, buffer->samples_avail() );
soundDriver->write(soundFinalWave, numSamples);
systemOnWriteDataToSoundBuffer(soundFinalWave, numSamples);
#else
// We want to write the data frame by frame to support legacy audio drivers // We want to write the data frame by frame to support legacy audio drivers
// that don't use the length parameter of the write method. // that don't use the length parameter of the write method.
// TODO: Update the Win32 audio drivers (DS, OAL, XA2), and flush all the // TODO: Update the Win32 audio drivers (DS, OAL, XA2), and flush all the
// samples at once to help reducing the audio delay on all platforms. // samples at once to help reducing the audio delay on all platforms.
int soundBufferLen = ( soundSampleRate / 60 ) << 2; int soundBufferLen = ( soundSampleRate / 60 ) * 4;
// soundBufferLen should have a whole number of sample pairs // soundBufferLen should have a whole number of sample pairs
assert( soundBufferLen % ((sizeof *soundFinalWave)<<1) == 0 ); assert( soundBufferLen % (2 * sizeof *soundFinalWave) == 0 );
// number of samples in output buffer // number of samples in output buffer
int const out_buf_size = soundBufferLen / sizeof *soundFinalWave; int const out_buf_size = soundBufferLen / sizeof *soundFinalWave;
@ -380,16 +379,15 @@ void flush_samples(Multi_Buffer * buffer)
soundDriver->write(soundFinalWave, soundBufferLen); soundDriver->write(soundFinalWave, soundBufferLen);
systemOnWriteDataToSoundBuffer(soundFinalWave, soundBufferLen); systemOnWriteDataToSoundBuffer(soundFinalWave, soundBufferLen);
} }
#endif
} }
static void apply_filtering() static void apply_filtering()
{ {
soundFiltering_ = soundFiltering; soundFiltering_ = soundFiltering;
// Yes, I changed soundFiltering_ to soundFiltering, the reason is int const base_freq = (int) (32768 - soundFiltering_ * 16384);
// to eliminate a write-read dependency int const nyquist = stereo_buffer->sample_rate() / 2;
int const base_freq = 32768 - (int) (soundFiltering * 16384.0f);
int const nyquist = stereo_buffer->sample_rate() >> 1;
for ( int i = 0; i < 3; i++ ) for ( int i = 0; i < 3; i++ )
{ {
@ -458,6 +456,13 @@ static void remake_stereo_buffer()
pcm [0].pcm.init(); pcm [0].pcm.init();
pcm [1].pcm.init(); pcm [1].pcm.init();
// APU
if ( !gb_apu )
{
gb_apu = new Gb_Apu; // TODO: handle out of memory
reset_apu();
}
// Stereo_Buffer // Stereo_Buffer
delete stereo_buffer; delete stereo_buffer;
stereo_buffer = 0; stereo_buffer = 0;
@ -471,13 +476,7 @@ static void remake_stereo_buffer()
pcm [1].which = 1; pcm [1].which = 1;
apply_filtering(); apply_filtering();
// APU // Volume Level
if ( !gb_apu )
{
gb_apu = new Gb_Apu; // TODO: handle out of memory
reset_apu();
}
apply_muting(); apply_muting();
apply_volume(); apply_volume();
} }
@ -596,8 +595,8 @@ static struct {
gb_apu_state_t apu; gb_apu_state_t apu;
// old state // old state
int soundDSBValue;
u8 soundDSAValue; u8 soundDSAValue;
int soundDSBValue;
} state; } state;
// Old GBA sound state format // Old GBA sound state format
@ -755,16 +754,25 @@ static void skip_read( gzFile in, int count )
} }
} }
#ifdef __LIBRETRO__
void soundSaveGame( u8 *&out )
#else
void soundSaveGame( gzFile out ) void soundSaveGame( gzFile out )
#endif
{ {
gb_apu->save_state( &state.apu ); gb_apu->save_state( &state.apu );
// Be sure areas for expansion get written as zero // Be sure areas for expansion get written as zero
memset( dummy_state, 0, sizeof dummy_state ); memset( dummy_state, 0, sizeof dummy_state );
#ifdef __LIBRETRO__
utilWriteDataMem( out, gba_state );
#else
utilWriteData( out, gba_state ); utilWriteData( out, gba_state );
#endif
} }
#ifndef __LIBRETRO__
static void soundReadGameOld( gzFile in, int version ) static void soundReadGameOld( gzFile in, int version )
{ {
// Read main data // Read main data
@ -799,19 +807,28 @@ static void soundReadGameOld( gzFile in, int version )
(void) utilReadInt( in ); // ignore quality (void) utilReadInt( in ); // ignore quality
} }
#endif
#include <stdio.h> #include <stdio.h>
#ifdef __LIBRETRO__
void soundReadGame(const u8*& in, int version )
#else
void soundReadGame( gzFile in, int version ) void soundReadGame( gzFile in, int version )
#endif
{ {
// Prepare APU and default state // Prepare APU and default state
reset_apu(); reset_apu();
gb_apu->save_state( &state.apu ); gb_apu->save_state( &state.apu );
if ( version > SAVE_GAME_VERSION_9 ) if ( version > SAVE_GAME_VERSION_9 )
#ifdef __LIBRETRO__
utilReadDataMem( in, gba_state );
#else
utilReadData( in, gba_state ); utilReadData( in, gba_state );
else else
soundReadGameOld( in, version ); soundReadGameOld( in, version );
#endif
gb_apu->load_state( state.apu ); gb_apu->load_state( state.apu );
write_SGCNT0_H( READ16LE( &ioMem [SGCNT0_H] ) & 0x770F ); write_SGCNT0_H( READ16LE( &ioMem [SGCNT0_H] ) & 0x770F );

View File

@ -74,8 +74,13 @@ extern int SOUND_CLOCK_TICKS; // Number of 16.8 MHz clocks between calls to so
extern int soundTicks; // Number of 16.8 MHz clocks until soundTick() will be called extern int soundTicks; // Number of 16.8 MHz clocks until soundTick() will be called
// Saves/loads emulator state // Saves/loads emulator state
#ifdef __LIBRETRO__
void soundSaveGame( u8 *& );
void soundReadGame(const u8*& in, int version );
#else
void soundSaveGame( gzFile ); void soundSaveGame( gzFile );
void soundReadGame( gzFile, int version ); void soundReadGame( gzFile, int version );
#endif
class Multi_Buffer; class Multi_Buffer;

View File

@ -1058,7 +1058,7 @@ void elfParseCFA(u8 *top)
if(id == 0xffffffff) { if(id == 0xffffffff) {
// skip version // skip version
*data++; (*data)++;
ELFcie *cie = (ELFcie *)calloc(1, sizeof(ELFcie)); ELFcie *cie = (ELFcie *)calloc(1, sizeof(ELFcie));

View File

@ -15,6 +15,7 @@
#include <ogcsys.h> #include <ogcsys.h>
#include <unistd.h> #include <unistd.h>
#include <wiiuse/wpad.h> #include <wiiuse/wpad.h>
#include <wupc/wupc.h>
#include <sys/iosupport.h> #include <sys/iosupport.h>
#ifdef HW_RVL #ifdef HW_RVL
@ -51,7 +52,8 @@ int ShutdownRequested = 0;
int ResetRequested = 0; int ResetRequested = 0;
int ExitRequested = 0; int ExitRequested = 0;
char appPath[1024] = { 0 }; char appPath[1024] = { 0 };
char loadedFile[1024] = { 0 };
/**************************************************************************** /****************************************************************************
* Shutdown / Reboot / Exit * Shutdown / Reboot / Exit
@ -341,6 +343,7 @@ int main(int argc, char *argv[])
SYS_SetPowerCallback(ShutdownCB); SYS_SetPowerCallback(ShutdownCB);
SYS_SetResetCallback(ResetCB); SYS_SetResetCallback(ResetCB);
WUPC_Init();
WPAD_Init(); WPAD_Init();
WPAD_SetPowerButtonCallback((WPADShutdownCallback)ShutdownCB); WPAD_SetPowerButtonCallback((WPADShutdownCallback)ShutdownCB);
DI_Init(); DI_Init();

View File

@ -16,7 +16,7 @@
#include "utils/FreeTypeGX.h" #include "utils/FreeTypeGX.h"
#define APPNAME "Visual Boy Advance GX" #define APPNAME "Visual Boy Advance GX"
#define APPVERSION "2.2.8" #define APPVERSION "2.3.3"
#define APPFOLDER "vbagx" #define APPFOLDER "vbagx"
#define PREF_FILE_NAME "settings.xml" #define PREF_FILE_NAME "settings.xml"
#define PAL_FILE_NAME "palettes.xml" #define PAL_FILE_NAME "palettes.xml"
@ -40,7 +40,8 @@ enum {
enum { enum {
FILE_SRAM, FILE_SRAM,
FILE_SNAPSHOT, FILE_SNAPSHOT,
FILE_ROM FILE_ROM,
FILE_BORDER_PNG
}; };
enum { enum {
@ -66,16 +67,20 @@ struct SGCSettings{
float gbaZoomVert; // GBA vertical zoom amount float gbaZoomVert; // GBA vertical zoom amount
float gbZoomHor; // GB horizontal zoom amount float gbZoomHor; // GB horizontal zoom amount
float gbZoomVert; // GB vertical zoom amount float gbZoomVert; // GB vertical zoom amount
int gbFixed;
int gbaFixed;
int AutoLoad; int AutoLoad;
int AutoSave; int AutoSave;
int LoadMethod; // For ROMS: Auto, SD, DVD, USB, Network (SMB) int LoadMethod; // For ROMS: Auto, SD, DVD, USB, Network (SMB)
int SaveMethod; // For SRAM, Freeze, Prefs: Auto, SD, USB, SMB int SaveMethod; // For SRAM, Freeze, Prefs: Auto, SD, USB, SMB
int AppendAuto; // 0 - no, 1 - yes
int videomode; // 0 - automatic, 1 - NTSC (480i), 2 - Progressive (480p), 3 - PAL (50Hz), 4 - PAL (60Hz) int videomode; // 0 - automatic, 1 - NTSC (480i), 2 - Progressive (480p), 3 - PAL (50Hz), 4 - PAL (60Hz)
int scaling; // 0 - default, 1 - partial stretch, 2 - stretch to fit, 3 - widescreen correction int scaling; // 0 - default, 1 - partial stretch, 2 - stretch to fit, 3 - widescreen correction
int render; // 0 - original, 1 - filtered, 2 - unfiltered int render; // 0 - original, 1 - filtered, 2 - unfiltered
int xshift; // video output shift int xshift; // video output shift
int yshift; int yshift;
int colorize; // colorize Mono Gameboy games int colorize; // colorize Mono Gameboy games
int gbaFrameskip; // turn on auto-frameskip for GBA games
int WiiControls; // Match Wii Game int WiiControls; // Match Wii Game
int WiimoteOrientation; int WiimoteOrientation;
int ExitAction; int ExitAction;
@ -83,15 +88,20 @@ struct SGCSettings{
int SFXVolume; int SFXVolume;
int Rumble; int Rumble;
int language; int language;
int OffsetMinutesUTC; // Used for clock on MBC3 and TAMA5
int GBHardware; // Mapped to gbEmulatorType in VBA
int SGBBorder;
char LoadFolder[MAXPATHLEN]; // Path to game files char LoadFolder[MAXPATHLEN]; // Path to game files
char LastFileLoaded[MAXPATHLEN]; //Last file loaded filename
char SaveFolder[MAXPATHLEN]; // Path to save files char SaveFolder[MAXPATHLEN]; // Path to save files
char CheatFolder[MAXPATHLEN]; // Path to cheat files char CheatFolder[MAXPATHLEN]; // Path to cheat files
char ScreenshotsFolder[MAXPATHLEN]; //Path to screenshots files
char BorderFolder[MAXPATHLEN]; // Path to Super Game Boy border files
char smbip[80]; char smbip[80];
char smbuser[20]; char smbuser[20];
char smbpwd[20]; char smbpwd[20];
char smbshare[20]; char smbshare[20];
}; };
void ExitApp(); void ExitApp();
void ShutdownWii(); void ShutdownWii();
bool SupportedIOS(u32 ios); bool SupportedIOS(u32 ios);
@ -102,7 +112,7 @@ extern int ConfigRequested;
extern int ShutdownRequested; extern int ShutdownRequested;
extern int ExitRequested; extern int ExitRequested;
extern char appPath[]; extern char appPath[];
extern char loadedFile[];
extern FreeTypeGX *fontSystem[]; extern FreeTypeGX *fontSystem[];
#endif #endif

View File

@ -16,6 +16,9 @@
#include <malloc.h> #include <malloc.h>
#include <ogc/lwp_watchdog.h> #include <ogc/lwp_watchdog.h>
#include <sys/stat.h>
#include <errno.h>
#include "vbagx.h" #include "vbagx.h"
#include "fileop.h" #include "fileop.h"
#include "filebrowser.h" #include "filebrowser.h"
@ -46,6 +49,9 @@
#include "vba/gb/gbCheats.h" #include "vba/gb/gbCheats.h"
#include "vba/gb/gbSound.h" #include "vba/gb/gbSound.h"
#include "goomba/goombarom.h"
#include "goomba/goombasav.h"
static u32 start; static u32 start;
int cartridgeType = 0; int cartridgeType = 0;
u32 RomIdCode; u32 RomIdCode;
@ -72,7 +78,7 @@ int systemGreenShift = 0;
int systemColorDepth = 0; int systemColorDepth = 0;
u16 systemGbPalette[24]; u16 systemGbPalette[24];
u16 systemColorMap16[0x10000]; u16 systemColorMap16[0x10000];
u32 *systemColorMap32 = NULL; u32 systemColorMap32[0x10000];
void gbSetPalette(u32 RRGGBB[]); void gbSetPalette(u32 RRGGBB[]);
bool StartColorizing(); bool StartColorizing();
@ -141,29 +147,36 @@ void system10Frames(int rate)
if (cartridgeType == 2) // GBA games require frameskipping if (cartridgeType == 2) // GBA games require frameskipping
{ {
// consider increasing skip if (!GCSettings.gbaFrameskip)
if(speed < 60) {
systemFrameSkip += 4;
else if(speed < 70)
systemFrameSkip += 3;
else if(speed < 80)
systemFrameSkip += 2;
else if(speed < 98)
++systemFrameSkip;
// consider decreasing skip
else if(speed > 185)
systemFrameSkip -= 3;
else if(speed > 145)
systemFrameSkip -= 2;
else if(speed > 125)
systemFrameSkip -= 1;
// correct invalid frame skip values
if(systemFrameSkip > 20)
systemFrameSkip = 20;
else if(systemFrameSkip < 0)
systemFrameSkip = 0; systemFrameSkip = 0;
}
else
{
// consider increasing skip
if(speed < 60)
systemFrameSkip += 4;
else if(speed < 70)
systemFrameSkip += 3;
else if(speed < 80)
systemFrameSkip += 2;
else if(speed < 98)
++systemFrameSkip;
// consider decreasing skip
else if(speed > 185)
systemFrameSkip -= 3;
else if(speed > 145)
systemFrameSkip -= 2;
else if(speed > 125)
systemFrameSkip -= 1;
// correct invalid frame skip values
if(systemFrameSkip > 20)
systemFrameSkip = 20;
else if(systemFrameSkip < 0)
systemFrameSkip = 0;
}
} }
lastTime = gettime(); lastTime = gettime();
} }
@ -268,6 +281,34 @@ bool LoadBatteryOrState(char * filepath, int action, bool silent)
// load the file into savebuffer // load the file into savebuffer
offset = LoadFile(filepath, silent); offset = LoadFile(filepath, silent);
if (cartridgeType == 1 && goomba_is_sram(savebuffer)) {
void* cleaned = goomba_cleanup(savebuffer);
if (savebuffer == NULL) {
ErrorPrompt(goomba_last_error());
offset = 0;
} else {
if (cleaned != savebuffer) {
memcpy(savebuffer, cleaned, GOOMBA_COLOR_SRAM_SIZE);
free(cleaned);
}
stateheader* sh = stateheader_for(savebuffer, RomTitle);
if (sh == NULL) {
ErrorPrompt(goomba_last_error());
offset = 0;
} else {
goomba_size_t outsize;
void* gbc_sram = goomba_extract(savebuffer, sh, &outsize);
if (gbc_sram == NULL) {
ErrorPrompt(goomba_last_error());
offset = 0;
} else {
memcpy(savebuffer, gbc_sram, outsize);
offset = outsize;
free(gbc_sram);
}
}
}
}
// load savebuffer into VBA memory // load savebuffer into VBA memory
if (offset > 0) if (offset > 0)
{ {
@ -319,6 +360,9 @@ bool LoadBatteryOrStateAuto(int action, bool silent)
if (LoadBatteryOrState(filepath, action, SILENT)) if (LoadBatteryOrState(filepath, action, SILENT))
return true; return true;
if (!GCSettings.AppendAuto)
return false;
// look for file with no number or Auto appended // look for file with no number or Auto appended
if(!MakeFilePath(filepath2, action, ROMFilename, -1)) if(!MakeFilePath(filepath2, action, ROMFilename, -1))
return false; return false;
@ -372,6 +416,41 @@ bool SaveBatteryOrState(char * filepath, int action, bool silent)
datasize = MemgbWriteBatteryFile((char *)savebuffer); datasize = MemgbWriteBatteryFile((char *)savebuffer);
else else
datasize = MemCPUWriteBatteryFile((char *)savebuffer); datasize = MemCPUWriteBatteryFile((char *)savebuffer);
if (cartridgeType == 1) {
const char* generic_goomba_error = "Cannot save SRAM in Goomba format (did not load correctly.)";
// check for goomba sram format
char* old_sram = (char*)malloc(GOOMBA_COLOR_SRAM_SIZE);
size_t br = LoadFile(old_sram, filepath, GOOMBA_COLOR_SRAM_SIZE, true);
if (br >= GOOMBA_COLOR_SRAM_SIZE && goomba_is_sram(old_sram)) {
void* cleaned = goomba_cleanup(old_sram);
if (cleaned == NULL) {
ErrorPrompt(generic_goomba_error);
datasize = 0;
} else {
if (cleaned != old_sram) {
free(old_sram);
old_sram = (char*)cleaned;
}
stateheader* sh = stateheader_for(old_sram, RomTitle);
if (sh == NULL) {
// Game probably doesn't use SRAM
datasize = 0;
} else {
void* new_sram = goomba_new_sav(old_sram, sh, savebuffer, datasize);
if (new_sram == NULL) {
ErrorPrompt(goomba_last_error());
datasize = 0;
} else {
memcpy(savebuffer, new_sram, GOOMBA_COLOR_SRAM_SIZE);
datasize = GOOMBA_COLOR_SRAM_SIZE;
free(new_sram);
}
}
}
}
free(old_sram);
}
} }
else else
{ {
@ -411,6 +490,30 @@ bool SaveBatteryOrStateAuto(int action, bool silent)
return SaveBatteryOrState(filepath, action, silent); return SaveBatteryOrState(filepath, action, silent);
} }
/****************************************************************************
* Save Screenshot / Preview image
***************************************************************************/
int SavePreviewImg(char * filepath, bool silent)
{
int device;
if(!FindDevice(filepath, &device))
return 0;
if(gameScreenPngSize > 0)
{
char screenpath[1024];
strcpy(screenpath, filepath);
screenpath[strlen(screenpath)] = 0;
sprintf(screenpath, "%s.png", screenpath);
SaveFile((char *)gameScreenPng, screenpath, gameScreenPngSize, silent);
}
if(!silent)
InfoPrompt ("Save successful");
return 1;
}
/**************************************************************************** /****************************************************************************
* Sound * Sound
@ -614,11 +717,14 @@ void systemUpdateMotionSensor()
****************************************************************************/ ****************************************************************************/
static int srcWidth = 0; static int srcWidth = 0;
static int srcHeight = 0; static int srcHeight = 0;
static int srcPitch = 0;
void systemDrawScreen() void systemDrawScreen()
{ {
GX_Render( srcWidth, srcHeight, pix, srcPitch ); GX_Render(
srcWidth,
srcHeight,
pix
);
} }
static bool ValidGameId(u32 id) static bool ValidGameId(u32 id)
@ -710,6 +816,8 @@ static void gbApplyPerImagePreferences()
RomIdCode = SWEP5; RomIdCode = SWEP5;
else if (strcmp(RomTitle, "SRJ DMG") == 0) else if (strcmp(RomTitle, "SRJ DMG") == 0)
RomIdCode = SWEP6; RomIdCode = SWEP6;
else if (strcmp(RomTitle, "KID DRACULA") == 0)
RomIdCode = KIDDRACULA;
} }
// look for matching palettes if a monochrome gameboy game // look for matching palettes if a monochrome gameboy game
// (or if a Super Gameboy game, but the palette will be ignored later in that case) // (or if a Super Gameboy game, but the palette will be ignored later in that case)
@ -825,11 +933,143 @@ void LoadPatch()
FreeSaveBuffer (); FreeSaveBuffer ();
} }
void SaveSGBBorderIfNoneExists(const void* buffer) {
char* borderPath = NULL;
FILE* f = NULL;
void* rgba8 = NULL;
IMGCTX pngContext = NULL;
int err;
struct stat s;
borderPath = AllocAndGetPNGBorderPath(NULL);
char* slash = strrchr(borderPath, '/');
*slash = '\0'; // cut string off at directory name
err = stat(borderPath, &s);
if (err == -1) goto cleanup;
if (!S_ISDIR(s.st_mode)) goto cleanup;
*slash = '/'; // restore slash, bring filename back
err = stat(borderPath, &s);
if (err != -1 || errno != ENOENT) goto cleanup;
f = fopen(borderPath, "wb");
if (!f) goto cleanup;
rgba8 = malloc(256*224*3);
if (!rgba8) goto cleanup;
pngContext = PNGU_SelectImageFromBuffer(rgba8);
if (pngContext == NULL) goto cleanup;
PNGU_EncodeFromLinearRGB565(pngContext, 256, 224, buffer, 258);
fwrite(rgba8, 1, 256*224*3, f);
cleanup:
if (borderPath) free(borderPath);
if (f) fclose(f);
if (rgba8) free(rgba8);
if (pngContext) PNGU_ReleaseImageContext(pngContext);
}
char* AllocAndGetPNGBorderPath(const char* title) {
const char* method = pathPrefix[GCSettings.LoadMethod];
const char* folder = GCSettings.BorderFolder;
char tmp[13];
// If no title was passed in, get the rom title
if (title == NULL) {
if (cartridgeType == 1) {
title = gb_get_title(gbRom, NULL);
} else if (cartridgeType == 2) {
memcpy(tmp, rom + 0xA0, 12);
tmp[12] = '\0';
title = tmp;
}
}
size_t length = strlen(method) + strlen(folder) + strlen(title) + 6;
char* path = (char*)malloc(length);
if (path) sprintf(path, "%s%s/%s.png", method, folder, title);
return path;
}
void LoadPNGBorder(const char* fallback)
{
void* png_tmp_buf = malloc(1024*1024);
char* borderPath = AllocAndGetPNGBorderPath(NULL);
PNGUPROP imgProp;
IMGCTX ctx = NULL;
char error[1024]; error[1023] = 0;
int r;
bool borderLoaded = LoadFile((char*)png_tmp_buf, borderPath, 1024*1024, SILENT);
if (!borderLoaded) {
// Try default border.png
free(borderPath);
borderPath = AllocAndGetPNGBorderPath(fallback);
borderLoaded = LoadFile((char*)png_tmp_buf, borderPath, 1024*1024, SILENT);
}
if (!borderLoaded) goto cleanup;
ctx = PNGU_SelectImageFromBuffer(png_tmp_buf);
if (ctx == NULL) {
snprintf(error, 1023, "Error reading %s", borderPath);
ErrorPrompt(error);
goto cleanup;
}
r = PNGU_GetImageProperties(ctx, &imgProp);
if (r != PNGU_OK) {
snprintf(error, 1023, "PNGU properties error (%d): %s", r, borderPath);
ErrorPrompt(error);
goto cleanup;
}
if (imgProp.imgWidth > 640 || imgProp.imgHeight > 480) {
snprintf(error, 1023, "Wrong size (should be 640x480 or smaller): %s", borderPath);
ErrorPrompt(error);
goto cleanup;
}
InitialBorder = (u16*)malloc(640*480*2);
r = PNGU_DecodeTo4x4RGB565 (ctx, imgProp.imgWidth, imgProp.imgHeight, InitialBorder);
if (r != PNGU_OK) {
snprintf(error, 1023, "PNGU decoding error (%d): %s", r, borderPath);
ErrorPrompt(error);
free(InitialBorder);
InitialBorder = NULL;
goto cleanup;
}
InitialBorderWidth = imgProp.imgWidth;
InitialBorderHeight = imgProp.imgHeight;
cleanup:
if (png_tmp_buf) free(png_tmp_buf);
if (borderPath) free(borderPath);
if (ctx) PNGU_ReleaseImageContext(ctx);
}
extern bool gbUpdateSizes(); extern bool gbUpdateSizes();
bool LoadGBROM() bool LoadGBROM()
{ {
gbRom = (u8 *)malloc(1024*1024*4); // allocate 4 MB to GB ROM gbEmulatorType = GCSettings.GBHardware;
if (browserList[browser.selIndex].length > 1024*1024*8) {
InfoPrompt("ROM size is too large (> 8 MB)");
return false;
}
gbRom = (u8 *)malloc(1024*1024*8); // 32 MB is too much for sure
if (!gbRom) {
InfoPrompt("Unable to allocate 8 MB of memory");
return false;
}
bios = (u8 *)calloc(1,0x100); bios = (u8 *)calloc(1,0x100);
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
@ -848,16 +1088,51 @@ bool LoadGBROM()
gbRomSize = LoadSzFile(szpath, (unsigned char *)gbRom); gbRomSize = LoadSzFile(szpath, (unsigned char *)gbRom);
} }
const void* firstRom = gb_first_rom(gbRom, gbRomSize);
const void* secondRom = gb_next_rom(gbRom, gbRomSize, firstRom);
if (firstRom != NULL && firstRom != gbRom) {
char msgbuf[32];
const void* rom;
for (rom = firstRom; rom != NULL; rom = gb_next_rom(gbRom, gbRomSize, rom)) {
sprintf(msgbuf, "Load %s?", gb_get_title(rom, NULL));
if (secondRom == NULL || YesNoPrompt(msgbuf, true)) {
gbRomSize = gb_rom_size(rom);
memmove(gbRom, rom, gbRomSize);
break;
}
}
if (rom == NULL) {
InfoPrompt("No more ROMs found in the file.");
return false;
}
}
if (GCSettings.SGBBorder == 2) LoadPNGBorder("default");
if(gbRomSize <= 0) if(gbRomSize <= 0)
return false; return false;
return gbUpdateSizes(); return gbUpdateSizes();
} }
bool utilIsZipFile(const char* file)
{
if(strlen(file) > 4)
{
char * p = strrchr(file,'.');
if(p != NULL)
{
if(strcasecmp(p, ".zip") == 0)
return true;
}
}
return false;
}
bool LoadVBAROM() bool LoadVBAROM()
{ {
cartridgeType = 0; cartridgeType = 0;
bool loaded = false; int loaded = 0;
// image type (checks file extension) // image type (checks file extension)
if(utilIsGBAImage(browserList[browser.selIndex].filename)) if(utilIsGBAImage(browserList[browser.selIndex].filename))
@ -907,49 +1182,57 @@ bool LoadVBAROM()
srcWidth = 0; srcWidth = 0;
srcHeight = 0; srcHeight = 0;
srcPitch = 0;
VMClose(); // cleanup GBA memory VMClose(); // cleanup GBA memory
gbCleanUp(); // cleanup GB memory gbCleanUp(); // cleanup GB memory
switch(cartridgeType) if (InitialBorder != NULL) {
free(InitialBorder);
InitialBorder = NULL;
}
SGBBorderLoadedFromGame = false; // don't try to copy sgb border from game to png unless we're in sgb mode
if(cartridgeType == 2)
{ {
case 2: emulator = GBASystem;
emulator = GBASystem; srcWidth = 240;
srcWidth = 240; srcHeight = 160;
srcHeight = 160; loaded = VMCPULoadROM();
loaded = VMCPULoadROM(); soundSetSampleRate(22050); //44100 / 2
srcPitch = 484; cpuSaveType = 0;
soundSetSampleRate(22050); //44100 / 2 if (loaded == 2) {
cpuSaveType = 0; loaded = 0;
break; cartridgeType = 1;
} else if (loaded == 1 && GCSettings.SGBBorder == 2) {
LoadPNGBorder("defaultgba");
}
}
case 1: if (cartridgeType == 1)
emulator = GBSystem; {
emulator = GBSystem;
gbBorderOn = (GCSettings.SGBBorder == 1);
gbBorderOn = 0; // GB borders always off if(gbBorderOn)
{
srcWidth = 256;
srcHeight = 224;
gbBorderLineSkip = 256;
gbBorderColumnSkip = 48;
gbBorderRowSkip = 40;
SGBBorderLoadedFromGame = false; // try to load the border during rendering
}
else
{
srcWidth = 160;
srcHeight = 144;
gbBorderLineSkip = 160;
gbBorderColumnSkip = 0;
gbBorderRowSkip = 0;
}
if(gbBorderOn) loaded = LoadGBROM();
{ soundSetSampleRate(44100);
srcWidth = 256;
srcHeight = 224;
gbBorderLineSkip = 256;
gbBorderColumnSkip = 48;
gbBorderRowSkip = 40;
}
else
{
srcWidth = 160;
srcHeight = 144;
gbBorderLineSkip = 160;
gbBorderColumnSkip = 0;
gbBorderRowSkip = 0;
}
loaded = LoadGBROM();
srcPitch = 324;
soundSetSampleRate(44100);
break;
} }
if(!loaded) if(!loaded)
@ -960,7 +1243,11 @@ bool LoadVBAROM()
else else
{ {
// Setup GX // Setup GX
GX_Render_Init(srcWidth, srcHeight); if (InitialBorder) {
GX_Render_Init(InitialBorderWidth, InitialBorderHeight);
} else {
GX_Render_Init(srcWidth, srcHeight);
}
if (cartridgeType == 1) if (cartridgeType == 1)
{ {
@ -1023,9 +1310,9 @@ void InitialisePalette()
// Build GBPalette // Build GBPalette
for( i = 0; i < 24; ) for( i = 0; i < 24; )
{ {
systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10); systemGbPalette[i++] = (0x1c) | (0x1e << 5) | (0x1c << 10);
systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10); systemGbPalette[i++] = (0x10) | (0x17 << 5) | (0x0b << 10);
systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10); systemGbPalette[i++] = (0x27) | (0x0c << 5) | (0x0a << 10);
systemGbPalette[i++] = 0; systemGbPalette[i++] = 0;
} }
// Set palette etc - Fixed to RGB565 // Set palette etc - Fixed to RGB565

View File

@ -28,5 +28,6 @@ bool LoadBatteryOrState(char * filepath, int action, bool silent);
bool LoadBatteryOrStateAuto(int action, bool silent); bool LoadBatteryOrStateAuto(int action, bool silent);
bool SaveBatteryOrState(char * filepath, int action, bool silent); bool SaveBatteryOrState(char * filepath, int action, bool silent);
bool SaveBatteryOrStateAuto(int action, bool silent); bool SaveBatteryOrStateAuto(int action, bool silent);
bool SavePreviewImg (char * filepath, bool silent);
#endif #endif

View File

@ -11,6 +11,7 @@
#include <gccore.h> #include <gccore.h>
#include <ogcsys.h> #include <ogcsys.h>
#include <ogc/machine/processor.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -19,6 +20,7 @@
#include "vbagx.h" #include "vbagx.h"
#include "menu.h" #include "menu.h"
#include "input.h" #include "input.h"
#include "vbasupport.h"
s32 CursorX, CursorY; s32 CursorX, CursorY;
bool CursorVisible; bool CursorVisible;
@ -41,6 +43,11 @@ int gameScreenPngSize = 0;
int screenheight = 480; int screenheight = 480;
int screenwidth = 640; int screenwidth = 640;
u16 *InitialBorder = NULL;
int InitialBorderWidth = 0;
int InitialBorderHeight = 0;
bool SGBBorderLoadedFromGame = false;
/*** 3D GX ***/ /*** 3D GX ***/
#define DEFAULT_FIFO_SIZE ( 256 * 1024 ) #define DEFAULT_FIFO_SIZE ( 256 * 1024 )
static u8 gp_fifo[DEFAULT_FIFO_SIZE] ATTRIBUTE_ALIGN(32); static u8 gp_fifo[DEFAULT_FIFO_SIZE] ATTRIBUTE_ALIGN(32);
@ -160,7 +167,7 @@ static inline void draw_init(void)
GX_InitTexObj(&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, GX_InitTexObj(&texobj, texturemem, vwidth, vheight, GX_TF_RGB565,
GX_CLAMP, GX_CLAMP, GX_FALSE); GX_CLAMP, GX_CLAMP, GX_FALSE);
if (!(GCSettings.render&1)) if (GCSettings.render == 2)
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,2.5,9.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1); // original/unfiltered video mode: force texture filtering OFF GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,2.5,9.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1); // original/unfiltered video mode: force texture filtering OFF
} }
@ -246,7 +253,7 @@ static inline void draw_cursor(Mtx v)
GX_InitTexObj(&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, GX_InitTexObj(&texobj, texturemem, vwidth, vheight, GX_TF_RGB565,
GX_CLAMP, GX_CLAMP, GX_FALSE); GX_CLAMP, GX_CLAMP, GX_FALSE);
if (!(GCSettings.render&1)) if (GCSettings.render == 2)
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,2.5,9.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1); // original/unfiltered video mode: force texture filtering OFF GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,2.5,9.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1); // original/unfiltered video mode: force texture filtering OFF
} }
#endif #endif
@ -290,6 +297,12 @@ static GXRModeObj * FindVideoMode()
case 4: // PAL (60Hz) case 4: // PAL (60Hz)
mode = &TVEurgb60Hz480IntDf; mode = &TVEurgb60Hz480IntDf;
break; break;
case 5: // NTSC (240p)
mode = &TVNtsc240Ds;
break;
case 6: // PAL (60Hz 240p)
mode = &TVEurgb60Hz240Ds;
break;
default: default:
mode = VIDEO_GetPreferredMode(NULL); mode = VIDEO_GetPreferredMode(NULL);
@ -316,7 +329,7 @@ static GXRModeObj * FindVideoMode()
if (mode == &TVPal576IntDfScale) if (mode == &TVPal576IntDfScale)
pal = true; pal = true;
if (CONF_GetAspectRatio() == CONF_ASPECT_16_9) /*if (CONF_GetAspectRatio() == CONF_ASPECT_16_9 && mode->xfbHeight != 240)
{ {
if (pal) if (pal)
{ {
@ -334,9 +347,9 @@ static GXRModeObj * FindVideoMode()
mode->efbHeight = 456; mode->efbHeight = 456;
mode->viWidth = 686; mode->viWidth = 686;
} }
else else*/
{ {
mode->viWidth = 672; mode->viWidth = 704;
} }
if (pal) if (pal)
@ -453,10 +466,7 @@ static inline void UpdateScaling()
TvAspectRatio = 4.0f/3.0f; TvAspectRatio = 4.0f/3.0f;
#endif #endif
if (vwidth == 240) // GBA GameboyAspectRatio = ((vwidth * 1.0) / vheight);
GameboyAspectRatio = 240.0f/160.0f; // assumes square pixels on GB Advance
else // GB or GBC
GameboyAspectRatio = 160.0f/144.0f; // assumes square pixels on GB Colour
if (TvAspectRatio>GameboyAspectRatio) if (TvAspectRatio>GameboyAspectRatio)
{ {
@ -476,17 +486,37 @@ static inline void UpdateScaling()
} }
// change zoom // change zoom
if (vwidth == 240) // GBA float zoomHor, zoomVert;
int fixed;
if (cartridgeType == 2) // GBA
{ {
xscale *= GCSettings.gbaZoomHor; zoomHor = GCSettings.gbaZoomHor;
yscale *= GCSettings.gbaZoomVert; zoomVert = GCSettings.gbaZoomVert;
fixed = GCSettings.gbaFixed;
} }
else else
{ {
xscale *= GCSettings.gbZoomHor; zoomHor = GCSettings.gbZoomHor;
yscale *= GCSettings.gbZoomVert; zoomVert = GCSettings.gbZoomVert;
fixed = GCSettings.gbFixed;
} }
if (fixed) {
xscale = 320;
yscale = 240;
} else {
xscale *= zoomHor;
yscale *= zoomVert;
}
#ifdef HW_RVL
if (fixed && CONF_GetAspectRatio() == CONF_ASPECT_16_9 && (*(u32*)(0xCD8005A0) >> 16) == 0xCAFE) // Wii U
{
/* vWii widescreen patch by tueidj */
write32(0xd8006a0, fixed ? 0x30000002 : 0x30000004), mask32(0xd8006a8, 0, 2);
}
#endif
// Set new aspect // Set new aspect
square[0] = square[9] = -xscale + GCSettings.xshift; square[0] = square[9] = -xscale + GCSettings.xshift;
square[3] = square[6] = xscale + GCSettings.xshift; square[3] = square[6] = xscale + GCSettings.xshift;
@ -498,7 +528,23 @@ static inline void UpdateScaling()
memset(&view, 0, sizeof(Mtx)); memset(&view, 0, sizeof(Mtx));
guLookAt(view, &cam.pos, &cam.up, &cam.view); guLookAt(view, &cam.pos, &cam.up, &cam.view);
GX_SetViewport(0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1); if (fixed) {
int ratio = fixed % 10;
bool widescreen = fixed / 10;
float vw = vwidth * ratio;
if (widescreen) vw /= 4.0 / 3.0;
float vh = vheight * ratio;
// 240p adjustment
if (GCSettings.videomode == 5 || GCSettings.videomode == 6) vw *= 2;
float vx = (vmode->fbWidth - vw) / 2;
float vy = (vmode->efbHeight - vh) / 2;
GX_SetViewport(vx, vy, vw, vh, 0, 1);
} else {
GX_SetViewport(0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1);
}
updateScaling = 0; updateScaling = 0;
} }
@ -523,7 +569,13 @@ ResetVideo_Emu ()
GX_SetDispCopySrc (0, 0, rmode->fbWidth, rmode->efbHeight); GX_SetDispCopySrc (0, 0, rmode->fbWidth, rmode->efbHeight);
GX_SetDispCopyDst (rmode->fbWidth, rmode->xfbHeight); GX_SetDispCopyDst (rmode->fbWidth, rmode->xfbHeight);
GX_SetCopyFilter (rmode->aa, rmode->sample_pattern, (GCSettings.render == 1) ? GX_TRUE : GX_FALSE, rmode->vfilter); // deflickering filter only for filtered mode u8 sharp[7] = {0,0,21,22,21,0,0};
u8 soft[7] = {8,8,10,12,10,8,8};
u8* vfilter =
GCSettings.render == 3 ? sharp
: GCSettings.render == 4 ? soft
: rmode->vfilter;
GX_SetCopyFilter (rmode->aa, rmode->sample_pattern, (GCSettings.render != 2) ? GX_TRUE : GX_FALSE, vfilter); // deflickering filter only for filtered mode
GX_SetFieldMode (rmode->field_rendering, ((rmode->viHeight == 2 * rmode->xfbHeight) ? GX_ENABLE : GX_DISABLE)); GX_SetFieldMode (rmode->field_rendering, ((rmode->viHeight == 2 * rmode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
@ -542,7 +594,7 @@ ResetVideo_Emu ()
// reinitialize texture // reinitialize texture
GX_InvalidateTexAll (); GX_InvalidateTexAll ();
GX_InitTexObj (&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE); // initialize the texture obj we are going to use GX_InitTexObj (&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE); // initialize the texture obj we are going to use
if (!(GCSettings.render&1)) if (GCSettings.render == 2)
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,2.5,9.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1); // original/unfiltered video mode: force texture filtering OFF GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,2.5,9.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1); // original/unfiltered video mode: force texture filtering OFF
GX_Flush(); GX_Flush();
@ -569,26 +621,55 @@ void GX_Render_Init(int width, int height)
vheight = height; vheight = height;
} }
bool borderAreaEmpty(const u16* buffer) {
u16 reference = buffer[0];
for (int y=0; y<40; y++) {
for (int x=0; x<256; x++) {
if (buffer[258*y + x] != reference) return false;
}
}
for (int y=40; y<184; y++) {
for (int x=0; x<48; x++) {
if (buffer[258*y + x] != reference) return false;
}
for (int x=208; x<224; x++) {
if (buffer[258*y + x] != reference) return false;
}
}
for (int y=184; y<224; y++) {
for (int x=0; x<256; x++) {
if (buffer[258*y + x] != reference) return false;
}
}
return true;
}
/**************************************************************************** /****************************************************************************
* GX_Render * GX_Render
* *
* Pass in a buffer, width and height to update as a tiled RGB565 texture * Pass in a buffer, width and height to update as a tiled RGB565 texture
* (2 bytes per pixel)
****************************************************************************/ ****************************************************************************/
void GX_Render(int width, int height, u8 * buffer, int pitch) void GX_Render(int gbWidth, int gbHeight, u8 * buffer)
{ {
int borderWidth = InitialBorder ? InitialBorderWidth : gbWidth;
int borderHeight = InitialBorder ? InitialBorderHeight : gbHeight;
int h, w; int h, w;
long long int *dst = (long long int *) texturemem; int gbPitch = gbWidth * 2 + 4;
long long int *dst = (long long int *) texturemem; // Pointer in 8-byte units / 4-pixel units
long long int *src1 = (long long int *) buffer; long long int *src1 = (long long int *) buffer;
long long int *src2 = (long long int *) (buffer + pitch); long long int *src2 = (long long int *) (buffer + gbPitch);
long long int *src3 = (long long int *) (buffer + (pitch << 1)); long long int *src3 = (long long int *) (buffer + (gbPitch << 1));
long long int *src4 = (long long int *) (buffer + (pitch * 3)); long long int *src4 = (long long int *) (buffer + (gbPitch * 3));
int rowpitch = (pitch >> 3) * 3; int srcrowpitch = (gbPitch >> 3) * 3;
int rowadjust = ( pitch % 8 ) << 2; int srcrowadjust = ( gbPitch % 8 ) << 2;
int dstrowpitch = borderWidth - gbWidth;
vwidth = width; vwidth = borderWidth;
vheight = height; vheight = borderHeight;
int vwid2 = (vwidth >> 2); int vwid2 = (gbWidth >> 2);
char *ra = NULL; char *ra = NULL;
// Ensure previous vb has complete // Ensure previous vb has complete
@ -606,7 +687,26 @@ void GX_Render(int width, int height, u8 * buffer, int pitch)
GX_SetTevOp(GX_TEVSTAGE0, GX_DECAL); GX_SetTevOp(GX_TEVSTAGE0, GX_DECAL);
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
for (h = 0; h < vheight; h += 4) if (gbWidth == 256 && gbHeight == 224 && !SGBBorderLoadedFromGame) {
if (borderAreaEmpty((u16*)buffer)) {
// TODO: don't paint empty SGB border
} else {
// don't try to load the default border anymore
SGBBorderLoadedFromGame = true;
SaveSGBBorderIfNoneExists(buffer);
}
}
// The InitialBorder, if any, should already be properly tiled
if (InitialBorder) {
memcpy(dst, InitialBorder, borderWidth * borderHeight * 2);
int rows_to_skip = (borderHeight - gbHeight) / 2;
if (rows_to_skip > 0) dst += rows_to_skip * borderWidth / 4;
dst += (borderWidth - gbWidth) / 2;
}
for (h = 0; h < gbHeight; h += 4)
{ {
for (w = 0; w < vwid2; ++w) for (w = 0; w < vwid2; ++w)
{ {
@ -616,21 +716,22 @@ void GX_Render(int width, int height, u8 * buffer, int pitch)
*dst++ = *src4++; *dst++ = *src4++;
} }
src1 += rowpitch; src1 += srcrowpitch;
src2 += rowpitch; src2 += srcrowpitch;
src3 += rowpitch; src3 += srcrowpitch;
src4 += rowpitch; src4 += srcrowpitch;
dst += dstrowpitch;
if ( rowadjust ) if ( srcrowadjust )
{ {
ra = (char *)src1; ra = (char *)src1;
src1 = (long long int *)(ra + rowadjust); src1 = (long long int *)(ra + srcrowadjust);
ra = (char *)src2; ra = (char *)src2;
src2 = (long long int *)(ra + rowadjust); src2 = (long long int *)(ra + srcrowadjust);
ra = (char *)src3; ra = (char *)src3;
src3 = (long long int *)(ra + rowadjust); src3 = (long long int *)(ra + srcrowadjust);
ra = (char *)src4; ra = (char *)src4;
src4 = (long long int *)(ra + rowadjust); src4 = (long long int *)(ra + srcrowadjust);
} }
} }
@ -690,6 +791,14 @@ void TakeScreenshot()
void void
ResetVideo_Menu () ResetVideo_Menu ()
{ {
#ifdef HW_RVL
if (CONF_GetAspectRatio() == CONF_ASPECT_16_9 && (*(u32*)(0xCD8005A0) >> 16) == 0xCAFE) // Wii U
{
/* vWii widescreen patch by tueidj */
write32(0xd8006a0, 0x30000004), mask32(0xd8006a8, 0, 2);
}
#endif
Mtx44 p; Mtx44 p;
f32 yscale; f32 yscale;
u32 xfbHeight; u32 xfbHeight;

View File

@ -16,7 +16,7 @@
void InitializeVideo (); void InitializeVideo ();
void GX_Render_Init(int width, int height); void GX_Render_Init(int width, int height);
void GX_Render(int width, int height, u8 * buffer, int pitch); void GX_Render(int gbWidth, int gbHeight, u8 * buffer);
void StopGX(); void StopGX();
void ResetVideo_Emu(); void ResetVideo_Emu();
void ResetVideo_Menu(); void ResetVideo_Menu();
@ -38,4 +38,11 @@ extern u8 * gameScreenPng;
extern int gameScreenPngSize; extern int gameScreenPngSize;
extern u32 FrameTimer; extern u32 FrameTimer;
char *AllocAndGetPNGBorderPath(const char* title);
void SaveSGBBorderIfNoneExists(const void* buffer);
extern u16 *InitialBorder;
extern int InitialBorderWidth;
extern int InitialBorderHeight;
extern bool SGBBorderLoadedFromGame;
#endif #endif

View File

@ -25,6 +25,7 @@
#include "vba/gba/Globals.h" #include "vba/gba/Globals.h"
#include "vba/Util.h" #include "vba/Util.h"
#include "vba/common/Port.h" #include "vba/common/Port.h"
#include "goomba/goombarom.h"
#define MEM_BAD 0xff #define MEM_BAD 0xff
#define MEM_VM 0x01 #define MEM_VM 0x01
@ -152,10 +153,9 @@ static void VMAllocGBA( void )
* MEM2 version of GBA CPULoadROM * MEM2 version of GBA CPULoadROM
****************************************************************************/ ****************************************************************************/
bool VMCPULoadROM() int VMCPULoadROM()
{ {
VMClose(); VMClose();
VMAllocGBA();
GBAROMSize = 0; GBAROMSize = 0;
if(!inSz) if(!inSz)
@ -163,7 +163,7 @@ bool VMCPULoadROM()
char filepath[1024]; char filepath[1024];
if(!MakeFilePath(filepath, FILE_ROM)) if(!MakeFilePath(filepath, FILE_ROM))
return false; return 0;
GBAROMSize = LoadFile ((char *)rom, filepath, browserList[browser.selIndex].length, NOTSILENT); GBAROMSize = LoadFile ((char *)rom, filepath, browserList[browser.selIndex].length, NOTSILENT);
} }
@ -172,17 +172,26 @@ bool VMCPULoadROM()
GBAROMSize = LoadSzFile(szpath, (unsigned char *)rom); GBAROMSize = LoadSzFile(szpath, (unsigned char *)rom);
} }
if(gb_first_rom(rom, GBAROMSize)) {
int r = YesNoPrompt("This file contains uncompressed Game Boy (Color) ROMs. Do you want to run these?", true);
if (r) {
return 2;
}
}
VMAllocGBA();
if(GBAROMSize) if(GBAROMSize)
{ {
flashInit(); flashInit();
eepromInit(); eepromInit();
CPUUpdateRenderBuffers( true ); CPUUpdateRenderBuffers( true );
return true; return 1;
} }
else else
{ {
VMClose(); VMClose();
return false; return 0;
} }
} }
#else #else

View File

@ -11,7 +11,7 @@
#ifndef __VBAVMHDR__ #ifndef __VBAVMHDR__
#define __VBAVMHDR__ #define __VBAVMHDR__
bool VMCPULoadROM(); int VMCPULoadROM();
void VMClose(); void VMClose();
#ifdef USE_VM #ifdef USE_VM

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<app version="2.2.8"> <app version="2.2.8">
<file url="http://vba-wii.googlecode.com/files/Visual%20Boy%20Advance%20GX%202.2.8.zip"></file> <file url="http://github.com/dborth/vba-wii/releases/download/2.2.8/Visual.Boy.Advance.GX.2.2.8.zip"></file>
</app> </app>