mirror of
https://github.com/cc65/cc65.git
synced 2025-01-01 03:30:20 +00:00
Finished indirect function calls.
Debugged zero page location tracking. git-svn-id: svn://svn.cc65.org/cc65/trunk@968 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
f4fbbc3dcc
commit
5d0a52b7ac
@ -137,7 +137,7 @@ static int NumArg (const char* Arg, unsigned long* Num)
|
||||
static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D)
|
||||
/* Set the Use and Chg in E */
|
||||
{
|
||||
unsigned short Use;
|
||||
const ZPInfo* Info;
|
||||
|
||||
/* If this is a subroutine call, or a jump to an external function,
|
||||
* lookup the information about this function and use it. The jump itself
|
||||
@ -162,20 +162,21 @@ static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D)
|
||||
case AM65_ZPX:
|
||||
case AM65_ABSX:
|
||||
case AM65_ABSY:
|
||||
if (IsZPName (E->Arg, &Use) && Use != REG_NONE) {
|
||||
Info = GetZPInfo (E->Arg);
|
||||
if (Info && Info->ByteUse != REG_NONE) {
|
||||
if (E->OPC == OP65_ASL || E->OPC == OP65_DEC ||
|
||||
E->OPC == OP65_INC || E->OPC == OP65_LSR ||
|
||||
E->OPC == OP65_ROL || E->OPC == OP65_ROR ||
|
||||
E->OPC == OP65_TRB || E->OPC == OP65_TSB) {
|
||||
/* The zp loc is both, input and output */
|
||||
E->Chg |= Use;
|
||||
E->Use |= Use;
|
||||
E->OPC == OP65_INC || E->OPC == OP65_LSR ||
|
||||
E->OPC == OP65_ROL || E->OPC == OP65_ROR ||
|
||||
E->OPC == OP65_TRB || E->OPC == OP65_TSB) {
|
||||
/* The zp loc is both, input and output */
|
||||
E->Chg |= Info->ByteUse;
|
||||
E->Use |= Info->ByteUse;
|
||||
} else if ((E->Info & OF_STORE) != 0) {
|
||||
/* Just output */
|
||||
E->Chg |= Use;
|
||||
/* Just output */
|
||||
E->Chg |= Info->ByteUse;
|
||||
} else {
|
||||
/* Input only */
|
||||
E->Use |= Use;
|
||||
/* Input only */
|
||||
E->Use |= Info->ByteUse;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -183,9 +184,10 @@ static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D)
|
||||
case AM65_ZPX_IND:
|
||||
case AM65_ZP_INDY:
|
||||
case AM65_ZP_IND:
|
||||
if (IsZPName (E->Arg, &Use) && Use != REG_NONE) {
|
||||
Info = GetZPInfo (E->Arg);
|
||||
if (Info && Info->ByteUse != REG_NONE) {
|
||||
/* These addressing modes will never change the zp loc */
|
||||
E->Use |= Use;
|
||||
E->Use |= Info->WordUse;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -774,7 +776,7 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
||||
Out->RegX = In->RegA;
|
||||
break;
|
||||
|
||||
case OP65_TAY:
|
||||
case OP65_TAY:
|
||||
Out->RegY = In->RegA;
|
||||
break;
|
||||
|
||||
@ -821,17 +823,10 @@ static char* RegInfoDesc (unsigned U, char* Buf)
|
||||
strcat (Buf, U & REG_A? "A" : "_");
|
||||
strcat (Buf, U & REG_X? "X" : "_");
|
||||
strcat (Buf, U & REG_Y? "Y" : "_");
|
||||
strcat (Buf, U & REG_SP? "S" : "_");
|
||||
strcat (Buf, U & REG_TMP1? "T1" : "__");
|
||||
strcat (Buf, U & REG_TMP2? "T2" : "__");
|
||||
strcat (Buf, U & REG_TMP3? "T3" : "__");
|
||||
strcat (Buf, U & REG_TMP4? "T4" : "__");
|
||||
strcat (Buf, U & REG_PTR1? "1" : "_");
|
||||
strcat (Buf, U & REG_PTR2? "2" : "_");
|
||||
strcat (Buf, U & REG_PTR3? "3" : "_");
|
||||
strcat (Buf, U & REG_PTR4? "4" : "_");
|
||||
strcat (Buf, U & REG_SAVE? "V" : "_");
|
||||
strcat (Buf, U & REG_BANK? "B" : "_");
|
||||
|
||||
return Buf;
|
||||
}
|
||||
|
@ -2373,15 +2373,33 @@ void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
|
||||
|
||||
|
||||
|
||||
void g_callind (unsigned Flags, unsigned ArgSize)
|
||||
/* Call subroutine with address in AX */
|
||||
void g_callind (unsigned Flags, unsigned ArgSize, int Offs)
|
||||
/* Call subroutine indirect */
|
||||
{
|
||||
if ((Flags & CF_FIXARGC) == 0) {
|
||||
/* Pass arg count */
|
||||
ldyconst (ArgSize);
|
||||
if ((Flags & CF_LOCAL) == 0) {
|
||||
/* Address is in a/x */
|
||||
if ((Flags & CF_FIXARGC) == 0) {
|
||||
/* Pass arg count */
|
||||
ldyconst (ArgSize);
|
||||
}
|
||||
AddCodeLine ("jsr callax");
|
||||
} else {
|
||||
/* The address is on stack, offset is on Val */
|
||||
Offs -= oursp;
|
||||
CheckLocalOffs (Offs);
|
||||
AddCodeLine ("pha");
|
||||
AddCodeLine ("ldy #$%02X", Offs);
|
||||
AddCodeLine ("lda (sp),y");
|
||||
AddCodeLine ("sta jmpvec+1");
|
||||
AddCodeLine ("iny");
|
||||
AddCodeLine ("lda (sp),y");
|
||||
AddCodeLine ("sta jmpvec+2");
|
||||
AddCodeLine ("pla");
|
||||
AddCodeLine ("jsr jmpvec");
|
||||
}
|
||||
AddCodeLine ("jsr callax"); /* do the call */
|
||||
oursp += ArgSize; /* callee pops args */
|
||||
|
||||
/* Callee pops args */
|
||||
oursp += ArgSize;
|
||||
}
|
||||
|
||||
|
||||
|
@ -370,8 +370,8 @@ void g_swap (unsigned flags);
|
||||
void g_call (unsigned Flags, const char* Label, unsigned ArgSize);
|
||||
/* Call the specified subroutine name */
|
||||
|
||||
void g_callind (unsigned Flags, unsigned ArgSize);
|
||||
/* Call subroutine with address in AX */
|
||||
void g_callind (unsigned Flags, unsigned ArgSize, int Offs);
|
||||
/* Call subroutine indirect */
|
||||
|
||||
void g_jump (unsigned Label);
|
||||
/* Jump to specified internal label number */
|
||||
|
@ -112,9 +112,9 @@ static const FuncInfo FuncInfoTable[] = {
|
||||
{ "incsp6", REG_NONE, REG_Y },
|
||||
{ "incsp7", REG_NONE, REG_Y },
|
||||
{ "incsp8", REG_NONE, REG_Y },
|
||||
{ "laddeq", REG_EAXY | REG_PTR1, REG_EAXY },
|
||||
{ "laddeq1", REG_Y | REG_PTR1, REG_EAXY },
|
||||
{ "laddeqa", REG_AY | REG_PTR1, REG_EAXY },
|
||||
{ "laddeq", REG_EAXY|REG_PTR1_LO, REG_EAXY | REG_PTR1_HI },
|
||||
{ "laddeq1", REG_Y | REG_PTR1_LO, REG_EAXY | REG_PTR1_HI },
|
||||
{ "laddeqa", REG_AY | REG_PTR1_LO, REG_EAXY | REG_PTR1_HI },
|
||||
{ "ldaidx", REG_AXY, REG_AX | REG_PTR1 },
|
||||
{ "ldauidx", REG_AXY, REG_AX | REG_PTR1 },
|
||||
{ "ldax0sp", REG_Y, REG_AX },
|
||||
@ -143,6 +143,7 @@ static const FuncInfo FuncInfoTable[] = {
|
||||
{ "shreax4", REG_EAX, REG_AX | REG_TMP1 },
|
||||
{ "staspidx", REG_A | REG_Y, REG_Y | REG_TMP1 | REG_PTR1 },
|
||||
{ "stax0sp", REG_AX, REG_Y },
|
||||
{ "staxysp", REG_AXY, REG_Y },
|
||||
{ "tosicmp", REG_AX, REG_AXY | REG_SREG },
|
||||
{ "tosdiva0", REG_AX, REG_ALL },
|
||||
{ "tosdivax", REG_AX, REG_ALL },
|
||||
@ -158,26 +159,23 @@ static const FuncInfo FuncInfoTable[] = {
|
||||
#define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
|
||||
|
||||
/* Table with names of zero page locations used by the compiler */
|
||||
typedef struct ZPInfo ZPInfo;
|
||||
struct ZPInfo {
|
||||
unsigned char Len; /* Length of the following string */
|
||||
char Name[11]; /* Name of zero page symbol */
|
||||
unsigned short RegInfo; /* Register info for this symbol */
|
||||
};
|
||||
static const ZPInfo ZPInfoTable[] = {
|
||||
{ 4, "ptr1", REG_PTR1 },
|
||||
{ 4, "ptr2", REG_PTR2 },
|
||||
{ 4, "ptr3", REG_PTR3 },
|
||||
{ 4, "ptr4", REG_PTR4 },
|
||||
{ 7, "regbank", REG_BANK },
|
||||
{ 7, "regsave", REG_SAVE },
|
||||
{ 2, "sp", REG_SP },
|
||||
{ 0, "sreg", REG_SREG_LO },
|
||||
{ 0, "sreg+1", REG_SREG_HI },
|
||||
{ 4, "tmp1", REG_TMP1 },
|
||||
{ 4, "tmp2", REG_TMP2 },
|
||||
{ 4, "tmp3", REG_TMP3 },
|
||||
{ 4, "tmp4", REG_TMP4 },
|
||||
{ 0, "ptr1", REG_PTR1_LO, REG_PTR1 },
|
||||
{ 0, "ptr1+1", REG_PTR1_HI, REG_PTR1 },
|
||||
{ 0, "ptr2", REG_PTR2_LO, REG_PTR2 },
|
||||
{ 0, "ptr2+1", REG_PTR2_HI, REG_PTR2 },
|
||||
{ 4, "ptr3", REG_NONE, REG_NONE },
|
||||
{ 4, "ptr4", REG_NONE, REG_NONE },
|
||||
{ 7, "regbank", REG_NONE, REG_NONE },
|
||||
{ 0, "regsave", REG_SAVE_LO, REG_SAVE },
|
||||
{ 0, "regsave+1", REG_SAVE_HI, REG_SAVE },
|
||||
{ 2, "sp", REG_NONE, REG_NONE },
|
||||
{ 0, "sreg", REG_SREG_LO, REG_SREG },
|
||||
{ 0, "sreg+1", REG_SREG_HI, REG_SREG },
|
||||
{ 0, "tmp1", REG_TMP1, REG_TMP1 },
|
||||
{ 0, "tmp2", REG_NONE, REG_NONE },
|
||||
{ 0, "tmp3", REG_NONE, REG_NONE },
|
||||
{ 0, "tmp4", REG_NONE, REG_NONE },
|
||||
};
|
||||
#define ZPInfoCount (sizeof(ZPInfoTable) / sizeof(ZPInfoTable[0]))
|
||||
|
||||
@ -259,10 +257,10 @@ void GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Function not found - assume all CPU registers are input, and all
|
||||
/* Function not found - assume that the primary register is input, and all
|
||||
* registers are changed
|
||||
*/
|
||||
*Use = REG_AXY;
|
||||
*Use = REG_EAXY;
|
||||
*Chg = REG_ALL;
|
||||
}
|
||||
|
||||
@ -294,27 +292,14 @@ static int CompareZPInfo (const void* Name, const void* Info)
|
||||
|
||||
|
||||
|
||||
int IsZPName (const char* Name, unsigned short* RegInfo)
|
||||
/* Return true if the given name is a zero page symbol. If the RegInfo
|
||||
* pointer is not NULL, it is filled with the register info for the
|
||||
* zero page location found.
|
||||
const ZPInfo* GetZPInfo (const char* Name)
|
||||
/* If the given name is a zero page symbol, return a pointer to the info
|
||||
* struct for this symbol, otherwise return NULL.
|
||||
*/
|
||||
{
|
||||
/* Search for the zp location in the list */
|
||||
const ZPInfo* Info = bsearch (Name, ZPInfoTable, ZPInfoCount,
|
||||
sizeof(ZPInfo), CompareZPInfo);
|
||||
|
||||
/* Did we find it? */
|
||||
if (Info) {
|
||||
/* Found, store register info if requested. */
|
||||
if (RegInfo) {
|
||||
*RegInfo = Info->RegInfo;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
/* Not found */
|
||||
return 0;
|
||||
}
|
||||
return bsearch (Name, ZPInfoTable, ZPInfoCount,
|
||||
sizeof(ZPInfo), CompareZPInfo);
|
||||
}
|
||||
|
||||
|
||||
|
@ -60,32 +60,42 @@ struct CodeSeg;
|
||||
#define REG_X 0x0002U
|
||||
#define REG_Y 0x0004U
|
||||
#define REG_TMP1 0x0008U
|
||||
#define REG_TMP2 0x0010U
|
||||
#define REG_TMP3 0x0020U
|
||||
#define REG_TMP4 0x0040U
|
||||
#define REG_PTR1 0x0080U
|
||||
#define REG_PTR2 0x0100U
|
||||
#define REG_PTR3 0x0200U
|
||||
#define REG_PTR4 0x0400U
|
||||
#define REG_SREG_LO 0x0800U
|
||||
#define REG_SREG_HI 0x1000U
|
||||
#define REG_SP 0x2000U
|
||||
#define REG_SAVE 0x4000U
|
||||
#define REG_BANK 0x8000U
|
||||
#define REG_PTR1_LO 0x0010U
|
||||
#define REG_PTR1_HI 0x0020U
|
||||
#define REG_PTR2_LO 0x0040U
|
||||
#define REG_PTR2_HI 0x0080U
|
||||
#define REG_SREG_LO 0x0100U
|
||||
#define REG_SREG_HI 0x0200U
|
||||
#define REG_SAVE_LO 0x0400U
|
||||
#define REG_SAVE_HI 0x0800U
|
||||
|
||||
/* Combined register defines */
|
||||
#define REG_PTR1 (REG_PTR1_LO | REG_PTR1_HI)
|
||||
#define REG_PTR2 (REG_PTR2_LO | REG_PTR2_HI)
|
||||
#define REG_SREG (REG_SREG_LO | REG_SREG_HI)
|
||||
#define REG_SAVE (REG_SAVE_LO | REG_SAVE_HI)
|
||||
#define REG_AX (REG_A | REG_X)
|
||||
#define REG_AY (REG_A | REG_Y)
|
||||
#define REG_XY (REG_X | REG_Y)
|
||||
#define REG_AXY (REG_AX | REG_Y)
|
||||
#define REG_EAX (REG_AX | REG_SREG)
|
||||
#define REG_EAXY (REG_EAX | REG_Y)
|
||||
#define REG_ZP 0xFFF0U
|
||||
#define REG_ZP 0xFFF8U
|
||||
#define REG_ALL 0xFFFFU
|
||||
|
||||
|
||||
|
||||
/* Zero page register info */
|
||||
typedef struct ZPInfo ZPInfo;
|
||||
struct ZPInfo {
|
||||
unsigned char Len; /* Length of the following string */
|
||||
char Name[11]; /* Name of zero page symbol */
|
||||
unsigned short ByteUse; /* Register info for this symbol */
|
||||
unsigned short WordUse; /* Register info for 16 bit access */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
@ -98,10 +108,9 @@ void GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg);
|
||||
* load all registers.
|
||||
*/
|
||||
|
||||
int IsZPName (const char* Name, unsigned short* RegInfo);
|
||||
/* Return true if the given name is a zero page symbol. If the RegInfo
|
||||
* pointer is not NULL, it is filled with the register info for the
|
||||
* zero page location found.
|
||||
const ZPInfo* GetZPInfo (const char* Name);
|
||||
/* If the given name is a zero page symbol, return a pointer to the info
|
||||
* struct for this symbol, otherwise return NULL.
|
||||
*/
|
||||
|
||||
unsigned GetRegInfo (struct CodeSeg* S, unsigned Index, unsigned Wanted);
|
||||
|
@ -323,7 +323,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
|
||||
if ((OPC->Info & OF_BRA) != 0) {
|
||||
/* Branch */
|
||||
AM = AM65_BRA;
|
||||
} else if (IsZPName (Arg, 0)) {
|
||||
} else if (GetZPInfo(Arg) != 0) {
|
||||
AM = AM65_ZP;
|
||||
} else {
|
||||
AM = AM65_ABS;
|
||||
@ -338,7 +338,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
|
||||
Reg = toupper (*L);
|
||||
L = SkipSpace (L+1);
|
||||
if (Reg == 'X') {
|
||||
if (IsZPName (Arg, 0)) {
|
||||
if (GetZPInfo(Arg) != 0) {
|
||||
AM = AM65_ZPX;
|
||||
} else {
|
||||
AM = AM65_ABSX;
|
||||
|
@ -774,35 +774,29 @@ static void FunctionCall (int k, ExprDesc* lval)
|
||||
/* If the function is not a fastcall function, load the pointer to
|
||||
* the function into the primary.
|
||||
*/
|
||||
if (!IsFastCallFunc (lval->Type)) {
|
||||
if (!IsFastCall) {
|
||||
|
||||
/* Not a fastcall function - we may use the primary */
|
||||
if (PtrOnStack) {
|
||||
/* If we have no parameters, the pointer is still in the
|
||||
* primary. Remove the code to push it and correct the
|
||||
* stack pointer.
|
||||
*/
|
||||
if (ParamSize == 0) {
|
||||
RemoveCode (Mark);
|
||||
pop (CF_PTR);
|
||||
PtrOnStack = 0;
|
||||
} else {
|
||||
/* Load from the saved copy */
|
||||
g_getlocal (CF_PTR, PtrOffs);
|
||||
}
|
||||
/* If we have no parameters, the pointer is still in the
|
||||
* primary. Remove the code to push it and correct the
|
||||
* stack pointer.
|
||||
*/
|
||||
if (ParamSize == 0) {
|
||||
RemoveCode (Mark);
|
||||
pop (CF_PTR);
|
||||
PtrOnStack = 0;
|
||||
} else {
|
||||
/* Load from the saved copy */
|
||||
g_getlocal (CF_PTR, PtrOffs);
|
||||
}
|
||||
} else {
|
||||
/* Load from original location */
|
||||
exprhs (CF_NONE, k, lval);
|
||||
}
|
||||
|
||||
/* Call the function */
|
||||
g_callind (TypeOf (lval->Type), ParamSize);
|
||||
|
||||
/* If we have a pointer on stack, remove it */
|
||||
if (PtrOnStack) {
|
||||
g_space (- (int) sizeofarg (CF_PTR));
|
||||
pop (CF_PTR);
|
||||
}
|
||||
g_callind (TypeOf (lval->Type), ParamSize, PtrOffs);
|
||||
|
||||
} else {
|
||||
|
||||
@ -811,11 +805,16 @@ static void FunctionCall (int k, ExprDesc* lval)
|
||||
* Since fastcall functions may never be variadic, we can use the
|
||||
* index register for this purpose.
|
||||
*/
|
||||
Error ("Not implemented");
|
||||
pop (CF_PTR);
|
||||
g_callind (CF_LOCAL, ParamSize, PtrOffs);
|
||||
}
|
||||
|
||||
/* Skip T_PTR */
|
||||
/* If we have a pointer on stack, remove it */
|
||||
if (PtrOnStack) {
|
||||
g_space (- (int) sizeofarg (CF_PTR));
|
||||
pop (CF_PTR);
|
||||
}
|
||||
|
||||
/* Skip T_PTR */
|
||||
++lval->Type;
|
||||
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user