More funcinfo on register usage fixes.

This commit is contained in:
acqn 2020-09-18 20:23:02 +08:00 committed by Oliver Schmidt
parent fe003eedd4
commit 0bfa13722b
4 changed files with 386 additions and 312 deletions

View File

@ -172,6 +172,10 @@ static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D)
if (Info && Info->ByteUse != REG_NONE) {
/* These addressing modes will never change the zp loc */
E->Use |= Info->WordUse;
if ((E->Use & REG_SP) != 0) {
E->Use |= SLV_IND;
}
}
break;

View File

@ -82,269 +82,296 @@ struct FuncInfo {
unsigned Chg; /* Changed/destroyed registers */
};
/* Note for the shift functions: Shifts are done modulo 32, so all shift
/* Functions that change the SP are regarded as using the SP as well.
** The callax/jmpvec functions may call a function that uses/changes more
** registers, so we should further check the info of the called function
** or just play it safe.
** Note for the shift functions: Shifts are done modulo 32, so all shift
** routines are marked to use only the A register. The remainder is ignored
** anyway.
*/
static const FuncInfo FuncInfoTable[] = {
{ "addeq0sp", REG_AX, PSTATE_ALL | REG_AXY },
{ "addeqysp", REG_AXY, PSTATE_ALL | REG_AXY },
{ "addysp", REG_Y, PSTATE_ALL | REG_NONE },
{ "aslax1", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "aslax2", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "aslax3", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "aslax4", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "aslaxy", REG_AXY, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "asleax1", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "asleax2", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "asleax3", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "asleax4", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "asrax1", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "asrax2", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "asrax3", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "asrax4", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "asraxy", REG_AXY, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "asreax1", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "asreax2", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "asreax3", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "asreax4", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "bcasta", REG_A, PSTATE_ALL | REG_AX },
{ "bcastax", REG_AX, PSTATE_ALL | REG_AX },
{ "bcasteax", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "bnega", REG_A, PSTATE_ALL | REG_AX },
{ "bnegax", REG_AX, PSTATE_ALL | REG_AX },
{ "bnegeax", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "booleq", PSTATE_Z, PSTATE_ALL | REG_AX },
{ "boolge", PSTATE_N, PSTATE_ALL | REG_AX },
{ "boolgt", PSTATE_ZN, PSTATE_ALL | REG_AX },
{ "boolle", PSTATE_ZN, PSTATE_ALL | REG_AX },
{ "boollt", PSTATE_N, PSTATE_ALL | REG_AX },
{ "boolne", PSTATE_Z, PSTATE_ALL | REG_AX },
{ "booluge", PSTATE_C, PSTATE_ALL | REG_AX },
{ "boolugt", PSTATE_CZ, PSTATE_ALL | REG_AX },
{ "boolule", PSTATE_CZ, PSTATE_ALL | REG_AX },
{ "boolult", PSTATE_C, PSTATE_ALL | REG_AX },
{ "callax", REG_AX, PSTATE_ALL | REG_ALL },
{ "complax", REG_AX, PSTATE_ALL | REG_AX },
{ "decax1", REG_AX, PSTATE_ALL | REG_AX },
{ "decax2", REG_AX, PSTATE_ALL | REG_AX },
{ "decax3", REG_AX, PSTATE_ALL | REG_AX },
{ "decax4", REG_AX, PSTATE_ALL | REG_AX },
{ "decax5", REG_AX, PSTATE_ALL | REG_AX },
{ "decax6", REG_AX, PSTATE_ALL | REG_AX },
{ "decax7", REG_AX, PSTATE_ALL | REG_AX },
{ "decax8", REG_AX, PSTATE_ALL | REG_AX },
{ "decaxy", REG_AXY, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "deceaxy", REG_EAXY, PSTATE_ALL | REG_EAX },
{ "decsp1", REG_NONE, PSTATE_ALL | REG_Y },
{ "decsp2", REG_NONE, PSTATE_ALL | REG_A },
{ "decsp3", REG_NONE, PSTATE_ALL | REG_A },
{ "decsp4", REG_NONE, PSTATE_ALL | REG_A },
{ "decsp5", REG_NONE, PSTATE_ALL | REG_A },
{ "decsp6", REG_NONE, PSTATE_ALL | REG_A },
{ "decsp7", REG_NONE, PSTATE_ALL | REG_A },
{ "decsp8", REG_NONE, PSTATE_ALL | REG_A },
{ "incax1", REG_AX, PSTATE_ALL | REG_AX },
{ "incax2", REG_AX, PSTATE_ALL | REG_AX },
{ "incax3", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incax4", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incax5", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incax6", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incax7", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incax8", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incaxy", REG_AXY, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incsp1", REG_NONE, PSTATE_ALL | REG_NONE },
{ "incsp2", REG_NONE, PSTATE_ALL | REG_Y },
{ "incsp3", REG_NONE, PSTATE_ALL | REG_Y },
{ "incsp4", REG_NONE, PSTATE_ALL | REG_Y },
{ "incsp5", REG_NONE, PSTATE_ALL | REG_Y },
{ "incsp6", REG_NONE, PSTATE_ALL | REG_Y },
{ "incsp7", REG_NONE, PSTATE_ALL | REG_Y },
{ "incsp8", REG_NONE, PSTATE_ALL | REG_Y },
{ "laddeq", REG_EAXY|REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI },
{ "laddeq0sp", REG_EAX, PSTATE_ALL | REG_EAXY },
{ "laddeq1", REG_Y | REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI },
{ "laddeqa", REG_AY | REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI },
{ "laddeqysp", REG_EAXY, PSTATE_ALL | REG_EAXY },
{ "ldaidx", REG_AXY, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "ldauidx", REG_AXY, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "ldax0sp", REG_NONE, PSTATE_ALL | REG_AXY },
{ "ldaxi", REG_AX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "ldaxidx", REG_AXY, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "ldaxysp", REG_Y, PSTATE_ALL | REG_AXY },
{ "ldeax0sp", REG_NONE, PSTATE_ALL | REG_EAXY },
{ "ldeaxi", REG_AX, PSTATE_ALL | REG_EAXY | REG_PTR1 },
{ "ldeaxidx", REG_AXY, PSTATE_ALL | REG_EAXY | REG_PTR1 },
{ "ldeaxysp", REG_Y, PSTATE_ALL | REG_EAXY },
{ "leaa0sp", REG_A, PSTATE_ALL | REG_AX },
{ "leaaxsp", REG_AX, PSTATE_ALL | REG_AX },
{ "lsubeq", REG_EAXY|REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI },
{ "lsubeq0sp", REG_EAX, PSTATE_ALL | REG_EAXY },
{ "lsubeq1", REG_Y | REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI },
{ "lsubeqa", REG_AY | REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI },
{ "lsubeqysp", REG_EAXY, PSTATE_ALL | REG_EAXY },
{ "mulax10", REG_AX, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "mulax3", REG_AX, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "mulax5", REG_AX, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "mulax6", REG_AX, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "mulax7", REG_AX, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "mulax9", REG_AX, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "negax", REG_AX, PSTATE_ALL | REG_AX },
{ "push0", REG_NONE, PSTATE_ALL | REG_AXY },
{ "push0ax", REG_AX, PSTATE_ALL | REG_Y | REG_SREG },
{ "push1", REG_NONE, PSTATE_ALL | REG_AXY },
{ "push2", REG_NONE, PSTATE_ALL | REG_AXY },
{ "push3", REG_NONE, PSTATE_ALL | REG_AXY },
{ "push4", REG_NONE, PSTATE_ALL | REG_AXY },
{ "push5", REG_NONE, PSTATE_ALL | REG_AXY },
{ "push6", REG_NONE, PSTATE_ALL | REG_AXY },
{ "push7", REG_NONE, PSTATE_ALL | REG_AXY },
{ "pusha", REG_A, PSTATE_ALL | REG_Y },
{ "pusha0", REG_A, PSTATE_ALL | REG_XY },
{ "pusha0sp", REG_NONE, PSTATE_ALL | REG_AY },
{ "pushaFF", REG_A, PSTATE_ALL | REG_Y },
{ "pushax", REG_AX, PSTATE_ALL | REG_Y },
{ "pushaysp", REG_Y, PSTATE_ALL | REG_AY },
{ "pushc0", REG_NONE, PSTATE_ALL | REG_A | REG_Y },
{ "pushc1", REG_NONE, PSTATE_ALL | REG_A | REG_Y },
{ "pushc2", REG_NONE, PSTATE_ALL | REG_A | REG_Y },
{ "pusheax", REG_EAX, PSTATE_ALL | REG_Y },
{ "pushl0", REG_NONE, PSTATE_ALL | REG_AXY },
{ "pushw", REG_AX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "pushw0sp", REG_NONE, PSTATE_ALL | REG_AXY },
{ "pushwidx", REG_AXY, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "pushwysp", REG_Y, PSTATE_ALL | REG_AXY },
{ "regswap", REG_AXY, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "regswap1", REG_XY, PSTATE_ALL | REG_A },
{ "regswap2", REG_XY, PSTATE_ALL | REG_A | REG_Y },
{ "return0", REG_NONE, PSTATE_ALL | REG_AX },
{ "return1", REG_NONE, PSTATE_ALL | REG_AX },
{ "shlax1", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shlax2", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shlax3", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shlax4", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shlaxy", REG_AXY, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "shleax1", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "shleax2", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "shleax3", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "shleax4", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "shrax1", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shrax2", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shrax3", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shrax4", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shraxy", REG_AXY, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "shreax1", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "shreax2", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "shreax3", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "shreax4", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "staspidx", REG_A | REG_Y, PSTATE_ALL | REG_Y | REG_TMP1 | REG_PTR1 },
{ "stax0sp", REG_AX, PSTATE_ALL | REG_Y },
{ "staxspidx", REG_AXY, PSTATE_ALL | REG_TMP1 | REG_PTR1 },
{ "staxysp", REG_AXY, PSTATE_ALL | REG_Y },
{ "steax0sp", REG_EAX, PSTATE_ALL | REG_Y },
{ "steaxysp", REG_EAXY, PSTATE_ALL | REG_Y },
{ "subeq0sp", REG_AX, PSTATE_ALL | REG_AXY },
{ "subeqysp", REG_AXY, PSTATE_ALL | REG_AXY },
{ "subysp", REG_Y, PSTATE_ALL | REG_AY },
{ "tosadd0ax", REG_AX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tosadda0", REG_A, PSTATE_ALL | REG_AXY },
{ "tosaddax", REG_AX, PSTATE_ALL | REG_AXY },
{ "tosaddeax", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tosand0ax", REG_AX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tosanda0", REG_A, PSTATE_ALL | REG_AXY },
{ "tosandax", REG_AX, PSTATE_ALL | REG_AXY },
{ "tosandeax", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tosaslax", REG_A, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "tosasleax", REG_A, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tosasrax", REG_A, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "tosasreax", REG_A, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tosdiv0ax", REG_AX, PSTATE_ALL | REG_ALL },
{ "tosdiva0", REG_A, PSTATE_ALL | REG_ALL },
{ "tosdivax", REG_AX, PSTATE_ALL | REG_ALL },
{ "tosdiveax", REG_EAX, PSTATE_ALL | REG_ALL },
{ "toseq00", REG_NONE, PSTATE_ALL | REG_AXY | REG_SREG },
{ "toseqa0", REG_A, PSTATE_ALL | REG_AXY | REG_SREG },
{ "toseqax", REG_AX, PSTATE_ALL | REG_AXY | REG_SREG },
{ "toseqeax", REG_EAX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "tosge00", REG_NONE, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosgea0", REG_A, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosgeax", REG_AX, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosgeeax", REG_EAX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "tosgt00", REG_NONE, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosgta0", REG_A, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosgtax", REG_AX, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosgteax", REG_EAX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "tosicmp", REG_AX, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosicmp0", REG_A, PSTATE_ALL | REG_AXY | REG_SREG },
{ "toslcmp", REG_EAX, PSTATE_ALL | REG_A | REG_Y | REG_PTR1 },
{ "tosle00", REG_NONE, PSTATE_ALL | REG_AXY | REG_SREG },
{ "toslea0", REG_A, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosleax", REG_AX, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosleeax", REG_EAX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "toslt00", REG_NONE, PSTATE_ALL | REG_AXY | REG_SREG },
{ "toslta0", REG_A, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosltax", REG_AX, PSTATE_ALL | REG_AXY | REG_SREG },
{ "toslteax", REG_EAX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "tosmod0ax", REG_AX, PSTATE_ALL | REG_ALL },
{ "tosmodeax", REG_EAX, PSTATE_ALL | REG_ALL },
{ "tosmul0ax", REG_AX, PSTATE_ALL | REG_ALL },
{ "tosmula0", REG_A, PSTATE_ALL | REG_ALL },
{ "tosmulax", REG_AX, PSTATE_ALL | REG_ALL },
{ "tosmuleax", REG_EAX, PSTATE_ALL | REG_ALL },
{ "tosne00", REG_NONE, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosnea0", REG_A, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosneax", REG_AX, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosneeax", REG_EAX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "tosor0ax", REG_AX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tosora0", REG_A, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "tosorax", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "tosoreax", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tosrsub0ax", REG_AX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tosrsuba0", REG_A, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "tosrsubax", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "tosrsubeax", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tosshlax", REG_A, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "tosshleax", REG_A, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tosshrax", REG_A, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "tosshreax", REG_A, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tossub0ax", REG_AX, PSTATE_ALL | REG_EAXY },
{ "tossuba0", REG_A, PSTATE_ALL | REG_AXY },
{ "tossubax", REG_AX, PSTATE_ALL | REG_AXY },
{ "tossubeax", REG_EAX, PSTATE_ALL | REG_EAXY },
{ "tosudiv0ax", REG_AX, PSTATE_ALL | (REG_ALL & ~REG_SAVE) },
{ "tosudiva0", REG_A, PSTATE_ALL | REG_EAXY | REG_PTR1 }, /* also ptr4 */
{ "tosudivax", REG_AX, PSTATE_ALL | REG_EAXY | REG_PTR1 }, /* also ptr4 */
{ "tosudiveax", REG_EAX, PSTATE_ALL | (REG_ALL & ~REG_SAVE) },
{ "tosuge00", REG_NONE, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosugea0", REG_A, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosugeax", REG_AX, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosugeeax", REG_EAX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "tosugt00", REG_NONE, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosugta0", REG_A, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosugtax", REG_AX, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosugteax", REG_EAX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "tosule00", REG_NONE, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosulea0", REG_A, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosuleax", REG_AX, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosuleeax", REG_EAX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "tosult00", REG_NONE, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosulta0", REG_A, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosultax", REG_AX, PSTATE_ALL | REG_AXY | REG_SREG },
{ "tosulteax", REG_EAX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "tosumod0ax", REG_AX, PSTATE_ALL | (REG_ALL & ~REG_SAVE) },
{ "tosumoda0", REG_A, PSTATE_ALL | REG_EAXY | REG_PTR1 }, /* also ptr4 */
{ "tosumodax", REG_AX, PSTATE_ALL | REG_EAXY | REG_PTR1 }, /* also ptr4 */
{ "tosumodeax", REG_EAX, PSTATE_ALL | (REG_ALL & ~REG_SAVE) },
{ "tosumul0ax", REG_AX, PSTATE_ALL | REG_ALL },
{ "tosumula0", REG_A, PSTATE_ALL | REG_ALL },
{ "tosumulax", REG_AX, PSTATE_ALL | REG_ALL },
{ "tosumuleax", REG_EAX, PSTATE_ALL | REG_ALL },
{ "tosxor0ax", REG_AX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tosxora0", REG_A, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "tosxorax", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "tosxoreax", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "tsteax", REG_EAX, PSTATE_ALL | REG_Y },
{ "utsteax", REG_EAX, PSTATE_ALL | REG_Y },
{ "addeq0sp", SLV_TOP | REG_AX, PSTATE_ALL | REG_AXY },
{ "addeqysp", SLV_IND | REG_AXY, PSTATE_ALL | REG_AXY },
{ "addysp", REG_SP | REG_Y, PSTATE_ALL | REG_SP },
{ "along", REG_A, PSTATE_ALL | REG_X | REG_SREG },
{ "aslax1", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "aslax2", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "aslax3", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "aslax4", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "aslaxy", REG_AXY, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "asleax1", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "asleax2", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "asleax3", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "asleax4", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "asrax1", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "asrax2", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "asrax3", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "asrax4", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "asraxy", REG_AXY, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "asreax1", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "asreax2", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "asreax3", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "asreax4", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "aulong", REG_NONE, PSTATE_ALL | REG_X | REG_SREG },
{ "axlong", REG_X, PSTATE_ALL | REG_Y | REG_SREG },
{ "axulong", REG_NONE, PSTATE_ALL | REG_Y | REG_SREG },
{ "bcasta", REG_A, PSTATE_ALL | REG_AX },
{ "bcastax", REG_AX, PSTATE_ALL | REG_AX },
{ "bcasteax", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "bnega", REG_A, PSTATE_ALL | REG_AX },
{ "bnegax", REG_AX, PSTATE_ALL | REG_AX },
{ "bnegeax", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "booleq", PSTATE_Z, PSTATE_ALL | REG_AX },
{ "boolge", PSTATE_N, PSTATE_ALL | REG_AX },
{ "boolgt", PSTATE_ZN, PSTATE_ALL | REG_AX },
{ "boolle", PSTATE_ZN, PSTATE_ALL | REG_AX },
{ "boollt", PSTATE_N, PSTATE_ALL | REG_AX },
{ "boolne", PSTATE_Z, PSTATE_ALL | REG_AX },
{ "booluge", PSTATE_C, PSTATE_ALL | REG_AX },
{ "boolugt", PSTATE_CZ, PSTATE_ALL | REG_AX },
{ "boolule", PSTATE_CZ, PSTATE_ALL | REG_AX },
{ "boolult", PSTATE_C, PSTATE_ALL | REG_AX },
{ "callax", REG_AX, PSTATE_ALL | REG_ALL }, /* PSTATE_ZN | REG_PTR1 */
{ "complax", REG_AX, PSTATE_ALL | REG_AX },
{ "decax1", REG_AX, PSTATE_ALL | REG_AX },
{ "decax2", REG_AX, PSTATE_ALL | REG_AX },
{ "decax3", REG_AX, PSTATE_ALL | REG_AX },
{ "decax4", REG_AX, PSTATE_ALL | REG_AX },
{ "decax5", REG_AX, PSTATE_ALL | REG_AX },
{ "decax6", REG_AX, PSTATE_ALL | REG_AX },
{ "decax7", REG_AX, PSTATE_ALL | REG_AX },
{ "decax8", REG_AX, PSTATE_ALL | REG_AX },
{ "decaxy", REG_AXY, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "deceaxy", REG_EAXY, PSTATE_ALL | REG_EAX },
{ "decsp1", REG_SP, PSTATE_ALL | REG_SP | REG_Y },
{ "decsp2", REG_SP, PSTATE_ALL | REG_SP | REG_A },
{ "decsp3", REG_SP, PSTATE_ALL | REG_SP | REG_A },
{ "decsp4", REG_SP, PSTATE_ALL | REG_SP | REG_A },
{ "decsp5", REG_SP, PSTATE_ALL | REG_SP | REG_A },
{ "decsp6", REG_SP, PSTATE_ALL | REG_SP | REG_A },
{ "decsp7", REG_SP, PSTATE_ALL | REG_SP | REG_A },
{ "decsp8", REG_SP, PSTATE_ALL | REG_SP | REG_A },
{ "enter", REG_SP | REG_Y, PSTATE_ALL | REG_SP | REG_AY },
{ "incax1", REG_AX, PSTATE_ALL | REG_AX },
{ "incax2", REG_AX, PSTATE_ALL | REG_AX },
{ "incax3", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incax4", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incax5", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incax6", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incax7", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incax8", REG_AX, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incaxy", REG_AXY, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "incsp1", REG_SP, PSTATE_ALL | REG_SP },
{ "incsp2", REG_SP, PSTATE_ALL | REG_SP | REG_Y },
{ "incsp3", REG_SP, PSTATE_ALL | REG_SP | REG_Y },
{ "incsp4", REG_SP, PSTATE_ALL | REG_SP | REG_Y },
{ "incsp5", REG_SP, PSTATE_ALL | REG_SP | REG_Y },
{ "incsp6", REG_SP, PSTATE_ALL | REG_SP | REG_Y },
{ "incsp7", REG_SP, PSTATE_ALL | REG_SP | REG_Y },
{ "incsp8", REG_SP, PSTATE_ALL | REG_SP | REG_Y },
{ "jmpvec", REG_EVERYTHING, PSTATE_ALL | REG_ALL }, /* NONE */
{ "laddeq", REG_EAXY | REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI },
{ "laddeq0sp", SLV_TOP | REG_EAX, PSTATE_ALL | REG_EAXY },
{ "laddeq1", REG_Y | REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI },
{ "laddeqa", REG_AY | REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI },
{ "laddeqysp", SLV_IND | REG_EAXY, PSTATE_ALL | REG_EAXY },
{ "ldaidx", REG_AXY, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "ldauidx", REG_AXY, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "ldax0sp", SLV_TOP, PSTATE_ALL | REG_AXY },
{ "ldaxi", REG_AX, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "ldaxidx", REG_AXY, PSTATE_ALL | REG_AXY | REG_PTR1 },
{ "ldaxysp", SLV_IND | REG_Y, PSTATE_ALL | REG_AXY },
{ "ldeax0sp", SLV_TOP, PSTATE_ALL | REG_EAXY },
{ "ldeaxi", REG_AX, PSTATE_ALL | REG_EAXY | REG_PTR1 },
{ "ldeaxidx", REG_AXY, PSTATE_ALL | REG_EAXY | REG_PTR1 },
{ "ldeaxysp", SLV_IND | REG_Y, PSTATE_ALL | REG_EAXY },
{ "leaa0sp", REG_SP | REG_A, PSTATE_ALL | REG_AX },
{ "leaaxsp", REG_SP | REG_AX, PSTATE_ALL | REG_AX },
{ "leave00", REG_SP, PSTATE_ALL | REG_SP | REG_AXY },
{ "leave0", REG_SP, PSTATE_ALL | REG_SP | REG_XY },
{ "leave", REG_SP, PSTATE_ALL | REG_SP | REG_Y },
{ "leavey00", REG_SP, PSTATE_ALL | REG_SP | REG_AXY },
{ "leavey0", REG_SP, PSTATE_ALL | REG_SP | REG_XY },
{ "leavey", REG_SP | REG_Y, PSTATE_ALL | REG_SP | REG_Y },
{ "lsubeq", REG_EAXY | REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI },
{ "lsubeq0sp", SLV_TOP | REG_EAX, PSTATE_ALL | REG_EAXY },
{ "lsubeq1", REG_Y | REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI },
{ "lsubeqa", REG_AY | REG_PTR1_LO, PSTATE_ALL | REG_EAXY | REG_PTR1_HI },
{ "lsubeqysp", SLV_IND | REG_EAXY, PSTATE_ALL | REG_EAXY },
{ "mulax10", REG_AX, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "mulax3", REG_AX, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "mulax5", REG_AX, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "mulax6", REG_AX, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "mulax7", REG_AX, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "mulax9", REG_AX, PSTATE_ALL | REG_AX | REG_PTR1 },
{ "negax", REG_AX, PSTATE_ALL | REG_AX },
{ "negeax", REG_EAX, PSTATE_ALL | REG_EAX },
{ "popa", SLV_TOP, PSTATE_ALL | REG_SP | REG_AY },
{ "popax", SLV_TOP, PSTATE_ALL | REG_SP | REG_AXY },
{ "popeax", SLV_TOP, PSTATE_ALL | REG_SP | REG_EAXY },
{ "push0", REG_SP, PSTATE_ALL | REG_SP | REG_AXY },
{ "push0ax", REG_SP | REG_AX, PSTATE_ALL | REG_SP | REG_Y | REG_SREG },
{ "push1", REG_SP, PSTATE_ALL | REG_SP | REG_AXY },
{ "push2", REG_SP, PSTATE_ALL | REG_SP | REG_AXY },
{ "push3", REG_SP, PSTATE_ALL | REG_SP | REG_AXY },
{ "push4", REG_SP, PSTATE_ALL | REG_SP | REG_AXY },
{ "push5", REG_SP, PSTATE_ALL | REG_SP | REG_AXY },
{ "push6", REG_SP, PSTATE_ALL | REG_SP | REG_AXY },
{ "push7", REG_SP, PSTATE_ALL | REG_SP | REG_AXY },
{ "pusha", REG_SP | REG_A, PSTATE_ALL | REG_SP | REG_Y },
{ "pusha0", REG_SP | REG_A, PSTATE_ALL | REG_SP | REG_XY },
{ "pusha0sp", SLV_TOP, PSTATE_ALL | REG_SP | REG_AY },
{ "pushaFF", REG_SP | REG_A, PSTATE_ALL | REG_SP | REG_Y },
{ "pushax", REG_SP | REG_AX, PSTATE_ALL | REG_SP | REG_Y },
{ "pushaysp", SLV_IND | REG_Y, PSTATE_ALL | REG_SP | REG_AY },
{ "pushc0", REG_SP, PSTATE_ALL | REG_SP | REG_A | REG_Y },
{ "pushc1", REG_SP, PSTATE_ALL | REG_SP | REG_A | REG_Y },
{ "pushc2", REG_SP, PSTATE_ALL | REG_SP | REG_A | REG_Y },
{ "pusheax", REG_SP | REG_EAX, PSTATE_ALL | REG_SP | REG_Y },
{ "pushl0", REG_SP, PSTATE_ALL | REG_SP | REG_AXY },
{ "pushw", REG_SP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_PTR1 },
{ "pushw0sp", SLV_TOP, PSTATE_ALL | REG_SP | REG_AXY },
{ "pushwidx", REG_SP | REG_AXY, PSTATE_ALL | REG_SP | REG_AXY | REG_PTR1 },
{ "pushwysp", SLV_IND | REG_Y, PSTATE_ALL | REG_SP | REG_AXY },
{ "regswap", REG_AXY, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "regswap1", REG_XY, PSTATE_ALL | REG_A },
{ "regswap2", REG_XY, PSTATE_ALL | REG_A | REG_Y },
{ "resteax", REG_SAVE, PSTATE_ZN | REG_EAX }, /* also uses regsave+2/+3 */
{ "return0", REG_NONE, PSTATE_ALL | REG_AX },
{ "return1", REG_NONE, PSTATE_ALL | REG_AX },
{ "saveeax", REG_EAX, PSTATE_ZN | REG_Y | REG_SAVE }, /* also regsave+2/+3 */
{ "shlax1", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shlax2", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shlax3", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shlax4", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shlaxy", REG_AXY, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "shleax1", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "shleax2", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "shleax3", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "shleax4", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "shrax1", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shrax2", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shrax3", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shrax4", REG_AX, PSTATE_ALL | REG_AX | REG_TMP1 },
{ "shraxy", REG_AXY, PSTATE_ALL | REG_AXY | REG_TMP1 },
{ "shreax1", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "shreax2", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "shreax3", REG_EAX, PSTATE_ALL | REG_EAX | REG_TMP1 },
{ "shreax4", REG_EAX, PSTATE_ALL | REG_EAXY | REG_TMP1 },
{ "staspidx", SLV_TOP | REG_AY, PSTATE_ALL | REG_SP | REG_Y | REG_TMP1 | REG_PTR1 },
{ "stax0sp", REG_SP | REG_AX, PSTATE_ALL | SLV_TOP | REG_Y },
{ "staxspidx", SLV_TOP | REG_AXY, PSTATE_ALL | REG_SP | REG_TMP1 | REG_PTR1 },
{ "staxysp", REG_SP | REG_AXY, PSTATE_ALL | SLV_IND | REG_Y },
{ "steax0sp", REG_SP | REG_EAX, PSTATE_ALL | SLV_TOP | REG_Y },
{ "steaxspidx", SLV_TOP | REG_EAXY, PSTATE_ALL | REG_SP | REG_Y | REG_TMP1 | REG_PTR1 }, /* also tmp2, tmp3 */
{ "steaxysp", REG_SP | REG_EAXY, PSTATE_ALL | SLV_IND | REG_Y },
{ "subeq0sp", SLV_TOP | REG_AX, PSTATE_ALL | REG_AXY },
{ "subeqysp", SLV_IND | REG_AXY, PSTATE_ALL | REG_AXY },
{ "subysp", REG_SP | REG_Y, PSTATE_ALL | REG_SP | REG_AY },
{ "swapstk", SLV_TOP | REG_AX, PSTATE_ALL | SLV_TOP | REG_AXY }, /* also ptr4 */
{ "tosadd0ax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tosadda0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY },
{ "tosaddax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY },
{ "tosaddeax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tosand0ax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tosanda0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY },
{ "tosandax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY },
{ "tosandeax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tosaslax", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_TMP1 },
{ "tosasleax", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tosasrax", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_TMP1 },
{ "tosasreax", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tosdiv0ax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_ALL },
{ "tosdiva0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_ALL },
{ "tosdivax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_ALL },
{ "tosdiveax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_ALL },
{ "toseq00", SLV_TOP, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "toseqa0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "toseqax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "toseqeax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_AXY | REG_PTR1 },
{ "tosge00", SLV_TOP, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosgea0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosgeax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosgeeax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_AXY | REG_PTR1 },
{ "tosgt00", SLV_TOP, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosgta0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosgtax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosgteax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_AXY | REG_PTR1 },
{ "tosicmp", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosicmp0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosint", SLV_TOP, PSTATE_ALL | REG_SP | REG_Y },
{ "toslcmp", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_A | REG_Y | REG_PTR1 },
{ "tosle00", SLV_TOP, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "toslea0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosleax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosleeax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_AXY | REG_PTR1 },
{ "toslong", SLV_TOP, PSTATE_ALL | REG_SP | REG_Y },
{ "toslt00", SLV_TOP, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "toslta0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosltax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "toslteax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_AXY | REG_PTR1 },
{ "tosmod0ax", SLV_TOP | REG_AX, PSTATE_ALL | REG_ALL },
{ "tosmodeax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_ALL },
{ "tosmul0ax", SLV_TOP | REG_AX, PSTATE_ALL | REG_ALL },
{ "tosmula0", SLV_TOP | REG_A, PSTATE_ALL | REG_ALL },
{ "tosmulax", SLV_TOP | REG_AX, PSTATE_ALL | REG_ALL },
{ "tosmuleax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_ALL },
{ "tosne00", SLV_TOP, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosnea0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosneax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosneeax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_AXY | REG_PTR1 },
{ "tosor0ax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tosora0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_TMP1 },
{ "tosorax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_TMP1 },
{ "tosoreax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tosrsub0ax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tosrsuba0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_TMP1 },
{ "tosrsubax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_TMP1 },
{ "tosrsubeax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tosshlax", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_TMP1 },
{ "tosshleax", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tosshrax", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_TMP1 },
{ "tosshreax", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tossub0ax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_EAXY },
{ "tossuba0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY },
{ "tossubax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY },
{ "tossubeax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_EAXY },
{ "tosudiv0ax", SLV_TOP | REG_AX, PSTATE_ALL | (REG_ALL & ~REG_SAVE) },
{ "tosudiva0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_EAXY | REG_PTR1 }, /* also ptr4 */
{ "tosudivax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_EAXY | REG_PTR1 }, /* also ptr4 */
{ "tosudiveax", SLV_TOP | REG_EAX, PSTATE_ALL | (REG_ALL & ~REG_SAVE) },
{ "tosuge00", SLV_TOP, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosugea0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosugeax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosugeeax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_AXY | REG_PTR1 },
{ "tosugt00", SLV_TOP, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosugta0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosugtax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosugteax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_AXY | REG_PTR1 },
{ "tosule00", SLV_TOP, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosulea0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosuleax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosuleeax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_AXY | REG_PTR1 },
{ "tosulong", SLV_TOP, PSTATE_ALL | REG_SP | REG_Y },
{ "tosult00", SLV_TOP, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosulta0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosultax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_SREG },
{ "tosulteax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_AXY | REG_PTR1 },
{ "tosumod0ax", SLV_TOP | REG_AX, PSTATE_ALL | (REG_ALL & ~REG_SAVE) },
{ "tosumoda0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_EAXY | REG_PTR1 }, /* also ptr4 */
{ "tosumodax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_EAXY | REG_PTR1 }, /* also ptr4 */
{ "tosumodeax", SLV_TOP | REG_EAX, PSTATE_ALL | (REG_ALL & ~REG_SAVE) },
{ "tosumul0ax", SLV_TOP | REG_AX, PSTATE_ALL | REG_ALL },
{ "tosumula0", SLV_TOP | REG_A, PSTATE_ALL | REG_ALL },
{ "tosumulax", SLV_TOP | REG_AX, PSTATE_ALL | REG_ALL },
{ "tosumuleax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_ALL },
{ "tosxor0ax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tosxora0", SLV_TOP | REG_A, PSTATE_ALL | REG_SP | REG_AXY | REG_TMP1 },
{ "tosxorax", SLV_TOP | REG_AX, PSTATE_ALL | REG_SP | REG_AXY | REG_TMP1 },
{ "tosxoreax", SLV_TOP | REG_EAX, PSTATE_ALL | REG_SP | REG_EAXY | REG_TMP1 },
{ "tsteax", REG_EAX, PSTATE_ALL | REG_Y },
{ "utsteax", REG_EAX, PSTATE_ALL | REG_Y },
};
#define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
@ -481,6 +508,7 @@ fncls_t GetFuncInfo (const char* Name, unsigned int* Use, unsigned int* Chg)
/* Did we find it in the top-level table? */
if (E && IsTypeFunc (E->Type)) {
FuncDesc* D = GetFuncDesc (E->Type);
*Use = REG_NONE;
/* A variadic function will use the Y register (the parameter list
** size is passed there). A fastcall function will use the A or A/X
@ -488,31 +516,40 @@ fncls_t GetFuncInfo (const char* Name, unsigned int* Use, unsigned int* Chg)
** we assume that any function will destroy all registers.
*/
if ((D->Flags & FD_VARIADIC) != 0) {
*Use = REG_Y;
*Use = REG_Y | REG_SP | SLV_TOP;
} else if (D->Flags & FD_CALL_WRAPPER) {
/* Wrappers may go to any functions, so mark them as using all
** registers.
*/
*Use = REG_EAXY;
} else if ((D->ParamCount > 0 || (D->Flags & FD_EMPTY) != 0) &&
IsFastcallFunc (E->Type)) {
} else if (D->ParamCount > 0 || (D->Flags & FD_EMPTY) != 0) {
/* Will use registers depending on the last param. If the last
** param has incomplete type, or if the function has not been
** prototyped yet, just assume __EAX__.
*/
if (D->LastParam != 0) {
switch (SizeOf (D->LastParam->Type)) {
case 1u:
*Use = REG_A;
break;
case 2u:
*Use = REG_AX;
break;
default:
*Use = REG_EAX;
if (IsFastcallFunc (E->Type)) {
if (D->LastParam != 0) {
switch (SizeOf (D->LastParam->Type)) {
case 1u:
*Use = REG_A;
break;
case 2u:
*Use = REG_AX;
break;
default:
*Use = REG_EAX;
}
if (D->ParamCount > 1) {
/* Passes other params on the stack */
*Use |= REG_SP | SLV_TOP;
}
} else {
/* We'll assume all */
*Use = REG_EAX | REG_SP | SLV_TOP;
}
} else {
*Use = REG_EAX;
/* Passes all params on the stack */
*Use = REG_SP | SLV_TOP;
}
} else {
/* Will not use any registers */
@ -551,6 +588,9 @@ fncls_t GetFuncInfo (const char* Name, unsigned int* Use, unsigned int* Chg)
/* Use the information we have */
*Use = Info->Use;
*Chg = Info->Chg;
if ((*Use & (SLV_TOP | SLV_IND)) != 0) {
*Use |= REG_SP;
}
} else {
/* It's an internal function we have no information for. If in
** debug mode, output an additional warning, so we have a chance

View File

@ -75,6 +75,8 @@ struct RegContents;
#define REG_SP_HI 0x2000U
/* Defines for some special register usage */
#define SLV_IND 0x00010000U /* Accesses (sp),y */
#define SLV_TOP 0x00020000U /* Accesses (sp),0 */
#define SLV_SP65 0x00200000U /* Accesses 6502 stack pointer */
#define SLV_PH65 0x00400000U /* Pushes onto 6502 stack */
#define SLV_PL65 0x00800000U /* Pops from 6502 stack */
@ -104,6 +106,7 @@ struct RegContents;
#define REG_EAXY (REG_EAX | REG_Y)
#define REG_ZP 0xFFF8U
#define REG_ALL 0xFFFFU
#define PSTATE_CZ (PSTATE_C | PSTATE_Z)
#define PSTATE_CZN (PSTATE_C | PSTATE_Z | PSTATE_N)
#define PSTATE_CZVN (PSTATE_C | PSTATE_Z | PSTATE_V | PSTATE_N)

View File

@ -827,21 +827,28 @@ void AdjustStackOffset (StackOpData* D, unsigned Offs)
CodeEntry* E = CS_GetEntry (D->Code, I);
/* Check against some things that should not happen */
CHECK ((E->Use & SLV_TOP) != SLV_TOP);
/* Check if this entry does a stack access, and if so, if it's a plain
** load from stack, since this is needed later.
*/
int Correction = 0;
if ((E->Use & REG_SP) != 0) {
if ((E->Use & SLV_IND) == SLV_IND) {
/* Check for some things that should not happen */
CHECK (E->AM == AM65_ZP_INDY || E->RI->In.RegY >= (short) Offs);
CHECK (strcmp (E->Arg, "sp") == 0);
/* We need to correct this one */
Correction = (E->OPC == OP65_LDA)? 2 : 1;
if (E->OPC != OP65_JSR) {
/* Check against some things that should not happen */
CHECK (E->AM == AM65_ZP_INDY && E->RI->In.RegY >= (short) Offs);
CHECK (strcmp (E->Arg, "sp") == 0);
/* We need to correct this one */
Correction = 2;
} else {
/* We need to correct this one */
Correction = 1;
}
} else if (CE_IsCallTo (E, "ldaxysp")) {
/* We need to correct this one */
Correction = 1;
}
if (Correction) {
@ -849,7 +856,7 @@ void AdjustStackOffset (StackOpData* D, unsigned Offs)
** value.
*/
CodeEntry* P = CS_GetPrevEntry (D->Code, I);
if (P && P->OPC == OP65_LDY && CE_IsConstImm (P)) {
if (P && P->OPC == OP65_LDY && CE_IsConstImm (P) && !CE_HasLabel (E)) {
/* The Y load is just before the stack access, adjust it */
CE_SetNumArg (P, P->Num - Offs);
} else {
@ -860,39 +867,59 @@ void AdjustStackOffset (StackOpData* D, unsigned Offs)
}
/* If we need the value of Y later, be sure to reload it */
if (RegYUsed (D->Code, I+1)) {
CodeEntry* N;
unsigned R = REG_Y | (E->Chg & ~REG_A);
R = GetRegInfo (D->Code, I + 1, R) & R;
if ((R & REG_Y) != 0) {
const char* Arg = MakeHexArg (E->RI->In.RegY);
if (Correction == 2 && (N = CS_GetNextEntry(D->Code, I)) != 0 &&
((N->Info & OF_ZBRA) != 0) && N->JumpTo != 0) {
/* The Y register is used but the load instruction loads A
** and is followed by a branch that evaluates the zero flag.
** This means that we cannot just insert the load insn
** for the Y register at this place, because it would
** destroy the Z flag. Instead place load insns at the
** target of the branch and after it.
** Note: There is a chance that this code won't work. The
** jump may be a backwards jump (in which case the stack
** offset has already been adjusted) or there may be other
** instructions between the load and the conditional jump.
** Currently the compiler does not generate such code, but
** it is possible to force the optimizer into something
** invalid by use of inline assembler.
*/
if ((R & PSTATE_ZN) != 0 && (R & ~(REG_Y | PSTATE_ZN)) == 0) {
CodeEntry* N;
if ((N = CS_GetNextEntry (D->Code, I)) != 0 &&
((N->Info & OF_ZBRA) != 0) && N->JumpTo != 0) {
/* The Y register is used but the load instruction loads A
** and is followed by a branch that evaluates the zero flag.
** This means that we cannot just insert the load insn
** for the Y register at this place, because it would
** destroy the Z flag. Instead place load insns at the
** target of the branch and after it.
** Note: There is a chance that this code won't work. The
** jump may be a backwards jump (in which case the stack
** offset has already been adjusted) or there may be other
** instructions between the load and the conditional jump.
** Currently the compiler does not generate such code, but
** it is possible to force the optimizer into something
** invalid by use of inline assembler.
** Note: In reality, this route is never taken as all
** callers of this function will just give up with
** optimization whenever they detect a branch.
*/
/* Add load insn after the branch */
CodeEntry* X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
InsertEntry (D, X, I+2);
/* Add load insn after the branch */
CodeEntry* X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
InsertEntry (D, X, I+2);
/* Add load insn before branch target */
CodeEntry* Y = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
int J = CS_GetEntryIndex (D->Code, N->JumpTo->Owner);
CHECK (J > I); /* Must not happen */
InsertEntry (D, Y, J);
/* Add load insn before branch target */
CodeEntry* Y = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
int J = CS_GetEntryIndex (D->Code, N->JumpTo->Owner);
CHECK (J > I); /* Must not happen */
InsertEntry (D, Y, J);
/* Move the label to the new insn */
CodeLabel* L = CS_GenLabel (D->Code, Y);
CS_MoveLabelRef (D->Code, N, L);
/* Move the label to the new insn */
CodeLabel* L = CS_GenLabel (D->Code, Y);
CS_MoveLabelRef (D->Code, N, L);
/* Skip the next two instructions in the next round */
I += 2;
} else {
/* This could be suboptimal but it will always work (unless stack overflows) */
CodeEntry* X = NewCodeEntry (OP65_PHP, AM65_IMP, 0, 0, E->LI);
InsertEntry (D, X, I+1);
X = NewCodeEntry (OP65_LDY, AM65_IMM, 0, 0, E->LI);
InsertEntry (D, X, I+2);
X = NewCodeEntry (OP65_PLP, AM65_IMP, 0, 0, E->LI);
InsertEntry (D, X, I+3);
/* Skip the three inserted instructions in the next round */
I += 3;
}
} else {
CodeEntry* X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
InsertEntry (D, X, I+1);