2017-08-15 20:02:54 +00:00
|
|
|
#include "stdafx.h"
|
|
|
|
|
2020-12-27 11:54:11 +00:00
|
|
|
#include "../../source/Windows/AppleWin.h"
|
2017-08-15 20:02:54 +00:00
|
|
|
#include "../../source/CPU.h"
|
|
|
|
|
|
|
|
#include "../../source/Debugger/Debugger_Types.h"
|
|
|
|
#include "../../source/Debugger/Debugger_Assembler.h" // Pull in default args for _6502_GetTargets()
|
|
|
|
|
|
|
|
// NB. DebugDefs.h must come after Debugger_Types.h which declares these as extern
|
|
|
|
#include "../../source/Debugger/DebugDefs.h"
|
|
|
|
|
2020-12-27 11:54:11 +00:00
|
|
|
// From FrameBase
|
|
|
|
class FrameBase
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FrameBase() { g_hFrameWindow = (HWND)0; }
|
|
|
|
HWND g_hFrameWindow;
|
|
|
|
};
|
|
|
|
|
|
|
|
// From Win32Frame
|
|
|
|
class Win32Frame : public FrameBase
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
// From AppleWin.cpp
|
|
|
|
FrameBase& GetFrame()
|
|
|
|
{
|
|
|
|
static Win32Frame sg_Win32Frame;
|
|
|
|
return sg_Win32Frame;
|
|
|
|
}
|
|
|
|
|
2017-08-15 20:02:54 +00:00
|
|
|
// From CPU.cpp
|
|
|
|
regsrec regs;
|
|
|
|
|
2021-10-15 20:08:16 +00:00
|
|
|
static eCpuType g_MainCPU = CPU_65C02;
|
|
|
|
|
|
|
|
eCpuType GetMainCpu(void)
|
|
|
|
{
|
|
|
|
return g_MainCPU;
|
|
|
|
}
|
|
|
|
|
2017-08-15 20:02:54 +00:00
|
|
|
// From Memory.cpp
|
|
|
|
LPBYTE mem = NULL; // TODO: Init
|
|
|
|
LPBYTE memdirty = NULL; // TODO: Init
|
|
|
|
|
|
|
|
//-------------------------------------
|
|
|
|
|
|
|
|
// From Debugger_Console.cpp
|
|
|
|
char g_aConsolePrompt[] = ">!"; // input, assembler // NUM_PROMPTS
|
|
|
|
char g_sConsolePrompt[] = ">"; // No, NOT Integer Basic! The nostalgic '*' "Monitor" doesn't look as good, IMHO. :-(
|
|
|
|
|
|
|
|
Update_t ConsoleUpdate ()
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ConsoleBufferPush ( const char * pText )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ConsoleBufferPushVa ( char* buf, size_t bufsz, const char * pFormat, va_list va )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// From Debugger_DisassemblerData.cpp
|
|
|
|
DisasmData_t* Disassembly_IsDataAddress ( WORD nAddress )
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// From Debugger_Parser.cpp
|
|
|
|
int g_nArgRaw;
|
|
|
|
Arg_t g_aArgRaw[ MAX_ARGS ]; // pre-processing
|
|
|
|
Arg_t g_aArgs [ MAX_ARGS ]; // post-processing (cooked)
|
|
|
|
|
|
|
|
bool ArgsGetValue ( Arg_t *pArg, WORD * pAddressValue_, const int nBase )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// From Debugger_Symbols.cpp
|
|
|
|
bool FindAddressFromSymbol ( const char* pSymbol, WORD * pAddress_, int * iTable_ )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------
|
|
|
|
|
|
|
|
void init(void)
|
|
|
|
{
|
2017-08-15 21:12:51 +00:00
|
|
|
mem = (LPBYTE)VirtualAlloc(NULL,128*1024,MEM_COMMIT,PAGE_READWRITE); // alloc >64K to test wrap-around at 64K boundary
|
2017-08-15 20:02:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void reset(void)
|
|
|
|
{
|
|
|
|
regs.a = 0;
|
|
|
|
regs.x = 0;
|
|
|
|
regs.y = 0;
|
|
|
|
regs.pc = 0x300;
|
|
|
|
regs.sp = 0x1FF;
|
|
|
|
regs.ps = 0;
|
|
|
|
regs.bJammed = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------
|
|
|
|
|
2017-08-15 21:12:51 +00:00
|
|
|
int GH445_test_PHn(BYTE op)
|
2017-08-15 20:02:54 +00:00
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
|
|
|
mem[regs.pc] = op;
|
|
|
|
|
|
|
|
regs.sp = 0x1FE;
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[2] != regs.sp) return 1;
|
|
|
|
|
|
|
|
regs.sp = 0x1FF;
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[2] != regs.sp) return 1;
|
|
|
|
|
|
|
|
regs.sp = 0x100;
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[2] != regs.sp) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-08-15 21:12:51 +00:00
|
|
|
int GH445_test_PLn(BYTE op)
|
2017-08-15 20:02:54 +00:00
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
|
|
|
mem[regs.pc] = op;
|
|
|
|
|
|
|
|
regs.sp = 0x1FE;
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[2] != (regs.sp+1)) return 1;
|
|
|
|
|
|
|
|
regs.sp = 0x1FF;
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[2] != 0x100) return 1;
|
|
|
|
|
|
|
|
regs.sp = 0x100;
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[2] != (regs.sp+1)) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-12-09 16:27:13 +00:00
|
|
|
int GH445_test_abs(BYTE op)
|
2017-08-15 21:12:51 +00:00
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
2019-12-09 16:27:13 +00:00
|
|
|
const WORD target2 = 0x1234;
|
|
|
|
|
2017-08-15 21:12:51 +00:00
|
|
|
mem[regs.pc] = op;
|
|
|
|
mem[(regs.pc+1)&0xFFFF] = (BYTE) (target2&0xff);
|
|
|
|
mem[(regs.pc+2)&0xFFFF] = (BYTE) ((target2>>8)&0xff);
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[2] != target2) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GH445_test_jsr(void)
|
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
2019-12-09 16:27:13 +00:00
|
|
|
WORD target2 = 0x1234;
|
|
|
|
|
|
|
|
mem[regs.pc] = OPCODE_JSR;
|
|
|
|
mem[(regs.pc+1)&0xFFFF] = (BYTE) (target2&0xff);
|
|
|
|
mem[(regs.pc+2)&0xFFFF] = (BYTE) ((target2>>8)&0xff);
|
2017-08-15 21:12:51 +00:00
|
|
|
|
|
|
|
regs.sp = 0x1FF;
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1 || TargetAddr[2] != target2) return 1;
|
2017-08-15 21:12:51 +00:00
|
|
|
|
|
|
|
regs.sp = 0x100;
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != 0x1FF || TargetAddr[2] != target2) return 1;
|
2017-08-15 21:12:51 +00:00
|
|
|
|
|
|
|
regs.sp = 0x101;
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1 || TargetAddr[2] != target2) return 1;
|
2017-08-15 21:12:51 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-12-09 16:27:13 +00:00
|
|
|
int GH445_test_brk(void)
|
2017-08-15 21:12:51 +00:00
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
2019-12-09 16:27:13 +00:00
|
|
|
mem[regs.pc] = OPCODE_BRK;
|
2017-08-15 21:12:51 +00:00
|
|
|
|
2019-12-09 16:27:13 +00:00
|
|
|
regs.sp = 0x1FF;
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1) return 1;
|
|
|
|
|
|
|
|
regs.sp = 0x100;
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != 0x1FF) return 1;
|
|
|
|
|
|
|
|
regs.sp = 0x101;
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GH445_test_rti_rts(WORD sp, const bool isRTI)
|
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
|
|
|
mem[regs.pc] = isRTI ? OPCODE_RTI : OPCODE_RTS;
|
2017-08-15 21:12:51 +00:00
|
|
|
regs.sp = sp;
|
2019-12-09 16:27:13 +00:00
|
|
|
|
|
|
|
WORD sp_addr_p=0, sp_addr_l=0, sp_addr_h=0;
|
|
|
|
if (isRTI)
|
|
|
|
{
|
|
|
|
sp_addr_p = 0x100 + ((regs.sp+1)&0xFF);
|
|
|
|
sp_addr_l = 0x100 + ((regs.sp+2)&0xFF);
|
|
|
|
sp_addr_h = 0x100 + ((regs.sp+3)&0xFF);
|
|
|
|
mem[sp_addr_p] = 0xEA;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sp_addr_l = 0x100 + ((regs.sp+1)&0xFF);
|
|
|
|
sp_addr_h = 0x100 + ((regs.sp+2)&0xFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
WORD ret_addr = 0x1234;
|
|
|
|
mem[sp_addr_l] = (BYTE) (ret_addr&0xFF);
|
|
|
|
mem[sp_addr_h] = (BYTE) ((ret_addr>>8)&0xFF);
|
|
|
|
|
|
|
|
if (!isRTI)
|
|
|
|
ret_addr++; // NB. return addr from stack is incremented before being transferred to PC
|
|
|
|
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[0] != sp_addr_l || TargetAddr[1] != sp_addr_h || TargetAddr[2] != ret_addr) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GH445_test_jmp(BYTE op)
|
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
|
|
|
const WORD target16 = 0x1234;
|
|
|
|
|
2020-01-04 17:43:20 +00:00
|
|
|
int target0=0, target1=0, target2=0;
|
2019-12-09 16:27:13 +00:00
|
|
|
if (op == OPCODE_JMP_A)
|
|
|
|
{
|
|
|
|
target0 = NO_6502_TARGET;
|
|
|
|
target1 = NO_6502_TARGET;
|
|
|
|
target2 = target16;
|
|
|
|
}
|
|
|
|
else if (op == OPCODE_JMP_NA)
|
|
|
|
{
|
|
|
|
target0 = target16;
|
|
|
|
target1 = (target16+1)&0xffff;
|
|
|
|
target2 = 0x5678;
|
|
|
|
mem[target0] = target2 & 0xff;
|
|
|
|
mem[target1] = (target2>>8) & 0xff;
|
|
|
|
}
|
|
|
|
else if (op == OPCODE_JMP_IAX)
|
|
|
|
{
|
|
|
|
target0 = (target16+regs.x)&0xffff;
|
|
|
|
target1 = (target16+regs.x+1)&0xffff;
|
|
|
|
target2 = 0xABCD;
|
|
|
|
mem[target0] = target2 & 0xff;
|
|
|
|
mem[target1] = (target2>>8) & 0xff;
|
|
|
|
}
|
2020-01-04 17:43:20 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
_ASSERT(0);
|
|
|
|
}
|
2019-12-09 16:27:13 +00:00
|
|
|
|
|
|
|
mem[regs.pc] = op;
|
|
|
|
mem[(regs.pc+1)&0xFFFF] = (BYTE) (target16&0xff);
|
|
|
|
mem[(regs.pc+2)&0xFFFF] = (BYTE) ((target16>>8)&0xff);
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != target0 || TargetAddr[1] != target1 || TargetAddr[2] != target2) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// bIgnoreBranch == true (default)
|
|
|
|
int GH445_test_Bcc(void)
|
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
|
|
|
mem[regs.pc] = 0x10; // BPL next-op
|
|
|
|
mem[regs.pc+1] = 0;
|
|
|
|
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[0] != NO_6502_TARGET || TargetAddr[1] != NO_6502_TARGET || TargetAddr[2] != NO_6502_TARGET) return 1;
|
|
|
|
|
|
|
|
mem[regs.pc] = 0x10; // BPL this-op
|
|
|
|
mem[regs.pc+1] = 0xfe;
|
|
|
|
|
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes);
|
|
|
|
if (!bRes || TargetAddr[0] != NO_6502_TARGET || TargetAddr[1] != NO_6502_TARGET || TargetAddr[2] != NO_6502_TARGET) return 1;
|
2017-08-15 21:12:51 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2017-08-15 20:02:54 +00:00
|
|
|
|
|
|
|
int GH445_test_sub(bool bIs65C02)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
2017-08-15 21:12:51 +00:00
|
|
|
mem[0x10000] = 0xDD; // Bad data if 64K wrap not working
|
|
|
|
mem[0x10001] = 0xDD;
|
|
|
|
|
|
|
|
mem[0x200] = 0xDD; // Bad data if SP wrap not working
|
|
|
|
mem[0x201] = 0xDD;
|
|
|
|
|
2019-12-09 16:27:13 +00:00
|
|
|
regs.pc = 0x300;
|
|
|
|
|
2017-08-15 21:12:51 +00:00
|
|
|
//
|
|
|
|
// PHn/PLn
|
|
|
|
|
|
|
|
res = GH445_test_PHn(0x08); // PHP
|
2017-08-15 20:02:54 +00:00
|
|
|
if (res) return res;
|
2017-08-15 21:12:51 +00:00
|
|
|
res = GH445_test_PHn(0x48); // PHA
|
2017-08-15 20:02:54 +00:00
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
if (bIs65C02)
|
|
|
|
{
|
2017-08-15 21:12:51 +00:00
|
|
|
res = GH445_test_PHn(0x5A); // PHY
|
2017-08-15 20:02:54 +00:00
|
|
|
if (res) return res;
|
2017-08-15 21:12:51 +00:00
|
|
|
res = GH445_test_PHn(0xDA); // PHX
|
2017-08-15 20:02:54 +00:00
|
|
|
if (res) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
|
2017-08-15 21:12:51 +00:00
|
|
|
res = GH445_test_PLn(0x28); // PLP
|
2017-08-15 20:02:54 +00:00
|
|
|
if (res) return res;
|
2017-08-15 21:12:51 +00:00
|
|
|
res = GH445_test_PLn(0x68); // PLA
|
2017-08-15 20:02:54 +00:00
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
if (bIs65C02)
|
|
|
|
{
|
2017-08-15 21:12:51 +00:00
|
|
|
res = GH445_test_PLn(0x7A); // PLY
|
2017-08-15 20:02:54 +00:00
|
|
|
if (res) return res;
|
2017-08-15 21:12:51 +00:00
|
|
|
res = GH445_test_PLn(0xFA); // PLX
|
2017-08-15 20:02:54 +00:00
|
|
|
if (res) return res;
|
|
|
|
}
|
|
|
|
|
2017-08-15 21:12:51 +00:00
|
|
|
//
|
2019-12-09 16:27:13 +00:00
|
|
|
// LDA abs
|
2017-08-15 21:12:51 +00:00
|
|
|
|
|
|
|
regs.pc = 0xFFFD;
|
2019-12-09 16:27:13 +00:00
|
|
|
res = GH445_test_abs(OPCODE_LDA_A); // LDA ABS
|
2017-08-15 21:12:51 +00:00
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
regs.pc = 0xFFFE;
|
2019-12-09 16:27:13 +00:00
|
|
|
res = GH445_test_abs(OPCODE_LDA_A); // LDA ABS
|
2017-08-15 21:12:51 +00:00
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
regs.pc = 0xFFFF;
|
2019-12-09 16:27:13 +00:00
|
|
|
res = GH445_test_abs(OPCODE_LDA_A); // LDA ABS
|
2017-08-15 21:12:51 +00:00
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
//
|
2019-12-09 16:27:13 +00:00
|
|
|
// JSR abs
|
2017-08-15 21:12:51 +00:00
|
|
|
|
|
|
|
res = GH445_test_jsr();
|
|
|
|
if (res) return res;
|
|
|
|
|
2019-12-09 16:27:13 +00:00
|
|
|
//
|
|
|
|
// BRK
|
|
|
|
|
|
|
|
mem[_6502_BRK_VECTOR+0] = 0x40; // BRK vector: $FA40
|
|
|
|
mem[_6502_BRK_VECTOR+1] = 0xFA;
|
|
|
|
|
|
|
|
regs.pc = 0x300;
|
|
|
|
res = GH445_test_brk();
|
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
//
|
|
|
|
// RTI
|
|
|
|
|
|
|
|
res = GH445_test_rti_rts(0x1FE, true);
|
|
|
|
if (res) return res;
|
|
|
|
res = GH445_test_rti_rts(0x1FF, true);
|
|
|
|
if (res) return res;
|
|
|
|
res = GH445_test_rti_rts(0x100, true);
|
|
|
|
if (res) return res;
|
|
|
|
|
2017-08-15 21:12:51 +00:00
|
|
|
//
|
|
|
|
// RTS
|
|
|
|
|
2019-12-09 16:27:13 +00:00
|
|
|
res = GH445_test_rti_rts(0x1FE, false);
|
|
|
|
if (res) return res;
|
|
|
|
res = GH445_test_rti_rts(0x1FF, false);
|
|
|
|
if (res) return res;
|
|
|
|
res = GH445_test_rti_rts(0x100, false);
|
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
//
|
|
|
|
// JMP
|
|
|
|
|
|
|
|
res = GH445_test_jmp(OPCODE_JMP_A); // JMP abs
|
2017-08-15 21:12:51 +00:00
|
|
|
if (res) return res;
|
2019-12-09 16:27:13 +00:00
|
|
|
|
|
|
|
res = GH445_test_jmp(OPCODE_JMP_NA); // JMP (abs)
|
2017-08-15 21:12:51 +00:00
|
|
|
if (res) return res;
|
2019-12-09 16:27:13 +00:00
|
|
|
|
|
|
|
if (bIs65C02)
|
|
|
|
{
|
|
|
|
regs.x = 0xff;
|
|
|
|
res = GH445_test_jmp(OPCODE_JMP_IAX); // JMP (abs,x)
|
|
|
|
if (res) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Bcc
|
|
|
|
|
|
|
|
res = GH445_test_Bcc();
|
2017-08-15 21:12:51 +00:00
|
|
|
if (res) return res;
|
|
|
|
|
2017-08-15 20:02:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GH445_test(void)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
g_aOpcodes = g_aOpcodes65C02;
|
|
|
|
res = GH445_test_sub(true);
|
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
g_aOpcodes = g_aOpcodes6502;
|
|
|
|
res = GH445_test_sub(false);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------
|
|
|
|
|
2019-12-09 16:27:13 +00:00
|
|
|
//
|
|
|
|
// bIncludeNextOpcodeAddress == false, check that:
|
|
|
|
// . TargetAddr[2] gets set, eg. for LDA abs
|
|
|
|
// . TargetAddr[2] == NO_6502_TARGET for control flow instructions, eg. BRK,RTI,RTS,JSR,JMP,Bcc
|
|
|
|
//
|
|
|
|
|
|
|
|
int GH451_test_abs(BYTE op)
|
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
|
|
|
const WORD target2 = 0x1234;
|
|
|
|
|
|
|
|
mem[regs.pc] = op;
|
|
|
|
mem[(regs.pc+1)&0xFFFF] = (BYTE) (target2&0xff);
|
|
|
|
mem[(regs.pc+2)&0xFFFF] = (BYTE) ((target2>>8)&0xff);
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, false);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[2] != target2) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GH451_test_jsr(void)
|
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
|
|
|
mem[regs.pc] = OPCODE_JSR;
|
|
|
|
|
|
|
|
regs.sp = 0x1FF;
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, false);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1 || TargetAddr[2] != NO_6502_TARGET) return 1;
|
|
|
|
|
|
|
|
regs.sp = 0x100;
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, false);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != 0x1FF || TargetAddr[2] != NO_6502_TARGET) return 1;
|
|
|
|
|
|
|
|
regs.sp = 0x101;
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, false);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1 || TargetAddr[2] != NO_6502_TARGET) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GH451_test_brk(void)
|
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
|
|
|
mem[regs.pc] = OPCODE_BRK;
|
|
|
|
|
|
|
|
regs.sp = 0x1FF;
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, false);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1 || TargetAddr[2] != NO_6502_TARGET) return 1;
|
|
|
|
|
|
|
|
regs.sp = 0x100;
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, false);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != 0x1FF || TargetAddr[2] != NO_6502_TARGET) return 1;
|
|
|
|
|
|
|
|
regs.sp = 0x101;
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, false);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1 || TargetAddr[2] != NO_6502_TARGET) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GH451_test_rti_rts(WORD sp, const bool isRTI)
|
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
|
|
|
mem[regs.pc] = isRTI ? OPCODE_RTI : OPCODE_RTS;
|
|
|
|
regs.sp = sp;
|
|
|
|
|
|
|
|
WORD sp_addr_p=0, sp_addr_l=0, sp_addr_h=0;
|
|
|
|
if (isRTI)
|
|
|
|
{
|
|
|
|
sp_addr_p = 0x100 + ((regs.sp+1)&0xFF);
|
|
|
|
sp_addr_l = 0x100 + ((regs.sp+2)&0xFF);
|
|
|
|
sp_addr_h = 0x100 + ((regs.sp+3)&0xFF);
|
|
|
|
mem[sp_addr_p] = 0xEA;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sp_addr_l = 0x100 + ((regs.sp+1)&0xFF);
|
|
|
|
sp_addr_h = 0x100 + ((regs.sp+2)&0xFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
WORD ret_addr = 0x1234;
|
|
|
|
mem[sp_addr_l] = (BYTE) (ret_addr&0xFF);
|
|
|
|
mem[sp_addr_h] = (BYTE) ((ret_addr>>8)&0xFF);
|
|
|
|
|
|
|
|
if (!isRTI)
|
|
|
|
ret_addr++; // NB. return addr from stack is incremented before being transferred to PC
|
|
|
|
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, false);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != sp_addr_l || TargetAddr[1] != sp_addr_h || TargetAddr[2] != NO_6502_TARGET) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GH451_test_jmp(BYTE op)
|
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
|
|
|
const WORD target16 = 0x1234;
|
|
|
|
|
2020-01-04 17:43:20 +00:00
|
|
|
int target0=0, target1=0;
|
2019-12-09 16:27:13 +00:00
|
|
|
if (op == OPCODE_JMP_A)
|
|
|
|
{
|
|
|
|
target0 = NO_6502_TARGET;
|
|
|
|
target1 = NO_6502_TARGET;
|
|
|
|
}
|
|
|
|
else if (op == OPCODE_JMP_NA)
|
|
|
|
{
|
|
|
|
target0 = target16;
|
|
|
|
target1 = (target16+1)&0xffff;
|
|
|
|
}
|
|
|
|
else if (op == OPCODE_JMP_IAX)
|
|
|
|
{
|
|
|
|
target0 = (target16+regs.x)&0xffff;
|
|
|
|
target1 = (target16+regs.x+1)&0xffff;
|
|
|
|
}
|
2020-01-04 17:43:20 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
_ASSERT(0);
|
|
|
|
}
|
2019-12-09 16:27:13 +00:00
|
|
|
|
|
|
|
mem[regs.pc] = op;
|
|
|
|
mem[(regs.pc+1)&0xFFFF] = (BYTE) (target16&0xff);
|
|
|
|
mem[(regs.pc+2)&0xFFFF] = (BYTE) ((target16>>8)&0xff);
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, false);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != target0 || TargetAddr[1] != target1 || TargetAddr[2] != NO_6502_TARGET) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// bIgnoreBranch == true
|
|
|
|
int GH451_test_Bcc(void)
|
|
|
|
{
|
|
|
|
bool bRes;
|
|
|
|
int TargetAddr[3];
|
|
|
|
int TargetBytes;
|
|
|
|
|
|
|
|
mem[regs.pc] = 0x10; // BPL next-op
|
|
|
|
mem[regs.pc+1] = 0;
|
|
|
|
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, false);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != NO_6502_TARGET || TargetAddr[1] != NO_6502_TARGET || TargetAddr[2] != NO_6502_TARGET) return 1;
|
|
|
|
|
|
|
|
mem[regs.pc] = 0x10; // BPL this-op
|
|
|
|
mem[regs.pc+1] = 0xfe;
|
|
|
|
|
2019-12-09 20:42:16 +00:00
|
|
|
bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, false);
|
2019-12-09 16:27:13 +00:00
|
|
|
if (!bRes || TargetAddr[0] != NO_6502_TARGET || TargetAddr[1] != NO_6502_TARGET || TargetAddr[2] != NO_6502_TARGET) return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GH451_test_sub(bool bIs65C02)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
mem[0x10000] = 0xDD; // Bad data if 64K wrap not working
|
|
|
|
mem[0x10001] = 0xDD;
|
|
|
|
|
|
|
|
mem[0x200] = 0xDD; // Bad data if SP wrap not working
|
|
|
|
mem[0x201] = 0xDD;
|
|
|
|
|
|
|
|
regs.pc = 0x300;
|
|
|
|
|
|
|
|
//
|
|
|
|
// LDA abs
|
|
|
|
|
|
|
|
res = GH451_test_abs(OPCODE_LDA_A);
|
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
//
|
|
|
|
// JSR abs
|
|
|
|
|
|
|
|
res = GH451_test_jsr();
|
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
//
|
|
|
|
// BRK
|
|
|
|
|
|
|
|
mem[_6502_BRK_VECTOR+0] = 0x40; // BRK vector: $FA40
|
|
|
|
mem[_6502_BRK_VECTOR+1] = 0xFA;
|
|
|
|
|
|
|
|
res = GH451_test_brk();
|
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
//
|
|
|
|
// RTI
|
|
|
|
|
|
|
|
res = GH451_test_rti_rts(0x1FE, true);
|
|
|
|
if (res) return res;
|
|
|
|
res = GH451_test_rti_rts(0x1FF, true);
|
|
|
|
if (res) return res;
|
|
|
|
res = GH451_test_rti_rts(0x100, true);
|
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
//
|
|
|
|
// RTS
|
|
|
|
|
|
|
|
res = GH451_test_rti_rts(0x1FE, false);
|
|
|
|
if (res) return res;
|
|
|
|
res = GH451_test_rti_rts(0x1FF, false);
|
|
|
|
if (res) return res;
|
|
|
|
res = GH451_test_rti_rts(0x100, false);
|
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
//
|
|
|
|
// JMP
|
|
|
|
|
|
|
|
res = GH451_test_jmp(OPCODE_JMP_A); // JMP abs
|
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
res = GH451_test_jmp(OPCODE_JMP_NA); // JMP (abs)
|
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
if (bIs65C02)
|
|
|
|
{
|
|
|
|
regs.x = 0xff;
|
|
|
|
res = GH451_test_jmp(OPCODE_JMP_IAX); // JMP (abs),x
|
|
|
|
if (res) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Bcc
|
|
|
|
|
|
|
|
res = GH451_test_Bcc();
|
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// debugger command 'bpm[r|w] addr16': JSR abs should not trigger a breakpoint at addr16
|
|
|
|
// . similarly for all other control flow opcodes (eg. Bcc, BRK, JMP, RTI, RTS)
|
|
|
|
int GH451_test(void)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
g_aOpcodes = g_aOpcodes65C02;
|
|
|
|
res = GH451_test_sub(true);
|
|
|
|
if (res) return res;
|
|
|
|
|
|
|
|
g_aOpcodes = g_aOpcodes6502;
|
|
|
|
res = GH451_test_sub(false);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------
|
|
|
|
|
2017-08-15 20:02:54 +00:00
|
|
|
int _tmain(int argc, _TCHAR* argv[])
|
|
|
|
{
|
|
|
|
int res = 1;
|
|
|
|
init();
|
|
|
|
reset();
|
|
|
|
|
|
|
|
res = GH445_test();
|
|
|
|
if (res) return res;
|
|
|
|
|
2019-12-09 16:27:13 +00:00
|
|
|
res = GH451_test();
|
|
|
|
if (res) return res;
|
|
|
|
|
2017-08-15 20:02:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|