mirror of
https://github.com/AppleWin/AppleWin.git
synced 2024-12-22 09:30:15 +00:00
. QoL cleanup (show RTS address) for step-over failure cases . Add source code for repro test 1 and 2
This commit is contained in:
parent
4e8006456f
commit
a3c6156508
@ -2294,7 +2294,8 @@ Update_t CmdStepOver (int nArgs)
|
||||
|
||||
while (nDebugSteps -- > 0)
|
||||
{
|
||||
int nOpcode = *(mem + regs.pc); // g_nDisasmCurAddress
|
||||
int nOpcode = *(mem + regs.pc);
|
||||
WORD nExpectedAddr = (regs.pc + 3) & _6502_MEM_END; // Wrap around 64K edge case when PC = $FFFD..$FFFF: 20 xx xx
|
||||
// int eMode = g_aOpcodes[ nOpcode ].addrmode;
|
||||
// int nByte = g_aOpmodes[eMode]._nBytes;
|
||||
// if ((eMode == AM_A) &&
|
||||
@ -2302,10 +2303,80 @@ Update_t CmdStepOver (int nArgs)
|
||||
CmdTrace(0);
|
||||
if (nOpcode == OPCODE_JSR)
|
||||
{
|
||||
/*
|
||||
Repro #2 Test when SP <= 0x01 before JSR and _6502_GetStackReturnAddress() fetch return address
|
||||
300:BA 86 FF A2 01 9A 20 0D 03 A6 FF 9A 60 A9 FF 20 A8 FC 60
|
||||
BPX 306
|
||||
MD1 100
|
||||
MD2 1E0
|
||||
|
||||
ORG $300
|
||||
TSX ; 300
|
||||
STX $FF ; 301
|
||||
LDX #1 ; 303
|
||||
TXS ; 305
|
||||
JSR DelayFF ; 306
|
||||
LDX $FF ; 309
|
||||
TXS ; 30B
|
||||
RTS ; 30C
|
||||
DelayFF LDA #$FF ; 30D
|
||||
JSR $FCA8 ; 30F
|
||||
RTS ; 312
|
||||
*/
|
||||
CmdStepOut(0);
|
||||
g_nDebugSteps = 0xFFFF;
|
||||
|
||||
int nMaxSteps = 0xFFFFF; // GH #1194
|
||||
g_nDebugSteps = nMaxSteps;
|
||||
|
||||
while (g_nDebugSteps != 0)
|
||||
{
|
||||
DebugContinueStepping(true);
|
||||
}
|
||||
|
||||
// If the PC isn't at the expected address after the JSR print a diagnostic so the user knows the stack may be buggered up
|
||||
if (regs.pc != nExpectedAddr)
|
||||
{
|
||||
WORD nActualAddr = _6502_GetStackReturnAddress();
|
||||
bool bValidAddr = (nActualAddr == nExpectedAddr);
|
||||
int nStackOffset = _6502_FindStackReturnAddress( nExpectedAddr ); // Trace stack to seee if our expected address is on it
|
||||
|
||||
/*
|
||||
ORG $300
|
||||
Main JSR HugeWait
|
||||
RTS
|
||||
HugeWait LDY #$FF
|
||||
Loop JSR Delay
|
||||
DEY
|
||||
BNE Loop
|
||||
RTS
|
||||
Delay LDA #$FF
|
||||
JSR $FCA8
|
||||
RTS
|
||||
|
||||
Repro #1
|
||||
1. MSVC: Revert line to repro: int nMaxSteps = 0xFFFF;
|
||||
2. MSVC: Set BP on line above: (regs.pc != nExpectedAddr)
|
||||
3. AppleWin:
|
||||
F7
|
||||
300:A0 FF 20 09 03 88 D0 FA 60 A9 FF 20 A8 FC 60
|
||||
BPX 30B
|
||||
F7
|
||||
CALL 768
|
||||
<Ctrl>-<Space>
|
||||
4. MSVC:Change regs.sp to one of 3 cases:
|
||||
Case Addr On Stack Top of Stack Diagnostic nStackOffset R SP Continue in emulator
|
||||
0 No No ERROR -1 regs.sp = 0x1F3
|
||||
1 Yes Yes INFO O regs.sp = 0x1F2 R PC FCB3
|
||||
2 Yes No WARN +1 regs.sp = 0x1F1 R S F1
|
||||
*/
|
||||
/**/ if (nStackOffset < 0) ConsolePrintFormat( CHC_ERROR "ERROR" CHC_ARG_SEP ":" CHC_ERROR " Didn't step over JSR! " CHC_ARG_SEP "(" CHC_DEFAULT "RTS " CHC_ARG_SEP "$" CHC_ADDRESS "%04X" CHC_DEFAULT " not found!" CHC_ARG_SEP ")", nExpectedAddr ); // Case 0
|
||||
else if (nStackOffset == 0) ConsolePrintFormat( CHC_INFO "INFO" CHC_ARG_SEP ":" CHC_INFO " Didn't step over JSR! " CHC_ARG_SEP "(" CHC_DEFAULT "RTS " CHC_ARG_SEP "$" CHC_ADDRESS "%04X" CHC_DEFAULT " on top of stack." CHC_ARG_SEP ")", nExpectedAddr ); // Case 1
|
||||
else /* */ ConsolePrintFormat( CHC_WARNING "WARN" CHC_ARG_SEP ":" CHC_WARNING " Didn't step over JSR! " CHC_ARG_SEP "(" CHC_DEFAULT "Stack has RTS " CHC_ARG_SEP "$" CHC_ADDRESS "%04X" CHC_DEFAULT " but needs fixup: " CHC_ARG_SEP "$" CHC_NUM_HEX "%02X" CHC_DEFAULT " bytes" CHC_ARG_SEP ")", nExpectedAddr, nStackOffset & 0xFF ); // Case 2
|
||||
|
||||
ConsolePrintFormat( CHC_DEFAULT " Please report '" CHC_SYMBOL "nMaxSteps" CHC_ARG_SEP " = " CHC_DEFAULT "0x" CHC_NUM_HEX "%04X" CHC_DEFAULT "' to:", nMaxSteps );
|
||||
ConsolePrintFormat( CHC_PATH " https://github.com/AppleWin/AppleWin/issues/1194" );
|
||||
ConsoleUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2317,13 +2388,11 @@ Update_t CmdStepOut (int nArgs)
|
||||
{
|
||||
// TODO: "RET" should probably pop the Call stack
|
||||
// Also see: CmdCursorJumpRetAddr
|
||||
WORD nAddress;
|
||||
if (_6502_GetStackReturnAddress( nAddress ))
|
||||
{
|
||||
nArgs = _Arg_1( nAddress );
|
||||
g_aArgs[1].sArg[0] = 0;
|
||||
CmdGo( 1, true );
|
||||
}
|
||||
WORD nAddress = _6502_GetStackReturnAddress();
|
||||
|
||||
nArgs = _Arg_1( nAddress );
|
||||
g_aArgs[1].sArg[0] = 0;
|
||||
CmdGo( 1, true );
|
||||
|
||||
return UPDATE_ALL;
|
||||
}
|
||||
@ -3296,22 +3365,19 @@ Update_t CmdCursorJumpPC (int nArgs)
|
||||
//===========================================================================
|
||||
Update_t CmdCursorJumpRetAddr (int nArgs)
|
||||
{
|
||||
WORD nAddress = 0;
|
||||
if (_6502_GetStackReturnAddress( nAddress ))
|
||||
{
|
||||
g_nDisasmCurAddress = nAddress;
|
||||
WORD nAddress = _6502_GetStackReturnAddress();
|
||||
g_nDisasmCurAddress = nAddress;
|
||||
|
||||
if (CURSOR_ALIGN_CENTER == nArgs)
|
||||
{
|
||||
WindowUpdateDisasmSize();
|
||||
}
|
||||
else
|
||||
if (CURSOR_ALIGN_TOP == nArgs)
|
||||
{
|
||||
g_nDisasmCurLine = 0;
|
||||
}
|
||||
DisasmCalcTopBotAddress();
|
||||
if (CURSOR_ALIGN_CENTER == nArgs)
|
||||
{
|
||||
WindowUpdateDisasmSize();
|
||||
}
|
||||
else
|
||||
if (CURSOR_ALIGN_TOP == nArgs)
|
||||
{
|
||||
g_nDisasmCurLine = 0;
|
||||
}
|
||||
DisasmCalcTopBotAddress();
|
||||
|
||||
return UPDATE_ALL;
|
||||
}
|
||||
@ -8609,7 +8675,7 @@ void DebugContinueStepping (const bool bCallerWillUpdateDisplay/*=false*/)
|
||||
bool skipStopReason = false;
|
||||
|
||||
if (regs.pc == g_nDebugStepUntil)
|
||||
stopReason = "PC matches 'Go until' address";
|
||||
stopReason = StrFormat( CHC_DEFAULT "Register " CHC_REGS "PC" CHC_DEFAULT " matches '" CHC_INFO "Go until" CHC_DEFAULT "' address $" CHC_ADDRESS "%04X", g_nDebugStepUntil);
|
||||
else if (g_bDebugBreakpointHit & BP_HIT_INVALID)
|
||||
stopReason = "Invalid opcode";
|
||||
else if (g_bDebugBreakpointHit & BP_HIT_OPCODE)
|
||||
|
@ -426,8 +426,64 @@ Fx BEQ r SBC (d),Y sbc (z) --- --- SBC d,X INC z,X --- SED SBC a,Y
|
||||
void AssemblerHashOpcodes ();
|
||||
void AssemblerHashDirectives ();
|
||||
|
||||
// Implementation ___________________________________________________________
|
||||
// Utility __________________________________________________________________
|
||||
|
||||
// === Stack ===
|
||||
|
||||
// Return stack offset if the address is on the stack, else -1 if not found
|
||||
//===========================================================================
|
||||
int _6502_FindStackReturnAddress (const WORD nAddress)
|
||||
{
|
||||
WORD nReturnAddress;
|
||||
WORD nStack = regs.sp + 1;
|
||||
int nDepth = -1; // not found
|
||||
|
||||
// Normally would <= _6502_STACK_END-1 since JSR always pushes 2 bytes
|
||||
// but the SP could be $00 before JSR forcing RTS address to be split $100/$1FF
|
||||
// or the SP could be $01 before JSR forcing RTS address to be at $100/$101
|
||||
// R PC 300
|
||||
// R S 0
|
||||
// 300:20 04 03 60 60
|
||||
// <Ctrl-Space>
|
||||
while (nStack <= (_6502_STACK_END + 1))
|
||||
{
|
||||
nReturnAddress = _6502_PeekStackReturnAddress(nStack);
|
||||
|
||||
if (nReturnAddress == nAddress)
|
||||
{
|
||||
nDepth = (nStack - 2 - regs.sp);
|
||||
return nDepth;
|
||||
}
|
||||
}
|
||||
|
||||
return nDepth;
|
||||
}
|
||||
|
||||
// NOTE: If the stack pointer is <= 01 before a JSR the stack will wrap around.
|
||||
//===========================================================================
|
||||
WORD _6502_GetStackReturnAddress ()
|
||||
{
|
||||
WORD nStack = regs.sp + 1;
|
||||
WORD nAddress = _6502_PeekStackReturnAddress(nStack);
|
||||
return nAddress;
|
||||
}
|
||||
|
||||
// NOTES: nStack is both an input and output;
|
||||
// If nStack is 0x1FF it WILL return overflow 0x200. Current callers are:
|
||||
// _6502_FindStackReturnAddress(), and
|
||||
// _6502_GetStackReturnAddress()
|
||||
// which DON'T return this overflow stack value to previous callers.
|
||||
//===========================================================================
|
||||
WORD _6502_PeekStackReturnAddress (WORD & nStack)
|
||||
{
|
||||
WORD nAddress;
|
||||
nAddress = ((unsigned) *(LPBYTE)(mem + 0x100 + (nStack & 0xFF)) ); nStack++;
|
||||
nAddress += ((unsigned) *(LPBYTE)(mem + 0x100 + (nStack & 0xFF)) << 8);
|
||||
nAddress++;
|
||||
return nAddress;
|
||||
}
|
||||
|
||||
// == Opcodes ===
|
||||
|
||||
//===========================================================================
|
||||
bool _6502_CalcRelativeOffset ( int nOpcode, int nBaseAddress, int nTargetAddress, WORD * pTargetOffset_ )
|
||||
@ -464,7 +520,6 @@ bool _6502_CalcRelativeOffset ( int nOpcode, int nBaseAddress, int nTargetAddres
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
int _6502_GetOpmodeOpbyte ( const int nBaseAddress, int & iOpmode_, int & nOpbyte_, const DisasmData_t** pData_ )
|
||||
{
|
||||
@ -566,25 +621,6 @@ void _6502_GetOpcodeOpmodeOpbyte (int & iOpcode_, int & iOpmode_, int & nOpbyte_
|
||||
iOpcode_ = _6502_GetOpmodeOpbyte( regs.pc, iOpmode_, nOpbyte_ );
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
bool _6502_GetStackReturnAddress (WORD & nAddress_)
|
||||
{
|
||||
unsigned nStack = regs.sp;
|
||||
nStack++;
|
||||
|
||||
if (nStack <= (_6502_STACK_END - 1))
|
||||
{
|
||||
nAddress_ = (unsigned)*(LPBYTE)(mem + nStack);
|
||||
nStack++;
|
||||
|
||||
nAddress_ += ((unsigned)*(LPBYTE)(mem + nStack)) << 8;
|
||||
nAddress_++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
bool _6502_GetTargets (WORD nAddress, int *pTargetPartial_, int *pTargetPartial2_, int *pTargetPointer_, int * pTargetBytes_,
|
||||
bool bIgnoreBranch /*= true*/, bool bIncludeNextOpcodeAddress /*= true*/ )
|
||||
|
@ -191,15 +191,21 @@ extern int g_aAssemblerFirstDirective[ NUM_ASSEMBLERS ];
|
||||
|
||||
// Prototypes _______________________________________________________________
|
||||
|
||||
// Stack
|
||||
int _6502_FindStackReturnAddress (const WORD nAddress);
|
||||
WORD _6502_GetStackReturnAddress ();
|
||||
WORD _6502_PeekStackReturnAddress (WORD & nStack);
|
||||
|
||||
// Opcodes
|
||||
int _6502_GetOpmodeOpbyte( const int iAddress, int & iOpmode_, int & nOpbytes_, const DisasmData_t** pData = NULL );
|
||||
void _6502_GetOpcodeOpmodeOpbyte( int & iOpcode_, int & iOpmode_, int & nOpbytes_ );
|
||||
bool _6502_GetStackReturnAddress( WORD & nAddress_ );
|
||||
bool _6502_GetTargets( WORD nAddress, int *pTargetPartial_, int *pTargetPartial2_, int *pTargetPointer_, int * pBytes_,
|
||||
bool bIgnoreBranch = true, bool bIncludeNextOpcodeAddress = true );
|
||||
bool _6502_GetTargetAddress( const WORD & nAddress, WORD & nTarget_ );
|
||||
bool _6502_IsOpcodeBranch( int nOpcode );
|
||||
bool _6502_IsOpcodeValid( int nOpcode );
|
||||
|
||||
// Assembler
|
||||
Hash_t AssemblerHashMnemonic ( const TCHAR * pMnemonic );
|
||||
// bool AssemblerGetAddressingMode ( int iArg, int nArgs, WORD nAddress, std::vector<int> & vOpcodes );
|
||||
void _CmdAssembleHashDump ();
|
||||
|
Loading…
Reference in New Issue
Block a user