X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcodegen.c;h=88cebe9a4b734ead469354eb1fb8d466a06a88f9;hb=9fc71c5e93f7e8270dd6f8fc3810b7b731bf1259;hp=7732f7f3437f794049b623a23a099fd6633e4c84;hpb=b3af17126c3ac6178e45b090555bed5f34507eaf;p=cc65 diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index 7732f7f34..88cebe9a4 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -6,9 +6,9 @@ /* */ /* */ /* */ -/* (C) 1998-2001 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ +/* (C) 1998-2004 Ullrich von Bassewitz */ +/* Römerstraße 52 */ +/* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ /* */ @@ -39,6 +39,8 @@ /* common */ #include "check.h" +#include "cpu.h" +#include "strbuf.h" #include "version.h" #include "xmalloc.h" #include "xsprintf.h" @@ -46,29 +48,19 @@ /* cc65 */ #include "asmcode.h" #include "asmlabel.h" +#include "casenode.h" #include "codeseg.h" -#include "cpu.h" #include "dataseg.h" #include "error.h" #include "global.h" #include "segments.h" +#include "stackptr.h" #include "textseg.h" #include "util.h" #include "codegen.h" -/*****************************************************************************/ -/* Data */ -/*****************************************************************************/ - - - -/* Compiler relative stack pointer */ -int oursp = 0; - - - /*****************************************************************************/ /* Helpers */ /*****************************************************************************/ @@ -94,45 +86,53 @@ static void CheckLocalOffs (unsigned Offs) -static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs) +static const char* GetLabelName (unsigned Flags, unsigned long Label, long Offs) { - static char lbuf [128]; /* Label name */ + static char Buf [256]; /* Label name */ /* Create the correct label name */ - switch (flags & CF_ADDRMASK) { + switch (Flags & CF_ADDRMASK) { case CF_STATIC: /* Static memory cell */ - sprintf (lbuf, "%s+%u", LocalLabelName (label), offs); + if (Offs) { + xsprintf (Buf, sizeof (Buf), "%s%+ld", LocalLabelName (Label), Offs); + } else { + xsprintf (Buf, sizeof (Buf), "%s", LocalLabelName (Label)); + } break; case CF_EXTERNAL: /* External label */ - sprintf (lbuf, "_%s+%u", (char*) label, offs); + if (Offs) { + xsprintf (Buf, sizeof (Buf), "_%s%+ld", (char*) Label, Offs); + } else { + xsprintf (Buf, sizeof (Buf), "_%s", (char*) Label); + } break; case CF_ABSOLUTE: /* Absolute address */ - sprintf (lbuf, "$%04X", (unsigned)((label+offs) & 0xFFFF)); + xsprintf (Buf, sizeof (Buf), "$%04X", (int)((Label+Offs) & 0xFFFF)); break; case CF_REGVAR: /* Variable in register bank */ - sprintf (lbuf, "regbank+%u", (unsigned)((label+offs) & 0xFFFF)); + xsprintf (Buf, sizeof (Buf), "regbank+%u", (unsigned)((Label+Offs) & 0xFFFF)); break; default: - Internal ("Invalid address flags"); + Internal ("Invalid address flags: %04X", Flags); } /* Return a pointer to the static buffer */ - return lbuf; + return Buf; } /*****************************************************************************/ -/* Pre- and postamble */ +/* Pre- and postamble */ /*****************************************************************************/ @@ -147,18 +147,26 @@ void g_preamble (void) /* Identify the compiler version */ AddTextLine (";"); AddTextLine ("; File generated by cc65 v %u.%u.%u", - VER_MAJOR, VER_MINOR, VER_PATCH); + VER_MAJOR, VER_MINOR, VER_PATCH); AddTextLine (";"); /* Insert some object file options */ AddTextLine ("\t.fopt\t\tcompiler,\"cc65 v %u.%u.%u\"", - VER_MAJOR, VER_MINOR, VER_PATCH); + VER_MAJOR, VER_MINOR, VER_PATCH); /* If we're producing code for some other CPU, switch the command set */ - if (CPU == CPU_65C02) { - AddTextLine ("\t.pc02"); + switch (CPU) { + case CPU_6502: AddTextLine ("\t.setcpu\t\t\"6502\""); break; + case CPU_6502X: AddTextLine ("\t.setcpu\t\t\"6502X\""); break; + case CPU_65SC02: AddTextLine ("\t.setcpu\t\t\"65SC02\""); break; + case CPU_65C02: AddTextLine ("\t.setcpu\t\t\"65C02\""); break; + case CPU_65816: AddTextLine ("\t.setcpu\t\t\"65816\""); break; + default: Internal ("Unknown CPU: %d", CPU); } + /* Use smart mode */ + AddTextLine ("\t.smart\t\ton"); + /* Allow auto import for runtime library routines */ AddTextLine ("\t.autoimport\ton"); @@ -169,7 +177,7 @@ void g_preamble (void) AddTextLine ("\t.debuginfo\t%s", (DebugInfo != 0)? "on" : "off"); /* Import the stack pointer for direct auto variable access */ - AddTextLine ("\t.importzp\tsp, sreg, regsave, regbank, tmp1, ptr1"); + AddTextLine ("\t.importzp\tsp, sreg, regsave, regbank, tmp1, ptr1, ptr2"); /* Define long branch macros */ AddTextLine ("\t.macpack\tlongbranch"); @@ -220,15 +228,11 @@ void g_usebss (void) -void g_segname (segment_t Seg, const char* Name) -/* Set the name of a segment */ +void g_segname (segment_t Seg) +/* Emit the name of a segment if necessary */ { - DataSeg* S; - - /* Remember the new name */ - NewSegName (Seg, Name); - /* Emit a segment directive for the data style segments */ + DataSeg* S; switch (Seg) { case SEG_RODATA: S = CS->ROData; break; case SEG_DATA: S = CS->Data; break; @@ -236,7 +240,7 @@ void g_segname (segment_t Seg, const char* Name) default: S = 0; break; } if (S) { - DS_AddLine (S, ".segment\t\"%s\"", Name); + DS_AddLine (S, ".segment\t\"%s\"", GetSegName (Seg)); } } @@ -262,6 +266,9 @@ unsigned sizeofarg (unsigned flags) case CF_LONG: return 4; + case CF_FLOAT: + return 4; + default: typeerror (flags); /* NOTREACHED */ @@ -274,7 +281,7 @@ unsigned sizeofarg (unsigned flags) int pop (unsigned flags) /* Pop an argument of the given size */ { - return oursp += sizeofarg (flags); + return StackPtr += sizeofarg (flags); } @@ -282,7 +289,7 @@ int pop (unsigned flags) int push (unsigned flags) /* Push an argument of the given size */ { - return oursp -= sizeofarg (flags); + return StackPtr -= sizeofarg (flags); } @@ -377,6 +384,14 @@ void g_defimport (const char* Name, int ZP) +void g_importmainargs (void) +/* Forced import of a special symbol that handles arguments to main */ +{ + AddTextLine ("\t.forceimport\tinitmainargs"); +} + + + /*****************************************************************************/ /* Load functions for various registers */ /*****************************************************************************/ @@ -439,21 +454,22 @@ void g_leave (void) /* Function epilogue */ { /* How many bytes of locals do we have to drop? */ - int k = -oursp; + unsigned k = (unsigned) -StackPtr; /* If we didn't have a variable argument list, don't call leave */ if (funcargs >= 0) { - /* Drop stackframe if needed */ + /* Drop stackframe if needed. We can only drop 255 bytes at a time. */ k += funcargs; - if (k > 0) { - if (k <= 8) { - AddCodeLine ("jsr incsp%d", k); + while (k > 0) { + unsigned ToDrop = (k > 255)? 255 : k; + if (ToDrop <= 8) { + AddCodeLine ("jsr incsp%d", k); } else { - CheckLocalOffs (k); - ldyconst (k); - AddCodeLine ("jsr addysp"); + ldyconst (ToDrop); + AddCodeLine ("jsr addysp"); } + k -= ToDrop; } } else { @@ -463,6 +479,11 @@ void g_leave (void) AddCodeLine ("jsr leave"); } else { /* We've a stack frame to drop */ + while (k > 255) { + ldyconst (255); + AddCodeLine ("jsr addysp"); + k -= 255; + } ldyconst (k); AddCodeLine ("jsr leavey"); } @@ -475,11 +496,51 @@ void g_leave (void) /*****************************************************************************/ -/* Register variables */ +/* Register variables */ /*****************************************************************************/ +void g_swap_regvars (int StackOffs, int RegOffs, unsigned Bytes) +/* Swap a register variable with a location on the stack */ +{ + /* Calculate the actual stack offset and check it */ + StackOffs -= StackPtr; + CheckLocalOffs (StackOffs); + + /* Generate code */ + if (Bytes == 1) { + + if (CodeSizeFactor < 165) { + ldyconst (StackOffs); + ldxconst (RegOffs); + AddCodeLine ("jsr regswap1"); + } else { + ldyconst (StackOffs); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("ldx regbank%+d", RegOffs); + AddCodeLine ("sta regbank%+d", RegOffs); + AddCodeLine ("txa"); + AddCodeLine ("sta (sp),y"); + } + + } else if (Bytes == 2) { + + ldyconst (StackOffs); + ldxconst (RegOffs); + AddCodeLine ("jsr regswap2"); + + } else { + + ldyconst (StackOffs); + ldxconst (RegOffs); + ldaconst (Bytes); + AddCodeLine ("jsr regswap"); + } +} + + + void g_save_regvars (int RegOffs, unsigned Bytes) /* Save register variables */ { @@ -512,7 +573,7 @@ void g_save_regvars (int RegOffs, unsigned Bytes) } /* We pushed stuff, correct the stack pointer */ - oursp -= Bytes; + StackPtr -= Bytes; } @@ -521,37 +582,68 @@ void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes) /* Restore register variables */ { /* Calculate the actual stack offset and check it */ - StackOffs -= oursp; + StackOffs -= StackPtr; CheckLocalOffs (StackOffs); /* Don't loop for up to two bytes */ if (Bytes == 1) { - ldyconst (StackOffs); - AddCodeLine ("lda (sp),y"); - AddCodeLine ("sta regbank%+d", RegOffs); + ldyconst (StackOffs); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta regbank%+d", RegOffs); } else if (Bytes == 2) { + ldyconst (StackOffs); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta regbank%+d", RegOffs); + AddCodeLine ("iny"); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta regbank%+d", RegOffs+1); + + } else if (Bytes == 3 && CodeSizeFactor >= 133) { + + ldyconst (StackOffs); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta regbank%+d", RegOffs); + AddCodeLine ("iny"); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta regbank%+d", RegOffs+1); + AddCodeLine ("iny"); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta regbank%+d", RegOffs+2); + + } else if (StackOffs <= RegOffs) { + + /* More bytes, but the relation between the register offset in the + * register bank and the stack offset allows us to generate short + * code that uses just one index register. + */ + unsigned Label = GetLocalLabel (); ldyconst (StackOffs); + g_defcodelabel (Label); AddCodeLine ("lda (sp),y"); - AddCodeLine ("sta regbank%+d", RegOffs); - AddCodeLine ("iny"); - AddCodeLine ("lda (sp),y"); - AddCodeLine ("sta regbank%+d", RegOffs+1); + AddCodeLine ("sta regbank%+d,y", RegOffs - StackOffs); + AddCodeLine ("iny"); + AddCodeLine ("cpy #$%02X", StackOffs + Bytes); + AddCodeLine ("bne %s", LocalLabelName (Label)); } else { - /* More than two bytes - loop */ - unsigned Label = GetLocalLabel (); - ldyconst (StackOffs+Bytes-1); - ldxconst (Bytes); - g_defcodelabel (Label); - AddCodeLine ("lda (sp),y"); - AddCodeLine ("sta regbank%+d,x", RegOffs-1); - AddCodeLine ("dey"); - AddCodeLine ("dex"); - AddCodeLine ("bne %s", LocalLabelName (Label)); + /* Ok, this is the generic code. We need to save X because the + * caller will only save A. + */ + unsigned Label = GetLocalLabel (); + AddCodeLine ("stx tmp1"); + ldyconst (StackOffs + Bytes - 1); + ldxconst (Bytes - 1); + g_defcodelabel (Label); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta regbank%+d,x", RegOffs); + AddCodeLine ("dey"); + AddCodeLine ("dex"); + AddCodeLine ("bpl %s", LocalLabelName (Label)); + AddCodeLine ("ldx tmp1"); } } @@ -559,12 +651,12 @@ void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes) /*****************************************************************************/ -/* Fetching memory cells */ +/* Fetching memory cells */ /*****************************************************************************/ -void g_getimmed (unsigned Flags, unsigned long Val, unsigned Offs) +void g_getimmed (unsigned Flags, unsigned long Val, long Offs) /* Load a constant into the primary register */ { unsigned char B1, B2, B3, B4; @@ -588,46 +680,46 @@ void g_getimmed (unsigned Flags, unsigned long Val, unsigned Offs) break; case CF_LONG: - /* Split the value into 4 bytes */ - B1 = (unsigned char) (Val >> 0); - B2 = (unsigned char) (Val >> 8); - B3 = (unsigned char) (Val >> 16); - B4 = (unsigned char) (Val >> 24); - - /* Remember which bytes are done */ - Done = 0; - - /* Load the value */ - AddCodeLine ("ldx #$%02X", B2); - Done |= 0x02; - if (B2 == B3) { - AddCodeLine ("stx sreg"); - Done |= 0x04; - } - if (B2 == B4) { - AddCodeLine ("stx sreg+1"); - Done |= 0x08; - } - if ((Done & 0x04) == 0 && B1 != B3) { - AddCodeLine ("lda #$%02X", B3); - AddCodeLine ("sta sreg"); - Done |= 0x04; - } - if ((Done & 0x08) == 0 && B1 != B4) { - AddCodeLine ("lda #$%02X", B4); - AddCodeLine ("sta sreg+1"); - Done |= 0x08; - } - AddCodeLine ("lda #$%02X", B1); - Done |= 0x01; - if ((Done & 0x04) == 0) { - CHECK (B1 == B3); - AddCodeLine ("sta sreg"); - } - if ((Done & 0x08) == 0) { - CHECK (B1 == B4); - AddCodeLine ("sta sreg+1"); - } + /* Split the value into 4 bytes */ + B1 = (unsigned char) (Val >> 0); + B2 = (unsigned char) (Val >> 8); + B3 = (unsigned char) (Val >> 16); + B4 = (unsigned char) (Val >> 24); + + /* Remember which bytes are done */ + Done = 0; + + /* Load the value */ + AddCodeLine ("ldx #$%02X", B2); + Done |= 0x02; + if (B2 == B3) { + AddCodeLine ("stx sreg"); + Done |= 0x04; + } + if (B2 == B4) { + AddCodeLine ("stx sreg+1"); + Done |= 0x08; + } + if ((Done & 0x04) == 0 && B1 != B3) { + AddCodeLine ("lda #$%02X", B3); + AddCodeLine ("sta sreg"); + Done |= 0x04; + } + if ((Done & 0x08) == 0 && B1 != B4) { + AddCodeLine ("lda #$%02X", B4); + AddCodeLine ("sta sreg+1"); + Done |= 0x08; + } + AddCodeLine ("lda #$%02X", B1); + Done |= 0x01; + if ((Done & 0x04) == 0) { + CHECK (B1 == B3); + AddCodeLine ("sta sreg"); + } + if ((Done & 0x08) == 0) { + CHECK (B1 == B4); + AddCodeLine ("sta sreg+1"); + } break; default: @@ -638,23 +730,23 @@ void g_getimmed (unsigned Flags, unsigned long Val, unsigned Offs) } else { - /* Some sort of label */ - const char* Label = GetLabelName (Flags, Val, Offs); + /* Some sort of label */ + const char* Label = GetLabelName (Flags, Val, Offs); - /* Load the address into the primary */ - AddCodeLine ("lda #<(%s)", Label); - AddCodeLine ("ldx #>(%s)", Label); + /* Load the address into the primary */ + AddCodeLine ("lda #<(%s)", Label); + AddCodeLine ("ldx #>(%s)", Label); } } -void g_getstatic (unsigned flags, unsigned long label, unsigned offs) +void g_getstatic (unsigned flags, unsigned long label, long offs) /* Fetch an static memory cell into the primary register */ { /* Create the correct label name */ - char* lbuf = GetLabelName (flags, label, offs); + const char* lbuf = GetLabelName (flags, label, offs); /* Check the size and generate the correct load operation */ switch (flags & CF_TYPE) { @@ -711,18 +803,14 @@ void g_getstatic (unsigned flags, unsigned long label, unsigned offs) void g_getlocal (unsigned flags, int offs) /* Fetch specified local object (local var). */ { - offs -= oursp; + offs -= StackPtr; CheckLocalOffs (offs); switch (flags & CF_TYPE) { case CF_CHAR: if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) { - if (CPU == CPU_65C02 && offs == 0) { - AddCodeLine ("lda (sp)"); - } else { - ldyconst (offs); - AddCodeLine ("lda (sp),y"); - } + ldyconst (offs); + AddCodeLine ("lda (sp),y"); } else { ldyconst (offs); AddCodeLine ("ldx #$00"); @@ -744,30 +832,14 @@ void g_getlocal (unsigned flags, int offs) AddCodeLine ("dey"); AddCodeLine ("ora (sp),y"); } else { - if (CodeSizeFactor > 180) { - ldyconst (offs + 1); - AddCodeLine ("lda (sp),y"); - AddCodeLine ("tax"); - AddCodeLine ("dey"); - AddCodeLine ("lda (sp),y"); - } else { - if (offs) { - ldyconst (offs+1); - AddCodeLine ("jsr ldaxysp"); - } else { - AddCodeLine ("jsr ldax0sp"); - } - } + ldyconst (offs+1); + AddCodeLine ("jsr ldaxysp"); } break; case CF_LONG: - if (offs) { - ldyconst (offs+3); - AddCodeLine ("jsr ldeaxysp"); - } else { - AddCodeLine ("jsr ldeax0sp"); - } + ldyconst (offs+3); + AddCodeLine ("jsr ldeaxysp"); break; default: @@ -811,22 +883,14 @@ void g_getind (unsigned flags, unsigned offs) AddCodeLine ("iny"); AddCodeLine ("ora (ptr1),y"); } else { - if (offs == 0) { - AddCodeLine ("jsr ldaxi"); - } else { - ldyconst (offs+1); - AddCodeLine ("jsr ldaxidx"); - } + ldyconst (offs+1); + AddCodeLine ("jsr ldaxidx"); } break; case CF_LONG: - if (offs == 0) { - AddCodeLine ("jsr ldeaxi"); - } else { - ldyconst (offs+3); - AddCodeLine ("jsr ldeaxidx"); - } + ldyconst (offs+3); + AddCodeLine ("jsr ldeaxidx"); if (flags & CF_TEST) { AddCodeLine ("jsr tsteax"); } @@ -844,7 +908,7 @@ void g_leasp (int offs) /* Fetch the address of the specified symbol into the primary register */ { /* Calculate the offset relative to sp */ - offs -= oursp; + offs -= StackPtr; /* For value 0 we do direct code */ if (offs == 0) { @@ -856,7 +920,7 @@ void g_leasp (int offs) AddCodeLine ("jsr leaasp"); /* Load effective address */ } else { unsigned L = GetLocalLabel (); - if (CPU == CPU_65C02 && offs == 1) { + if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && offs == 1) { AddCodeLine ("lda sp"); AddCodeLine ("ldx sp+1"); AddCodeLine ("ina"); @@ -885,22 +949,18 @@ void g_leavariadic (int Offs) unsigned ArgSizeOffs; /* Calculate the offset relative to sp */ - Offs -= oursp; + Offs -= StackPtr; /* Get the offset of the parameter which is stored at sp+0 on function * entry and check if this offset is reachable with a byte offset. */ - CHECK (oursp <= 0); - ArgSizeOffs = -oursp; + CHECK (StackPtr <= 0); + ArgSizeOffs = -StackPtr; CheckLocalOffs (ArgSizeOffs); /* Get the size of all parameters. */ - if (ArgSizeOffs == 0 && CPU == CPU_65C02) { - AddCodeLine ("lda (sp)"); - } else { - ldyconst (ArgSizeOffs); - AddCodeLine ("lda (sp),y"); - } + ldyconst (ArgSizeOffs); + AddCodeLine ("lda (sp),y"); /* Add the value of the stackpointer */ if (CodeSizeFactor > 250) { @@ -931,11 +991,11 @@ void g_leavariadic (int Offs) -void g_putstatic (unsigned flags, unsigned long label, unsigned offs) +void g_putstatic (unsigned flags, unsigned long label, long offs) /* Store the primary register into the specified static memory cell */ { /* Create the correct label name */ - char* lbuf = GetLabelName (flags, label, offs); + const char* lbuf = GetLabelName (flags, label, offs); /* Check the size and generate the correct store operation */ switch (flags & CF_TYPE) { @@ -969,7 +1029,7 @@ void g_putstatic (unsigned flags, unsigned long label, unsigned offs) void g_putlocal (unsigned Flags, int Offs, long Val) /* Put data into local object. */ { - Offs -= oursp; + Offs -= StackPtr; CheckLocalOffs (Offs); switch (Flags & CF_TYPE) { @@ -977,12 +1037,8 @@ void g_putlocal (unsigned Flags, int Offs, long Val) if (Flags & CF_CONST) { AddCodeLine ("lda #$%02X", (unsigned char) Val); } - if (CPU == CPU_65C02 && Offs == 0) { - AddCodeLine ("sta (sp)"); - } else { - ldyconst (Offs); - AddCodeLine ("sta (sp),y"); - } + ldyconst (Offs); + AddCodeLine ("sta (sp),y"); break; case CF_INT: @@ -994,41 +1050,25 @@ void g_putlocal (unsigned Flags, int Offs, long Val) /* Place high byte into X */ AddCodeLine ("tax"); } - if (CPU == CPU_65C02 && Offs == 0) { - AddCodeLine ("lda #$%02X", (unsigned char) Val); - AddCodeLine ("sta (sp)"); + if ((Val & 0xFF) == Offs+1) { + /* The value we need is already in Y */ + AddCodeLine ("tya"); + AddCodeLine ("dey"); } else { - if ((Val & 0xFF) == Offs+1) { - /* The value we need is already in Y */ - AddCodeLine ("tya"); - AddCodeLine ("dey"); - } else { - AddCodeLine ("dey"); - AddCodeLine ("lda #$%02X", (unsigned char) Val); - } - AddCodeLine ("sta (sp),y"); + AddCodeLine ("dey"); + AddCodeLine ("lda #$%02X", (unsigned char) Val); } + AddCodeLine ("sta (sp),y"); } else { if ((Flags & CF_NOKEEP) == 0 || CodeSizeFactor < 160) { - if (Offs) { - ldyconst (Offs); - AddCodeLine ("jsr staxysp"); - } else { - AddCodeLine ("jsr stax0sp"); - } + ldyconst (Offs); + AddCodeLine ("jsr staxysp"); } else { - if (CPU == CPU_65C02 && Offs == 0) { - AddCodeLine ("sta (sp)"); - ldyconst (1); - AddCodeLine ("txa"); - AddCodeLine ("sta (sp),y"); - } else { - ldyconst (Offs); - AddCodeLine ("sta (sp),y"); - AddCodeLine ("iny"); - AddCodeLine ("txa"); - AddCodeLine ("sta (sp),y"); - } + ldyconst (Offs); + AddCodeLine ("sta (sp),y"); + AddCodeLine ("iny"); + AddCodeLine ("txa"); + AddCodeLine ("sta (sp),y"); } } break; @@ -1037,12 +1077,8 @@ void g_putlocal (unsigned Flags, int Offs, long Val) if (Flags & CF_CONST) { g_getimmed (Flags, Val, 0); } - if (Offs) { - ldyconst (Offs); - AddCodeLine ("jsr steaxysp"); - } else { - AddCodeLine ("jsr steax0sp"); - } + ldyconst (Offs); + AddCodeLine ("jsr steaxysp"); break; default: @@ -1177,18 +1213,81 @@ void g_tosint (unsigned flags) -void g_reglong (unsigned flags) +void g_regint (unsigned Flags) +/* Make sure, the value in the primary register an int. Convert if necessary */ +{ + unsigned L; + + switch (Flags & CF_TYPE) { + + case CF_CHAR: + if (Flags & CF_FORCECHAR) { + /* Conversion is from char */ + if (Flags & CF_UNSIGNED) { + AddCodeLine ("ldx #$00"); + } else { + L = GetLocalLabel(); + AddCodeLine ("ldx #$00"); + AddCodeLine ("cmp #$80"); + AddCodeLine ("bcc %s", LocalLabelName (L)); + AddCodeLine ("dex"); + g_defcodelabel (L); + } + } + /* FALLTHROUGH */ + + case CF_INT: + case CF_LONG: + break; + + default: + typeerror (Flags); + } +} + + + +void g_reglong (unsigned Flags) /* Make sure, the value in the primary register a long. Convert if necessary */ { - switch (flags & CF_TYPE) { + unsigned L; + + switch (Flags & CF_TYPE) { case CF_CHAR: + if (Flags & CF_FORCECHAR) { + /* Conversion is from char */ + if (Flags & CF_UNSIGNED) { + if (CodeSizeFactor >= 200) { + AddCodeLine ("ldx #$00"); + AddCodeLine ("stx sreg"); + AddCodeLine ("stx sreg+1"); + } else { + AddCodeLine ("jsr aulong"); + } + } else { + if (CodeSizeFactor >= 366) { + L = GetLocalLabel(); + AddCodeLine ("ldx #$00"); + AddCodeLine ("cmp #$80"); + AddCodeLine ("bcc %s", LocalLabelName (L)); + AddCodeLine ("dex"); + g_defcodelabel (L); + AddCodeLine ("stx sreg"); + AddCodeLine ("stx sreg+1"); + } else { + AddCodeLine ("jsr along"); + } + } + } + /* FALLTHROUGH */ + case CF_INT: - if (flags & CF_UNSIGNED) { + if (Flags & CF_UNSIGNED) { if (CodeSizeFactor >= 200) { ldyconst (0); AddCodeLine ("sty sreg"); - AddCodeLine ("sty sreg+1"); + AddCodeLine ("sty sreg+1"); } else { AddCodeLine ("jsr axulong"); } @@ -1201,7 +1300,7 @@ void g_reglong (unsigned flags) break; default: - typeerror (flags); + typeerror (Flags); } } @@ -1269,9 +1368,14 @@ unsigned g_typecast (unsigned lhs, unsigned rhs) rtype = rhs & CF_TYPE; /* Check if a conversion is needed */ - if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) { - /* We must promote the primary register to long */ - g_reglong (rhs); + if ((rhs & CF_CONST) == 0) { + if (ltype == CF_LONG && rtype != CF_LONG) { + /* We must promote the primary register to long */ + g_reglong (rhs); + } else if (ltype == CF_INT && rtype != CF_INT) { + /* We must promote the primary register to int */ + g_regint (rhs); + } } /* Do not need any other action. If the left type is int, and the primary @@ -1444,7 +1548,7 @@ void g_addlocal (unsigned flags, int offs) unsigned L; /* Correct the offset and check it */ - offs -= oursp; + offs -= StackPtr; CheckLocalOffs (offs); switch (flags & CF_TYPE) { @@ -1486,13 +1590,13 @@ void g_addlocal (unsigned flags, int offs) -void g_addstatic (unsigned flags, unsigned long label, unsigned offs) +void g_addstatic (unsigned flags, unsigned long label, long offs) /* Add a static variable to ax */ { unsigned L; /* Create the correct label name */ - char* lbuf = GetLabelName (flags, label, offs); + const char* lbuf = GetLabelName (flags, label, offs); switch (flags & CF_TYPE) { @@ -1530,40 +1634,18 @@ void g_addstatic (unsigned flags, unsigned long label, unsigned offs) -/*****************************************************************************/ -/* Compares of ax with a variable with fixed address */ -/*****************************************************************************/ - - - -void g_cmplocal (unsigned flags, int offs) -/* Compare a local variable to ax */ -{ - Internal ("g_cmplocal not implemented"); -} - - - -void g_cmpstatic (unsigned flags, unsigned label, unsigned offs) -/* Compare a static variable to ax */ -{ - Internal ("g_cmpstatic not implemented"); -} - - - /*****************************************************************************/ /* Special op= functions */ /*****************************************************************************/ -void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs, +void g_addeqstatic (unsigned flags, unsigned long label, long offs, unsigned long val) /* Emit += for a static variable */ { /* Create the correct label name */ - char* lbuf = GetLabelName (flags, label, offs); + const char* lbuf = GetLabelName (flags, label, offs); /* Check the size and determine operation */ switch (flags & CF_TYPE) { @@ -1642,7 +1724,7 @@ void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs, if (val < 0x100) { AddCodeLine ("ldy #<(%s)", lbuf); AddCodeLine ("sty ptr1"); - AddCodeLine ("ldy #>(%s+1)", lbuf); + AddCodeLine ("ldy #>(%s)", lbuf); if (val == 1) { AddCodeLine ("jsr laddeq1"); } else { @@ -1657,7 +1739,7 @@ void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs, } else { AddCodeLine ("ldy #<(%s)", lbuf); AddCodeLine ("sty ptr1"); - AddCodeLine ("ldy #>(%s+1)", lbuf); + AddCodeLine ("ldy #>(%s)", lbuf); AddCodeLine ("jsr laddeq"); } break; @@ -1673,7 +1755,7 @@ void g_addeqlocal (unsigned flags, int offs, unsigned long val) /* Emit += for a local variable */ { /* Calculate the true offset, check it, load it into Y */ - offs -= oursp; + offs -= StackPtr; CheckLocalOffs (offs); /* Check the size and determine operation */ @@ -1704,23 +1786,35 @@ void g_addeqlocal (unsigned flags, int offs, unsigned long val) /* FALLTHROUGH */ case CF_INT: - if (flags & CF_CONST) { - g_getimmed (flags, val, 0); - } ldyconst (offs); - AddCodeLine ("jsr addeqysp"); + if (flags & CF_CONST) { + if (CodeSizeFactor >= 400) { + AddCodeLine ("clc"); + AddCodeLine ("lda #$%02X", (int)(val & 0xFF)); + AddCodeLine ("adc (sp),y"); + AddCodeLine ("sta (sp),y"); + AddCodeLine ("iny"); + AddCodeLine ("lda #$%02X", (int) ((val >> 8) & 0xFF)); + AddCodeLine ("adc (sp),y"); + AddCodeLine ("sta (sp),y"); + AddCodeLine ("tax"); + AddCodeLine ("dey"); + AddCodeLine ("lda (sp),y"); + } else { + g_getimmed (flags, val, 0); + AddCodeLine ("jsr addeqysp"); + } + } else { + AddCodeLine ("jsr addeqysp"); + } break; case CF_LONG: if (flags & CF_CONST) { g_getimmed (flags, val, 0); } - if (offs == 0) { - AddCodeLine ("jsr laddeq0sp"); - } else { - ldyconst (offs); - AddCodeLine ("jsr laddeqysp"); - } + ldyconst (offs); + AddCodeLine ("jsr laddeqysp"); break; default: @@ -1789,12 +1883,12 @@ void g_addeqind (unsigned flags, unsigned offs, unsigned long val) -void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs, +void g_subeqstatic (unsigned flags, unsigned long label, long offs, unsigned long val) /* Emit -= for a static variable */ { /* Create the correct label name */ - char* lbuf = GetLabelName (flags, label, offs); + const char* lbuf = GetLabelName (flags, label, offs); /* Check the size and determine operation */ switch (flags & CF_TYPE) { @@ -1813,10 +1907,9 @@ void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs, AddCodeLine ("sta %s", lbuf); } } else { + AddCodeLine ("eor #$FF"); AddCodeLine ("sec"); - AddCodeLine ("sta tmp1"); - AddCodeLine ("lda %s", lbuf); - AddCodeLine ("sbc tmp1"); + AddCodeLine ("adc %s", lbuf); AddCodeLine ("sta %s", lbuf); } if ((flags & CF_UNSIGNED) == 0) { @@ -1849,13 +1942,12 @@ void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs, AddCodeLine ("lda %s", lbuf); } } else { - AddCodeLine ("sta tmp1"); - AddCodeLine ("lda %s", lbuf); - AddCodeLine ("sbc tmp1"); + AddCodeLine ("eor #$FF"); + AddCodeLine ("adc %s", lbuf); AddCodeLine ("sta %s", lbuf); - AddCodeLine ("stx tmp1"); - AddCodeLine ("lda %s+1", lbuf); - AddCodeLine ("sbc tmp1"); + AddCodeLine ("txa"); + AddCodeLine ("eor #$FF"); + AddCodeLine ("adc %s+1", lbuf); AddCodeLine ("sta %s+1", lbuf); AddCodeLine ("tax"); AddCodeLine ("lda %s", lbuf); @@ -1867,13 +1959,9 @@ void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs, if (val < 0x100) { AddCodeLine ("ldy #<(%s)", lbuf); AddCodeLine ("sty ptr1"); - AddCodeLine ("ldy #>(%s+1)", lbuf); - if (val == 1) { - AddCodeLine ("jsr lsubeq1"); - } else { - AddCodeLine ("lda #$%02X", (unsigned char)val); - AddCodeLine ("jsr lsubeqa"); - } + AddCodeLine ("ldy #>(%s)", lbuf); + AddCodeLine ("lda #$%02X", (unsigned char)val); + AddCodeLine ("jsr lsubeqa"); } else { g_getstatic (flags, label, offs); g_dec (flags, val); @@ -1882,7 +1970,7 @@ void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs, } else { AddCodeLine ("ldy #<(%s)", lbuf); AddCodeLine ("sty ptr1"); - AddCodeLine ("ldy #>(%s+1)", lbuf); + AddCodeLine ("ldy #>(%s)", lbuf); AddCodeLine ("jsr lsubeq"); } break; @@ -1898,7 +1986,7 @@ void g_subeqlocal (unsigned flags, int offs, unsigned long val) /* Emit -= for a local variable */ { /* Calculate the true offset, check it, load it into Y */ - offs -= oursp; + offs -= StackPtr; CheckLocalOffs (offs); /* Check the size and determine operation */ @@ -1913,18 +2001,17 @@ void g_subeqlocal (unsigned flags, int offs, unsigned long val) AddCodeLine ("lda (sp),y"); AddCodeLine ("sbc #$%02X", (unsigned char)val); } else { - AddCodeLine ("sta tmp1"); - AddCodeLine ("lda (sp),y"); - AddCodeLine ("sbc tmp1"); + AddCodeLine ("eor #$FF"); + AddCodeLine ("adc (sp),y"); } AddCodeLine ("sta (sp),y"); if ((flags & CF_UNSIGNED) == 0) { - unsigned L = GetLocalLabel(); + unsigned L = GetLocalLabel(); AddCodeLine ("bpl %s", LocalLabelName (L)); - AddCodeLine ("dex"); - g_defcodelabel (L); - } - break; + AddCodeLine ("dex"); + g_defcodelabel (L); + } + break; } /* FALLTHROUGH */ @@ -1932,24 +2019,16 @@ void g_subeqlocal (unsigned flags, int offs, unsigned long val) if (flags & CF_CONST) { g_getimmed (flags, val, 0); } - if (offs == 0) { - AddCodeLine ("jsr subeq0sp"); - } else { - ldyconst (offs); - AddCodeLine ("jsr subeqysp"); - } + ldyconst (offs); + AddCodeLine ("jsr subeqysp"); break; case CF_LONG: if (flags & CF_CONST) { g_getimmed (flags, val, 0); } - if (offs == 0) { - AddCodeLine ("jsr lsubeq0sp"); - } else { - ldyconst (offs); - AddCodeLine ("jsr lsubeqysp"); - } + ldyconst (offs); + AddCodeLine ("jsr lsubeqysp"); break; default: @@ -2024,13 +2103,13 @@ void g_subeqind (unsigned flags, unsigned offs, unsigned long val) -void g_addaddr_local (unsigned flags, int offs) +void g_addaddr_local (unsigned flags attribute ((unused)), int offs) /* Add the address of a local variable to ax */ { unsigned L = 0; /* Add the offset */ - offs -= oursp; + offs -= StackPtr; if (offs != 0) { /* We cannot address more then 256 bytes of locals anyway */ L = GetLocalLabel(); @@ -2058,11 +2137,11 @@ void g_addaddr_local (unsigned flags, int offs) -void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs) +void g_addaddr_static (unsigned flags, unsigned long label, long offs) /* Add the address of a static variable to ax */ { /* Create the correct label name */ - char* lbuf = GetLabelName (flags, label, offs); + const char* lbuf = GetLabelName (flags, label, offs); /* Add the address to the current ax value */ AddCodeLine ("clc"); @@ -2268,36 +2347,20 @@ void g_test (unsigned flags) void g_push (unsigned flags, unsigned long val) /* Push the primary register or a constant value onto the stack */ { - unsigned char hi; - if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) { /* We have a constant 8 or 16 bit value */ if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) { /* Handle as 8 bit value */ - if (CodeSizeFactor >= 165 || val > 2) { - ldaconst (val); - AddCodeLine ("jsr pusha"); - } else { - AddCodeLine ("jsr pushc%d", (int) val); - } + ldaconst (val); + AddCodeLine ("jsr pusha"); } else { /* Handle as 16 bit value */ - hi = (unsigned char) (val >> 8); - if (val <= 7) { - AddCodeLine ("jsr push%u", (unsigned) val); - } else if (hi == 0 || hi == 0xFF) { - /* Use special function */ - ldaconst (val); - AddCodeLine ("jsr %s", (hi == 0)? "pusha0" : "pushaFF"); - } else { - /* Long way ... */ - g_getimmed (flags, val, 0); - AddCodeLine ("jsr pushax"); - } + g_getimmed (flags, val, 0); + AddCodeLine ("jsr pushax"); } } else { @@ -2371,20 +2434,38 @@ void g_call (unsigned Flags, const char* Label, unsigned ArgSize) ldyconst (ArgSize); } AddCodeLine ("jsr _%s", Label); - oursp += ArgSize; /* callee pops args */ + StackPtr += ArgSize; /* callee pops args */ } -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 -= StackPtr; + 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 */ + StackPtr += ArgSize; } @@ -2397,54 +2478,7 @@ void g_jump (unsigned Label) -void g_switch (unsigned Flags) -/* Output switch statement preamble */ -{ - switch (Flags & CF_TYPE) { - - case CF_CHAR: - case CF_INT: - AddCodeLine ("jsr switch"); - break; - - case CF_LONG: - AddCodeLine ("jsr lswitch"); - break; - - default: - typeerror (Flags); - - } -} - - - -void g_case (unsigned flags, unsigned label, unsigned long val) -/* Create table code for one case selector */ -{ - switch (flags & CF_TYPE) { - - case CF_CHAR: - case CF_INT: - AddCodeLine (".word $%04X, %s", - (unsigned)(val & 0xFFFF), - LocalLabelName (label)); - break; - - case CF_LONG: - AddCodeLine (".dword $%08lX", val); - AddCodeLine (".word %s", LocalLabelName (label)); - break; - - default: - typeerror (flags); - - } -} - - - -void g_truejump (unsigned flags, unsigned label) +void g_truejump (unsigned flags attribute ((unused)), unsigned label) /* Jump to label if zero flag clear */ { AddCodeLine ("jne %s", LocalLabelName (label)); @@ -2452,7 +2486,7 @@ void g_truejump (unsigned flags, unsigned label) -void g_falsejump (unsigned flags, unsigned label) +void g_falsejump (unsigned flags attribute ((unused)), unsigned label) /* Jump to label if zero flag set */ { AddCodeLine ("jeq %s", LocalLabelName (label)); @@ -2569,7 +2603,7 @@ void g_mul (unsigned flags, unsigned long val) if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) { /* Generate a shift instead */ g_asl (flags, p2); - return; + return; } /* If the right hand side is const, the lhs is not on stack but still @@ -2581,50 +2615,78 @@ void g_mul (unsigned flags, unsigned long val) case CF_CHAR: if (flags & CF_FORCECHAR) { - /* Handle some special cases */ - switch (val) { - - case 3: - AddCodeLine ("sta tmp1"); - AddCodeLine ("asl a"); - AddCodeLine ("clc"); - AddCodeLine ("adc tmp1"); - return; - - case 5: - AddCodeLine ("sta tmp1"); - AddCodeLine ("asl a"); - AddCodeLine ("asl a"); - AddCodeLine ("clc"); - AddCodeLine ("adc tmp1"); - return; - - case 10: - AddCodeLine ("sta tmp1"); - AddCodeLine ("asl a"); - AddCodeLine ("asl a"); - AddCodeLine ("clc"); - AddCodeLine ("adc tmp1"); - AddCodeLine ("asl a"); - return; - } - } - /* FALLTHROUGH */ + /* Handle some special cases */ + switch (val) { - case CF_INT: - break; + case 3: + AddCodeLine ("sta tmp1"); + AddCodeLine ("asl a"); + AddCodeLine ("clc"); + AddCodeLine ("adc tmp1"); + return; - case CF_LONG: - break; + case 5: + AddCodeLine ("sta tmp1"); + AddCodeLine ("asl a"); + AddCodeLine ("asl a"); + AddCodeLine ("clc"); + AddCodeLine ("adc tmp1"); + return; - default: - typeerror (flags); - } + case 6: + AddCodeLine ("sta tmp1"); + AddCodeLine ("asl a"); + AddCodeLine ("clc"); + AddCodeLine ("adc tmp1"); + AddCodeLine ("asl a"); + return; - /* If we go here, we didn't emit code. Push the lhs on stack and fall - * into the normal, non-optimized stuff. - */ - flags &= ~CF_FORCECHAR; /* Handle chars as ints */ + case 10: + AddCodeLine ("sta tmp1"); + AddCodeLine ("asl a"); + AddCodeLine ("asl a"); + AddCodeLine ("clc"); + AddCodeLine ("adc tmp1"); + AddCodeLine ("asl a"); + return; + } + } + /* FALLTHROUGH */ + + case CF_INT: + switch (val) { + case 3: + AddCodeLine ("jsr mulax3"); + return; + case 5: + AddCodeLine ("jsr mulax5"); + return; + case 6: + AddCodeLine ("jsr mulax6"); + return; + case 7: + AddCodeLine ("jsr mulax7"); + return; + case 9: + AddCodeLine ("jsr mulax9"); + return; + case 10: + AddCodeLine ("jsr mulax10"); + return; + } + break; + + case CF_LONG: + break; + + default: + typeerror (flags); + } + + /* If we go here, we didn't emit code. Push the lhs on stack and fall + * into the normal, non-optimized stuff. + */ + flags &= ~CF_FORCECHAR; /* Handle chars as ints */ g_push (flags & ~CF_CONST, 0); } @@ -2710,36 +2772,52 @@ void g_or (unsigned flags, unsigned long val) case CF_CHAR: if (flags & CF_FORCECHAR) { - if ((val & 0xFF) != 0xFF) { + if ((val & 0xFF) != 0) { AddCodeLine ("ora #$%02X", (unsigned char)val); } return; } /* FALLTHROUGH */ - case CF_INT: - if (val <= 0xFF) { - AddCodeLine ("ora #$%02X", (unsigned char)val); - return; - } - break; - - case CF_LONG: - if (val <= 0xFF) { - AddCodeLine ("ora #$%02X", (unsigned char)val); - return; - } - break; + case CF_INT: + if (val <= 0xFF) { + if ((val & 0xFF) != 0) { + AddCodeLine ("ora #$%02X", (unsigned char)val); + } + } else if ((val & 0xFF00) == 0xFF00) { + if ((val & 0xFF) != 0) { + AddCodeLine ("ora #$%02X", (unsigned char)val); + } + ldxconst (0xFF); + } else if (val != 0) { + AddCodeLine ("ora #$%02X", (unsigned char)val); + AddCodeLine ("pha"); + AddCodeLine ("txa"); + AddCodeLine ("ora #$%02X", (unsigned char)(val >> 8)); + AddCodeLine ("tax"); + AddCodeLine ("pla"); + } + return; - default: - typeerror (flags); - } + case CF_LONG: + if (val <= 0xFF) { + if ((val & 0xFF) != 0) { + AddCodeLine ("ora #$%02X", (unsigned char)val); + } + return; + } + break; - /* If we go here, we didn't emit code. Push the lhs on stack and fall - * into the normal, non-optimized stuff. - */ - g_push (flags & ~CF_CONST, 0); + default: + typeerror (flags); + } + /* If we go here, we didn't emit code. Push the lhs on stack and fall + * into the normal, non-optimized stuff. Note: The standard stuff will + * always work with ints. + */ + flags &= ~CF_FORCECHAR; + g_push (flags & ~CF_CONST, 0); } /* Use long way over the stack */ @@ -2780,16 +2858,17 @@ void g_xor (unsigned flags, unsigned long val) if (val != 0) { AddCodeLine ("eor #$%02X", (unsigned char)val); } - return; - } else if ((val & 0xFF) == 0) { + } else if (val != 0) { + if ((val & 0xFF) != 0) { + AddCodeLine ("eor #$%02X", (unsigned char)val); + } AddCodeLine ("pha"); AddCodeLine ("txa"); AddCodeLine ("eor #$%02X", (unsigned char)(val >> 8)); AddCodeLine ("tax"); AddCodeLine ("pla"); - return; } - break; + return; case CF_LONG: if (val <= 0xFF) { @@ -2804,11 +2883,12 @@ void g_xor (unsigned flags, unsigned long val) typeerror (flags); } - /* If we go here, we didn't emit code. Push the lhs on stack and fall - * into the normal, non-optimized stuff. - */ - g_push (flags & ~CF_CONST, 0); - + /* If we go here, we didn't emit code. Push the lhs on stack and fall + * into the normal, non-optimized stuff. Note: The standard stuff will + * always work with ints. + */ + flags &= ~CF_FORCECHAR; + g_push (flags & ~CF_CONST, 0); } /* Use long way over the stack */ @@ -2817,68 +2897,70 @@ void g_xor (unsigned flags, unsigned long val) -void g_and (unsigned flags, unsigned long val) +void g_and (unsigned Flags, unsigned long Val) /* Primary = TOS & Primary */ { static char* ops [12] = { - 0, "tosanda0", "tosandax", - 0, "tosanda0", "tosandax", - 0, 0, "tosandeax", - 0, 0, "tosandeax", + 0, "tosanda0", "tosandax", + 0, "tosanda0", "tosandax", + 0, 0, "tosandeax", + 0, 0, "tosandeax", }; /* If the right hand side is const, the lhs is not on stack but still * in the primary register. */ - if (flags & CF_CONST) { + if (Flags & CF_CONST) { - switch (flags & CF_TYPE) { + switch (Flags & CF_TYPE) { case CF_CHAR: - if (flags & CF_FORCECHAR) { - AddCodeLine ("and #$%02X", (unsigned char)val); - return; - } - /* FALLTHROUGH */ + if (Flags & CF_FORCECHAR) { + if ((Val & 0xFF) != 0xFF) { + AddCodeLine ("and #$%02X", (unsigned char)Val); + } + return; + } + /* FALLTHROUGH */ case CF_INT: - if ((val & 0xFFFF) != 0xFFFF) { - if (val <= 0xFF) { - ldxconst (0); - if (val == 0) { - ldaconst (0); - } else if (val != 0xFF) { - AddCodeLine ("and #$%02X", (unsigned char)val); - } - } else if ((val & 0xFF00) == 0xFF00) { - AddCodeLine ("and #$%02X", (unsigned char)val); - } else if ((val & 0x00FF) == 0x0000) { - AddCodeLine ("txa"); - AddCodeLine ("and #$%02X", (unsigned char)(val >> 8)); - AddCodeLine ("tax"); - ldaconst (0); - } else { - AddCodeLine ("tay"); - AddCodeLine ("txa"); - AddCodeLine ("and #$%02X", (unsigned char)(val >> 8)); - AddCodeLine ("tax"); - AddCodeLine ("tya"); - if ((val & 0x00FF) != 0x00FF) { - AddCodeLine ("and #$%02X", (unsigned char)val); - } - } - } + if ((Val & 0xFFFF) != 0xFFFF) { + if (Val <= 0xFF) { + ldxconst (0); + if (Val == 0) { + ldaconst (0); + } else if (Val != 0xFF) { + AddCodeLine ("and #$%02X", (unsigned char)Val); + } + } else if ((Val & 0xFF00) == 0xFF00) { + AddCodeLine ("and #$%02X", (unsigned char)Val); + } else if ((Val & 0x00FF) == 0x0000) { + AddCodeLine ("txa"); + AddCodeLine ("and #$%02X", (unsigned char)(Val >> 8)); + AddCodeLine ("tax"); + ldaconst (0); + } else { + AddCodeLine ("tay"); + AddCodeLine ("txa"); + AddCodeLine ("and #$%02X", (unsigned char)(Val >> 8)); + AddCodeLine ("tax"); + AddCodeLine ("tya"); + if ((Val & 0x00FF) != 0x00FF) { + AddCodeLine ("and #$%02X", (unsigned char)Val); + } + } + } return; case CF_LONG: - if (val <= 0xFF) { + if (Val <= 0xFF) { ldxconst (0); AddCodeLine ("stx sreg+1"); AddCodeLine ("stx sreg"); - if ((val & 0xFF) != 0xFF) { - AddCodeLine ("and #$%02X", (unsigned char)val); + if ((Val & 0xFF) != 0xFF) { + AddCodeLine ("and #$%02X", (unsigned char)Val); } return; - } else if (val == 0xFF00) { + } else if (Val == 0xFF00) { ldaconst (0); AddCodeLine ("sta sreg+1"); AddCodeLine ("sta sreg"); @@ -2887,18 +2969,19 @@ void g_and (unsigned flags, unsigned long val) break; default: - typeerror (flags); + typeerror (Flags); } - /* If we go here, we didn't emit code. Push the lhs on stack and fall - * into the normal, non-optimized stuff. - */ - g_push (flags & ~CF_CONST, 0); - + /* If we go here, we didn't emit code. Push the lhs on stack and fall + * into the normal, non-optimized stuff. Note: The standard stuff will + * always work with ints. + */ + Flags &= ~CF_FORCECHAR; + g_push (Flags & ~CF_CONST, 0); } /* Use long way over the stack */ - oper (flags, val, ops); + oper (Flags, Val, ops); } @@ -2907,10 +2990,10 @@ void g_asr (unsigned flags, unsigned long val) /* Primary = TOS >> Primary */ { static char* ops [12] = { - 0, "tosasra0", "tosasrax", - 0, "tosshra0", "tosshrax", - 0, 0, "tosasreax", - 0, 0, "tosshreax", + 0, "tosasra0", "tosasrax", + 0, "tosshra0", "tosshrax", + 0, 0, "tosasreax", + 0, 0, "tosshreax", }; /* If the right hand side is const, the lhs is not on stack but still @@ -2922,61 +3005,69 @@ void g_asr (unsigned flags, unsigned long val) case CF_CHAR: case CF_INT: - if (val >= 1 && val <= 4) { - if (flags & CF_UNSIGNED) { - AddCodeLine ("jsr shrax%ld", val); - } else { - AddCodeLine ("jsr asrax%ld", val); - } - return; - } else if (val == 8 && (flags & CF_UNSIGNED)) { + if (val >= 8 && (flags & CF_UNSIGNED)) { AddCodeLine ("txa"); ldxconst (0); + val -= 8; + } + if (val == 0) { + /* Done */ return; - } - break; + } else if (val >= 1 && val <= 4) { + if (flags & CF_UNSIGNED) { + AddCodeLine ("jsr shrax%ld", val); + } else { + AddCodeLine ("jsr asrax%ld", val); + } + return; + } + break; - case CF_LONG: - if (val >= 1 && val <= 4) { - if (flags & CF_UNSIGNED) { - AddCodeLine ("jsr shreax%ld", val); - } else { - AddCodeLine ("jsr asreax%ld", val); - } + case CF_LONG: + if (val == 0) { + /* Nothing to do */ return; - } else if (val == 8 && (flags & CF_UNSIGNED)) { - AddCodeLine ("txa"); - AddCodeLine ("ldx sreg"); - AddCodeLine ("ldy sreg+1"); - AddCodeLine ("sty sreg"); - AddCodeLine ("ldy #$00"); + } else if (val >= 1 && val <= 4) { + if (flags & CF_UNSIGNED) { + AddCodeLine ("jsr shreax%ld", val); + } else { + AddCodeLine ("jsr asreax%ld", val); + } + return; + } else if (val == 8 && (flags & CF_UNSIGNED)) { + AddCodeLine ("txa"); + AddCodeLine ("ldx sreg"); + AddCodeLine ("ldy sreg+1"); + AddCodeLine ("sty sreg"); + AddCodeLine ("ldy #$00"); AddCodeLine ("sty sreg+1"); - return; + return; } else if (val == 16) { - AddCodeLine ("ldy #$00"); - AddCodeLine ("ldx sreg+1"); - if ((flags & CF_UNSIGNED) == 0) { - unsigned L = GetLocalLabel(); - AddCodeLine ("bpl %s", LocalLabelName (L)); - AddCodeLine ("dey"); - g_defcodelabel (L); - } + AddCodeLine ("ldy #$00"); + AddCodeLine ("ldx sreg+1"); + if ((flags & CF_UNSIGNED) == 0) { + unsigned L = GetLocalLabel(); + AddCodeLine ("bpl %s", LocalLabelName (L)); + AddCodeLine ("dey"); + g_defcodelabel (L); + } AddCodeLine ("lda sreg"); - AddCodeLine ("sty sreg+1"); - AddCodeLine ("sty sreg"); - return; - } - break; - - default: - typeerror (flags); - } + AddCodeLine ("sty sreg+1"); + AddCodeLine ("sty sreg"); + return; + } + break; - /* If we go here, we didn't emit code. Push the lhs on stack and fall - * into the normal, non-optimized stuff. - */ - g_push (flags & ~CF_CONST, 0); + default: + typeerror (flags); + } + /* If we go here, we didn't emit code. Push the lhs on stack and fall + * into the normal, non-optimized stuff. Note: The standard stuff will + * always work with ints. + */ + flags &= ~CF_FORCECHAR; + g_push (flags & ~CF_CONST, 0); } /* Use long way over the stack */ @@ -2989,10 +3080,10 @@ void g_asl (unsigned flags, unsigned long val) /* Primary = TOS << Primary */ { static char* ops [12] = { - 0, "tosasla0", "tosaslax", - 0, "tosshla0", "tosshlax", - 0, 0, "tosasleax", - 0, 0, "tosshleax", + 0, "tosasla0", "tosaslax", + 0, "tosshla0", "tosshlax", + 0, 0, "tosasleax", + 0, 0, "tosshleax", }; @@ -3005,22 +3096,29 @@ void g_asl (unsigned flags, unsigned long val) case CF_CHAR: case CF_INT: - if (val >= 1 && val <= 4) { + if (val >= 8) { + AddCodeLine ("tax"); + AddCodeLine ("lda #$00"); + val -= 8; + } + if (val == 0) { + /* Done */ + return; + } else if (val >= 1 && val <= 4) { if (flags & CF_UNSIGNED) { AddCodeLine ("jsr shlax%ld", val); } else { - AddCodeLine ("jsr aslax%ld", val); + AddCodeLine ("jsr aslax%ld", val); } return; - } else if (val == 8) { - AddCodeLine ("tax"); - AddCodeLine ("lda #$00"); - return; - } + } break; case CF_LONG: - if (val >= 1 && val <= 4) { + if (val == 0) { + /* Nothing to do */ + return; + } else if (val >= 1 && val <= 4) { if (flags & CF_UNSIGNED) { AddCodeLine ("jsr shleax%ld", val); } else { @@ -3028,7 +3126,7 @@ void g_asl (unsigned flags, unsigned long val) } return; } else if (val == 8) { - AddCodeLine ("ldy sreg"); + AddCodeLine ("ldy sreg"); AddCodeLine ("sty sreg+1"); AddCodeLine ("stx sreg"); AddCodeLine ("tax"); @@ -3047,11 +3145,12 @@ void g_asl (unsigned flags, unsigned long val) typeerror (flags); } - /* If we go here, we didn't emit code. Push the lhs on stack and fall - * into the normal, non-optimized stuff. - */ - g_push (flags & ~CF_CONST, 0); - + /* If we go here, we didn't emit code. Push the lhs on stack and fall + * into the normal, non-optimized stuff. Note: The standard stuff will + * always work with ints. + */ + flags &= ~CF_FORCECHAR; + g_push (flags & ~CF_CONST, 0); } /* Use long way over the stack */ @@ -3060,22 +3159,30 @@ void g_asl (unsigned flags, unsigned long val) -void g_neg (unsigned flags) +void g_neg (unsigned Flags) /* Primary = -Primary */ { - switch (flags & CF_TYPE) { + switch (Flags & CF_TYPE) { case CF_CHAR: + if (Flags & CF_FORCECHAR) { + AddCodeLine ("eor #$FF"); + AddCodeLine ("clc"); + AddCodeLine ("adc #$01"); + return; + } + /* FALLTHROUGH */ + case CF_INT: AddCodeLine ("jsr negax"); break; case CF_LONG: - AddCodeLine ("jsr negeax"); + AddCodeLine ("jsr negeax"); break; default: - typeerror (flags); + typeerror (Flags); } } @@ -3105,12 +3212,18 @@ void g_bneg (unsigned flags) -void g_com (unsigned flags) +void g_com (unsigned Flags) /* Primary = ~Primary */ { - switch (flags & CF_TYPE) { + switch (Flags & CF_TYPE) { case CF_CHAR: + if (Flags & CF_FORCECHAR) { + AddCodeLine ("eor #$FF"); + return; + } + /* FALLTHROUGH */ + case CF_INT: AddCodeLine ("jsr complax"); break; @@ -3120,7 +3233,7 @@ void g_com (unsigned flags) break; default: - typeerror (flags); + typeerror (Flags); } } @@ -3140,9 +3253,9 @@ void g_inc (unsigned flags, unsigned long val) case CF_CHAR: if (flags & CF_FORCECHAR) { - if (CPU == CPU_65C02 && val <= 2) { + if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val <= 2) { while (val--) { - AddCodeLine ("ina"); + AddCodeLine ("ina"); } } else { AddCodeLine ("clc"); @@ -3153,7 +3266,7 @@ void g_inc (unsigned flags, unsigned long val) /* FALLTHROUGH */ case CF_INT: - if (CPU == CPU_65C02 && val == 1) { + if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val == 1) { unsigned L = GetLocalLabel(); AddCodeLine ("ina"); AddCodeLine ("bne %s", LocalLabelName (L)); @@ -3171,14 +3284,14 @@ void g_inc (unsigned flags, unsigned long val) } } else { /* Inline the code */ - if (val < 0x300) { + if (val <= 0x300) { if ((val & 0xFF) != 0) { - unsigned L = GetLocalLabel(); + unsigned L = GetLocalLabel(); AddCodeLine ("clc"); AddCodeLine ("adc #$%02X", (unsigned char) val); AddCodeLine ("bcc %s", LocalLabelName (L)); AddCodeLine ("inx"); - g_defcodelabel (L); + g_defcodelabel (L); } if (val >= 0x100) { AddCodeLine ("inx"); @@ -3186,6 +3299,9 @@ void g_inc (unsigned flags, unsigned long val) if (val >= 0x200) { AddCodeLine ("inx"); } + if (val >= 0x300) { + AddCodeLine ("inx"); + } } else { AddCodeLine ("clc"); if ((val & 0xFF) != 0) { @@ -3231,7 +3347,7 @@ void g_dec (unsigned flags, unsigned long val) case CF_CHAR: if (flags & CF_FORCECHAR) { - if (CPU == CPU_65C02 && val <= 2) { + if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val <= 2) { while (val--) { AddCodeLine ("dea"); } @@ -3315,9 +3431,9 @@ void g_eq (unsigned flags, unsigned long val) { static char* ops [12] = { "toseq00", "toseqa0", "toseqax", - "toseq00", "toseqa0", "toseqax", - 0, 0, "toseqeax", - 0, 0, "toseqeax", + "toseq00", "toseqa0", "toseqax", + 0, 0, "toseqeax", + 0, 0, "toseqeax", }; unsigned L; @@ -3330,19 +3446,19 @@ void g_eq (unsigned flags, unsigned long val) switch (flags & CF_TYPE) { case CF_CHAR: - if (flags & CF_FORCECHAR) { - AddCodeLine ("cmp #$%02X", (unsigned char)val); - AddCodeLine ("jsr booleq"); - return; - } + if (flags & CF_FORCECHAR) { + AddCodeLine ("cmp #$%02X", (unsigned char)val); + AddCodeLine ("jsr booleq"); + return; + } /* FALLTHROUGH */ case CF_INT: - L = GetLocalLabel(); + L = GetLocalLabel(); AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); AddCodeLine ("bne %s", LocalLabelName (L)); AddCodeLine ("cmp #$%02X", (unsigned char)val); - g_defcodelabel (L); + g_defcodelabel (L); AddCodeLine ("jsr booleq"); return; @@ -3354,10 +3470,11 @@ void g_eq (unsigned flags, unsigned long val) } /* If we go here, we didn't emit code. Push the lhs on stack and fall - * into the normal, non-optimized stuff. + * into the normal, non-optimized stuff. Note: The standard stuff will + * always work with ints. */ - g_push (flags & ~CF_CONST, 0); - + flags &= ~CF_FORCECHAR; + g_push (flags & ~CF_CONST, 0); } /* Use long way over the stack */ @@ -3394,11 +3511,11 @@ void g_ne (unsigned flags, unsigned long val) /* FALLTHROUGH */ case CF_INT: - L = GetLocalLabel(); + L = GetLocalLabel(); AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); AddCodeLine ("bne %s", LocalLabelName (L)); AddCodeLine ("cmp #$%02X", (unsigned char)val); - g_defcodelabel (L); + g_defcodelabel (L); AddCodeLine ("jsr boolne"); return; @@ -3410,10 +3527,11 @@ void g_ne (unsigned flags, unsigned long val) } /* If we go here, we didn't emit code. Push the lhs on stack and fall - * into the normal, non-optimized stuff. + * into the normal, non-optimized stuff. Note: The standard stuff will + * always work with ints. */ - g_push (flags & ~CF_CONST, 0); - + flags &= ~CF_FORCECHAR; + g_push (flags & ~CF_CONST, 0); } /* Use long way over the stack */ @@ -3428,7 +3546,7 @@ void g_lt (unsigned flags, unsigned long val) static char* ops [12] = { "toslt00", "toslta0", "tosltax", "tosult00", "tosulta0", "tosultax", - 0, 0, "toslteax", + 0, 0, "toslteax", 0, 0, "tosulteax", }; @@ -3437,67 +3555,94 @@ void g_lt (unsigned flags, unsigned long val) */ if (flags & CF_CONST) { - /* Give a warning in some special cases */ - if ((flags & CF_UNSIGNED) && val == 0) { - Warning ("Condition is never true"); - } - - /* Look at the type */ - switch (flags & CF_TYPE) { - - case CF_CHAR: - if (flags & CF_FORCECHAR) { - AddCodeLine ("cmp #$%02X", (unsigned char)val); - if (flags & CF_UNSIGNED) { - AddCodeLine ("jsr boolult"); - } else { - AddCodeLine ("jsr boollt"); - } - return; - } - /* FALLTHROUGH */ - - case CF_INT: - if ((flags & CF_UNSIGNED) == 0 && val == 0) { - /* If we have a signed compare against zero, we only need to - * test the high byte. - */ - AddCodeLine ("txa"); - AddCodeLine ("jsr boollt"); - return; - } - /* Direct code only for unsigned data types */ - if (flags & CF_UNSIGNED) { - unsigned L = GetLocalLabel(); - AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); - AddCodeLine ("bne %s", LocalLabelName (L)); - AddCodeLine ("cmp #$%02X", (unsigned char)val); - g_defcodelabel (L); - AddCodeLine ("jsr boolult"); - return; - } - break; - - case CF_LONG: - if ((flags & CF_UNSIGNED) == 0 && val == 0) { - /* If we have a signed compare against zero, we only need to - * test the high byte. - */ - AddCodeLine ("lda sreg+1"); - AddCodeLine ("jsr boollt"); - return; - } - break; - - default: - typeerror (flags); - } - - /* If we go here, we didn't emit code. Push the lhs on stack and fall - * into the normal, non-optimized stuff. - */ - g_push (flags & ~CF_CONST, 0); + /* Because the handling of the overflow flag is too complex for + * inlining, we can handle only unsigned compares, and signed + * compares against zero here. + */ + if (flags & CF_UNSIGNED) { + + /* Give a warning in some special cases */ + if (val == 0) { + Warning ("Condition is never true"); + AddCodeLine ("jsr return0"); + return; + } + + /* Look at the type */ + switch (flags & CF_TYPE) { + + case CF_CHAR: + if (flags & CF_FORCECHAR) { + AddCodeLine ("cmp #$%02X", (unsigned char)val); + AddCodeLine ("jsr boolult"); + return; + } + /* FALLTHROUGH */ + + case CF_INT: + /* If the low byte is zero, we must only test the high byte */ + AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); + if ((val & 0xFF) != 0) { + unsigned L = GetLocalLabel(); + AddCodeLine ("bne %s", LocalLabelName (L)); + AddCodeLine ("cmp #$%02X", (unsigned char)val); + g_defcodelabel (L); + } + AddCodeLine ("jsr boolult"); + return; + + case CF_LONG: + /* Do a subtraction */ + AddCodeLine ("cmp #$%02X", (unsigned char)val); + AddCodeLine ("txa"); + AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8)); + AddCodeLine ("lda sreg"); + AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 16)); + AddCodeLine ("lda sreg+1"); + AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 24)); + AddCodeLine ("jsr boolult"); + return; + + default: + typeerror (flags); + } + + } else if (val == 0) { + + /* Look at the type */ + switch (flags & CF_TYPE) { + + case CF_CHAR: + if (flags & CF_FORCECHAR) { + AddCodeLine ("tax"); + AddCodeLine ("jsr boollt"); + return; + } + /* FALLTHROUGH */ + + case CF_INT: + /* Just check the high byte */ + AddCodeLine ("txa"); + AddCodeLine ("jsr boollt"); + return; + + case CF_LONG: + /* Just check the high byte */ + AddCodeLine ("lda sreg+1"); + AddCodeLine ("jsr boollt"); + return; + + default: + typeerror (flags); + } + } + /* If we go here, we didn't emit code. Push the lhs on stack and fall + * into the normal, non-optimized stuff. Note: The standard stuff will + * always work with ints. + */ + flags &= ~CF_FORCECHAR; + g_push (flags & ~CF_CONST, 0); } /* Use long way over the stack */ @@ -3513,7 +3658,7 @@ void g_le (unsigned flags, unsigned long val) "tosle00", "toslea0", "tosleax", "tosule00", "tosulea0", "tosuleax", 0, 0, "tosleeax", - 0, 0, "tosuleeax", + 0, 0, "tosuleeax", }; @@ -3522,65 +3667,100 @@ void g_le (unsigned flags, unsigned long val) */ if (flags & CF_CONST) { - /* <= is not very effective on the 6502, so try to convert - * it into < if the value is in a valid range. - */ - /* Look at the type */ switch (flags & CF_TYPE) { case CF_CHAR: if (flags & CF_FORCECHAR) { if (flags & CF_UNSIGNED) { - if (val < 255) { - AddCodeLine ("cmp #$%02X", (unsigned char)val+1); - AddCodeLine ("jsr boolult"); + /* Unsigned compare */ + if (val < 0xFF) { + /* Use < instead of <= because the former gives + * better code on the 6502 than the latter. + */ + g_lt (flags, val+1); } else { - AddCodeLine ("cmp #$%02X", (unsigned char)val); - AddCodeLine ("jsr boolule"); + /* Always true */ + Warning ("Condition is always true"); + AddCodeLine ("jsr return1"); } } else { - if (val < 127) { - AddCodeLine ("cmp #$%02X", (unsigned char)val+1); - AddCodeLine ("jsr boollt"); + /* Signed compare */ + if ((long) val < 0x7F) { + /* Use < instead of <= because the former gives + * better code on the 6502 than the latter. + */ + g_lt (flags, val+1); } else { - AddCodeLine ("cmp #$%02X", (unsigned char)val); - AddCodeLine ("jsr boolle"); + /* Always true */ + Warning ("Condition is always true"); + AddCodeLine ("jsr return1"); } - } - return; - } - /* FALLTHROUGH */ - - case CF_INT: - if (flags & CF_UNSIGNED) { - unsigned L = GetLocalLabel(); - const char* Name = "boolule"; - if (val < 65535) { - ++val; - Name = "boolult"; - } - AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); - AddCodeLine ("bne %s", LocalLabelName (L)); - AddCodeLine ("cmp #$%02X", (unsigned char)val); - g_defcodelabel (L); - AddCodeLine ("jsr %s", Name); - return; - } - break; + } + return; + } + /* FALLTHROUGH */ - case CF_LONG: - break; + case CF_INT: + if (flags & CF_UNSIGNED) { + /* Unsigned compare */ + if (val < 0xFFFF) { + /* Use < instead of <= because the former gives + * better code on the 6502 than the latter. + */ + g_lt (flags, val+1); + } else { + /* Always true */ + Warning ("Condition is always true"); + AddCodeLine ("jsr return1"); + } + } else { + /* Signed compare */ + if ((long) val < 0x7FFF) { + g_lt (flags, val+1); + } else { + /* Always true */ + Warning ("Condition is always true"); + AddCodeLine ("jsr return1"); + } + } + return; - default: - typeerror (flags); - } + case CF_LONG: + if (flags & CF_UNSIGNED) { + /* Unsigned compare */ + if (val < 0xFFFFFFFF) { + /* Use < instead of <= because the former gives + * better code on the 6502 than the latter. + */ + g_lt (flags, val+1); + } else { + /* Always true */ + Warning ("Condition is always true"); + AddCodeLine ("jsr return1"); + } + } else { + /* Signed compare */ + if ((long) val < 0x7FFFFFFF) { + g_lt (flags, val+1); + } else { + /* Always true */ + Warning ("Condition is always true"); + AddCodeLine ("jsr return1"); + } + } + return; - /* If we go here, we didn't emit code. Push the lhs on stack and fall - * into the normal, non-optimized stuff. - */ - g_push (flags & ~CF_CONST, 0); + default: + typeerror (flags); + } + /* If we go here, we didn't emit code. Push the lhs on stack and fall + * into the normal, non-optimized stuff. Note: The standard stuff will + * always work with ints. + */ + flags &= ~CF_FORCECHAR; + g_push (flags & ~CF_CONST, 0); } /* Use long way over the stack */ @@ -3593,10 +3773,10 @@ void g_gt (unsigned flags, unsigned long val) /* Test for greater than */ { static char* ops [12] = { - "tosgt00", "tosgta0", "tosgtax", + "tosgt00", "tosgta0", "tosgtax", "tosugt00", "tosugta0", "tosugtax", - 0, 0, "tosgteax", - 0, 0, "tosugteax", + 0, 0, "tosgteax", + 0, 0, "tosugteax", }; @@ -3605,38 +3785,39 @@ void g_gt (unsigned flags, unsigned long val) */ if (flags & CF_CONST) { - /* > is not very effective on the 6502, so try to convert - * it into >= if the value is in a valid range. - */ - /* Look at the type */ switch (flags & CF_TYPE) { case CF_CHAR: if (flags & CF_FORCECHAR) { if (flags & CF_UNSIGNED) { - /* If we have a compare > 0, we will replace it by - * != 0 here, since both are identical but the latter - * is easier to optimize. - */ if (val == 0) { - AddCodeLine ("cmp #$%02X", (unsigned char)val); - AddCodeLine ("jsr boolne"); - } else if (val < 255) { - AddCodeLine ("cmp #$%02X", (unsigned char)val+1); - AddCodeLine ("jsr booluge"); + /* If we have a compare > 0, we will replace it by + * != 0 here, since both are identical but the + * latter is easier to optimize. + */ + g_ne (flags, val); + } else if (val < 0xFF) { + /* Use >= instead of > because the former gives + * better code on the 6502 than the latter. + */ + g_ge (flags, val+1); } else { - AddCodeLine ("cmp #$%02X", (unsigned char)val); - AddCodeLine ("jsr boolugt"); - } + /* Never true */ + Warning ("Condition is never true"); + AddCodeLine ("jsr return0"); + } } else { - if (val < 127) { - AddCodeLine ("cmp #$%02X", (unsigned char)val+1); - AddCodeLine ("jsr boolge"); - } else { - AddCodeLine ("cmp #$%02X", (unsigned char)val); - AddCodeLine ("jsr boolgt"); - } + if ((long) val < 0x7F) { + /* Use >= instead of > because the former gives + * better code on the 6502 than the latter. + */ + g_ge (flags, val+1); + } else { + /* Never true */ + Warning ("Condition is never true"); + AddCodeLine ("jsr return0"); + } } return; } @@ -3644,43 +3825,76 @@ void g_gt (unsigned flags, unsigned long val) case CF_INT: if (flags & CF_UNSIGNED) { - /* If we have a compare > 0, we will replace it by - * != 0 here, since both are identical but the latter - * is easier to optimize. - */ - if (val == 0) { - AddCodeLine ("stx tmp1"); - AddCodeLine ("ora tmp1"); - AddCodeLine ("jsr boolne"); - } else { - unsigned L = GetLocalLabel(); - const char* Name = "boolugt"; - if (val < 65535) { - ++val; - Name = "booluge"; - } - AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); - AddCodeLine ("bne %s", LocalLabelName (L)); - AddCodeLine ("cmp #$%02X", (unsigned char)val); - g_defcodelabel (L); - AddCodeLine ("jsr %s", Name); - } - return; - } - break; - - case CF_LONG: - break; + /* Unsigned compare */ + if (val == 0) { + /* If we have a compare > 0, we will replace it by + * != 0 here, since both are identical but the latter + * is easier to optimize. + */ + g_ne (flags, val); + } else if (val < 0xFFFF) { + /* Use >= instead of > because the former gives better + * code on the 6502 than the latter. + */ + g_ge (flags, val+1); + } else { + /* Never true */ + Warning ("Condition is never true"); + AddCodeLine ("jsr return0"); + } + } else { + /* Signed compare */ + if ((long) val < 0x7FFF) { + g_ge (flags, val+1); + } else { + /* Never true */ + Warning ("Condition is never true"); + AddCodeLine ("jsr return0"); + } + } + return; - default: - typeerror (flags); - } + case CF_LONG: + if (flags & CF_UNSIGNED) { + /* Unsigned compare */ + if (val == 0) { + /* If we have a compare > 0, we will replace it by + * != 0 here, since both are identical but the latter + * is easier to optimize. + */ + g_ne (flags, val); + } else if (val < 0xFFFFFFFF) { + /* Use >= instead of > because the former gives better + * code on the 6502 than the latter. + */ + g_ge (flags, val+1); + } else { + /* Never true */ + Warning ("Condition is never true"); + AddCodeLine ("jsr return0"); + } + } else { + /* Signed compare */ + if ((long) val < 0x7FFFFFFF) { + g_ge (flags, val+1); + } else { + /* Never true */ + Warning ("Condition is never true"); + AddCodeLine ("jsr return0"); + } + } + return; - /* If we go here, we didn't emit code. Push the lhs on stack and fall - * into the normal, non-optimized stuff. - */ - g_push (flags & ~CF_CONST, 0); + default: + typeerror (flags); + } + /* If we go here, we didn't emit code. Push the lhs on stack and fall + * into the normal, non-optimized stuff. Note: The standard stuff will + * always work with ints. + */ + flags &= ~CF_FORCECHAR; + g_push (flags & ~CF_CONST, 0); } /* Use long way over the stack */ @@ -3705,67 +3919,95 @@ void g_ge (unsigned flags, unsigned long val) */ if (flags & CF_CONST) { - /* Give a warning in some special cases */ - if ((flags & CF_UNSIGNED) && val == 0) { - Warning ("Condition is always true"); - } + /* Because the handling of the overflow flag is too complex for + * inlining, we can handle only unsigned compares, and signed + * compares against zero here. + */ + if (flags & CF_UNSIGNED) { + + /* Give a warning in some special cases */ + if (val == 0) { + Warning ("Condition is always true"); + AddCodeLine ("jsr return1"); + return; + } + + /* Look at the type */ + switch (flags & CF_TYPE) { + + case CF_CHAR: + if (flags & CF_FORCECHAR) { + AddCodeLine ("cmp #$%02X", (unsigned char)val); + AddCodeLine ("jsr booluge"); + return; + } + /* FALLTHROUGH */ + + case CF_INT: + /* If the low byte is zero, we must only test the high byte */ + AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); + if ((val & 0xFF) != 0) { + unsigned L = GetLocalLabel(); + AddCodeLine ("bne %s", LocalLabelName (L)); + AddCodeLine ("cmp #$%02X", (unsigned char)val); + g_defcodelabel (L); + } + AddCodeLine ("jsr booluge"); + return; + + case CF_LONG: + /* Do a subtraction */ + AddCodeLine ("cmp #$%02X", (unsigned char)val); + AddCodeLine ("txa"); + AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8)); + AddCodeLine ("lda sreg"); + AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 16)); + AddCodeLine ("lda sreg+1"); + AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 24)); + AddCodeLine ("jsr booluge"); + return; + + default: + typeerror (flags); + } + + } else if (val == 0) { + + /* Look at the type */ + switch (flags & CF_TYPE) { + + case CF_CHAR: + if (flags & CF_FORCECHAR) { + AddCodeLine ("tax"); + AddCodeLine ("jsr boolge"); + return; + } + /* FALLTHROUGH */ + + case CF_INT: + /* Just test the high byte */ + AddCodeLine ("txa"); + AddCodeLine ("jsr boolge"); + return; + + case CF_LONG: + /* Just test the high byte */ + AddCodeLine ("lda sreg+1"); + AddCodeLine ("jsr boolge"); + return; + + default: + typeerror (flags); + } + } - /* Look at the type */ - switch (flags & CF_TYPE) { - - case CF_CHAR: - if (flags & CF_FORCECHAR) { - AddCodeLine ("cmp #$%02X", (unsigned char)val); - if (flags & CF_UNSIGNED) { - AddCodeLine ("jsr booluge"); - } else { - AddCodeLine ("jsr boolge"); - } - return; - } - /* FALLTHROUGH */ - - case CF_INT: - if ((flags & CF_UNSIGNED) == 0 && val == 0) { - /* If we have a signed compare against zero, we only need to - * test the high byte. - */ - AddCodeLine ("txa"); - AddCodeLine ("jsr boolge"); - return; - } - /* Direct code only for unsigned data types */ - if (flags & CF_UNSIGNED) { - unsigned L = GetLocalLabel(); - AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); - AddCodeLine ("bne %s", LocalLabelName (L)); - AddCodeLine ("cmp #$%02X", (unsigned char)val); - g_defcodelabel (L); - AddCodeLine ("jsr booluge"); - return; - } - break; - - case CF_LONG: - if ((flags & CF_UNSIGNED) == 0 && val == 0) { - /* If we have a signed compare against zero, we only need to - * test the high byte. - */ - AddCodeLine ("lda sreg+1"); - AddCodeLine ("jsr boolge"); - return; - } - break; - - default: - typeerror (flags); - } - - /* If we go here, we didn't emit code. Push the lhs on stack and fall - * into the normal, non-optimized stuff. - */ - g_push (flags & ~CF_CONST, 0); + /* If we go here, we didn't emit code. Push the lhs on stack and fall + * into the normal, non-optimized stuff. Note: The standard stuff will + * always work with ints. + */ + flags &= ~CF_FORCECHAR; + g_push (flags & ~CF_CONST, 0); } /* Use long way over the stack */ @@ -3788,7 +4030,7 @@ void g_res (unsigned n) -void g_defdata (unsigned flags, unsigned long val, unsigned offs) +void g_defdata (unsigned flags, unsigned long val, long offs) /* Define data with the size given in flags */ { if (flags & CF_CONST) { @@ -3820,7 +4062,7 @@ void g_defdata (unsigned flags, unsigned long val, unsigned offs) const char* Label = GetLabelName (flags, val, offs); /* Labels are always 16 bit */ - AddDataLine ("\t.word\t%s", Label); + AddDataLine ("\t.addr\t%s", Label); } } @@ -3863,80 +4105,178 @@ void g_defbytes (const void* Bytes, unsigned Count) -void g_zerobytes (unsigned n) -/* Output n bytes of data initialized with zero */ +void g_zerobytes (unsigned Count) +/* Output Count bytes of data initialized with zero */ { - AddDataLine ("\t.res\t%u,$00", n); + if (Count > 0) { + AddDataLine ("\t.res\t%u,$00", Count); + } } -/*****************************************************************************/ -/* User supplied assembler code */ -/*****************************************************************************/ +void g_initregister (unsigned Label, unsigned Reg, unsigned Size) +/* Initialize a register variable from static initialization data */ +{ + /* Register variables do always have less than 128 bytes */ + unsigned CodeLabel = GetLocalLabel (); + ldxconst (Size-1); + g_defcodelabel (CodeLabel); + AddCodeLine ("lda %s,x", GetLabelName (CF_STATIC, Label, 0)); + AddCodeLine ("sta %s,x", GetLabelName (CF_REGVAR, Reg, 0)); + AddCodeLine ("dex"); + AddCodeLine ("bpl %s", LocalLabelName (CodeLabel)); +} -void g_asmcode (const char* Line, int Len) -/* Output one line of assembler code. If Len is greater than zero, it is used - * as the maximum number of characters to use from Line. - */ +void g_initauto (unsigned Label, unsigned Size) +/* Initialize a local variable at stack offset zero from static data */ { - if (Len >= 0) { - AddCodeLine ("%.*s", Len, Line); + unsigned CodeLabel = GetLocalLabel (); + + CheckLocalOffs (Size); + if (Size <= 128) { + ldyconst (Size-1); + g_defcodelabel (CodeLabel); + AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0)); + AddCodeLine ("sta (sp),y"); + AddCodeLine ("dey"); + AddCodeLine ("bpl %s", LocalLabelName (CodeLabel)); + } else if (Size <= 256) { + ldyconst (0); + g_defcodelabel (CodeLabel); + AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0)); + AddCodeLine ("sta (sp),y"); + AddCodeLine ("iny"); + AddCodeLine ("cpy #$%02X", (unsigned char) Size); + AddCodeLine ("bne %s", LocalLabelName (CodeLabel)); + } +} + + + +void g_initstatic (unsigned InitLabel, unsigned VarLabel, unsigned Size) +/* Initialize a static local variable from static initialization data */ +{ + if (Size <= 128) { + unsigned CodeLabel = GetLocalLabel (); + ldyconst (Size-1); + g_defcodelabel (CodeLabel); + AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0)); + AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0)); + AddCodeLine ("dey"); + AddCodeLine ("bpl %s", LocalLabelName (CodeLabel)); + } else if (Size <= 256) { + unsigned CodeLabel = GetLocalLabel (); + ldyconst (0); + g_defcodelabel (CodeLabel); + AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0)); + AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0)); + AddCodeLine ("iny"); + AddCodeLine ("cpy #$%02X", (unsigned char) Size); + AddCodeLine ("bne %s", LocalLabelName (CodeLabel)); } else { - AddCodeLine ("%s", Line); + /* Use the easy way here: memcpy */ + g_getimmed (CF_STATIC, VarLabel, 0); + AddCodeLine ("jsr pushax"); + g_getimmed (CF_STATIC, InitLabel, 0); + AddCodeLine ("jsr pushax"); + g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, Size, 0); + AddCodeLine ("jsr %s", GetLabelName (CF_EXTERNAL, (unsigned long) "memcpy", 0)); } } /*****************************************************************************/ -/* Inlined known functions */ +/* Switch statement */ /*****************************************************************************/ -void g_strlen (unsigned flags, unsigned long val, unsigned offs) -/* Inline the strlen() function */ +void g_switch (Collection* Nodes, unsigned DefaultLabel, unsigned Depth) +/* Generate code for a switch statement */ { - /* We need a label in both cases */ - unsigned label = GetLocalLabel (); + unsigned NextLabel = 0; + unsigned I; + + /* Setup registers and determine which compare insn to use */ + const char* Compare; + switch (Depth) { + case 1: + Compare = "cmp #$%02X"; + break; + case 2: + Compare = "cpx #$%02X"; + break; + case 3: + AddCodeLine ("ldy sreg"); + Compare = "cpy #$%02X"; + break; + case 4: + AddCodeLine ("ldy sreg+1"); + Compare = "cpy #$%02X"; + break; + default: + Internal ("Invalid depth in g_switch: %u", Depth); + } - /* Two different encodings */ - if (flags & CF_CONST) { + /* Walk over all nodes */ + for (I = 0; I < CollCount (Nodes); ++I) { - /* The address of the string is constant. Create the correct label name */ - char* lbuf = GetLabelName (flags, val, offs); + /* Get the next case node */ + CaseNode* N = CollAtUnchecked (Nodes, I); - /* Generate the strlen code */ - AddCodeLine ("ldy #$FF"); - g_defcodelabel (label); - AddCodeLine ("iny"); - AddCodeLine ("lda %s,y", lbuf); - AddCodeLine ("bne %s", LocalLabelName (label)); - AddCodeLine ("tax"); - AddCodeLine ("tya"); + /* If we have a next label, define it */ + if (NextLabel) { + g_defcodelabel (NextLabel); + NextLabel = 0; + } - } else { + /* Do the compare */ + AddCodeLine (Compare, CN_GetValue (N)); - /* Address not constant but in primary */ - if (CodeSizeFactor < 400) { - /* This is too much code, so call strlen instead of inlining */ - AddCodeLine ("jsr _strlen"); - } else { - /* Inline the function */ - AddCodeLine ("sta ptr1"); - AddCodeLine ("stx ptr1+1"); - AddCodeLine ("ldy #$FF"); - g_defcodelabel (label); - AddCodeLine ("iny"); - AddCodeLine ("lda (ptr1),y"); - AddCodeLine ("bne %s", LocalLabelName (label)); - AddCodeLine ("tax"); - AddCodeLine ("tya"); - } + /* If this is the last level, jump directly to the case code if found */ + if (Depth == 1) { + + /* Branch if equal */ + g_falsejump (0, CN_GetLabel (N)); + + } else { + + /* Determine the next label */ + if (I == CollCount (Nodes) - 1) { + /* Last node means not found */ + g_truejump (0, DefaultLabel); + } else { + /* Jump to the next check */ + NextLabel = GetLocalLabel (); + g_truejump (0, NextLabel); + } + + /* Check the next level */ + g_switch (N->Nodes, DefaultLabel, Depth-1); + + } } + + /* If we go here, we haven't found the label */ + g_jump (DefaultLabel); +} + + + +/*****************************************************************************/ +/* User supplied assembler code */ +/*****************************************************************************/ + + + +void g_asmcode (struct StrBuf* B) +/* Output one line of assembler code. */ +{ + AddCodeLine ("%.*s", SB_GetLen (B), SB_GetConstBuf (B)); }