LINK: Add AdaMN's work for reference

git-svn-id: https://svn.code.sf.net/p/vbam/code/branches/adamn-link@1140 a31d4220-a93d-0410-bf67-fe4944624d44
This commit is contained in:
bgk 2012-10-01 16:55:36 +00:00
parent b2d9c51e5f
commit ed7e1247b1
30 changed files with 3834 additions and 402 deletions

Binary file not shown.

View File

@ -24,7 +24,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseOfMfc>Static</UseOfMfc> <UseOfMfc>Static</UseOfMfc>
<CharacterSet>NotSet</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -49,13 +49,13 @@
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)$(Platform)\$(Configuration)\</OutDir> <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)$(Platform)\$(Configuration)_temp\</IntDir> <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)$(Platform)\$(Configuration)_temp\</IntDir>
<PreBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</PreBuildEventUseInBuild> <PreBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</PreBuildEventUseInBuild>
<PreLinkEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</PreLinkEventUseInBuild> <PreLinkEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</PreLinkEventUseInBuild>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental> <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<PostBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</PostBuildEventUseInBuild> <PostBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</PostBuildEventUseInBuild>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)$(Platform)\$(Configuration)\</OutDir> <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)$(Platform)\$(Configuration)_temp\</IntDir> <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)$(Platform)\$(Configuration)_temp\</IntDir>
<PreBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</PreBuildEventUseInBuild> <PreBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</PreBuildEventUseInBuild>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" /> <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" /> <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
@ -66,9 +66,9 @@
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Template|Win32'" /> <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Template|Win32'" />
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Template|Win32'" /> <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Template|Win32'" />
<LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">C:\Program Files (x86)\OpenAL 1.1 SDK\libs\Win32;C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86;$(LibraryPath)</LibraryPath> <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%programfiles%\OpenAL 1.1 SDK\libs\Win32;$(DXSDK_DIR)\lib\x86;$(LibraryPath)</LibraryPath>
<LibraryPath Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">C:\Program Files (x86)\OpenAL 1.1 SDK\libs\Win32;C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86;$(LibraryPath)</LibraryPath> <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">C:\Program Files (x86)\OpenAL 1.1 SDK\libs\Win32;C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x86;$(LibraryPath)</LibraryPath>
<IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">C:\Program Files (x86)\OpenAL 1.1 SDK\include;C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include;$(IncludePath)</IncludePath> <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%programfiles%\OpenAL 1.1 SDK\include;$(DXSDK_DIR)\Include;$(IncludePath)</IncludePath>
<IncludePath Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">C:\Program Files (x86)\OpenAL 1.1 SDK\include;C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include;$(IncludePath)</IncludePath> <IncludePath Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">C:\Program Files (x86)\OpenAL 1.1 SDK\include;C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include;$(IncludePath)</IncludePath>
<IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%programfiles%\OpenAL 1.1 SDK\include;$(DXSDK_DIR)\Include;$(IncludePath)</IncludePath> <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%programfiles%\OpenAL 1.1 SDK\include;$(DXSDK_DIR)\Include;$(IncludePath)</IncludePath>
<LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%programfiles%\OpenAL 1.1 SDK\libs\Win32;$(DXSDK_DIR)\lib\x86;$(LibraryPath)</LibraryPath> <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%programfiles%\OpenAL 1.1 SDK\libs\Win32;$(DXSDK_DIR)\lib\x86;$(LibraryPath)</LibraryPath>
@ -100,7 +100,7 @@
<TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType> <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
<PrecompiledHeader> <PrecompiledHeader>
</PrecompiledHeader> </PrecompiledHeader>
<ProgramDataBaseFileName>$(IntDir)$(ProjectName).pdb</ProgramDataBaseFileName> <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat> <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile> </ClCompile>
@ -124,6 +124,7 @@
<DataExecutionPrevention> <DataExecutionPrevention>
</DataExecutionPrevention> </DataExecutionPrevention>
<MinimumRequiredVersion>5.0</MinimumRequiredVersion> <MinimumRequiredVersion>5.0</MinimumRequiredVersion>
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -177,6 +178,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<RandomizedBaseAddress>false</RandomizedBaseAddress> <RandomizedBaseAddress>false</RandomizedBaseAddress>
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
</Link> </Link>
<NASM> <NASM>
<Optimization>1</Optimization> <Optimization>1</Optimization>
@ -709,7 +711,7 @@
</ImportGroup> </ImportGroup>
<ProjectExtensions> <ProjectExtensions>
<VisualStudio> <VisualStudio>
<UserProperties RESOURCE_FILE="\Users\Shawn\Desktop\shuffle2proj\vba-m\src\win32\VBA.rc" /> <UserProperties RESOURCE_FILE="" />
</VisualStudio> </VisualStudio>
</ProjectExtensions> </ProjectExtensions>
</Project> </Project>

View File

@ -61,6 +61,7 @@ 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 system1Frames(int rate, int count);
extern void systemFrame(); extern void systemFrame();
extern void systemGbBorderOn(); extern void systemGbBorderOn();
@ -86,6 +87,9 @@ extern int systemFrameSkip;
extern int systemSaveUpdateCounter; extern int systemSaveUpdateCounter;
extern int systemSpeed; extern int systemSpeed;
extern int lastSA;
extern int lastSR;
#define SYSTEM_SAVE_UPDATED 30 #define SYSTEM_SAVE_UPDATED 30
#define SYSTEM_SAVE_NOT_UPDATED 0 #define SYSTEM_SAVE_NOT_UPDATED 0

View File

@ -14,6 +14,7 @@ License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h" #include "blargg_source.h"
#include "../system.h"
unsigned const vol_reg = 0xFF24; unsigned const vol_reg = 0xFF24;
unsigned const stereo_reg = 0xFF25; unsigned const stereo_reg = 0xFF25;
@ -318,6 +319,9 @@ void Gb_Apu::write_register( blip_time_t time, unsigned addr, int data )
int old_data = regs [reg]; int old_data = regs [reg];
regs [reg] = data; regs [reg] = data;
//if(lastSA>=0x70 && lastSA<=0x75)
//log("CH3 Addr:%04X = %04X Regs[%d]:%02X->%02X\n",lastSA,lastSR,reg,old_data,data);
if ( addr < vol_reg ) if ( addr < vol_reg )
{ {
// Oscillator // Oscillator

View File

@ -38,6 +38,7 @@ inline void Gb_Osc::update_amp( blip_time_t time, int new_amp )
{ {
last_amp = new_amp; last_amp = new_amp;
med_synth->offset( time, delta, output ); med_synth->offset( time, delta, output );
//good_synth->offset( time, delta, output );
} }
} }
@ -280,12 +281,12 @@ inline void Gb_Wave::write_register( int frame_phase, int reg, int old_data, int
switch ( reg ) switch ( reg )
{ {
case 0: case 0: //NR30
if ( !dac_enabled() ) if ( !dac_enabled() )
enabled = false; enabled = false;
break; break;
case 1: case 1: //NR31
length_ctr = max_len - data; length_ctr = max_len - data;
break; break;
@ -571,9 +572,9 @@ void Gb_Noise::run( blip_time_t time, blip_time_t end_time )
void Gb_Wave::run( blip_time_t time, blip_time_t end_time ) void Gb_Wave::run( blip_time_t time, blip_time_t end_time )
{ {
// Calc volume // Calc volume
static byte const volumes [8] = { 0, 4, 2, 1, 3, 3, 3, 3 }; static byte const volumes [8] = { 0, 4, 2, 1, 3, 3, 3, 3 }; //4 = 100%
int const volume_shift = 2; int const volume_shift = 2;
int const volume_idx = regs [2] >> 5 & (agb_mask | 3); // 2 bits on DMG/CGB, 3 on AGB int const volume_idx = regs [2] >> 5 & (agb_mask | 3); // 2 bits on DMG/CGB, 3 on AGB //AdamN: osc.regs[2]=apu.regs[12] (NR32)
int const volume_mul = volumes [volume_idx]; int const volume_mul = volumes [volume_idx];
// Determine what will be generated // Determine what will be generated
@ -585,10 +586,10 @@ void Gb_Wave::run( blip_time_t time, blip_time_t end_time )
if ( dac_enabled() ) if ( dac_enabled() )
{ {
// Play inaudible frequencies as constant amplitude // Play inaudible frequencies as constant amplitude
amp = 8 << 4; // really depends on average of all samples in wave amp = 8 << 4; // really depends on average of all samples in wave //AdamN: can we use this->last_amp instead?
// if delay is larger, constant amplitude won't start yet // if delay is larger, constant amplitude won't start yet
if ( frequency() <= 0x7FB || delay > 15 * clk_mul ) if ( frequency() <= 0x7FB || delay > 15 * clk_mul ) //2043
{ {
if ( volume_mul ) if ( volume_mul )
playing = (int) enabled; playing = (int) enabled;
@ -609,13 +610,14 @@ void Gb_Wave::run( blip_time_t time, blip_time_t end_time )
// wave size and bank // wave size and bank
int const size20_mask = 0x20; int const size20_mask = 0x20;
int const flags = regs [0] & agb_mask; int const flags = regs [0] & agb_mask; //AdamN: osc.regs[0]=apu.regs[10] (NR30)
int const wave_mask = (flags & size20_mask) | 0x1F; int const wave_mask = (flags & size20_mask) | 0x1F; //AdamN: Bank Dimension
int swap_banks = 0; int swap_banks = 0;
if ( flags & bank40_mask ) if ( flags & bank40_mask ) //AdamN: Bank 1
{ {
swap_banks = flags & size20_mask; swap_banks = flags & size20_mask; //AdamN: Bank Dimension, swap_banks = Use 2 Banks (64 digits)
wave += bank_size/2 - (swap_banks >> 1); wave += bank_size/2 - (swap_banks >> 1);
//wave = &this->wave_ram[bank_size/2 - (swap_banks >> 1)];
} }
int ph = this->phase ^ swap_banks; int ph = this->phase ^ swap_banks;
@ -640,13 +642,14 @@ void Gb_Wave::run( blip_time_t time, blip_time_t end_time )
ph = (ph + 1) & wave_mask; ph = (ph + 1) & wave_mask;
// Scale by volume // Scale by volume
int amp = (nybble * volume_mul) >> (volume_shift + 4); int amp = (nybble * volume_mul) >> (volume_shift + 4); //AdamN: should we use +dac_bias in here?
int delta = amp - lamp; int delta = amp - lamp;
if ( delta ) if ( delta )
{ {
lamp = amp; lamp = amp;
med_synth->offset_inline( time, delta, out ); med_synth->offset_inline( time, delta, out );
//good_synth->offset_inline( time, delta, out );
} }
time += per; time += per;
} }

View File

@ -165,11 +165,11 @@ private:
int period() const { return (2048 - frequency()) * (2 * clk_mul); } int period() const { return (2048 - frequency()) * (2 * clk_mul); }
// Non-zero if DAC is enabled // Non-zero if DAC is enabled
int dac_enabled() const { return regs [0] & 0x80; } int dac_enabled() const { return regs [0] & 0x80; } //AdamN: osc.regs[0]=apu.regs[10]
void corrupt_wave(); void corrupt_wave();
BOOST::uint8_t* wave_bank() const { return &wave_ram [(~regs [0] & bank40_mask) >> 2 & agb_mask]; } BOOST::uint8_t* wave_bank() const { return &wave_ram [(~regs [0] & bank40_mask) >> 2 & agb_mask]; } //AdamN: osc.regs[0]=apu.regs[10]
// Wave index that would be accessed, or -1 if no access would occur // Wave index that would be accessed, or -1 if no access would occur
int access( unsigned addr ) const; int access( unsigned addr ) const;

View File

@ -14,6 +14,8 @@
#include "gbSGB.h" #include "gbSGB.h"
#include "gbSound.h" #include "gbSound.h"
#include "../Util.h" #include "../Util.h"
#include "../gba/GBALink.h"
//#include "../gba/Globals.h"
#ifdef __GNUC__ #ifdef __GNUC__
#define _stricmp strcasecmp #define _stricmp strcasecmp
@ -790,16 +792,81 @@ void gbWriteMemory(register u16 address, register u8 value)
} }
case 0x01: { case 0x01: {
#ifdef GBA_LOGGING
if(gbMemory[0xff01]!=value)
if(systemVerbose & VERBOSE_SIO) {
log("SioSB(%04X) : %02X %02X->%02X %d\n", PC.W-2, gbMemory[0xff02], gbMemory[0xff01], value, GetTickCount() ); //register_LY
}
#endif
gbMemory[0xff01] = value; gbMemory[0xff01] = value;
//if(value==0xff/*0x00*/) LinkFirstTime = true;
return; return;
} }
// serial control // serial control
case 0x02: { case 0x02: {
#ifdef GBA_LOGGING
if(gbMemory[0xff02]!=value)
if(systemVerbose & VERBOSE_SIO) {
log("SioSC(%04X) : %02X->%02X %02X %d\n", PC.W-2, gbMemory[0xff02], value, gbMemory[0xff01], GetTickCount() ); //register_LY
}
#endif
gbSerialOn = (value & 0x80); gbSerialOn = (value & 0x80);
//if(gba_link_enabled && lanlink.connected)
if( EmuReseted ||(gbMemory[0xff02] & 0x7c)||(value & 0x7c)||(!(value & 0x81)) ) { //trying to detect whether the game has exited multiplay mode, pokemon blue start w/ 0x7e while pocket racing start w/ 0x7c
LinkFirstTime = true;
if( EmuReseted ||(gbMemory[0xff02] & 0x7c)||(value & 0x7c) )
if(lanlink.connected)
if(linkid) lc.DiscardData();
else ls.DiscardData(1);
}
EmuReseted = false;
gbMemory[0xff02] = value; gbMemory[0xff02] = value;
if(gbSerialOn) { if(gbSerialOn) {
gbSerialTicks = GBSERIAL_CLOCK_TICKS; gbSerialTicks = GBSERIAL_CLOCK_TICKS;
LinkIsWaiting = true;
//Do data exchange, master initiate the transfer
//may cause visual artifact if not processed immediately, is it due to IRQ stuff or invalid data being exchanged?
if( (value & 1) /*|| (!LinkFirstTime)*/ ) { //&& !linkid //internal clock
if(gbSerialFunction) {
gbSIO_SC = value;
LogStrPush("gbWrite");
//if(linkid /*&& (value & 1)*/) {gbMemory[0xff01] = 0xff; LinkFirstTime = true;} else
gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); //gbSerialFunction/gbStartLink/gbPrinter
LogStrPop(7);
} else gbMemory[0xff01]=0xff;
//gbSerialTicks = GBSERIAL_CLOCK_TICKS; //1; //0; //wrong value in gbSerialTicks could cause visual artifact
gbMemory[0xff02] &= 0x7f;
gbSerialOn = 0;
//if(register_IE & 8)
gbMemory[0xff0f] = register_IF |= 8;
//gbSerialBits = 0;
//LinkFirstTime = false;
//if(!(value & 1)) LinkFirstTime = true;
} /*else //external clock
{
u16 dat = 0;
//if(gbSerialFunction)
{
gbSIO_SC = value;
LogStrPush("gbWrite");
dat = gbLinkUpdate(gbMemory[0xff01]);
gbMemory[0xff01] = (dat >> 8); //gbSerialFunction/gbStartLink/gbPrinter
LogStrPop(7);
}
if(dat & 1) {
//gbSerialTicks = GBSERIAL_CLOCK_TICKS; //1; //0; //wrong value in gbSerialTicks could cause visual artifact
gbMemory[0xff02] &= 0x7f;
gbSerialOn = 0;
//if(register_IE & 8)
gbMemory[0xff0f] = register_IF |= 8;
//gbSerialBits = 0;
//LinkFirstTime = false;
//if(!(value & 1)) LinkFirstTime = true;
}
}*/
#ifdef OLD_GB_LINK #ifdef OLD_GB_LINK
if(linkConnected) { if(linkConnected) {
if(value & 1) { if(value & 1) {
@ -2174,6 +2241,8 @@ void gbGetHardwareType()
void gbReset() void gbReset()
{ {
EmuReseted = true;
LinkFirstTime = true;
gbGetHardwareType(); gbGetHardwareType();
oldRegister_WY = 146; oldRegister_WY = 146;
@ -4487,6 +4556,8 @@ void gbDrawLine()
void gbEmulate(int ticksToStop) void gbEmulate(int ticksToStop)
{ {
if(EmuCtr>0) {log("Emu inside Emu:%d\n",EmuCtr);return;}
gbRegister tempRegister; gbRegister tempRegister;
u8 tempValue; u8 tempValue;
s8 offset; s8 offset;
@ -4916,8 +4987,9 @@ void gbEmulate(int ticksToStop)
gbFrameCount++; gbFrameCount++;
systemFrame(); systemFrame();
if((gbFrameCount % 10) == 0) /*if((gbFrameCount % 10) == 0)
system10Frames(60); system10Frames(60);*/
system1Frames(60, gbFrameCount);
if(gbFrameCount >= 60) { if(gbFrameCount >= 60) {
u32 currentTime = systemGetClock(); u32 currentTime = systemGetClock();
@ -5186,8 +5258,9 @@ void gbEmulate(int ticksToStop)
systemFrame(); systemFrame();
if((gbFrameCount % 10) == 0) /*if((gbFrameCount % 10) == 0)
system10Frames(60); system10Frames(60);*/
system1Frames(60, gbFrameCount);
if(gbFrameCount >= 60) { if(gbFrameCount >= 60) {
u32 currentTime = systemGetClock(); u32 currentTime = systemGetClock();
@ -5206,7 +5279,33 @@ void gbEmulate(int ticksToStop)
gbMemory[0xff41] = register_STAT; gbMemory[0xff41] = register_STAT;
// serial emulation // serial emulation
if(gbSerialOn) { gbSerialOn = (gbMemory[0xff02] & 0x80);
/*if(gba_link_enabled && lanlink.connected && (register_LY>=144)) {
//if(gbSerialOn)
{
u16 dat = 0;
if(gbSerialFunction) { // external device
gbSIO_SC = gbMemory[0xff02];
LogStrPush("gbEmu");
if(!LinkFirstTime) dat = (gbSerialFunction(gbMemory[0xff01]) << 8) | 1; else
dat = gbLinkUpdate(gbMemory[0xff01]);
gbMemory[0xff01] = (dat >> 8);
LogStrPop(5);
if(gbSerialOn && (dat & 1)) {
gbMemory[0xff02] &= 0x7f;
gbSerialOn = 0;
//if(register_IE & 8)
gbMemory[0xff0f] = register_IF |= 8;
}
} //else gbMemory[0xff01] = 0xff;
}
gbSerialTicks = 1; //GBSERIAL_CLOCK_TICKS; //0; //seems to cause varies visual artifact if gbSerialTicks value isn't right
gbSerialBits = 0;
}*/
static int SIOctr = 0;
SIOctr++;
if(!lanlink.speed || (SIOctr % 5))
if(gbSerialOn) { //Transfer Started
#ifdef OLD_GB_LINK #ifdef OLD_GB_LINK
if(linkConnected) { if(linkConnected) {
gbSerialTicks -= clockTicks; gbSerialTicks -= clockTicks;
@ -5229,7 +5328,7 @@ void gbEmulate(int ticksToStop)
} }
} else { } else {
#endif #endif
if(gbMemory[0xff02] & 1) { if(gbMemory[0xff02] & 1) { //internal clocks (master)
gbSerialTicks -= clockTicks; gbSerialTicks -= clockTicks;
// overflow // overflow
@ -5238,16 +5337,61 @@ void gbEmulate(int ticksToStop)
// gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1); // gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1);
// increment number of shifted bits // increment number of shifted bits
gbSerialBits++; gbSerialBits++;
if(gbSerialBits == 8) { if(gbSerialBits >= 8) {
// end of transmission // end of transmission
if(gbSerialFunction) // external device /*if(gbSerialFunction) { // external device
gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); gbSIO_SC = gbMemory[0xff02];
else LogStrPush("gbEmu");
gbMemory[0xff01] = 0xff; gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); //gbStartLik/gbPrinter
LogStrPop(5);
LinkFirstTime = false;
} else
gbMemory[0xff01] = 0xff;*/
gbSerialTicks = 0; gbSerialTicks = 0;
//if(!linkid)
/*{
gbMemory[0xff02] &= 0x7f; gbMemory[0xff02] &= 0x7f;
gbSerialOn = 0; gbSerialOn = 0;
gbMemory[0xff0f] = register_IF |= 8; gbMemory[0xff0f] = register_IF |= 8;
}*/
gbSerialBits = 0;
} else
gbSerialTicks += GBSERIAL_CLOCK_TICKS;
}
} else //external clocks (slave)
{
gbSerialTicks -= clockTicks;
// overflow
while(gbSerialTicks <= 0) {
// shift serial byte to right and put a 1 bit in its place
// gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1);
// increment number of shifted bits
gbSerialBits++;
if(gbSerialBits >= 8) {
// end of transmission
u16 dat = 0;
if(!LinkIsWaiting) {
if(lanlink.connected)
if(linkid) lc.DiscardData();
else ls.DiscardData(1);
} else
if(gbSerialFunction) { // external device
gbSIO_SC = gbMemory[0xff02];
LogStrPush("gbEmu");
if(!LinkFirstTime) dat = (gbSerialFunction(gbMemory[0xff01]) << 8) | 1; else //external clock not suppose to start a transfer, but there are time where both side using external clock and couldn't communicate properly
dat = gbLinkUpdate(gbMemory[0xff01]);
gbMemory[0xff01] = (dat >> 8);
LogStrPop(5);
} //else
//gbMemory[0xff01] = 0xff;
gbSerialTicks = 0;
if(dat & 1) //if(linkid)
{
gbMemory[0xff02] &= 0x7f;
gbSerialOn = 0;
gbMemory[0xff0f] = register_IF |= 8;
}
gbSerialBits = 0; gbSerialBits = 0;
} else } else
gbSerialTicks += GBSERIAL_CLOCK_TICKS; gbSerialTicks += GBSERIAL_CLOCK_TICKS;

View File

@ -1,6 +1,8 @@
#ifndef GBGLOBALS_H #ifndef GBGLOBALS_H
#define GBGLOBALS_H #define GBGLOBALS_H
#define VERBOSE_SIO 2048
extern int gbRomSizeMask; extern int gbRomSizeMask;
extern int gbRomSize; extern int gbRomSize;
extern int gbRamSize; extern int gbRamSize;

View File

@ -657,7 +657,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 EMIT2(test,eax,eax), SETCOND_LOGICAL) #define OP_MVNS CHECK_PC(OP_MVN EMIT2(test,eax,eax), SETCOND_LOGICAL) //AdamN: NOT eax doesn't affect any flags in x86 so need to add TEST for SETCOND_LOGICAL to works properly
// ALU cleanup macro // ALU cleanup macro
#define ALU_FINISH ALU_TRAILER #define ALU_FINISH ALU_TRAILER

View File

@ -22,6 +22,10 @@
#include "agbprint.h" #include "agbprint.h"
#include "GBALink.h" #include "GBALink.h"
#ifdef _MSC_VER //#ifdef _WIN32
#include "../Win32/WinHelper.h" // AdamN: for CCriticalSection
#endif
#ifdef PROFILING #ifdef PROFILING
#include "prof/prof.h" #include "prof/prof.h"
#endif #endif
@ -32,6 +36,8 @@
extern int emulating; extern int emulating;
extern bool AppTerminated = false;
int SWITicks = 0; int SWITicks = 0;
int IRQTicks = 0; int IRQTicks = 0;
@ -59,6 +65,9 @@ bool cpuFlashEnabled = true;
bool cpuEEPROMEnabled = true; bool cpuEEPROMEnabled = true;
bool cpuEEPROMSensorEnabled = false; bool cpuEEPROMSensorEnabled = false;
bool breakpt = false;
u32 breakaddr = 0xffffffff;
u32 cpuPrefetch[2]; u32 cpuPrefetch[2];
int cpuTotalTicks = 0; int cpuTotalTicks = 0;
@ -815,7 +824,7 @@ static bool CPUReadState(gzFile gzFile)
THUMB_PREFETCH; THUMB_PREFETCH;
} }
CPUUpdateRegister(0x204, CPUReadHalfWordQuick(0x4000204)); CPUUpdateRegister(0x204, CPUReadHalfWordQuick(0x4000204)); //WAITCNT
return true; return true;
} }
@ -1779,7 +1788,8 @@ void CPUSoftwareInterrupt(int comment)
#endif #endif
if(useBios) { if(useBios) {
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) { //if(comment>0x2A) //AdamN: what is the idea of flooding the log with all interrupts?? having a stats showing how many times each interrupt being called might be more usefull than flooding
if(systemVerbose & VERBOSE_SWI) { //AdamN: trying to capture only the impossible (should be logged even when logging not enabled tho)
log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment, log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
armState ? armNextPC - 4: armNextPC -2, armState ? armNextPC - 4: armNextPC -2,
reg[0].I, reg[0].I,
@ -1827,31 +1837,31 @@ void CPUSoftwareInterrupt(int comment)
stopState = true; stopState = true;
cpuNextEvent = cpuTotalTicks; cpuNextEvent = cpuTotalTicks;
break; break;
case 0x04: case 0x04: //AdamN: IntrWait
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) { if(systemVerbose & VERBOSE_SWI) {
log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n", log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n",
reg[0].I, reg[0].I,
reg[1].I, reg[1].I, //AdamN: Interrupt flag(s) to wait for (same format as IE/IF registers)
VCOUNT); VCOUNT);
} }
#endif #endif
CPUSoftwareInterrupt(); CPUSoftwareInterrupt(); //AdamN: Forcefully sets IME=1 and wait in Halt state until one (or more) of the specified interrupt(s) occurs.
break; break;
case 0x05: case 0x05: //AdamN: this VBlankIntrWait oftenly called (every 1/60 sec) so it should be handled properly
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) { if(systemVerbose & VERBOSE_SWI) {
log("VBlankIntrWait: (VCOUNT = %2d)\n", log("VBlankIntrWait: (VCOUNT = %2d)\n",
VCOUNT); VCOUNT);
} }
#endif #endif
CPUSoftwareInterrupt(); CPUSoftwareInterrupt(); //AdamN: set r0=1,r1=1 then execute IntrWait
break; break;
case 0x06: case 0x06: //AdamN: Div oftenly called so it should be handled properly
CPUSoftwareInterrupt(); BIOS_Div(); //CPUSoftwareInterrupt();
break; break;
case 0x07: case 0x07: //AdamN: DivArm
CPUSoftwareInterrupt(); BIOS_DivARM(); //CPUSoftwareInterrupt();
break; break;
case 0x08: case 0x08:
BIOS_Sqrt(); BIOS_Sqrt();
@ -1862,7 +1872,7 @@ void CPUSoftwareInterrupt(int comment)
case 0x0A: case 0x0A:
BIOS_ArcTan2(); BIOS_ArcTan2();
break; break;
case 0x0B: case 0x0B: //AdamN: CpuSet oftenly called so it should be handled properly
{ {
int len = (reg[2].I & 0x1FFFFF) >>1; int len = (reg[2].I & 0x1FFFFF) >>1;
if (!(((reg[0].I & 0xe000000) == 0) || if (!(((reg[0].I & 0xe000000) == 0) ||
@ -1888,7 +1898,7 @@ void CPUSoftwareInterrupt(int comment)
} }
BIOS_CpuSet(); BIOS_CpuSet();
break; break;
case 0x0C: case 0x0C: //AdamN: CpuFastSet oftenly called so it should be handled properly
{ {
int len = (reg[2].I & 0x1FFFFF) >>5; int len = (reg[2].I & 0x1FFFFF) >>5;
if (!(((reg[0].I & 0xe000000) == 0) || if (!(((reg[0].I & 0xe000000) == 0) ||
@ -2005,7 +2015,7 @@ void CPUSoftwareInterrupt(int comment)
#ifdef GBA_LOGGING #ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) { if(systemVerbose & VERBOSE_SWI) {
log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n", log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n",
reg[0].I, reg[0].I, //AdamN: r0=BIAS Level (0=Level 000h, any other value=Level 200h), r1=Delay Count on NDS (GBA uses a fixed delay count of 8)
VCOUNT); VCOUNT);
} }
#endif #endif
@ -2014,10 +2024,147 @@ void CPUSoftwareInterrupt(int comment)
else else
soundResume(); soundResume();
break; break;
/*case 0x1A: //AdamN: SoundDriverInit, calling sequences after SoundDriverInit then SoundChannelClear then SoundDriverMode, then repeated SoundDriverVSync+SoundDriverMain
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) {
log("SoundDriverInit: 0x%08x (VCOUNT = %2d)\n",
reg[0].I, //AdamN: Pointer to SoundArea structure
VCOUNT);
}
#endif
CPUSoftwareInterrupt();
break;*/
case 0x1B: //AdamN: SoundDriverMode
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) {
log("SoundDriverMode: 0x%08x (VCOUNT = %2d)\n",
reg[0].I, //AdamN: Sound driver operation mode
VCOUNT);
}
#endif
//CPUSoftwareInterrupt();
break;
case 0x1C: //AdamN: SoundDriverMain (no param)
//CPUSoftwareInterrupt(); //AdamN: Call (using/after SoundDriverVSync) every 1/60 of a second, immediately after the V-Blank interrupt. After that, this routine is called after BG and OBJ processing is executed.
break;
case 0x1D: //AdamN: SoundDriverVSync
//CPUSoftwareInterrupt(); //AdamN: Resets the sound DMA (no param) to sync the BIOS sound driver
break;
case 0x1E: //AdamN: SoundChannelClear
//CPUSoftwareInterrupt(); //AdamN: Clears all direct sound channels and stops the sound (no param)
break;
case 0x1F: case 0x1F:
BIOS_MidiKey2Freq(); BIOS_MidiKey2Freq();
break; break;
case 0x2A: case 0x20: //AdamN: SoundWhatever0/MusicPlayerOpen
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) {
log("MusicPlayerOpen: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
armState ? armNextPC - 4: armNextPC -2,
reg[0].I,
reg[1].I,
reg[2].I,
VCOUNT);
}
#endif
//CPUSoftwareInterrupt();
break;
case 0x21: //AdamN: SoundWhatever1/MusicPlayerStart
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) {
log("MusicPlayerStart: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
armState ? armNextPC - 4: armNextPC -2,
reg[0].I,
reg[1].I,
reg[2].I,
VCOUNT);
}
#endif
//CPUSoftwareInterrupt();
break;
case 0x22: //AdamN: SoundWhatever2/MusicPlayerStop
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) {
log("MusicPlayerStop: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
armState ? armNextPC - 4: armNextPC -2,
reg[0].I,
reg[1].I,
reg[2].I,
VCOUNT);
}
#endif
//CPUSoftwareInterrupt();
break;
case 0x23: //AdamN: SoundWhatever3/MusicPlayerContinue
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) {
log("MusicPlayerContinue: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
armState ? armNextPC - 4: armNextPC -2,
reg[0].I,
reg[1].I,
reg[2].I,
VCOUNT);
}
#endif
//CPUSoftwareInterrupt();
break;
case 0x24: //AdamN: SoundWhatever4/MusicPlayerFadeOut
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) {
log("MusicPlayerFadeOut: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
armState ? armNextPC - 4: armNextPC -2,
reg[0].I,
reg[1].I,
reg[2].I,
VCOUNT);
}
#endif
//CPUSoftwareInterrupt();
break;
case 0x25: //AdamN: MultiBoot
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) {
log("MultiBoot: 0x%08x,0x%08x (VCOUNT = %2d)\n",
reg[0].I, //AdamN: Pointer to MultiBootParam structure
reg[1].I, //AdamN: Transfer Mode
VCOUNT);
}
#endif
//CPUSoftwareInterrupt();
break;
case 0x26: //AdamN: HardReset
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) {
log("HardReset: (VCOUNT = %2d)\n",
VCOUNT);
}
#endif
CPUSoftwareInterrupt(); //Fully reset to Nintendo intro (no param)
break;
case 0x27: //AdamN: CustomHalt
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) {
log("CustomHalt: 0x%08x (VCOUNT = %2d)\n",
reg[2].I, //AdamN: 8bit param (00h=Halt, 80h=Stop)
VCOUNT);
}
#endif
CPUSoftwareInterrupt();
break;
case 0x28: //AdamN: SoundDriverVSyncOff
//CPUSoftwareInterrupt(); //AdamN: Stop sound DMA (no param) to prevent sound DMA from overflowing and playing noise when the game loading (as SoundDriverVSync might missed the 1/60sec interval)
break;
case 0x29: //AdamN: SoundDriverVSyncOn
//CPUSoftwareInterrupt(); //AdamN: Restarts the sound DMA stopped with SoundDriverVSyncOff (no param) to restore sound driver operation
break;
case 0x2A: //AdamN: SoundGetJumpList
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SWI) {
log("SoundGetJumpList: 0x%08x (VCOUNT = %2d)\n",
reg[0].I, //AdamN: Destination address (must be aligned by 4) (120h bytes buffer)
VCOUNT);
}
#endif
BIOS_SndDriverJmpTableCopy(); BIOS_SndDriverJmpTableCopy();
// let it go, because we don't really emulate this function // let it go, because we don't really emulate this function
default: default:
@ -2034,11 +2181,12 @@ void CPUSoftwareInterrupt(int comment)
if(!disableMessage) { if(!disableMessage) {
systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION, systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION,
N_("Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."), N_("Unsupported BIOS Function %02X called from %08x. A BIOS file is needed in order to get correct behaviour."),
comment, comment,
armMode ? armNextPC - 4: armNextPC - 2); armMode ? armNextPC - 4: armNextPC - 2);
disableMessage = true; disableMessage = true;
} }
//CPUSoftwareInterrupt(); //AdamN: not needed as it could cause the game to stop when there are no bios file
break; break;
} }
} }
@ -2405,6 +2553,9 @@ void CPUUpdateRegister(u32 address, u16 value)
{ {
case 0x00: case 0x00:
{ // we need to place the following code in { } because we declare & initialize variables in a case statement { // we need to place the following code in { } because we declare & initialize variables in a case statement
/*if((value & 4)&&((DISPCNT & 0x0010)!=(value & 0x0010))) {
log("DISPCNT(%08x) : %04X->%04X %04X R0=%08X R1=%08X R2=%08X R14=%08X Z=%d (VCOUNT = %d)\n", armState ? armNextPC - 4: armNextPC -2, DISPCNT, value, DISPSTAT, reg[0].I, reg[1].I, reg[2].I, reg[14].I, Z_FLAG, VCOUNT);
}*/
if((value & 7) > 5) { if((value & 7) > 5) {
// display modes above 0-5 are prohibited // display modes above 0-5 are prohibited
DISPCNT = (value & 7); DISPCNT = (value & 7);
@ -2626,7 +2777,11 @@ void CPUUpdateRegister(u32 address, u16 value)
case 0x7c: case 0x7c:
case 0x80: case 0x80:
case 0x84: case 0x84:
lastSR = value & 0xFF;
lastSA = address&0xFF;
soundEvent(address&0xFF, (u8)(value & 0xFF)); soundEvent(address&0xFF, (u8)(value & 0xFF));
lastSR = value >> 8;
lastSA = (address&0xFF)+1;
soundEvent((address&0xFF)+1, (u8)(value>>8)); soundEvent((address&0xFF)+1, (u8)(value>>8));
break; break;
case 0x82: case 0x82:
@ -2643,6 +2798,8 @@ void CPUUpdateRegister(u32 address, u16 value)
case 0x9a: case 0x9a:
case 0x9c: case 0x9c:
case 0x9e: case 0x9e:
lastSR = value;
lastSA = address&0xFF;
soundEvent(address&0xFF, value); soundEvent(address&0xFF, value);
break; break;
case 0xB0: case 0xB0:
@ -2822,16 +2979,79 @@ void CPUUpdateRegister(u32 address, u16 value)
timerOnOffDelay|=8; timerOnOffDelay|=8;
cpuNextEvent = cpuTotalTicks; cpuNextEvent = cpuTotalTicks;
break; break;
case COMM_SIODATA32_L:
if(READ16LE(&ioMem[COMM_SIODATA32_L]) != value) {
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SIO) {
log("SIODATAL(%d) : %04X %04X %04X->%04X %04X %04X %04X %04X (VCOUNT = %d)\n", GetTickCount(), READ16LE(&ioMem[COMM_RCNT]), READ16LE(&ioMem[COMM_SIOCNT]), READ16LE(&ioMem[COMM_SIOMULTI0]), value, READ16LE(&ioMem[COMM_SIOMULTI1]), READ16LE(&ioMem[COMM_SIOMULTI2]), READ16LE(&ioMem[COMM_SIOMULTI3]), READ16LE(&ioMem[COMM_SIOMLT_SEND]), VCOUNT );
}
#endif
}
UPDATE_REG(COMM_SIODATA32_L, value);
break;
case COMM_SIODATA32_H:
if(READ16LE(&ioMem[COMM_SIODATA32_H]) != value) {
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SIO) {
log("SIODATAH(%d) : %04X %04X %04X %04X->%04X %04X %04X %04X (VCOUNT = %d)\n", GetTickCount(), READ16LE(&ioMem[COMM_RCNT]), READ16LE(&ioMem[COMM_SIOCNT]), READ16LE(&ioMem[COMM_SIOMULTI0]), READ16LE(&ioMem[COMM_SIOMULTI1]), value, READ16LE(&ioMem[COMM_SIOMULTI2]), READ16LE(&ioMem[COMM_SIOMULTI3]), READ16LE(&ioMem[COMM_SIOMLT_SEND]), VCOUNT );
}
#endif
}
UPDATE_REG(COMM_SIODATA32_H, value);
break;
case COMM_SIOCNT: case COMM_SIOCNT:
if(READ16LE(&ioMem[COMM_SIOCNT]) != (/*READ16LE(&ioMem[COMM_SIOCNT]) &*/ value)) {
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SIO) {
if(value & 0x4000)
log("SIOCNT(%08x) : %04X %04X->%04X %04X %04X %04X %04X %04X (VCOUNT = %d)\n", armState ? armNextPC - 4: armNextPC -2, READ16LE(&ioMem[COMM_RCNT]), READ16LE(&ioMem[COMM_SIOCNT]), value, READ16LE(&ioMem[COMM_SIOMULTI0]), READ16LE(&ioMem[COMM_SIOMULTI1]), READ16LE(&ioMem[COMM_SIOMULTI2]), READ16LE(&ioMem[COMM_SIOMULTI3]), READ16LE(&ioMem[COMM_SIOMLT_SEND]), VCOUNT );
}
#endif
}
if( EmuReseted ) { //trying to detect whether the game has exited multiplay mode (ie. game restarted)
EmuReseted = false;
LinkFirstTime = true;
if(lanlink.connected)
if(linkid) lc.DiscardData();
else ls.DiscardData(1);
}
//UPDATE_REG(COMM_SIOCNT, value);
lanlink.mode = GetSIOMode(value, READ16LE(&ioMem[COMM_RCNT]));
if(lanlink.mode!=GetSIOMode(READ16LE(&ioMem[COMM_SIOCNT]), READ16LE(&ioMem[COMM_RCNT]))) LinkFirstTime = true;
StartLink(value); StartLink(value);
/*switch (GetSIOMode(value, READ16LE(&ioMem[COMM_RCNT]))) {
case MULTIPLAYER:
if(LinkHandlerActive) {
if (value & 0x80) { //AdamN: Start/Busy Bit.7=1 (Active/Transfering)
LinkCmdQueue(1,value);
c_s.Lock(); //AdamN: Locking resource to prevent deadlock
//UPDATE_REG(COMM_SIOCNT, value); //AdamN: when using socket handler SIOCNT need to be updated as soon as possible because program might be reading it and ORing it for the next update
LinkParam1=value;
LinkCommand|=1; //AdamN: StartLink command
c_s.Unlock(); //AdamN: Locking resource to prevent deadlock
} else UPDATE_REG(COMM_SIOCNT, value);
} else {
LogStrPush("CPUUpdReg");
//UPDATE_REG(COMM_SIOCNT, value); //just for testing the effect
if (value & 0x80) { //AdamN: Start/Busy Bit.7=1 (Active/Transfering)
StartLink(value); //AdamN: using blocking sockets here can cause noticibly delays
} else UPDATE_REG(COMM_SIOCNT, value);
LogStrPop(9);
}
break;
case NORMAL8:
case NORMAL32:
case UART:
default:
UPDATE_REG(COMM_SIOCNT, value);
break;
} */
/* /*
// old code path for no linking... // old code path for no linking...
{ {
if (value & 0x80) { if (value & 0x80) { //Start bit.7
value &= 0xff7f; value &= 0xff7f;
if ((value & 1) && (value & 0x4000)) { if ((value & 1) && (value & 0x4000)) { //IRQ Enable bit.14
UPDATE_REG(COMM_SIODATA8, 0xFF); UPDATE_REG(COMM_SIODATA8, 0xFF);
IF |= 0x80; IF |= 0x80;
UPDATE_REG(0x202, IF); UPDATE_REG(0x202, IF);
@ -2843,25 +3063,66 @@ void CPUUpdateRegister(u32 address, u16 value)
*/ */
break; break;
case COMM_SIODATA8: case COMM_SIODATA8: //AdamN: 8bit(SIODATA8) on Normal/UART(up to 4x8bit with FIFO), 16bit(SIOMLT_SEND) on Multiplayer mode
if (gba_link_enabled) if(READ16LE(&ioMem[COMM_SIOMLT_SEND]) != (/*READ16LE(&ioMem[COMM_SIOMLT_SEND]) &*/ value)) {
LinkSSend(value); #ifdef GBA_LOGGING
UPDATE_REG(COMM_RCNT, value); if(systemVerbose & VERBOSE_SIO) {
log("SIODATA(%d) : %04X %04X %04X %04X %04X %04X %04X->%04X (VCOUNT = %d)\n", GetTickCount(), READ16LE(&ioMem[COMM_RCNT]), READ16LE(&ioMem[COMM_SIOCNT]), READ16LE(&ioMem[COMM_SIOMULTI0]), READ16LE(&ioMem[COMM_SIOMULTI1]), READ16LE(&ioMem[COMM_SIOMULTI2]), READ16LE(&ioMem[COMM_SIOMULTI3]), READ16LE(&ioMem[COMM_SIOMLT_SEND]), value, VCOUNT );
}
#endif
}
UPDATE_REG(COMM_SIODATA8, value); //COMM_SIOMLT_SEND
/*if (gba_link_enabled && lanlink.connected) //AdamN: added active connection checking, don't send any packet if there are no connection
LinkSSend(value); //AdamN: Does sending packet really needed in this part?(as transfers are initiated by SIOCNT)
UPDATE_REG(COMM_RCNT, value); //AdamN: is this really necessary?? seems to break connection
*/
/*if(linkid && (READ16LE(&ioMem[COMM_SIOMLT_SEND]) & 0x3f)==0x0f) {
lc.WaitForData(-1);
LinkUpdate2(0);
}*/
break; break;
case 0x130: case 0x130: //AdamN: KEYINPUT
P1 |= (value & 0x3FF); P1 |= (value & 0x3FF);
UPDATE_REG(0x130, P1); UPDATE_REG(0x130, P1);
break; break;
case 0x132: case 0x132: //AdamN: KEYCNT
UPDATE_REG(0x132, value & 0xC3FF); UPDATE_REG(0x132, value & 0xC3FF);
break; break;
case COMM_RCNT: case COMM_RCNT: //AdamN: often reach here even when no connection yet
StartGPLink(value); /*if(lanlink.connected)
if(linkid) {
lc.DiscardData(); //AdamN: discarding may cause server to wait for infinity
} else {
//ls.DiscardData();
}*/
lanlink.mode = GetSIOMode(READ16LE(&ioMem[COMM_SIOCNT]), value);
if(READ16LE(&ioMem[COMM_RCNT]) != (/*READ16LE(&ioMem[COMM_RCNT]) &*/ value)) {
#ifdef GBA_LOGGING
if(systemVerbose & VERBOSE_SIO) {
log("RCNT(%d) : %04X->%04X %04X %04X %04X %04X %04X (VCOUNT = %d)\n", GetTickCount(), READ16LE(&ioMem[COMM_RCNT]), value, READ16LE(&ioMem[COMM_SIOCNT]), READ16LE(&ioMem[COMM_SIOMULTI0]), READ16LE(&ioMem[COMM_SIOMULTI1]), READ16LE(&ioMem[COMM_SIOMULTI2]), READ16LE(&ioMem[COMM_SIOMULTI3]), VCOUNT );
}
#endif
}
/*if(LinkHandlerActive) {
LinkCmdQueue(2,value);
c_s.Lock(); //AdamN: Locking resource to prevent deadlock
LinkParam2=value;
LinkCommand|=2; //AdamN: StartGPLink command
c_s.Unlock(); //AdamN: Locking resource to prevent deadlock
} else {
LogStrPush("CPUUpdReg");*/
StartGPLink(value); //AdamN: doesn't need to be put in different thread as it doesn't send/recv data
/*LogStrPop(9);
}*/
break; break;
/*case COMM_IR:
StartIRLink(value); //AdamN: not made yet tho, probably not useful
break;*/
case COMM_JOYCNT: case COMM_JOYCNT:
{ {
u16 cur = READ16LE(&ioMem[COMM_JOYCNT]); u16 cur = READ16LE(&ioMem[COMM_JOYCNT]);
@ -3128,6 +3389,8 @@ void CPUInit(const char *biosFileName, bool useBiosFile)
void CPUReset() void CPUReset()
{ {
EmuReseted = true;
LinkFirstTime = true;
if(gbaSaveType == 0) { if(gbaSaveType == 0) {
if(eepromInUse) if(eepromInUse)
gbaSaveType = 3; gbaSaveType = 3;
@ -3475,21 +3738,27 @@ extern void winlog(const char *, ...);
void CPULoop(int ticks) void CPULoop(int ticks)
{ {
if(EmuCtr>0) {log("Emu inside Emu:%d\n",EmuCtr);return;}
int clockTicks; int clockTicks;
int timerOverflow = 0; int timerOverflow = 0;
// variable used by the CPU core // variable used by the CPU core
cpuTotalTicks = 0; cpuTotalTicks = 0;
cpuBreakLoop = false; //
// shuffle2: what's the purpose? // shuffle2: what's the purpose?
if(gba_link_enabled) /*if(gba_link_enabled && lanlink.connected && lanlink.mode==MULTIPLAYER && frameCount < systemFrameSkip)
cpuNextEvent = 1; //if(linkid)
cpuNextEvent = 159; //224; //else; //AdamN: this is to prevent CPU from executing too many opcodes when frame being skipped which cause Linking instability (ie. in-game timeout reached on client)
else */
cpuNextEvent = CPUUpdateTicks(); //cpuNextEvent = 1; //224 //AdamN: this will cause slowdown?*/
bool NewFrame = false;
cpuBreakLoop = false; //cpuBreakLoop = false;
cpuNextEvent = CPUUpdateTicks(); //cpuNextEvent = CPUUpdateTicks(); //
if(cpuNextEvent > ticks) if(cpuNextEvent > ticks)
cpuNextEvent = ticks; cpuNextEvent = ticks;
for(;;) { for(;;) {
#ifndef FINAL_VERSION #ifndef FINAL_VERSION
if(systemDebug) { if(systemDebug) {
@ -3526,6 +3795,7 @@ void CPULoop(int ticks)
} }
#endif /* FINAL_VERSION */ #endif /* FINAL_VERSION */
if(breakpt && armNextPC==breakaddr) holdState=true; //AdamN: checking for breakpoint
if(!holdState && !SWITicks) { if(!holdState && !SWITicks) {
if(armState) { if(armState) {
if (!armExecute()) if (!armExecute())
@ -3581,7 +3851,7 @@ void CPULoop(int ticks)
lcdTicks += 224; lcdTicks += 224;
DISPSTAT |= 2; DISPSTAT |= 2;
UPDATE_REG(0x04, DISPSTAT); UPDATE_REG(0x04, DISPSTAT);
if(DISPSTAT & 16) { if(DISPSTAT & 16) { // entering H-Blank
IF |= 2; IF |= 2;
UPDATE_REG(0x202, IF); UPDATE_REG(0x202, IF);
} }
@ -3608,12 +3878,15 @@ void CPULoop(int ticks)
DISPSTAT &= 0xFFFD; DISPSTAT &= 0xFFFD;
if(VCOUNT == 160) { if(VCOUNT == 160) {
count++; count++;
NewFrame = true;
systemFrame(); systemFrame();
if((count % 10) == 0) { /*if((count % 10) == 0) {
system10Frames(60); system10Frames(60);
} }*/
if(count == 60) { system1Frames(60, count);
if(count >= 60) {
u32 time = systemGetClock(); u32 time = systemGetClock();
if(time != lastTime) { if(time != lastTime) {
u32 t = 100000/(time - lastTime); u32 t = 100000/(time - lastTime);
@ -3623,6 +3896,7 @@ void CPULoop(int ticks)
lastTime = time; lastTime = time;
count = 0; count = 0;
} }
u32 joy = 0; u32 joy = 0;
// update joystick information // update joystick information
if(systemReadJoypads()) if(systemReadJoypads())
@ -3667,11 +3941,12 @@ void CPULoop(int ticks)
DISPSTAT |= 1; DISPSTAT |= 1;
DISPSTAT &= 0xFFFD; DISPSTAT &= 0xFFFD;
UPDATE_REG(0x04, DISPSTAT); UPDATE_REG(0x04, DISPSTAT);
if(DISPSTAT & 0x0008) { if(DISPSTAT & 0x0008) { //entering V-Blank
IF |= 1; IF |= 1;
UPDATE_REG(0x202, IF); UPDATE_REG(0x202, IF);
} }
CPUCheckDMA(1, 0x0f); CPUCheckDMA(1, 0x0f);
if(frameCount >= framesToSkip) { if(frameCount >= framesToSkip) {
systemDrawScreen(); systemDrawScreen();
frameCount = 0; frameCount = 0;
@ -3786,7 +4061,10 @@ void CPULoop(int ticks)
} }
break; break;
} }
} } //else //AdamN: this seems to fix the instability of linking when frame being skipped, but it causes artifact at the top lines when connection established in game, does cpu executes more opcodes when frameskipped?
//frameCount++; //AdamN: shouldn't increase frameCount here, instead do something useless just to delay before calling LinkUpdate to maintain stability
//if(lanlink.connected) if(linkid) cpuNextEvent = cpuTotalTicks;/*lc.WaitForData(0); else ls.WaitForData(0);*/
// entering H-Blank // entering H-Blank
DISPSTAT |= 2; DISPSTAT |= 2;
UPDATE_REG(0x04, DISPSTAT); UPDATE_REG(0x04, DISPSTAT);
@ -3796,6 +4074,7 @@ void CPULoop(int ticks)
IF |= 2; IF |= 2;
UPDATE_REG(0x202, IF); UPDATE_REG(0x202, IF);
} }
//
} }
} }
} }
@ -3942,8 +4221,21 @@ void CPULoop(int ticks)
if (gba_joybus_enabled) if (gba_joybus_enabled)
JoyBusUpdate(clockTicks); JoyBusUpdate(clockTicks);
if (gba_link_enabled) if (gba_link_enabled && (lanlink.connected || !lanlink.active)) { //AdamN: don't update if there are no connection
LinkUpdate(clockTicks); LinkUpdate(clockTicks); //AdamN: when frame being skipped LinkUpdate might not be called(?) thus causing instability
NewFrame = false;
//if(LinkHandlerActive) {
//LinkCmdQueue(8,clockTicks);
//c_s.Lock(); //AdamN: Locking resource to prevent deadlock
//LinkParam8=clockTicks;
//LinkCommand|=8; //AdamN: LinkUpdate command
//c_s.Unlock(); //AdamN: Locking resource to prevent deadlock
//} else if(/*(clockTicks & 1)&&*/(lanlink.connected)) { //AdamN: it seems LinkUpdate need to be called every cycle, occasionally doesn't works
//LogStrPush("CPULoop");
//LinkUpdate2(clockTicks); //AdamN: using blocking sockets here can cause noticibly delays
//LogStrPop(7);
//}
}
cpuNextEvent = CPUUpdateTicks(); cpuNextEvent = CPUUpdateTicks();
@ -3960,8 +4252,11 @@ void CPULoop(int ticks)
} }
// shuffle2: what's the purpose? // shuffle2: what's the purpose?
if(gba_link_enabled) /*if(gba_link_enabled && lanlink.connected)
cpuNextEvent = 1; cpuNextEvent = 1; //AdamN: this will cause great slowdown*/
/*if(gba_link_enabled && lanlink.connected && lanlink.mode==MULTIPLAYER && frameCount < systemFrameSkip)
//if(linkid)
cpuNextEvent = 159; //224;*/ //cpuTotalTicks+224; //AdamN: this is to prevent CPU from executing too many opcodes when frame being skipped which cause Linking instability (ie. in-game timeout reached on client)
if(IF && (IME & 1) && armIrqEnable) { if(IF && (IME & 1) && armIrqEnable) {
int res = IF & IE; int res = IF & IE;

View File

@ -66,6 +66,12 @@ extern bool armState;
extern int armMode; extern int armMode;
extern void (*cpuSaveGameFunc)(u32,u8); extern void (*cpuSaveGameFunc)(u32,u8);
extern int cpuNextEvent;
extern int cpuTotalTicks;
extern bool holdState;
extern bool breakpt;
extern u32 breakaddr;
#ifdef BKPT_SUPPORT #ifdef BKPT_SUPPORT
extern u8 freezeWorkRAM[0x40000]; extern u8 freezeWorkRAM[0x40000];
extern u8 freezeInternalRAM[0x8000]; extern u8 freezeInternalRAM[0x8000];

File diff suppressed because it is too large Load Diff

View File

@ -4,30 +4,41 @@
#include <SFML/Network.hpp> #include <SFML/Network.hpp>
#endif #endif
#ifdef _MSC_VER //#ifdef _WIN32
#include "../Win32/WinHelper.h" // AdamN: for CCriticalSection
#endif
#define LINK_PARENTLOST 0x80 #define LINK_PARENTLOST 0x80
#define UNSUPPORTED -1 #define UNSUPPORTED -1
#define MULTIPLAYER 0 #define MULTIPLAYER 0
#define NORMAL8 1 #define NORMAL8 1
#define NORMAL32 2 #define NORMAL32 2 //AdamN: wireless use normal32 also
#define UART 3 #define UART 3
#define JOYBUS 4 #define JOYBUS 4
#define GP 5 #define GP 5
#define INFRARED 6 //AdamN: Infrared Register at 4000136h
#define RFU_INIT 0 #define RFU_INIT 0
#define RFU_COMM 1 #define RFU_COMM 1
#define RFU_SEND 2 #define RFU_SEND 2
#define RFU_RECV 3 #define RFU_RECV 3
#define COMM_SIODATA32_L 0x120 #define COMM_SIODATA32_L 0x120 //AdamN: Lower 16bit on Normal mode
#define COMM_SIODATA32_H 0x122 #define COMM_SIODATA32_H 0x122 //AdamN: Higher 16bit on Normal mode
#define COMM_SIOMULTI0 0x120 //AdamN: SIOMULTI0 (16bit) on MultiPlayer mode (Parent/Master)
#define COMM_SIOMULTI1 0x122 //AdamN: SIOMULTI1 (16bit) on MultiPlayer mode (Child1/Slave1)
#define COMM_SIOMULTI2 0x124 //AdamN: SIOMULTI2 (16bit) on MultiPlayer mode (Child2/Slave2)
#define COMM_SIOMULTI3 0x126 //AdamN: SIOMULTI3 (16bit) on MultiPlayer mode (Child3/Slave3)
#define COMM_SIOCNT 0x128 #define COMM_SIOCNT 0x128
#define COMM_SIODATA8 0x12a #define COMM_SIODATA8 0x12a //AdamN: 8bit on Normal/UART mode, (up to 4x8bit with FIFO)
#define COMM_RCNT 0x134 #define COMM_SIOMLT_SEND 0x12a //AdamN: SIOMLT_SEND (16bit R/W) on MultiPlayer mode (local outgoing)
#define COMM_RCNT 0x134 //AdamN: SIO Mode (4bit data) on GeneralPurpose mode
#define COMM_IR 0x136 //AdamN: Infrared Register (16bit) 1bit data at a time(LED On/Off)?
#define COMM_JOYCNT 0x140 #define COMM_JOYCNT 0x140
#define COMM_JOY_RECV_L 0x150 #define COMM_JOY_RECV_L 0x150 //AdamN: Send/Receive 8bit Lower first then 8bit Higher
#define COMM_JOY_RECV_H 0x152 #define COMM_JOY_RECV_H 0x152
#define COMM_JOY_TRANS_L 0x154 #define COMM_JOY_TRANS_L 0x154 //AdamN: Send/Receive 8bit Lower first then 8bit Higher
#define COMM_JOY_TRANS_H 0x156 #define COMM_JOY_TRANS_H 0x156
#define COMM_JOYSTAT 0x158 #define COMM_JOYSTAT 0x158 //AdamN: Send/Receive 8bit lower only
#define JOYSTAT_RECV 2 #define JOYSTAT_RECV 2
#define JOYSTAT_SEND 8 #define JOYSTAT_SEND 8
@ -53,11 +64,14 @@ typedef struct {
int lastlinktime; int lastlinktime;
u8 numgbas; u8 numgbas;
u8 linkflags; u8 linkflags;
int rfu_q[4]; int rfu_q[5];
u8 rfu_request[4]; u16 rfu_qid[5];
int rfu_linktime[4]; u8 rfu_request[5];
u32 rfu_bdata[4][7]; u16 rfu_reqid[5];
u32 rfu_data[4][32]; int rfu_linktime[5];
u32 rfu_bdata[5][7]; //for 0x16/0x1d/0x1e?
u32 rfu_gdata[5]; //for 0x17/0x19?/0x1e?
u32 rfu_data[5][32]; //for 0x24-0x26
} LINKDATA; } LINKDATA;
class lserver{ class lserver{
@ -65,56 +79,81 @@ class lserver{
fd_set fdset; fd_set fdset;
timeval wsocktimeout; timeval wsocktimeout;
//timeval udptimeout; //timeval udptimeout;
public:
char inbuffer[256], outbuffer[256]; char inbuffer[256], outbuffer[256];
int *intinbuffer; int *intinbuffer;
u16 *u16inbuffer; u16 *u16inbuffer;
u32 *u32inbuffer;
int *intoutbuffer; int *intoutbuffer;
u16 *u16outbuffer; u16 *u16outbuffer;
u32 *u32outbuffer;
int insize, outsize;
int counter; int counter;
int done; int done;
public:
int howmanytimes; int howmanytimes;
SOCKET tcpsocket[4]; SOCKET tcpsocket[5];
SOCKADDR_IN udpaddr[4]; SOCKADDR_IN udpaddr[5];
DWORD latency[5];
lserver(void); lserver(void);
int Init(void*); int Init(void*);
void Send(void); BOOL Send(void);
void Recv(void); BOOL Recv(void);
BOOL WaitForData(int ms);
BOOL SendData(int size, int nretry = 0);
BOOL SendData(const char *buf, int size, int nretry = 0);
BOOL RecvData(int size, int idx, bool peek = false);
BOOL IsDataReady(void);
int DiscardData(int idx);
}; };
class lclient{ class lclient{
fd_set fdset; fd_set fdset;
timeval wsocktimeout; timeval wsocktimeout;
public:
char inbuffer[256], outbuffer[256]; char inbuffer[256], outbuffer[256];
int *intinbuffer; int *intinbuffer;
u16 *u16inbuffer; u16 *u16inbuffer;
u32 *u32inbuffer;
int *intoutbuffer; int *intoutbuffer;
u16 *u16outbuffer; u16 *u16outbuffer;
int numbytes; u32 *u32outbuffer;
public: int numbytes, insize, outsize;
bool oncesend; bool oncesend;
SOCKADDR_IN serverinfo; SOCKADDR_IN serverinfo;
SOCKET noblock; SOCKET noblock;
int numtransfers; int numtransfers;
lclient(void); lclient(void);
int Init(LPHOSTENT, void*); int Init(LPHOSTENT, void*);
void Send(void); BOOL Send(void);
void Recv(void); BOOL Recv(void);
void CheckConn(void); void CheckConn(void);
BOOL SendData(int size, int nretry = 0);
BOOL SendData(const char *buf, int size, int nretry = 0);
BOOL RecvData(int size, bool peek = false);
BOOL WaitForData(int ms);
BOOL IsDataReady(void);
int DiscardData(void);
}; };
typedef struct { typedef struct {
SOCKET tcpsocket; SOCKET tcpsocket;
//SOCKET udpsocket; //SOCKET udpsocket;
DWORD latency;
int numgbas; int numgbas;
HANDLE thread; HANDLE thread;
u8 type; u8 type;
u8 server; u8 server;
bool terminate; bool terminate;
bool connected; bool connected;
bool speed; bool speed; //speedhack
bool active; bool active;
int mode;
} LANLINKDATA; } LANLINKDATA;
typedef struct {
u16 Command;
u16 Param;
} LINKCMDPRM;
#endif #endif
extern bool gba_joybus_enabled; extern bool gba_joybus_enabled;
@ -124,24 +163,47 @@ extern sf::IPAddress joybusHostAddr;
extern void JoyBusConnect(); extern void JoyBusConnect();
extern void JoyBusShutdown(); extern void JoyBusShutdown();
extern void JoyBusUpdate(int ticks); extern void JoyBusUpdate(int ticks);
extern inline int GetSIOMode(u16 siocnt, u16 rcnt);
extern bool gba_link_enabled; extern bool gba_link_enabled;
#ifdef _MSC_VER #ifdef _MSC_VER
extern void LogStrPush(const char *str);
extern void LogStrPop(int len);
extern void LinkCmdQueue(u16 Cmd, u16 Prm);
extern u8 gbStartLink(u8 b);
extern u16 gbLinkUpdate(u8 b);
extern void StartLink(u16); extern void StartLink(u16);
extern void StartLink2(u16);
extern void StartGPLink(u16); extern void StartGPLink(u16);
extern void LinkSSend(u16); extern void LinkSSend(u16);
extern void LinkUpdate(int); extern void LinkUpdate(int);
extern void LinkUpdate2(int ticks, int FrameCnt);
extern void LinkChildStop(); extern void LinkChildStop();
extern void LinkChildSend(u16); extern void LinkChildSend(u16);
extern void CloseLanLink(); extern void CloseLink(); //CloseLanLink(); //AdamN: this should be CloseLink isn't?
extern char *MakeInstanceFilename(const char *Input); extern char *MakeInstanceFilename(const char *Input);
extern LANLINKDATA lanlink; extern LANLINKDATA lanlink;
extern int vbaid; extern int vbaid;
extern bool rfu_enabled; extern bool rfu_enabled;
extern int linktimeout; extern int linktimeout;
extern u8 gbSIO_SC;
extern lclient lc; extern lclient lc;
extern lserver ls;
extern int linkid; extern int linkid;
extern bool linkdatarecvd[4];
extern bool LinkIsWaiting;
extern bool LinkFirstTime;
extern bool EmuReseted;
extern int EmuCtr;
extern WinHelper::CCriticalSection c_s; //AdamN: critical section object to lock shared resource on multithread as CWnd is not thread-safe
extern int LinkCommand;
extern int LinkParam1;
extern int LinkParam2;
extern int LinkParam4;
extern int LinkParam8;
extern bool LinkHandlerActive;
//extern CPtrList LinkCmdList;
#else // These are stubbed for now #else // These are stubbed for now
inline void StartLink(u16){} inline void StartLink(u16){}
inline void StartGPLink(u16){} inline void StartGPLink(u16){}

View File

@ -15,6 +15,8 @@
#define VERBOSE_UNDEFINED 256 #define VERBOSE_UNDEFINED 256
#define VERBOSE_AGBPRINT 512 #define VERBOSE_AGBPRINT 512
#define VERBOSE_SOUNDOUTPUT 1024 #define VERBOSE_SOUNDOUTPUT 1024
#define VERBOSE_SIO 2048
#define VERBOSE_LINK 4096
extern reg_pair reg[45]; extern reg_pair reg[45];
extern bool ioReadable[0x400]; extern bool ioReadable[0x400];

View File

@ -303,7 +303,7 @@ void soundEvent(u32 address, u16 data)
{ {
switch ( address ) switch ( address )
{ {
case SGCNT0_H: case SGCNT0_H: //SOUNDCNT_H
write_SGCNT0_H( data ); write_SGCNT0_H( data );
break; break;
@ -319,7 +319,7 @@ void soundEvent(u32 address, u16 data)
WRITE16LE( &ioMem[address], data ); WRITE16LE( &ioMem[address], data );
break; break;
case 0x88: case 0x88: //SOUNDBIAS
data &= 0xC3FF; data &= 0xC3FF;
WRITE16LE( &ioMem[address], data ); WRITE16LE( &ioMem[address], data );
break; break;

View File

@ -856,7 +856,7 @@ void BIOS_RegisterRamReset(u32 flags)
// no need to trace here. this is only called directly from GBA.cpp // no need to trace here. this is only called directly from GBA.cpp
// to emulate bios initialization // to emulate bios initialization
CPUUpdateRegister(0x0, 0x80); CPUUpdateRegister(0x0, 0x80); //DISPCNT
if(flags) { if(flags) {
if(flags & 0x01) { if(flags & 0x01) {
@ -894,35 +894,35 @@ void BIOS_RegisterRamReset(u32 flags)
for(i = 0; i < 0x18; i++) for(i = 0; i < 0x18; i++)
CPUUpdateRegister(0xb0+i*2, 0); CPUUpdateRegister(0xb0+i*2, 0);
CPUUpdateRegister(0x130, 0); CPUUpdateRegister(0x130, 0); //KEYINPUT
CPUUpdateRegister(0x20, 0x100); CPUUpdateRegister(0x20, 0x100); //BG2PA
CPUUpdateRegister(0x30, 0x100); CPUUpdateRegister(0x30, 0x100); //BG3PA
CPUUpdateRegister(0x26, 0x100); CPUUpdateRegister(0x26, 0x100); //BG2PD
CPUUpdateRegister(0x36, 0x100); CPUUpdateRegister(0x36, 0x100); //BG3PD
} }
if(flags & 0x20) { if(flags & 0x20) {
int i; int i;
for(i = 0; i < 8; i++) for(i = 0; i < 8; i++)
CPUUpdateRegister(0x110+i*2, 0); CPUUpdateRegister(0x110+i*2, 0); //Unused Registers after Timer Register?
CPUUpdateRegister(0x134, 0x8000); CPUUpdateRegister(0x134, 0x8000); //COMM_RCNT for GP/JOYBUS?
for(i = 0; i < 7; i++) for(i = 0; i < 7; i++)
CPUUpdateRegister(0x140+i*2, 0); CPUUpdateRegister(0x140+i*2, 0); //Unused Registers after COMM_JOYCNT?
} }
if(flags & 0x40) { if(flags & 0x40) {
int i; int i;
CPUWriteByte(0x4000084, 0); CPUWriteByte(0x4000084, 0); //SOUNDCNT_X, Is this realy needed as below it's rewritten right?
CPUWriteByte(0x4000084, 0x80); CPUWriteByte(0x4000084, 0x80); //SOUNDCNT_X, Rewritten above?
CPUWriteMemory(0x4000080, 0x880e0000); CPUWriteMemory(0x4000080, 0x880e0000); //SOUNDCNT_L
CPUUpdateRegister(0x88, CPUReadHalfWord(0x4000088)&0x3ff); CPUUpdateRegister(0x88, CPUReadHalfWord(0x4000088)&0x3ff); //SOUNDBIAS
CPUWriteByte(0x4000070, 0x70); CPUWriteByte(0x4000070, 0x70); //SOUND3CNT_L
for(i = 0; i < 8; i++) for(i = 0; i < 8; i++)
CPUUpdateRegister(0x90+i*2, 0); CPUUpdateRegister(0x90+i*2, 0);
CPUWriteByte(0x4000070, 0); CPUWriteByte(0x4000070, 0); //SOUND3CNT_L, Rewritten again?
for(i = 0; i < 8; i++) for(i = 0; i < 8; i++)
CPUUpdateRegister(0x90+i*2, 0); CPUUpdateRegister(0x90+i*2, 0);
CPUWriteByte(0x4000084, 0); CPUWriteByte(0x4000084, 0); //SOUNDCNT_X, Another Rewriten??
} }
} }
} }

View File

@ -43,6 +43,8 @@ public:
void reset(); // stop and reset the secondary sound buffer void reset(); // stop and reset the secondary sound buffer
void resume(); // resume the secondary sound buffer void resume(); // resume the secondary sound buffer
void write(u16 * finalWave, int length); // write the emulated sound to the secondary sound buffer void write(u16 * finalWave, int length); // write the emulated sound to the secondary sound buffer
// Configuration Changes
void setThrottle( unsigned short throttle );
}; };
@ -191,6 +193,8 @@ bool DirectSound::init(long sampleRate)
return false; return false;
} }
setThrottle(theApp.throttle); //AdamN: setting sound pitch to current throttle
return true; return true;
} }
@ -240,7 +244,7 @@ void DirectSound::write(u16 * finalWave, int length)
LPVOID lpvPtr2; LPVOID lpvPtr2;
DWORD dwBytes2 = 0; DWORD dwBytes2 = 0;
if( !speedup && synchronize && !theApp.throttle ) { if( !speedup && synchronize /*&& !theApp.throttle*/ ) {
hr = dsbSecondary->GetStatus(&status); hr = dsbSecondary->GetStatus(&status);
if( status & DSBSTATUS_PLAYING ) { if( status & DSBSTATUS_PLAYING ) {
if( !soundPaused ) { if( !soundPaused ) {
@ -310,6 +314,18 @@ void DirectSound::write(u16 * finalWave, int length)
} }
} }
void DirectSound::setThrottle( unsigned short throttle ) //AdamN: doesn't works quite right yet
{
if(!pDirectSound) return;
if( dsbSecondary == NULL ) return;
if( throttle == 0 ) throttle = 100;
//HRESULT hr = dsbPrimary->SetFrequency( (DWORD)(soundGetSampleRate() * throttle / 100.0f) ); //AdamN: may not be valid for primary buffer, also need to check CAPS whether frequency is supported or not
//ASSERT( hr == S_OK );
HRESULT hr = dsbSecondary->SetFrequency( (DWORD)(soundGetSampleRate() * throttle / 100.0f) ); //AdamN: may need to use IDirectMusicSegment8::SetLength to adjust the inverval for looping to prevent silence when pitch is higher than normal pitch or restarted/relooped when pitch is lower than normal before it finished the whole stream
ASSERT( hr == S_OK );
}
SoundDriver *newDirectSound() SoundDriver *newDirectSound()
{ {
return new DirectSound(); return new DirectSound();

View File

@ -33,10 +33,15 @@ Disassemble::Disassemble(CWnd* pParent /*=NULL*/)
m_t = FALSE; m_t = FALSE;
m_v = FALSE; m_v = FALSE;
m_z = FALSE; m_z = FALSE;
m_breakpt = FALSE;
m_autostep = FALSE;
mode = -1; mode = -1;
//}}AFX_DATA_INIT //}}AFX_DATA_INIT
mode = 0; mode = 0;
address = 0; address = 0;
//breakaddr = 0xffffffff;
//breakpt = false;
autostep = false;
autoUpdate = false; autoUpdate = false;
count = 1; count = 1;
} }
@ -56,6 +61,9 @@ void Disassemble::DoDataExchange(CDataExchange* pDX)
DDX_Check(pDX, IDC_V, m_v); DDX_Check(pDX, IDC_V, m_v);
DDX_Check(pDX, IDC_Z, m_z); DDX_Check(pDX, IDC_Z, m_z);
DDX_Radio(pDX, IDC_AUTOMATIC, mode); DDX_Radio(pDX, IDC_AUTOMATIC, mode);
DDX_Check(pDX, IDC_BREAK_AT, m_breakpt);
DDX_Control(pDX, IDC_ADDRESS2, m_address2);
DDX_Check(pDX, IDC_AUTO_STEP, m_autostep);
//}}AFX_DATA_MAP //}}AFX_DATA_MAP
} }
@ -73,6 +81,8 @@ BEGIN_MESSAGE_MAP(Disassemble, CDialog)
ON_BN_CLICKED(IDC_THUMB, OnThumb) ON_BN_CLICKED(IDC_THUMB, OnThumb)
ON_WM_VSCROLL() ON_WM_VSCROLL()
//}}AFX_MSG_MAP //}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_BREAK_AT, &Disassemble::OnBnClickedBreakAt)
ON_BN_CLICKED(IDC_STEPINTO, &Disassemble::OnBnClickedStepinto)
END_MESSAGE_MAP() END_MESSAGE_MAP()
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -338,3 +348,38 @@ void Disassemble::PostNcDestroy()
{ {
delete this; delete this;
} }
void Disassemble::OnBnClickedBreakAt()
{
// TODO: Add your control notification handler code here
CString buffer;
m_address2.GetWindowText(buffer);
sscanf(buffer, "%x", &breakaddr);
//if (mode==1)
breakaddr&=0xfffffffc;
//else if (mode==2)
// breakaddr&=0xfffffffe;
m_breakpt = !m_breakpt;
breakpt = (bool)m_breakpt;
refresh();
}
void Disassemble::OnBnClickedStepinto()
{
// TODO: Add your control notification handler code here
if(rom != NULL)
{
if(armState)
breakaddr = breakaddr + 4;
else
breakaddr = breakaddr + 2;
char buffer[20];
sprintf(buffer, _T("%08x"), breakaddr);
m_address2.SetWindowText(buffer);
cpuNextEvent = 1; //cpuTotalTicks;
holdState = false;
refresh();
}
}

View File

@ -22,13 +22,17 @@ class Disassemble : public ResizeDlg, IUpdateListener
void refresh(); void refresh();
int count; int count;
bool autoUpdate; bool autoUpdate;
//bool breakpt;
bool autostep;
u32 address; u32 address;
//u32 breakaddr;
Disassemble(CWnd* pParent = NULL); // standard constructor Disassemble(CWnd* pParent = NULL); // standard constructor
// Dialog Data // Dialog Data
//{{AFX_DATA(Disassemble) //{{AFX_DATA(Disassemble)
enum { IDD = IDD_DISASSEMBLE }; enum { IDD = IDD_DISASSEMBLE };
CEdit m_address; CEdit m_address;
CEdit m_address2;
CListBox m_list; CListBox m_list;
BOOL m_c; BOOL m_c;
BOOL m_f; BOOL m_f;
@ -37,6 +41,8 @@ class Disassemble : public ResizeDlg, IUpdateListener
BOOL m_t; BOOL m_t;
BOOL m_v; BOOL m_v;
BOOL m_z; BOOL m_z;
BOOL m_breakpt;
BOOL m_autostep;
int mode; int mode;
//}}AFX_DATA //}}AFX_DATA
@ -67,6 +73,9 @@ class Disassemble : public ResizeDlg, IUpdateListener
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
//}}AFX_MSG //}}AFX_MSG
DECLARE_MESSAGE_MAP() DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedBreakAt();
afx_msg void OnBnClickedStepinto();
}; };
//{{AFX_INSERT_LOCATION}} //{{AFX_INSERT_LOCATION}}

View File

@ -1,8 +1,13 @@
#include "stdafx.h" #include "stdafx.h"
//#include "afxctl.h"
#include "vba.h" #include "vba.h"
#include "LinkOptions.h" #include "LinkOptions.h"
#include "../gba/GBALink.h" #include "../gba/GBALink.h"
/*#ifdef _MSC_VER //#ifdef _WIN32
#include "WinHelper.h" // AdamN: MFC MultiThreading
#endif*/
extern lserver ls; extern lserver ls;
#ifdef _DEBUG #ifdef _DEBUG
@ -49,7 +54,7 @@ void LinkOptions::DoDataExchange(CDataExchange* pDX)
BOOL LinkOptions::OnInitDialog(){ BOOL LinkOptions::OnInitDialog(){
TCITEM tabitem; TCITEM tabitem;
char tabtext[3][8] = {"General", "Server", "Client"}; char tabtext[3][8] = {_T("General"), _T("Server"), _T("Client")};
int i; int i;
CDialog::OnInitDialog(); CDialog::OnInitDialog();
@ -145,6 +150,11 @@ void LinkServer::DoDataExchange(CDataExchange* pDX)
{ {
CDialog::DoDataExchange(pDX); CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(LinkServer) //{{AFX_DATA_MAP(LinkServer)
BOOL ok = (theApp.cartridgeType != IMAGE_GB);
GetDlgItem(IDC_LINK3P)->EnableWindow(ok);
GetDlgItem(IDC_LINK4P)->EnableWindow(ok);
GetDlgItem(IDC_LINK5P)->EnableWindow(rfu_enabled && ok);
DDX_Radio(pDX, IDC_LINK2P, m_numplayers); DDX_Radio(pDX, IDC_LINK2P, m_numplayers);
DDX_Radio(pDX, IDC_LINKTCP, m_prottype); DDX_Radio(pDX, IDC_LINKTCP, m_prottype);
DDX_Check(pDX, IDC_SSPEED, m_speed); DDX_Check(pDX, IDC_SSPEED, m_speed);
@ -195,7 +205,7 @@ BOOL LinkServer::OnInitDialog()
{ {
CDialog::OnInitDialog(); CDialog::OnInitDialog();
m_numplayers = lanlink.numgbas; m_numplayers = max(lanlink.numgbas-1,0);
m_prottype = lanlink.type; m_prottype = lanlink.type;
m_speed = lanlink.speed; m_speed = lanlink.speed;
@ -455,14 +465,14 @@ void LinkOptions::OnOk()
void LinkGeneral::OnRadio1() void LinkGeneral::OnRadio1()
{ {
m_type = 0; m_type = 0;
lanlink.active = 0; lanlink.active = 0; //Single Computer
GetParent()->Invalidate(); GetParent()->Invalidate();
} }
void LinkGeneral::OnRadio2() void LinkGeneral::OnRadio2()
{ {
m_type = 1; m_type = 1;
lanlink.active = 1; lanlink.active = 1; //Networks
GetParent()->Invalidate(); GetParent()->Invalidate();
} }
@ -473,7 +483,7 @@ BOOL LinkGeneral::OnInitDialog(){
CDialog::OnInitDialog(); CDialog::OnInitDialog();
m_timeout.LimitText(5); m_timeout.LimitText(5);
sprintf(timeout, "%d", linktimeout); sprintf(timeout, _T("%d"), linktimeout);
m_timeout.SetWindowText(timeout); m_timeout.SetWindowText(timeout);
m_type = lanlink.active; m_type = lanlink.active;
@ -504,8 +514,8 @@ void LinkServer::OnServerStart()
if((errorcode=ls.Init(&dlg))!=0){ if((errorcode=ls.Init(&dlg))!=0){
char message[50]; char message[50];
sprintf(message, "Error %d occured.\nPlease try again.", errorcode); sprintf(message, _T("Error %d occured.\nPlease try again."), errorcode);
MessageBox(message, "Error", MB_OK); MessageBox(message, _T("Error"), MB_OK);
return; return;
} }
@ -520,6 +530,7 @@ BOOL LinkClient::OnInitDialog()
m_prottype = lanlink.type; m_prottype = lanlink.type;
m_hacks = lanlink.speed; m_hacks = lanlink.speed;
m_serverip.SetWindowText(_T("localhost"));
UpdateData(FALSE); UpdateData(FALSE);
@ -541,9 +552,10 @@ void LinkClient::OnLinkConnect()
m_serverip.GetWindowText(ipaddress, 30); m_serverip.GetWindowText(ipaddress, 30);
if((errorcode=lc.Init(gethostbyname(ipaddress), &dlg))!=0){ if((errorcode=lc.Init(gethostbyname(ipaddress), &dlg))!=0){
char message[50]; char message[50];
sprintf(message, "Error %d occured.\nPlease try again.", errorcode); sprintf(message, _T("Error %d occured.\nPlease try again."), errorcode);
MessageBox(message, "Error", MB_OK); MessageBox(message, _T("Error"), MB_OK);
return; return;
} }
dlg.DoModal(); dlg.DoModal();
@ -557,7 +569,7 @@ void LinkOptions::GetAllData(LinkGeneral *src)
src->UpdateData(true); src->UpdateData(true);
src->m_timeout.GetWindowText(timeout, 5); src->m_timeout.GetWindowText(timeout, 5);
sscanf(timeout, "%d", &linktimeout); sscanf(timeout, _T("%d"), &linktimeout);
if(src->m_type==0){ if(src->m_type==0){
lanlink.speed = 0; lanlink.speed = 0;
@ -593,6 +605,7 @@ void ServerWait::DoDataExchange(CDataExchange* pDX)
//}}AFX_DATA_MAP //}}AFX_DATA_MAP
} }
BEGIN_MESSAGE_MAP(ServerWait, CDialog) BEGIN_MESSAGE_MAP(ServerWait, CDialog)
//{{AFX_MSG_MAP(ServerWait) //{{AFX_MSG_MAP(ServerWait)
ON_BN_CLICKED(ID_CANCEL, OnCancel) ON_BN_CLICKED(ID_CANCEL, OnCancel)
@ -604,7 +617,9 @@ END_MESSAGE_MAP()
void ServerWait::OnCancel() void ServerWait::OnCancel()
{ {
lanlink.terminate = true; c_s.Lock(); //AdamN: Locking resource to prevent deadlock
lanlink.terminate = true; //AdamN: accessing this might not be thread-safe w/o locking
c_s.Unlock(); //AdamN: Unlock it after use
CDialog::OnCancel(); CDialog::OnCancel();
} }

View File

@ -33,6 +33,7 @@ Logging::Logging(CWnd* pParent /*=NULL*/)
m_dma3 = FALSE; m_dma3 = FALSE;
m_agbprint = FALSE; m_agbprint = FALSE;
m_undefined = FALSE; m_undefined = FALSE;
m_sio = FALSE;
//}}AFX_DATA_INIT //}}AFX_DATA_INIT
} }
@ -52,6 +53,8 @@ void Logging::DoDataExchange(CDataExchange* pDX)
DDX_Check(pDX, IDC_VERBOSE_AGBPRINT, m_agbprint); DDX_Check(pDX, IDC_VERBOSE_AGBPRINT, m_agbprint);
DDX_Check(pDX, IDC_VERBOSE_UNDEFINED, m_undefined); DDX_Check(pDX, IDC_VERBOSE_UNDEFINED, m_undefined);
DDX_Check(pDX, IDC_VERBOSE_SOUNDOUTPUT, m_sound_output); DDX_Check(pDX, IDC_VERBOSE_SOUNDOUTPUT, m_sound_output);
DDX_Check(pDX, IDC_VERBOSE_SIO, m_sio);
DDX_Check(pDX, IDC_VERBOSE_LINK, m_link);
} }
@ -69,10 +72,13 @@ BEGIN_MESSAGE_MAP(Logging, CDialog)
ON_BN_CLICKED(IDC_VERBOSE_UNALIGNED_ACCESS, OnVerboseUnalignedAccess) ON_BN_CLICKED(IDC_VERBOSE_UNALIGNED_ACCESS, OnVerboseUnalignedAccess)
ON_BN_CLICKED(IDC_VERBOSE_UNDEFINED, OnVerboseUndefined) ON_BN_CLICKED(IDC_VERBOSE_UNDEFINED, OnVerboseUndefined)
ON_BN_CLICKED(IDC_VERBOSE_SOUNDOUTPUT, OnVerboseSoundoutput) ON_BN_CLICKED(IDC_VERBOSE_SOUNDOUTPUT, OnVerboseSoundoutput)
ON_BN_CLICKED(IDC_VERBOSE_SIO, OnVerboseSIO)
ON_BN_CLICKED(IDC_SAVE, OnSave) ON_BN_CLICKED(IDC_SAVE, OnSave)
ON_EN_ERRSPACE(IDC_LOG, OnErrspaceLog) ON_EN_ERRSPACE(IDC_LOG, OnErrspaceLog)
ON_EN_MAXTEXT(IDC_LOG, OnMaxtextLog) ON_EN_MAXTEXT(IDC_LOG, OnMaxtextLog)
ON_WM_CLOSE() ON_WM_CLOSE()
// ON_BN_CLICKED(IDC_VERBOSE_LINK, &Logging::OnBnClickedVerboseLink)
ON_BN_CLICKED(IDC_VERBOSE_LINK, &Logging::OnVerboseLink)
END_MESSAGE_MAP() END_MESSAGE_MAP()
@ -147,6 +153,16 @@ void Logging::OnVerboseSoundoutput()
systemVerbose ^= VERBOSE_SOUNDOUTPUT; systemVerbose ^= VERBOSE_SOUNDOUTPUT;
} }
void Logging::OnVerboseSIO()
{
systemVerbose ^= VERBOSE_SIO;
}
void Logging::OnVerboseLink()
{
systemVerbose ^= VERBOSE_LINK;
}
void Logging::OnSave() void Logging::OnSave()
{ {
int len = m_log.GetWindowTextLength(); int len = m_log.GetWindowTextLength();
@ -213,6 +229,8 @@ BOOL Logging::OnInitDialog()
m_undefined = (systemVerbose & VERBOSE_UNDEFINED) != 0; m_undefined = (systemVerbose & VERBOSE_UNDEFINED) != 0;
m_agbprint = (systemVerbose & VERBOSE_AGBPRINT) != 0; m_agbprint = (systemVerbose & VERBOSE_AGBPRINT) != 0;
m_sound_output = (systemVerbose & VERBOSE_SOUNDOUTPUT) != 0; m_sound_output = (systemVerbose & VERBOSE_SOUNDOUTPUT) != 0;
m_sio = (systemVerbose & VERBOSE_SIO) != 0;
m_link = (systemVerbose & VERBOSE_LINK) != 0;
UpdateData(FALSE); UpdateData(FALSE);
m_log.LimitText(-1); m_log.LimitText(-1);
@ -293,3 +311,7 @@ void toolsClearLog()
Logging::instance->clearLog(); Logging::instance->clearLog();
} }
} }

View File

@ -27,6 +27,8 @@ public:
BOOL m_agbprint; BOOL m_agbprint;
BOOL m_undefined; BOOL m_undefined;
BOOL m_sound_output; BOOL m_sound_output;
BOOL m_sio;
BOOL m_link;
// Overrides // Overrides
protected: protected:
@ -47,6 +49,8 @@ protected:
afx_msg void OnVerboseUnalignedAccess(); afx_msg void OnVerboseUnalignedAccess();
afx_msg void OnVerboseUndefined(); afx_msg void OnVerboseUndefined();
afx_msg void OnVerboseSoundoutput(); afx_msg void OnVerboseSoundoutput();
afx_msg void OnVerboseSIO();
afx_msg void OnVerboseLink();
afx_msg void OnSave(); afx_msg void OnSave();
afx_msg void OnClose(); afx_msg void OnClose();
afx_msg void OnErrspaceLog(); afx_msg void OnErrspaceLog();

View File

@ -40,7 +40,12 @@
void MainWnd::OnOptionsFrameskipThrottleNothrottle() void MainWnd::OnOptionsFrameskipThrottleNothrottle()
{ {
theApp.updateThrottle( 0 ); // disable theApp.updateThrottle( 0 ); // disable
theApp.autoFrameSkip = false; /*if(theApp.autoFrameSkip) {
frameSkip = 0;
gbFrameSkip = 0;
systemFrameSkip = 0;
}
theApp.autoFrameSkip = false;*/
} }
void MainWnd::OnUpdateOptionsFrameskipThrottleNothrottle(CCmdUI* pCmdUI) void MainWnd::OnUpdateOptionsFrameskipThrottleNothrottle(CCmdUI* pCmdUI)
@ -52,7 +57,7 @@ void MainWnd::OnUpdateOptionsFrameskipThrottleNothrottle(CCmdUI* pCmdUI)
void MainWnd::OnOptionsFrameskipThrottle25() void MainWnd::OnOptionsFrameskipThrottle25()
{ {
theApp.updateThrottle( 25 ); theApp.updateThrottle( 25 );
theApp.autoFrameSkip = false; //theApp.autoFrameSkip = false;
} }
void MainWnd::OnUpdateOptionsFrameskipThrottle25(CCmdUI* pCmdUI) void MainWnd::OnUpdateOptionsFrameskipThrottle25(CCmdUI* pCmdUI)
@ -64,7 +69,7 @@ void MainWnd::OnUpdateOptionsFrameskipThrottle25(CCmdUI* pCmdUI)
void MainWnd::OnOptionsFrameskipThrottle50() void MainWnd::OnOptionsFrameskipThrottle50()
{ {
theApp.updateThrottle( 50 ); theApp.updateThrottle( 50 );
theApp.autoFrameSkip = false; //theApp.autoFrameSkip = false;
} }
void MainWnd::OnUpdateOptionsFrameskipThrottle50(CCmdUI* pCmdUI) void MainWnd::OnUpdateOptionsFrameskipThrottle50(CCmdUI* pCmdUI)
@ -76,7 +81,7 @@ void MainWnd::OnUpdateOptionsFrameskipThrottle50(CCmdUI* pCmdUI)
void MainWnd::OnOptionsFrameskipThrottle100() void MainWnd::OnOptionsFrameskipThrottle100()
{ {
theApp.updateThrottle( 100 ); theApp.updateThrottle( 100 );
theApp.autoFrameSkip = false; //theApp.autoFrameSkip = false;
} }
void MainWnd::OnUpdateOptionsFrameskipThrottle100(CCmdUI* pCmdUI) void MainWnd::OnUpdateOptionsFrameskipThrottle100(CCmdUI* pCmdUI)
@ -88,7 +93,7 @@ void MainWnd::OnUpdateOptionsFrameskipThrottle100(CCmdUI* pCmdUI)
void MainWnd::OnOptionsFrameskipThrottle150() void MainWnd::OnOptionsFrameskipThrottle150()
{ {
theApp.updateThrottle( 150 ); theApp.updateThrottle( 150 );
theApp.autoFrameSkip = false; //theApp.autoFrameSkip = false;
} }
void MainWnd::OnUpdateOptionsFrameskipThrottle150(CCmdUI* pCmdUI) void MainWnd::OnUpdateOptionsFrameskipThrottle150(CCmdUI* pCmdUI)
@ -100,7 +105,7 @@ void MainWnd::OnUpdateOptionsFrameskipThrottle150(CCmdUI* pCmdUI)
void MainWnd::OnOptionsFrameskipThrottle200() void MainWnd::OnOptionsFrameskipThrottle200()
{ {
theApp.updateThrottle( 200 ); theApp.updateThrottle( 200 );
theApp.autoFrameSkip = false; //theApp.autoFrameSkip = false;
} }
void MainWnd::OnUpdateOptionsFrameskipThrottle200(CCmdUI* pCmdUI) void MainWnd::OnUpdateOptionsFrameskipThrottle200(CCmdUI* pCmdUI)
@ -116,7 +121,7 @@ void MainWnd::OnOptionsFrameskipThrottleOther()
if( v ) { if( v ) {
theApp.updateThrottle( v ); theApp.updateThrottle( v );
theApp.autoFrameSkip = false; //theApp.autoFrameSkip = false;
} }
} }
@ -137,12 +142,16 @@ void MainWnd::OnOptionsFrameskipAutomatic()
theApp.autoFrameSkip = !theApp.autoFrameSkip; theApp.autoFrameSkip = !theApp.autoFrameSkip;
if(!theApp.autoFrameSkip && emulating) if(!theApp.autoFrameSkip && emulating)
theApp.updateFrameSkip(); theApp.updateFrameSkip();
else else if(theApp.autoFrameSkip)
{ {
theApp.throttle = false; //theApp.throttle = false;
frameSkip = 0; frameSkip = 9;
gbFrameSkip = 9;
systemFrameSkip = 0; systemFrameSkip = 0;
} }
//frameSkip = 0;
//gbFrameSkip = 0;
//systemFrameSkip = 0;
} }
void MainWnd::OnUpdateOptionsFrameskipAutomatic(CCmdUI* pCmdUI) void MainWnd::OnUpdateOptionsFrameskipAutomatic(CCmdUI* pCmdUI)
@ -152,6 +161,7 @@ void MainWnd::OnUpdateOptionsFrameskipAutomatic(CCmdUI* pCmdUI)
BOOL MainWnd::OnOptionsFrameskip(UINT nID) BOOL MainWnd::OnOptionsFrameskip(UINT nID)
{ {
//theApp.autoFrameSkip = false;
switch(nID) { switch(nID) {
case ID_OPTIONS_VIDEO_FRAMESKIP_0: case ID_OPTIONS_VIDEO_FRAMESKIP_0:
case ID_OPTIONS_VIDEO_FRAMESKIP_1: case ID_OPTIONS_VIDEO_FRAMESKIP_1:
@ -166,7 +176,7 @@ BOOL MainWnd::OnOptionsFrameskip(UINT nID)
} }
if(emulating) if(emulating)
theApp.updateFrameSkip(); theApp.updateFrameSkip();
theApp.updateThrottle( 0 ); //theApp.updateThrottle( 0 );
return TRUE; return TRUE;
break; break;
case ID_OPTIONS_VIDEO_FRAMESKIP_6: case ID_OPTIONS_VIDEO_FRAMESKIP_6:
@ -180,7 +190,7 @@ BOOL MainWnd::OnOptionsFrameskip(UINT nID)
} }
if(emulating) if(emulating)
theApp.updateFrameSkip(); theApp.updateFrameSkip();
theApp.updateThrottle( 0 ); //theApp.updateThrottle( 0 );
return TRUE; return TRUE;
break; break;
} }
@ -585,8 +595,13 @@ void MainWnd::OnUpdateOptionsEmulatorDisablestatusmessages(CCmdUI* pCmdUI)
void MainWnd::OnOptionsEmulatorSynchronize() void MainWnd::OnOptionsEmulatorSynchronize()
{ {
synchronize = !synchronize; synchronize = !synchronize;
if (synchronize) if (synchronize) {
theApp.throttle = false; //theApp.throttle = false;
//theApp.autoFrameSkip = false;
frameSkip = 0;
gbFrameSkip = 0;
systemFrameSkip = 0;
}
} }
void MainWnd::OnUpdateOptionsEmulatorSynchronize(CCmdUI* pCmdUI) void MainWnd::OnUpdateOptionsEmulatorSynchronize(CCmdUI* pCmdUI)
@ -1023,6 +1038,8 @@ void MainWnd::OnUpdateOptionsGameboyBorder(CCmdUI* pCmdUI)
void MainWnd::OnOptionsGameboyPrinter() void MainWnd::OnOptionsGameboyPrinter()
{ {
theApp.winGbPrinterEnabled = !theApp.winGbPrinterEnabled; theApp.winGbPrinterEnabled = !theApp.winGbPrinterEnabled;
if(gba_link_enabled)
gbSerialFunction = gbStartLink; else
if(theApp.winGbPrinterEnabled) if(theApp.winGbPrinterEnabled)
gbSerialFunction = gbPrinterSend; gbSerialFunction = gbPrinterSend;
else else
@ -1560,7 +1577,7 @@ void MainWnd::OnOptionsLinkRFU()
if(rfu_enabled) rfu_enabled = false; if(rfu_enabled) rfu_enabled = false;
else { else {
rfu_enabled = true; rfu_enabled = true;
MessageBox("Please note this is the first version\nof RFU emulation code and it's not 100% bug free.\nAlso only 2 players single computer are supported at this time.", "Warning", MB_OK); //MessageBox("Please note this is the first version\nof RFU emulation code and it's not 100% bug free.\nAlso only 2 players single computer are supported at this time.", "Warning", MB_OK);
} }
} }
@ -1572,6 +1589,12 @@ void MainWnd::OnUpdateOptionsLinkEnable(CCmdUI* pCmdUI)
void MainWnd::OnOptionsLinkEnable() void MainWnd::OnOptionsLinkEnable()
{ {
gba_link_enabled = !gba_link_enabled; gba_link_enabled = !gba_link_enabled;
if(gba_link_enabled)
gbSerialFunction = gbStartLink; else
if(theApp.winGbPrinterEnabled)
gbSerialFunction = gbPrinterSend;
else
gbSerialFunction = NULL;
} }
void MainWnd::OnUpdateOptionsLinkRFU(CCmdUI* pCmdUI) void MainWnd::OnUpdateOptionsLinkRFU(CCmdUI* pCmdUI)

View File

@ -42,6 +42,7 @@ public:
void reset(); // stop and reset the secondary sound buffer void reset(); // stop and reset the secondary sound buffer
void resume(); // play/resume the secondary sound buffer void resume(); // play/resume the secondary sound buffer
void write(u16 * finalWave, int length); // write the emulated sound to a sound buffer void write(u16 * finalWave, int length); // write the emulated sound to a sound buffer
void setThrottle( unsigned short throttle ); //pitch
private: private:
OPENALFNTABLE ALFunction; OPENALFNTABLE ALFunction;
@ -181,6 +182,8 @@ bool OpenAL::init(long sampleRate)
initialized = true; initialized = true;
setThrottle(theApp.throttle); //setting pitch to current throttle
return true; return true;
} }
@ -281,7 +284,7 @@ void OpenAL::write(u16 * finalWave, int length)
} }
} }
if( !speedup && synchronize && !theApp.throttle ) { if( !speedup && synchronize /*&& !theApp.throttle*/ ) {
// wait until at least one buffer has finished // wait until at least one buffer has finished
while( nBuffersProcessed == 0 ) { while( nBuffersProcessed == 0 ) {
winlog( " waiting...\n" ); winlog( " waiting...\n" );
@ -320,6 +323,20 @@ void OpenAL::write(u16 * finalWave, int length)
} }
} }
void OpenAL::setThrottle( unsigned short throttle )
{
if( !initialized ) return;
winlog( "OpenAL::setThrottle\n" );
debugState();
if( throttle == 0 ) throttle = 100;
ALFunction.alSourcef(source, AL_PITCH, (float)throttle / 100.0f );
ASSERT_SUCCESS;
debugState(); //AdamN: is this needed?
}
SoundDriver *newOpenAL() SoundDriver *newOpenAL()
{ {
winlog( "newOpenAL\n" ); winlog( "newOpenAL\n" );

View File

@ -59,8 +59,8 @@ void Throttle::OnOk()
{ {
UpdateData(); UpdateData();
if(m_throttle < 5 || m_throttle > 1000) if(m_throttle < 5 || m_throttle > 2000)
systemMessage(IDS_INVALID_THROTTLE_VALUE, "Invalid throttle value. Please enter a number between 5 and 1000"); systemMessage(IDS_INVALID_THROTTLE_VALUE, "Invalid throttle value. Please enter a number between 5 and 2000");
else else
EndDialog(m_throttle); EndDialog(m_throttle);
} }

View File

@ -149,6 +149,9 @@ void winOutput(const char *, u32);
void (*dbgSignal)(int,int) = winSignal; void (*dbgSignal)(int,int) = winSignal;
void (*dbgOutput)(const char *, u32) = winOutput; void (*dbgOutput)(const char *, u32) = winOutput;
int lastSA = 0;
int lastSR = 0;
#ifdef MMX #ifdef MMX
extern "C" bool cpu_mmx; extern "C" bool cpu_mmx;
#endif #endif
@ -156,7 +159,7 @@ extern "C" bool cpu_mmx;
namespace Sm60FPS namespace Sm60FPS
{ {
float K_fCpuSpeed = 100.0f; // was 98.0f before, but why? float K_fCpuSpeed = 100.0f; // was 98.0f before, but why?
float K_fTargetFps = 60.0f * K_fCpuSpeed / 100; float K_fTargetFps = 60.0f * K_fCpuSpeed / 100.0f;
float K_fDT = 1000.0f / K_fTargetFps; float K_fDT = 1000.0f / K_fTargetFps;
u32 dwTimeElapse; u32 dwTimeElapse;
@ -167,6 +170,7 @@ namespace Sm60FPS
float fCurFPS; float fCurFPS;
bool bLastSkip; bool bLastSkip;
int nCurSpeed; int nCurSpeed;
float nPrvSpeed;
int bSaveMoreCPU; int bSaveMoreCPU;
}; };
@ -336,8 +340,21 @@ VBA::VBA()
} }
} }
CString DataHex(const char *buf, int len) {
CString dat = _T("");
if(buf!=NULL && len>0) {
for(int i=0; i<len; i++) {
dat.AppendFormat(_T("%02X "), (byte)buf[i]);
}
}
return dat;
}
VBA::~VBA() VBA::~VBA()
{ {
c_s.Lock();
AppTerminated = true;
c_s.Unlock();
rpiCleanup(); rpiCleanup();
InterframeCleanup(); InterframeCleanup();
@ -352,6 +369,8 @@ VBA::~VBA()
JoyBusShutdown(); JoyBusShutdown();
CloseLink(); //AdamN: closing connections gracefully
saveSettings(); saveSettings();
if(moviePlaying) { if(moviePlaying) {
@ -422,6 +441,8 @@ BOOL VBA::InitInstance()
#endif #endif
#endif #endif
//SetProcessAffinityMask(GetCurrentProcess(), 1); //AdamN: using only 1 CPU for all threads in this process for testing if there were bug caused by deadlock
SetRegistryKey(_T("VBA")); SetRegistryKey(_T("VBA"));
remoteSetProtocol(0); remoteSetProtocol(0);
@ -447,6 +468,7 @@ BOOL VBA::InitInstance()
if(!InitLink()) if(!InitLink())
return FALSE; return FALSE;
lanlink.mode = NORMAL8;
bool force = false; bool force = false;
@ -839,18 +861,21 @@ void VBA::updateFilter()
void VBA::updateThrottle( unsigned short throttle ) void VBA::updateThrottle( unsigned short throttle )
{ {
//if(throttle>100 && synchronize) throttle = 100; //max speed when audio sync enabled is 100%
this->throttle = throttle; this->throttle = throttle;
if( throttle ) { if( throttle ) {
Sm60FPS::K_fCpuSpeed = (float)throttle; Sm60FPS::K_fCpuSpeed = (float)throttle;
Sm60FPS::K_fTargetFps = 60.0f * Sm60FPS::K_fCpuSpeed / 100; Sm60FPS::K_fTargetFps = 60.0f * Sm60FPS::K_fCpuSpeed / 100;
Sm60FPS::K_fDT = 1000.0f / Sm60FPS::K_fTargetFps; Sm60FPS::K_fDT = 1000.0f / Sm60FPS::K_fTargetFps;
autoFrameSkip = false; /*autoFrameSkip = true;
frameSkip = 0; frameSkip = 0;
systemFrameSkip = 0; gbFrameSkip = 0;
systemFrameSkip = 0;*/
} }
soundSetThrottle(throttle); soundSetThrottle(throttle); //AdamN: only XAudio2 that have this feature? (added for OpenAL)
} }
@ -1065,14 +1090,13 @@ void systemFrame()
void system10Frames(int rate) void system10Frames(int rate)
{ {
if( theApp.autoFrameSkip ) if( theApp.autoFrameSkip )
{ {
u32 time = systemGetClock(); u32 time = systemGetClock();
u32 diff = time - theApp.autoFrameSkipLastTime; u32 diff = time - theApp.autoFrameSkipLastTime;
theApp.autoFrameSkipLastTime = time;
if( diff ) { if( diff ) {
// countermeasure against div/0 when debugging // countermeasure against div/0 when debugging
theApp.autoFrameSkipLastTime = time;
Sm60FPS::nCurSpeed = (1000000/rate)/diff; Sm60FPS::nCurSpeed = (1000000/rate)/diff;
} else { } else {
Sm60FPS::nCurSpeed = 100; Sm60FPS::nCurSpeed = 100;
@ -1112,6 +1136,96 @@ void system10Frames(int rate)
#endif #endif
} }
void system1Frames(int rate, int count) //AdamN: update skippedframes faster to make sure it didn't cause too many frames or too little frames being skipped
{
if( theApp.autoFrameSkip ) //AdamN: CurSpeed might need to be updated regardless of autoframeskip for throttle to works properly w/o autoframeskip
{
theApp.autoFrameSkipCount++;
u32 time = systemGetClock();
u32 diff = time - theApp.autoFrameSkipLastTime;
if( diff) {
// countermeasure against div/0 when debugging
int tm = (diff/theApp.autoFrameSkipCount);
float cspd = (100000.0f/rate/*60.0f*/)/tm; //calc current speed smoothly (frame 1-10,2-11,3-12,so on)
Sm60FPS::nCurSpeed = (int)cspd; //(500000/rate)/diff;
if(theApp.autoFrameSkipCount >= 10) { //60
theApp.autoFrameSkipCount--; //= 0; //to maintain 10 frames per update
theApp.autoFrameSkipLastTime += tm ; //theApp.autoFrameSkipLastTime2;
//theApp.autoFrameSkipLastTime2 += tm; //rough prediction of nextframe's time
}/* else if(theApp.autoFrameSkipCount == 2)
theApp.autoFrameSkipLastTime2 = time;*/
//if(theApp.autoFrameSkip)
{
float tgtspd = Sm60FPS::K_fCpuSpeed;
int maxfs = gbFrameSkip;
if(theApp.cartridgeType == IMAGE_GBA) maxfs = frameSkip;
//if(speedup && (count % 10)==0) theApp.updateThrottle(Sm60FPS::nCurSpeed); //update throttle on turbo, may slows down things
//if(synchronize && tgtspd>100.0f) float tgtspd = 100.0f; //max speed when audio sync enabled is 100%, this is to prevent skippedframe piling up since CurSpeed never goes beyond 100
if((systemFrameSkip < maxfs) && (Sm60FPS::nCurSpeed < tgtspd*0.94f/**0.89f *0.845f*/)) { //*0.7f
/*if(maxfs==9) //special feature for auto-frameskip-cap=9
if(Sm60FPS::nCurSpeed <= 1.01f*Sm60FPS::nPrvSpeed && systemFrameSkip>3) { //if frameskipping no longer effective, don't skip more
systemFrameSkip--;
//Sm60FPS::nPrvSpeed = 0.0f; //0.99f*Sm60FPS::nPrvSpeed;
} else
Sm60FPS::nPrvSpeed = (float)Sm60FPS::nCurSpeed;*/
//frameSkip += 1;
//gbFrameSkip += 1;
systemFrameSkip += 1; //frames to skip for the next n frames
} else
if((systemFrameSkip > 0) && (Sm60FPS::nCurSpeed > tgtspd/**1.02f*//**1.1f *1.4f*/)) { //*1.07f
//frameSkip -= 1;
//gbFrameSkip -= 1;
systemFrameSkip -= 1; //frames to skip for the next n frames
}
//Sm60FPS::nPrvSpeed = Sm60FPS::nCurSpeed;
}
//theApp.autoFrameSkipCount = 0;
} else {
/*if(theApp.autoFrameSkipCount == 2)
theApp.autoFrameSkipLastTime2 = time;*/
if(!Sm60FPS::nCurSpeed)
Sm60FPS::nCurSpeed = (int)Sm60FPS::K_fCpuSpeed; //100;
//frameSkip = 0;
//gbFrameSkip = 0;
//systemFrameSkip = 0;
}
}
if((count % 10)!=0) return;
if(theApp.rewindMemory) {
if(++theApp.rewindCounter >= (theApp.rewindTimer)) {
theApp.rewindSaveNeeded = true;
theApp.rewindCounter = 0;
}
}
if(systemSaveUpdateCounter) {
if(--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) {
((MainWnd *)theApp.m_pMainWnd)->writeBatteryFile();
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
}
}
theApp.wasPaused = false;
// Old autoframeskip crap... might be useful later. autoframeskip Ifdef above might be useless as well now
// theApp.autoFrameSkipLastTime = time;
#ifdef LOG_PERFORMANCE
if( systemSpeedCounter >= PERFORMANCE_INTERVAL ) {
// log performance every PERFORMANCE_INTERVAL frames
float a = 0.0f;
for( unsigned short i = 0 ; i < PERFORMANCE_INTERVAL ; i++ ) {
a += (float)systemSpeedTable[i];
}
a /= (float)PERFORMANCE_INTERVAL;
log( _T("Speed: %f\n"), a );
systemSpeedCounter = 0;
}
#endif
}
void systemScreenMessage(const char *msg) void systemScreenMessage(const char *msg)
{ {
theApp.screenMessage = true; theApp.screenMessage = true;
@ -1163,7 +1277,7 @@ SoundDriver * systemSoundInit()
if( drv ) { if( drv ) {
if (theApp.throttle) if (theApp.throttle)
drv->setThrottle( theApp.throttle ); drv->setThrottle( theApp.throttle ); //AdamN: XAudio2 seems the only one who has this feature?
} }
return drv; return drv;
@ -1251,10 +1365,13 @@ BOOL VBA::OnIdle(LONG lCount)
if(debugger) if(debugger)
return TRUE; // continue loop return TRUE; // continue loop
return !::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE); return !::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE);
} else if(emulating && active && !paused) { } else if(emulating && (gba_link_enabled || active) && !paused) {
for(int i = 0; i < 2; i++) { for(int i = 0; i < 2; i++) {
emulator.emuMain(emulator.emuCount); emulator.emuMain(emulator.emuCount); //emuMain=CPULoop,emuCount=250000
if(lanlink.connected&&linkid&&lc.numtransfers==0) lc.CheckConn(); if(/*gba_link_enabled &&*/ lanlink.connected && linkid && lc.numtransfers==0 && (theApp.cartridgeType == IMAGE_GBA) && !rfu_enabled) {
if(/*(i & 1) &&*/ !LinkHandlerActive)
lc.CheckConn(); //AdamN: This is Needed for Client/Slave to works properly, but does it need to be called twice in the FOR loop?
}
if(rewindSaveNeeded && rewindMemory && emulator.emuWriteMemState) { if(rewindSaveNeeded && rewindMemory && emulator.emuWriteMemState) {
rewindCount++; rewindCount++;
@ -1622,6 +1739,8 @@ void VBA::loadSettings()
rfu_enabled = regQueryDwordValue("RFU", false) ? true : false; rfu_enabled = regQueryDwordValue("RFU", false) ? true : false;
gba_link_enabled = regQueryDwordValue("linkEnabled", false) ? true : false; gba_link_enabled = regQueryDwordValue("linkEnabled", false) ? true : false;
if(gba_link_enabled)
gbSerialFunction = gbStartLink;
gba_joybus_enabled = regQueryDwordValue("joybusEnabled", false) ? true : false; gba_joybus_enabled = regQueryDwordValue("joybusEnabled", false) ? true : false;
buffer = regQueryStringValue("joybusHostAddr", ""); buffer = regQueryStringValue("joybusHostAddr", "");
@ -2620,11 +2739,11 @@ void Sm60FPS_Init()
} }
bool Sm60FPS_CanSkipFrame() bool Sm60FPS_CanSkipFrame() //AdamN: autoframeskipping here doesn't seems to give much effect, more like only giving up to 1 frame skipped(per 10 frames) instead of up to 9 frames
{ {
if( theApp.autoFrameSkip ) { /*if( theApp.autoFrameSkip )*/ { //AdamN: this is the reason why throttle doesn't works properly w/o autoframeskip
if( Sm60FPS::nFrameCnt == 0 ) { if( Sm60FPS::nFrameCnt == 0 ) {
Sm60FPS::nFrameCnt = 0; //Sm60FPS::nFrameCnt = 0; //AdamN: is this really necessary?
Sm60FPS::dwTimeElapse = 0; Sm60FPS::dwTimeElapse = 0;
Sm60FPS::dwTime0 = GetTickCount(); Sm60FPS::dwTime0 = GetTickCount();
} else { } else {
@ -2634,14 +2753,18 @@ bool Sm60FPS_CanSkipFrame()
if( Sm60FPS::nCurSpeed > Sm60FPS::K_fCpuSpeed ) { if( Sm60FPS::nCurSpeed > Sm60FPS::K_fCpuSpeed ) {
Sm60FPS::fWantFPS += 1; Sm60FPS::fWantFPS += 1;
if( Sm60FPS::fWantFPS > Sm60FPS::K_fTargetFps ){ //frameSkip = 0;
Sm60FPS::fWantFPS = Sm60FPS::K_fTargetFps; //systemFrameSkip = 0;
if( Sm60FPS::fWantFPS > Sm60FPS::K_fTargetFps/**(systemFrameSkip+1)*/ ){
Sm60FPS::fWantFPS = Sm60FPS::K_fTargetFps/**(systemFrameSkip+1)*/;
} }
} else { } else {
if( Sm60FPS::nCurSpeed < (Sm60FPS::K_fCpuSpeed - 5) ) { if( Sm60FPS::nCurSpeed < (Sm60FPS::K_fCpuSpeed/**0.94f*/ /*- 5*/) ) {
Sm60FPS::fWantFPS -= 1; Sm60FPS::fWantFPS -= 1;
if( Sm60FPS::fWantFPS < 30.f ) { //frameSkip += 1;
Sm60FPS::fWantFPS = 30.f; //systemFrameSkip += 1;
if( Sm60FPS::fWantFPS < 6.f/*30.f*/ ) {
Sm60FPS::fWantFPS = 6.f/*30.f*/;
} }
} }
} }
@ -2649,12 +2772,15 @@ bool Sm60FPS_CanSkipFrame()
Sm60FPS::dwTime1 = GetTickCount(); Sm60FPS::dwTime1 = GetTickCount();
Sm60FPS::dwTimeElapse += (Sm60FPS::dwTime1 - Sm60FPS::dwTime0); Sm60FPS::dwTimeElapse += (Sm60FPS::dwTime1 - Sm60FPS::dwTime0);
Sm60FPS::dwTime0 = Sm60FPS::dwTime1; Sm60FPS::dwTime0 = Sm60FPS::dwTime1;
if( !Sm60FPS::bLastSkip && if( !Sm60FPS::bLastSkip &&
( (Sm60FPS::fWantFPS < Sm60FPS::K_fTargetFps) || Sm60FPS::bSaveMoreCPU) ) { ( (Sm60FPS::fWantFPS < Sm60FPS::K_fTargetFps/**(systemFrameSkip+1)*/) || Sm60FPS::bSaveMoreCPU) ) {
Sm60FPS::fCurFPS = (float)Sm60FPS::nFrameCnt * 1000 / Sm60FPS::dwTimeElapse; Sm60FPS::fCurFPS = (float)Sm60FPS::nFrameCnt * 1000 / Sm60FPS::dwTimeElapse;
if( (Sm60FPS::fCurFPS < Sm60FPS::K_fTargetFps) || Sm60FPS::bSaveMoreCPU ) { if( (Sm60FPS::fCurFPS < Sm60FPS::K_fTargetFps/**(systemFrameSkip+1)*/) || Sm60FPS::bSaveMoreCPU ) {
Sm60FPS::bLastSkip = true; Sm60FPS::bLastSkip = true;
Sm60FPS::nFrameCnt++; Sm60FPS::nFrameCnt++;
//frameSkip += 1;
//systemFrameSkip += 1;
return true; return true;
} }
} }
@ -2662,6 +2788,8 @@ bool Sm60FPS_CanSkipFrame()
} }
Sm60FPS::bLastSkip = false; Sm60FPS::bLastSkip = false;
Sm60FPS::nFrameCnt++; Sm60FPS::nFrameCnt++;
//frameSkip = 0;
//systemFrameSkip = 0;
} }
return false; return false;
} }
@ -2669,9 +2797,11 @@ bool Sm60FPS_CanSkipFrame()
void Sm60FPS_Sleep() void Sm60FPS_Sleep()
{ {
if( theApp.autoFrameSkip ) { if(!speedup) /*if( theApp.autoFrameSkip )*/ { //AdamN: this is the reason why throttle doesn't works properly w/o autoframeskip
u32 dwTimePass = Sm60FPS::dwTimeElapse + (GetTickCount() - Sm60FPS::dwTime0); u32 dwTimePass = Sm60FPS::dwTimeElapse + (GetTickCount() - Sm60FPS::dwTime0);
u32 dwTimeShould = (u32)(Sm60FPS::nFrameCnt * Sm60FPS::K_fDT); float kfdt = Sm60FPS::K_fDT;
if(!theApp.autoFrameSkip) kfdt*=(systemFrameSkip+1);
u32 dwTimeShould = (u32)(Sm60FPS::nFrameCnt * kfdt);
if( dwTimeShould > dwTimePass ) { if( dwTimeShould > dwTimePass ) {
Sleep(dwTimeShould - dwTimePass); Sleep(dwTimeShould - dwTimePass);
} }

View File

@ -124,6 +124,8 @@ class VBA : public CWinApp
bool tripleBuffering; bool tripleBuffering;
unsigned short throttle; unsigned short throttle;
u32 autoFrameSkipLastTime; u32 autoFrameSkipLastTime;
u32 autoFrameSkipLastTime2;
int autoFrameSkipCount;
bool autoFrameSkip; bool autoFrameSkip;
bool vsync; bool vsync;
bool changingVideoSize; bool changingVideoSize;
@ -255,6 +257,27 @@ class VBA : public CWinApp
extern VBA theApp; extern VBA theApp;
extern int emulating; extern int emulating;
extern bool AppTerminated; //AdamN: to mark Application is exiting for other threads to check
extern CString DataHex(const char *buf, int len); //AdamN: buffer to hex string
namespace Sm60FPS
{
extern float K_fCpuSpeed; // was 98.0f before, but why?
extern float K_fTargetFps;
extern float K_fDT;
extern u32 dwTimeElapse;
extern u32 dwTime0;
extern u32 dwTime1;
extern u32 nFrameCnt;
extern float fWantFPS;
extern float fCurFPS;
extern bool bLastSkip;
extern int nCurSpeed;
extern float nPrvSpeed;
extern int bSaveMoreCPU;
};
#ifdef MMX #ifdef MMX
extern "C" bool cpu_mmx; extern "C" bool cpu_mmx;
#endif #endif

View File

@ -132,13 +132,14 @@ BEGIN
CONTROL "Network",IDC_LINK_LAN,"Button",BS_AUTORADIOBUTTON,17,43,70,16 CONTROL "Network",IDC_LINK_LAN,"Button",BS_AUTORADIOBUTTON,17,43,70,16
END END
IDD_LINKTAB2 DIALOG 0, 0, 210, 113 IDD_LINKTAB2 DIALOGEX 0, 0, 210, 113
STYLE DS_SETFONT | WS_CHILD STYLE DS_SETFONT | WS_CHILD
FONT 8, "MS Sans Serif" FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN BEGIN
CONTROL "2",IDC_LINK2P,"Button",BS_AUTORADIOBUTTON | WS_GROUP,46,16,21,13 CONTROL "2",IDC_LINK2P,"Button",BS_AUTORADIOBUTTON | WS_GROUP,33,17,21,13
CONTROL "3",IDC_LINK3P,"Button",BS_AUTORADIOBUTTON,94,16,21,13 CONTROL "3",IDC_LINK3P,"Button",BS_AUTORADIOBUTTON,73,17,21,13
CONTROL "4",IDC_LINK4P,"Button",BS_AUTORADIOBUTTON,142,16,21,13 CONTROL "4",IDC_LINK4P,"Button",BS_AUTORADIOBUTTON,115,17,21,13
CONTROL "5",IDC_LINK5P,"Button",BS_AUTORADIOBUTTON,156,17,21,13
CONTROL "TCP/IP",IDC_LINKTCP,"Button",BS_AUTORADIOBUTTON | WS_GROUP,54,47,42,14 CONTROL "TCP/IP",IDC_LINKTCP,"Button",BS_AUTORADIOBUTTON | WS_GROUP,54,47,42,14
CONTROL "UDP",IDC_LINKUDP,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,121,47,33,14 CONTROL "UDP",IDC_LINKUDP,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,121,47,33,14
PUSHBUTTON "Start!",IDC_SERVERSTART,79,89,50,17 PUSHBUTTON "Start!",IDC_SERVERSTART,79,89,50,17
@ -162,17 +163,17 @@ BEGIN
CONTROL "On (fast)",IDC_SPEEDON,"Button",BS_AUTORADIOBUTTON,128,63,48,12 CONTROL "On (fast)",IDC_SPEEDON,"Button",BS_AUTORADIOBUTTON,128,63,48,12
END END
IDD_SERVERWAIT DIALOG 0, 0, 186, 90 IDD_SERVERWAIT DIALOGEX 0, 0, 186, 90
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Waiting for players" CAPTION "Waiting for players"
FONT 8, "MS Sans Serif" FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN BEGIN
PUSHBUTTON "Cancel",IDCANCEL,63,69,50,14 PUSHBUTTON "Cancel",IDCANCEL,63,69,50,14
CONTROL "Progress1",IDC_SERVERWAIT,"msctls_progress32",WS_BORDER,33,50,120,13 CONTROL "Progress1",IDC_SERVERWAIT,"msctls_progress32",WS_BORDER,33,50,120,13
LTEXT "",IDC_STATIC1,7,7,154,8 LTEXT "",IDC_STATIC1,7,7,178,8,SS_ENDELLIPSIS
LTEXT "",IDC_STATIC2,7,17,105,8 LTEXT "",IDC_STATIC2,7,17,175,8
LTEXT "",IDC_STATIC3,7,25,105,8 LTEXT "",IDC_STATIC3,7,25,175,8
LTEXT "",IDC_STATIC4,7,33,105,8 LTEXT "",IDC_STATIC4,7,33,175,8
END END
IDD_OPENDLG DIALOG 36, 24, 202, 117 IDD_OPENDLG DIALOG 36, 24, 202, 117
@ -740,10 +741,10 @@ BEGIN
GROUPBOX "Sprite",IDC_STATIC,8,67,154,30 GROUPBOX "Sprite",IDC_STATIC,8,67,154,30
END END
IDD_DISASSEMBLE DIALOG 0, 0, 402, 225 IDD_DISASSEMBLE DIALOGEX 0, 0, 402, 250
STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "Disassemble" CAPTION "Disassemble"
FONT 8, "MS Sans Serif" FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN BEGIN
CONTROL "Automatic",IDC_AUTOMATIC,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7,9,47,10 CONTROL "Automatic",IDC_AUTOMATIC,"Button",BS_AUTORADIOBUTTON | WS_GROUP,7,9,47,10
CONTROL "ARM",IDC_ARM,"Button",BS_AUTORADIOBUTTON,62,9,32,10 CONTROL "ARM",IDC_ARM,"Button",BS_AUTORADIOBUTTON,62,9,32,10
@ -800,6 +801,10 @@ BEGIN
LTEXT "",IDC_MODE,376,176,20,8,SS_NOPREFIX LTEXT "",IDC_MODE,376,176,20,8,SS_NOPREFIX
SCROLLBAR IDC_VSCROLL,283,25,10,161,SBS_VERT SCROLLBAR IDC_VSCROLL,283,25,10,161,SBS_VERT
PUSHBUTTON "Goto R15",IDC_GOPC,7,204,50,14 PUSHBUTTON "Goto R15",IDC_GOPC,7,204,50,14
CONTROL "Break at",IDC_BREAK_AT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,225,41,10
EDITTEXT IDC_ADDRESS2,53,222,65,14,ES_UPPERCASE | ES_AUTOHSCROLL | WS_GROUP
PUSHBUTTON "Step Into",IDC_STEPINTO,124,222,50,14
CONTROL "Auto Step",IDC_AUTO_STEP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,179,225,47,10
END END
IDD_GDB_PORT DIALOG 0, 0, 186, 51 IDD_GDB_PORT DIALOG 0, 0, 186, 51
@ -823,13 +828,12 @@ BEGIN
LTEXT "",IDC_PORT,143,7,36,8,SS_NOPREFIX LTEXT "",IDC_PORT,143,7,36,8,SS_NOPREFIX
END END
IDD_LOGGING DIALOGEX 0, 0, 382, 220 IDD_LOGGING DIALOGEX 0, 0, 382, 257
STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_TOOLWINDOW EXSTYLE WS_EX_TOOLWINDOW
CAPTION "Logging" CAPTION "Logging"
FONT 8, "MS Sans Serif", 0, 0, 0x0 FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN BEGIN
CONTROL "SWI",IDC_VERBOSE_SWI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,18,90,12
CONTROL "Unaligned memory",IDC_VERBOSE_UNALIGNED_ACCESS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,36,90,12 CONTROL "Unaligned memory",IDC_VERBOSE_UNALIGNED_ACCESS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,36,90,12
CONTROL "Illegal write",IDC_VERBOSE_ILLEGAL_WRITE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,54,90,12 CONTROL "Illegal write",IDC_VERBOSE_ILLEGAL_WRITE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,54,90,12
CONTROL "Illegal read",IDC_VERBOSE_ILLEGAL_READ,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,72,90,12 CONTROL "Illegal read",IDC_VERBOSE_ILLEGAL_READ,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,72,90,12
@ -839,12 +843,15 @@ BEGIN
CONTROL "DMA 3",IDC_VERBOSE_DMA3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,144,90,12 CONTROL "DMA 3",IDC_VERBOSE_DMA3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,144,90,12
CONTROL "Undefined instruction",IDC_VERBOSE_UNDEFINED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,162,90,12 CONTROL "Undefined instruction",IDC_VERBOSE_UNDEFINED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,162,90,12
CONTROL "AGBPrint",IDC_VERBOSE_AGBPRINT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,180,90,12 CONTROL "AGBPrint",IDC_VERBOSE_AGBPRINT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,180,90,12
EDITTEXT IDC_LOG,114,6,258,192,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL EDITTEXT IDC_LOG,114,6,258,226,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL
PUSHBUTTON "Save...",IDC_SAVE,114,204,48,12 PUSHBUTTON "Save...",IDC_SAVE,113,238,48,12
PUSHBUTTON "Clear",IDC_CLEAR,168,204,48,12 PUSHBUTTON "Clear",IDC_CLEAR,171,238,48,12
DEFPUSHBUTTON "OK",ID_OK,324,204,48,12 DEFPUSHBUTTON "OK",ID_OK,327,238,48,12
GROUPBOX "Verbose",IDC_STATIC,6,6,102,210 GROUPBOX "Verbose",IDC_STATIC,6,7,102,243
CONTROL "Sound output",IDC_VERBOSE_SOUNDOUTPUT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,198,90,12 CONTROL "Sound output",IDC_VERBOSE_SOUNDOUTPUT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,198,90,12
CONTROL "SIO",IDC_VERBOSE_SIO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,216,90,12
CONTROL "Link",IDC_VERBOSE_LINK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,233,90,12
CONTROL "SWI",IDC_VERBOSE_SWI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,19,90,12
END END
IDD_EXPORT_SPS DIALOGEX 0, 0, 248, 148 IDD_EXPORT_SPS DIALOGEX 0, 0, 248, 148
@ -1238,6 +1245,14 @@ BEGIN
BOTTOMMARGIN, 107 BOTTOMMARGIN, 107
END END
IDD_LINKTAB2, DIALOG
BEGIN
END
IDD_SERVERWAIT, DIALOG
BEGIN
END
IDD_OPENDLG, DIALOG IDD_OPENDLG, DIALOG
BEGIN BEGIN
RIGHTMARGIN, 165 RIGHTMARGIN, 165
@ -1424,7 +1439,7 @@ BEGIN
LEFTMARGIN, 7 LEFTMARGIN, 7
RIGHTMARGIN, 396 RIGHTMARGIN, 396
TOPMARGIN, 7 TOPMARGIN, 7
BOTTOMMARGIN, 218 BOTTOMMARGIN, 243
END END
IDD_GDB_PORT, DIALOG IDD_GDB_PORT, DIALOG
@ -1448,7 +1463,7 @@ BEGIN
LEFTMARGIN, 7 LEFTMARGIN, 7
RIGHTMARGIN, 375 RIGHTMARGIN, 375
TOPMARGIN, 7 TOPMARGIN, 7
BOTTOMMARGIN, 213 BOTTOMMARGIN, 250
END END
IDD_EXPORT_SPS, DIALOG IDD_EXPORT_SPS, DIALOG
@ -2225,13 +2240,21 @@ BEGIN
IDS_LOADED_CHEATS "Loaded cheats" IDS_LOADED_CHEATS "Loaded cheats"
IDS_ERROR_DISP_COLOR "Unsupported display setting for color depth: %d bits. \nWindows desktop must be in either 16-bit, 24-bit or 32-bit mode for this program to work in window mode." IDS_ERROR_DISP_COLOR "Unsupported display setting for color depth: %d bits. \nWindows desktop must be in either 16-bit, 24-bit or 32-bit mode for this program to work in window mode."
IDS_ADD_GSA_CODE "Add GameSharkAdvance code" IDS_ADD_GSA_CODE "Add GameSharkAdvance code"
IDS_FILTER_GSVSPS "GS & PAC Snapshots (*.SPS;*.XPS)_*.SPS;*.XPS_GameShark SP Snapshots (*.GSV)_*.gsv__"
IDS_FILTER_SPS "Gameshark Snapshot_*.SPS__" IDS_FILTER_SPS "Gameshark Snapshot_*.SPS__"
IDS_SELECT_SNAPSHOT_FILE "Select snapshot file" IDS_SELECT_SNAPSHOT_FILE "Select snapshot file"
IDS_FILTER_SAV "Battery file_*.SAV_Flash save_*.DAT__" IDS_FILTER_SAV "Battery file_*.SAV_Flash save_*.DAT__"
IDS_SELECT_BATTERY_FILE "Select battery file" IDS_SELECT_BATTERY_FILE "Select battery file"
END END
STRINGTABLE
BEGIN
IDS_INVALID_INTERVAL_VALUE
"Invalid rewind interval value. Please enter a number between 0 and 600 seconds."
IDS_REGISTRY "VisualBoyAdvance no longer uses the registry to store its settings. Your previous settings have been exported into the file: %s"
IDS_MOVIE_PLAY "Playing a movie will load a save state which may erase your previous battery saves. Please be sure to have a saved state if you don't want to loose any previous data."
IDS_FILTER_GSVSPS "GS & PAC Snapshots (*.SPS;*.XPS)_*.SPS;*.XPS_GameShark SP Snapshots (*.GSV)_*.gsv__"
END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_UNSUPPORTED_CHEAT_LIST_TYPE "Unsupported cheat list type %d" IDS_UNSUPPORTED_CHEAT_LIST_TYPE "Unsupported cheat list type %d"
@ -2292,14 +2315,6 @@ BEGIN
IDS_END_OF_MOVIE "end of movie" IDS_END_OF_MOVIE "end of movie"
END END
STRINGTABLE
BEGIN
IDS_INVALID_INTERVAL_VALUE
"Invalid rewind interval value. Please enter a number between 0 and 600 seconds."
IDS_REGISTRY "VisualBoyAdvance no longer uses the registry to store its settings. Your previous settings have been exported into the file: %s"
IDS_MOVIE_PLAY "Playing a movie will load a save state which may erase your previous battery saves. Please be sure to have a saved state if you don't want to loose any previous data."
END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_OAL_NODEVICE "There are no sound devices present on this system." IDS_OAL_NODEVICE "There are no sound devices present on this system."

View File

@ -278,6 +278,8 @@ bool XAudio2_Output::init(long sampleRate)
initialized = true; initialized = true;
setThrottle(theApp.throttle); //AdamN: setting sound pitch to current throttle
return true; return true;
} }
@ -303,7 +305,7 @@ void XAudio2_Output::write(u16 * finalWave, int length)
break; break;
} else { } else {
// the maximum number of buffers is currently queued // the maximum number of buffers is currently queued
if( synchronize && !speedup && !theApp.throttle ) { if( synchronize && !speedup /*&& !theApp.throttle*/ ) {
// wait for one buffer to finish playing // wait for one buffer to finish playing
WaitForSingleObject( notify.hBufferEndEvent, INFINITE ); WaitForSingleObject( notify.hBufferEndEvent, INFINITE );
} else { } else {

View File

@ -150,6 +150,7 @@
#define IDC_C_FLAG 1020 #define IDC_C_FLAG 1020
#define IDC_CONTINUE 1020 #define IDC_CONTINUE 1020
#define IDC_SAVE_DIR 1020 #define IDC_SAVE_DIR 1020
#define IDC_STEPINTO 1020
#define IDC_V_FLAG 1021 #define IDC_V_FLAG 1021
#define IDC_CAPTURE_DIR 1021 #define IDC_CAPTURE_DIR 1021
#define IDC_CHEAT_LIST 1021 #define IDC_CHEAT_LIST 1021
@ -215,6 +216,7 @@
#define IDS_VALUE_CANNOT_BE_EMPTY 1042 #define IDS_VALUE_CANNOT_BE_EMPTY 1042
#define IDS_ERROR_ON_STARTDOC 1043 #define IDS_ERROR_ON_STARTDOC 1043
#define IDC_R 1043 #define IDC_R 1043
#define IDC_ADDRESS2 1043
#define IDS_ERROR_ON_STARTPAGE 1044 #define IDS_ERROR_ON_STARTPAGE 1044
#define IDC_G 1044 #define IDC_G 1044
#define IDS_ERROR_PRINTING_ON_STRETCH 1045 #define IDS_ERROR_PRINTING_ON_STRETCH 1045
@ -459,6 +461,8 @@
#define IDC_ARM 1200 #define IDC_ARM 1200
#define IDC_THUMB 1201 #define IDC_THUMB 1201
#define IDC_AUTO_UPDATE 1204 #define IDC_AUTO_UPDATE 1204
#define IDC_BREAK_AT 1205
#define IDC_AUTO_STEP 1206
#define IDC_N 1210 #define IDC_N 1210
#define IDC_Z 1211 #define IDC_Z 1211
#define IDC_C 1212 #define IDC_C 1212
@ -491,6 +495,8 @@
#define IDC_VERBOSE_SOUNDOUTPUT 1235 #define IDC_VERBOSE_SOUNDOUTPUT 1235
#define IDC_NOTES 1236 #define IDC_NOTES 1236
#define IDC_CURRENT_ADDRESS_LABEL 1236 #define IDC_CURRENT_ADDRESS_LABEL 1236
#define IDC_VERBOSE_SIO 1236
#define IDC_VERBOSE_LINK 1237
#define IDC_LOAD 1238 #define IDC_LOAD 1238
#define IDC_SIZE_CONTROL 1240 #define IDC_SIZE_CONTROL 1240
#define IDC_MODES 1240 #define IDC_MODES 1240
@ -841,6 +847,7 @@
#define IDC_LINK3P 40325 #define IDC_LINK3P 40325
#define IDC_LINK4P 40326 #define IDC_LINK4P 40326
#define IDC_CLINKUDP 40327 #define IDC_CLINKUDP 40327
#define IDC_LINK5P 40327
#define IDC_SPEEDON 40328 #define IDC_SPEEDON 40328
#define ID_OPTIONS_EMULATOR_REMOVEINTROSGBA 40331 #define ID_OPTIONS_EMULATOR_REMOVEINTROSGBA 40331
#define ID_Menu 40332 #define ID_Menu 40332