X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcodegen.c;h=2b61e7a2acaba3fbf65c5c87f5ea795b52b86d45;hb=1366b6cbea1b374fa7502354cf2cb8a971f71c5f;hp=a41f9dfa21b8ff16b8eed04c5fcff62fa9a72778;hpb=3ff4baeafb23d7bc3a67c67f53ba49bdf1067f7c;p=cc65 diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index a41f9dfa2..2b61e7a2a 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -39,6 +39,7 @@ /* common */ #include "check.h" +#include "strbuf.h" #include "version.h" #include "xmalloc.h" #include "xsprintf.h" @@ -46,12 +47,14 @@ /* 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 "textseg.h" #include "util.h" #include "codegen.h" @@ -139,36 +142,52 @@ static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs) void g_preamble (void) /* Generate the assembler code preamble */ { - /* Create a new segment list */ + /* Create a new (global) segment list and remember it */ PushSegments (0); + GS = CS; /* Identify the compiler version */ + AddTextLine (";"); AddTextLine ("; File generated by cc65 v %u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH); + AddTextLine (";"); /* Insert some object file options */ - AddTextLine (".fopt\t\tcompiler,\"cc65 v %u.%u.%u\"", + AddTextLine ("\t.fopt\t\tcompiler,\"cc65 v %u.%u.%u\"", VER_MAJOR, VER_MINOR, VER_PATCH); /* If we're producing code for some other CPU, switch the command set */ if (CPU == CPU_65C02) { - AddTextLine (".pc02"); + AddTextLine ("\t.pc02"); } /* Allow auto import for runtime library routines */ - AddTextLine (".autoimport\ton"); + AddTextLine ("\t.autoimport\ton"); /* Switch the assembler into case sensitive mode */ - AddTextLine (".case\t\ton"); + AddTextLine ("\t.case\t\ton"); /* Tell the assembler if we want to generate debug info */ - AddTextLine (".debuginfo\t%s", (DebugInfo != 0)? "on" : "off"); + AddTextLine ("\t.debuginfo\t%s", (DebugInfo != 0)? "on" : "off"); /* Import the stack pointer for direct auto variable access */ - AddTextLine (".importzp\tsp, sreg, regsave, regbank, tmp1, ptr1"); + AddTextLine ("\t.importzp\tsp, sreg, regsave, regbank, tmp1, ptr1, ptr2"); /* Define long branch macros */ - AddTextLine (".macpack\tlongbranch"); + AddTextLine ("\t.macpack\tlongbranch"); +} + + + +void g_fileinfo (const char* Name, unsigned long Size, unsigned long MTime) +/* If debug info is enabled, place a file info into the source */ +{ + if (DebugInfo) { + /* We have to place this into the global text segment, so it will + * appear before all .dbg line statements. + */ + TS_AddLine (GS->Text, "\t.dbg\t\tfile, \"%s\", %lu, %lu", Name, Size, MTime); + } } @@ -203,8 +222,30 @@ void g_usebss (void) +void g_segname (segment_t Seg, const char* Name) +/* Set the name of a segment */ +{ + DataSeg* S; + + /* Remember the new name */ + NewSegName (Seg, Name); + + /* Emit a segment directive for the data style segments */ + switch (Seg) { + case SEG_RODATA: S = CS->ROData; break; + case SEG_DATA: S = CS->Data; break; + case SEG_BSS: S = CS->BSS; break; + default: S = 0; break; + } + if (S) { + DS_AddLine (S, ".segment\t\"%s\"", Name); + } +} + + + /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ @@ -286,7 +327,7 @@ static unsigned MakeByteOffs (unsigned Flags, unsigned Offs) void g_defcodelabel (unsigned label) /* Define a local code label */ { - AddCodeLabel (CS->Code, LocalLabelName (label)); + CS_AddLabel (CS->Code, LocalLabelName (label)); } @@ -396,77 +437,41 @@ void g_enter (unsigned flags, unsigned argsize) -void g_leave (int flags, int val) +void g_leave (void) /* Function epilogue */ { - int k; - char buf [40]; - - /* CF_REG is set if we're returning a value from the function */ - if ((flags & CF_REG) == 0) { - AddCodeHint ("x:-"); - AddCodeHint ("a:-"); - } - /* How many bytes of locals do we have to drop? */ - k = -oursp; + int k = -oursp; /* If we didn't have a variable argument list, don't call leave */ if (funcargs >= 0) { - /* Load a function return code if needed */ - if ((flags & CF_CONST) != 0) { - g_getimmed (flags, val, 0); - } - - /* Drop stackframe or leave with rts */ + /* Drop stackframe if needed */ k += funcargs; - if (k == 0) { - AddCodeHint ("y:-"); /* Y register no longer used */ - AddCodeLine ("rts"); - } else if (k <= 8) { - AddCodeHint ("y:-"); /* Y register no longer used */ - AddCodeLine ("jmp incsp%d", k); - } else { - CheckLocalOffs (k); - ldyconst (k); - AddCodeLine ("jmp addysp"); + if (k > 0) { + if (k <= 8) { + AddCodeLine ("jsr incsp%d", k); + } else { + CheckLocalOffs (k); + ldyconst (k); + AddCodeLine ("jsr addysp"); + } } } else { - strcpy (buf, "\tjmp\tleave"); - if (k) { + if (k == 0) { + /* Nothing to drop */ + AddCodeLine ("jsr leave"); + } else { /* We've a stack frame to drop */ ldyconst (k); - strcat (buf, "y"); - } else { - /* Y register no longer used */ - AddCodeHint ("y:-"); + AddCodeLine ("jsr leavey"); } - if (flags & CF_CONST) { - if ((flags & CF_TYPE) != CF_LONG) { - /* Constant int sized value given for return code */ - if (val == 0) { - /* Special case: return 0 */ - strcat (buf, "00"); - } else if (((val >> 8) & 0xFF) == 0) { - /* Special case: constant with high byte zero */ - ldaconst (val); /* Load low byte */ - strcat (buf, "0"); - } else { - /* Others: arbitrary constant value */ - g_getimmed (flags, val, 0); /* Load value */ - } - } else { - /* Constant long value: No shortcut possible */ - g_getimmed (flags, val, 0); - } - } - - /* Output the jump */ - AddCodeLine (buf); } + + /* Add the final rts */ + AddCodeLine ("rts"); } @@ -561,65 +566,74 @@ void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes) -void g_getimmed (unsigned flags, unsigned long val, unsigned offs) +void g_getimmed (unsigned Flags, unsigned long Val, unsigned Offs) /* Load a constant into the primary register */ { - if ((flags & CF_CONST) != 0) { + unsigned char B1, B2, B3, B4; + unsigned Done; + + + if ((Flags & CF_CONST) != 0) { /* Numeric constant */ - switch (flags & CF_TYPE) { + switch (Flags & CF_TYPE) { case CF_CHAR: - if ((flags & CF_FORCECHAR) != 0) { - ldaconst (val); + if ((Flags & CF_FORCECHAR) != 0) { + ldaconst (Val); break; } /* FALL THROUGH */ case CF_INT: - ldxconst ((val >> 8) & 0xFF); - ldaconst (val & 0xFF); + ldxconst ((Val >> 8) & 0xFF); + ldaconst (Val & 0xFF); break; case CF_LONG: - if (val < 0x100) { - AddCodeLine ("ldx #$00"); - AddCodeLine ("stx sreg+1"); - AddCodeLine ("stx sreg"); - AddCodeLine ("lda #$%02X", (unsigned char) val); - } else if ((val & 0xFFFF00FF) == 0) { - AddCodeLine ("lda #$00"); - AddCodeLine ("sta sreg+1"); - AddCodeLine ("sta sreg"); - AddCodeLine ("ldx #$%02X", (unsigned char) (val >> 8)); - } else if ((val & 0xFFFF0000) == 0 && CodeSizeFactor > 140) { - AddCodeLine ("lda #$00"); - AddCodeLine ("sta sreg+1"); - AddCodeLine ("sta sreg"); - AddCodeLine ("lda #$%02X", (unsigned char) val); - AddCodeLine ("ldx #$%02X", (unsigned char) (val >> 8)); - } else if ((val & 0xFFFFFF00) == 0xFFFFFF00) { - AddCodeLine ("ldx #$FF"); - AddCodeLine ("stx sreg+1"); - AddCodeLine ("stx sreg"); - if ((val & 0xFF) == 0xFF) { - AddCodeLine ("txa"); - } else { - AddCodeLine ("lda #$%02X", (unsigned char) val); - } - } else if ((val & 0xFFFF00FF) == 0xFFFF00FF) { - AddCodeLine ("lda #$FF"); - AddCodeLine ("sta sreg+1"); - AddCodeLine ("sta sreg"); - AddCodeLine ("ldx #$%02X", (unsigned char) (val >> 8)); - } else { - /* Call a subroutine that will load following value */ - AddCodeLine ("jsr ldeax"); - AddCodeLine (".dword $%08lX", val & 0xFFFFFFFF); + /* 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: - typeerror (flags); + typeerror (Flags); break; } @@ -627,7 +641,7 @@ void g_getimmed (unsigned flags, unsigned long val, unsigned offs) } else { /* Some sort of label */ - const char* Label = GetLabelName (flags, val, offs); + const char* Label = GetLabelName (Flags, Val, Offs); /* Load the address into the primary */ AddCodeLine ("lda #<(%s)", Label); @@ -655,9 +669,10 @@ void g_getstatic (unsigned flags, unsigned long label, unsigned offs) AddCodeLine ("lda %s", lbuf); /* load A from the label */ if (!(flags & CF_UNSIGNED)) { /* Must sign extend */ - AddCodeLine ("bpl *+3"); + unsigned L = GetLocalLabel (); + AddCodeLine ("bpl %s", LocalLabelName (L)); AddCodeLine ("dex"); - AddCodeHint ("x:!"); /* X is invalid now */ + g_defcodelabel (L); } } break; @@ -704,25 +719,17 @@ void g_getlocal (unsigned flags, int offs) 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 { - if (offs == 0) { - AddCodeLine ("ldx #$00"); - AddCodeLine ("lda (sp,x)"); - } else { - ldyconst (offs); - AddCodeLine ("ldx #$00"); - AddCodeLine ("lda (sp),y"); - } + ldyconst (offs); + AddCodeLine ("ldx #$00"); + AddCodeLine ("lda (sp),y"); if ((flags & CF_UNSIGNED) == 0) { - AddCodeLine ("bpl *+3"); + unsigned L = GetLocalLabel(); + AddCodeLine ("bpl %s", LocalLabelName (L)); AddCodeLine ("dex"); - AddCodeHint ("x:!"); /* X is invalid now */ + g_defcodelabel (L); } } break; @@ -742,23 +749,15 @@ void g_getlocal (unsigned flags, int offs) 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: @@ -784,54 +783,32 @@ void g_getind (unsigned flags, unsigned offs) case CF_CHAR: /* Character sized */ - if (offs) { - ldyconst (offs); - if (flags & CF_UNSIGNED) { - AddCodeLine ("jsr ldauidx"); - } else { - AddCodeLine ("jsr ldaidx"); - } - } else { - if (flags & CF_UNSIGNED) { - if (CodeSizeFactor > 250) { - AddCodeLine ("sta ptr1"); - AddCodeLine ("stx ptr1+1"); - AddCodeLine ("ldx #$00"); - AddCodeLine ("lda (ptr1,x)"); - } else { - AddCodeLine ("jsr ldaui"); - } - } else { - AddCodeLine ("jsr ldai"); - } - } + if (flags & CF_UNSIGNED) { + ldyconst (offs); + AddCodeLine ("jsr ldauidx"); + } else { + ldyconst (offs); + AddCodeLine ("jsr ldaidx"); + } break; case CF_INT: if (flags & CF_TEST) { - ldyconst (offs); + ldyconst (offs); AddCodeLine ("sta ptr1"); AddCodeLine ("stx ptr1+1"); AddCodeLine ("lda (ptr1),y"); 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"); } @@ -860,22 +837,22 @@ void g_leasp (int offs) ldaconst (offs); /* Load A with offset value */ AddCodeLine ("jsr leaasp"); /* Load effective address */ } else { + unsigned L = GetLocalLabel (); if (CPU == CPU_65C02 && offs == 1) { AddCodeLine ("lda sp"); AddCodeLine ("ldx sp+1"); AddCodeLine ("ina"); - AddCodeLine ("bne *+3"); + AddCodeLine ("bne %s", LocalLabelName (L)); AddCodeLine ("inx"); - AddCodeHint ("x:!"); /* Invalidate X */ } else { ldaconst (offs); AddCodeLine ("clc"); AddCodeLine ("ldx sp+1"); AddCodeLine ("adc sp"); - AddCodeLine ("bcc *+3"); + AddCodeLine ("bcc %s", LocalLabelName (L)); AddCodeLine ("inx"); - AddCodeHint ("x:!"); /* Invalidate X */ } + g_defcodelabel (L); } } } @@ -900,21 +877,18 @@ void g_leavariadic (int Offs) 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) { + unsigned L = GetLocalLabel(); AddCodeLine ("ldx sp+1"); AddCodeLine ("clc"); AddCodeLine ("adc sp"); - AddCodeLine ("bcc *+3"); + AddCodeLine ("bcc %s", LocalLabelName (L)); AddCodeLine ("inx"); - AddCodeHint ("x:!"); /* Invalidate X */ + g_defcodelabel (L); } else { AddCodeLine ("jsr leaasp"); } @@ -981,12 +955,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: @@ -998,41 +968,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; @@ -1041,12 +995,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: @@ -1104,30 +1054,18 @@ void g_putind (unsigned Flags, unsigned Offs) switch (Flags & CF_TYPE) { case CF_CHAR: - if (Offs) { - ldyconst (Offs); - AddCodeLine ("jsr staspidx"); - } else { - AddCodeLine ("jsr staspp"); - } + ldyconst (Offs); + AddCodeLine ("jsr staspidx"); break; case CF_INT: - if (Offs) { - ldyconst (Offs); - AddCodeLine ("jsr staxspidx"); - } else { - AddCodeLine ("jsr staxspp"); - } + ldyconst (Offs); + AddCodeLine ("jsr staxspidx"); break; case CF_LONG: - if (Offs) { - ldyconst (Offs); - AddCodeLine ("jsr steaxspidx"); - } else { - AddCodeLine ("jsr steaxspp"); - } + ldyconst (Offs); + AddCodeLine ("jsr steaxspidx"); break; default: @@ -1322,9 +1260,9 @@ void g_scale (unsigned flags, long val) } else if (val > 0) { /* Scale up */ - if ((p2 = powerof2 (val)) > 0 && p2 <= 3) { + if ((p2 = powerof2 (val)) > 0 && p2 <= 4) { - /* Factor is 2, 4 or 8, use special function */ + /* Factor is 2, 4, 8 and 16, use special function */ switch (flags & CF_TYPE) { case CF_CHAR: @@ -1337,11 +1275,11 @@ void g_scale (unsigned flags, long val) /* FALLTHROUGH */ case CF_INT: - if (CodeSizeFactor >= (p2+1)*130U) { + if (CodeSizeFactor >= (p2+1)*130U) { AddCodeLine ("stx tmp1"); while (p2--) { AddCodeLine ("asl a"); - AddCodeLine ("rol tmp1"); + AddCodeLine ("rol tmp1"); } AddCodeLine ("ldx tmp1"); } else { @@ -1377,9 +1315,9 @@ void g_scale (unsigned flags, long val) /* Scale down */ val = -val; - if ((p2 = powerof2 (val)) > 0 && p2 <= 3) { + if ((p2 = powerof2 (val)) > 0 && p2 <= 4) { - /* Factor is 2, 4 or 8, use special function */ + /* Factor is 2, 4, 8 and 16 use special function */ switch (flags & CF_TYPE) { case CF_CHAR: @@ -1457,6 +1395,8 @@ void g_scale (unsigned flags, long val) void g_addlocal (unsigned flags, int offs) /* Add a local variable to ax */ { + unsigned L; + /* Correct the offset and check it */ offs -= oursp; CheckLocalOffs (offs); @@ -1464,12 +1404,13 @@ void g_addlocal (unsigned flags, int offs) switch (flags & CF_TYPE) { case CF_CHAR: + L = GetLocalLabel(); AddCodeLine ("ldy #$%02X", offs & 0xFF); AddCodeLine ("clc"); AddCodeLine ("adc (sp),y"); - AddCodeLine ("bcc *+3"); + AddCodeLine ("bcc %s", LocalLabelName (L)); AddCodeLine ("inx"); - AddCodeHint ("x:!"); + g_defcodelabel (L); break; case CF_INT: @@ -1502,17 +1443,20 @@ void g_addlocal (unsigned flags, int offs) void g_addstatic (unsigned flags, unsigned long label, unsigned offs) /* Add a static variable to ax */ { + unsigned L; + /* Create the correct label name */ char* lbuf = GetLabelName (flags, label, offs); switch (flags & CF_TYPE) { case CF_CHAR: + L = GetLocalLabel(); AddCodeLine ("clc"); AddCodeLine ("adc %s", lbuf); - AddCodeLine ("bcc *+3"); + AddCodeLine ("bcc %s", LocalLabelName (L)); AddCodeLine ("inx"); - AddCodeHint ("x:!"); + g_defcodelabel (L); break; case CF_INT: @@ -1540,28 +1484,6 @@ 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 */ /*****************************************************************************/ @@ -1597,9 +1519,10 @@ void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs, AddCodeLine ("sta %s", lbuf); } if ((flags & CF_UNSIGNED) == 0) { - AddCodeLine ("bpl *+3"); + unsigned L = GetLocalLabel(); + AddCodeLine ("bpl %s", LocalLabelName (L)); AddCodeLine ("dex"); - AddCodeHint ("x:!"); /* Invalidate X */ + g_defcodelabel (L); } break; } @@ -1690,63 +1613,58 @@ void g_addeqlocal (unsigned flags, int offs, unsigned long val) case CF_CHAR: if (flags & CF_FORCECHAR) { - if (offs == 0) { - AddCodeLine ("ldx #$00"); - if (flags & CF_CONST) { - AddCodeLine ("clc"); - AddCodeLine ("lda #$%02X", (int)(val & 0xFF)); - AddCodeLine ("adc (sp,x)"); - AddCodeLine ("sta (sp,x)"); - } else { - AddCodeLine ("clc"); - AddCodeLine ("adc (sp,x)"); - AddCodeLine ("sta (sp,x)"); - } - } else { - ldyconst (offs); - AddCodeLine ("ldx #$00"); - if (flags & CF_CONST) { - AddCodeLine ("clc"); - AddCodeLine ("lda #$%02X", (int)(val & 0xFF)); - AddCodeLine ("adc (sp),y"); - AddCodeLine ("sta (sp),y"); - } else { - AddCodeLine ("clc"); - AddCodeLine ("adc (sp),y"); - AddCodeLine ("sta (sp),y"); - } - } + ldyconst (offs); + AddCodeLine ("ldx #$00"); + if (flags & CF_CONST) { + AddCodeLine ("clc"); + AddCodeLine ("lda #$%02X", (int)(val & 0xFF)); + AddCodeLine ("adc (sp),y"); + AddCodeLine ("sta (sp),y"); + } else { + AddCodeLine ("clc"); + AddCodeLine ("adc (sp),y"); + AddCodeLine ("sta (sp),y"); + } if ((flags & CF_UNSIGNED) == 0) { - AddCodeLine ("bpl *+3"); + unsigned L = GetLocalLabel(); + AddCodeLine ("bpl %s", LocalLabelName (L)); AddCodeLine ("dex"); - AddCodeHint ("x:!"); /* Invalidate X */ + g_defcodelabel (L); } break; } /* FALLTHROUGH */ case CF_INT: + ldyconst (offs); if (flags & CF_CONST) { - g_getimmed (flags, val, 0); - } - if (offs == 0) { - AddCodeLine ("jsr addeq0sp"); + 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 { - ldyconst (offs); - AddCodeLine ("jsr addeqysp"); - } + 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: @@ -1771,20 +1689,12 @@ void g_addeqind (unsigned flags, unsigned offs, unsigned long val) case CF_CHAR: AddCodeLine ("sta ptr1"); AddCodeLine ("stx ptr1+1"); - if (offs == 0) { - AddCodeLine ("ldx #$00"); - AddCodeLine ("lda #$%02X", (int)(val & 0xFF)); - AddCodeLine ("clc"); - AddCodeLine ("adc (ptr1,x)"); - AddCodeLine ("sta (ptr1,x)"); - } else { - AddCodeLine ("ldy #$%02X", offs); - AddCodeLine ("ldx #$00"); - AddCodeLine ("lda #$%02X", (int)(val & 0xFF)); - AddCodeLine ("clc"); - AddCodeLine ("adc (ptr1),y"); - AddCodeLine ("sta (ptr1),y"); - } + AddCodeLine ("ldy #$%02X", offs); + AddCodeLine ("ldx #$00"); + AddCodeLine ("lda #$%02X", (int)(val & 0xFF)); + AddCodeLine ("clc"); + AddCodeLine ("adc (ptr1),y"); + AddCodeLine ("sta (ptr1),y"); break; case CF_INT: @@ -1810,7 +1720,7 @@ void g_addeqind (unsigned flags, unsigned offs, unsigned long val) case CF_LONG: AddCodeLine ("jsr pushax"); /* Push the address */ - push (flags); /* Correct the internal sp */ + push (CF_PTR); /* Correct the internal sp */ g_getind (flags, offs); /* Fetch the value */ g_inc (flags, val); /* Increment value in primary */ g_putind (flags, offs); /* Store the value back */ @@ -1854,9 +1764,10 @@ void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs, AddCodeLine ("sta %s", lbuf); } if ((flags & CF_UNSIGNED) == 0) { - AddCodeLine ("bpl *+3"); + unsigned L = GetLocalLabel(); + AddCodeLine ("bpl %s", LocalLabelName (L)); AddCodeLine ("dex"); - AddCodeHint ("x:!"); /* Invalidate X */ + g_defcodelabel (L); } break; } @@ -1901,12 +1812,8 @@ void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs, 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 ("lda #$%02X", (unsigned char)val); + AddCodeLine ("jsr lsubeqa"); } else { g_getstatic (flags, label, offs); g_dec (flags, val); @@ -1952,9 +1859,10 @@ void g_subeqlocal (unsigned flags, int offs, unsigned long val) } AddCodeLine ("sta (sp),y"); if ((flags & CF_UNSIGNED) == 0) { - AddCodeLine ("bpl *+3"); + unsigned L = GetLocalLabel(); + AddCodeLine ("bpl %s", LocalLabelName (L)); AddCodeLine ("dex"); - AddCodeHint ("x:!"); /* Invalidate X */ + g_defcodelabel (L); } break; } @@ -1964,24 +1872,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: @@ -2006,20 +1906,12 @@ void g_subeqind (unsigned flags, unsigned offs, unsigned long val) case CF_CHAR: AddCodeLine ("sta ptr1"); AddCodeLine ("stx ptr1+1"); - if (offs == 0) { - AddCodeLine ("ldx #$00"); - AddCodeLine ("lda (ptr1,x)"); - AddCodeLine ("sec"); - AddCodeLine ("sbc #$%02X", (unsigned char)val); - AddCodeLine ("sta (ptr1,x)"); - } else { - AddCodeLine ("ldy #$%02X", offs); - AddCodeLine ("ldx #$00"); - AddCodeLine ("lda (ptr1),y"); - AddCodeLine ("sec"); - AddCodeLine ("sbc #$%02X", (unsigned char)val); - AddCodeLine ("sta (ptr1),y"); - } + AddCodeLine ("ldy #$%02X", offs); + AddCodeLine ("ldx #$00"); + AddCodeLine ("lda (ptr1),y"); + AddCodeLine ("sec"); + AddCodeLine ("sbc #$%02X", (unsigned char)val); + AddCodeLine ("sta (ptr1),y"); break; case CF_INT: @@ -2045,7 +1937,7 @@ void g_subeqind (unsigned flags, unsigned offs, unsigned long val) case CF_LONG: AddCodeLine ("jsr pushax"); /* Push the address */ - push (flags); /* Correct the internal sp */ + push (CF_PTR); /* Correct the internal sp */ g_getind (flags, offs); /* Fetch the value */ g_dec (flags, val); /* Increment value in primary */ g_putind (flags, offs); /* Store the value back */ @@ -2064,23 +1956,30 @@ 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; if (offs != 0) { /* We cannot address more then 256 bytes of locals anyway */ + L = GetLocalLabel(); CheckLocalOffs (offs); AddCodeLine ("clc"); AddCodeLine ("adc #$%02X", offs & 0xFF); - AddCodeLine ("bcc *+4"); /* Do also skip the CLC insn below */ + /* Do also skip the CLC insn below */ + AddCodeLine ("bcc %s", LocalLabelName (L)); AddCodeLine ("inx"); - AddCodeHint ("x:!"); /* Invalidate X */ } /* Add the current stackpointer value */ AddCodeLine ("clc"); + if (L != 0) { + /* Label was used above */ + g_defcodelabel (L); + } AddCodeLine ("adc sp"); AddCodeLine ("tay"); AddCodeLine ("txa"); @@ -2178,20 +2077,24 @@ void g_cmp (unsigned flags, unsigned long val) * will be set. */ { + unsigned L; + /* Check the size and determine operation */ switch (flags & CF_TYPE) { case CF_CHAR: if (flags & CF_FORCECHAR) { AddCodeLine ("cmp #$%02X", (unsigned char)val); - break; + break; } /* FALLTHROUGH */ case CF_INT: + L = GetLocalLabel(); AddCodeLine ("cmp #$%02X", (unsigned char)val); - AddCodeLine ("bne *+4"); + AddCodeLine ("bne %s", LocalLabelName (L)); AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); + g_defcodelabel (L); break; case CF_LONG: @@ -2297,36 +2200,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 { @@ -2405,15 +2292,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; } @@ -2426,54 +2331,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)); @@ -2481,7 +2339,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)); @@ -2598,7 +2456,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 @@ -2610,50 +2468,61 @@ 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"); + /* Handle some special cases */ + switch (val) { + + case 3: + AddCodeLine ("sta tmp1"); + 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; - } + 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 */ - case CF_INT: - break; + case CF_INT: + switch (val) { + case 3: + AddCodeLine ("jsr mulax3"); + return; + case 5: + AddCodeLine ("jsr mulax5"); + return; + case 10: + AddCodeLine ("jsr mulax10"); + return; + } + break; - case CF_LONG: - break; + case CF_LONG: + break; - default: - typeerror (flags); - } + 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 */ + /* 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); } @@ -2885,14 +2754,14 @@ void g_and (unsigned flags, unsigned long val) AddCodeLine ("and #$%02X", (unsigned char)(val >> 8)); AddCodeLine ("tax"); ldaconst (0); - } else { + } 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); + AddCodeLine ("and #$%02X", (unsigned char)val); } } } @@ -2936,10 +2805,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 @@ -2951,59 +2820,67 @@ void g_asr (unsigned flags, unsigned long val) case CF_CHAR: case CF_INT: - if (val >= 1 && val <= 3) { - 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 <= 3) { - 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) { - AddCodeLine ("bpl *+3"); - AddCodeLine ("dey"); - AddCodeHint ("y:!"); - } + 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; + AddCodeLine ("sty sreg+1"); + AddCodeLine ("sty sreg"); + return; + } + break; - default: - typeerror (flags); - } + default: + typeerror (flags); + } - /* If we go here, we didn't emit code. Push the lhs on stack and fall + /* 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); + */ + g_push (flags & ~CF_CONST, 0); } @@ -3017,10 +2894,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", }; @@ -3033,22 +2910,29 @@ void g_asl (unsigned flags, unsigned long val) case CF_CHAR: case CF_INT: - if (val >= 1 && val <= 3) { + 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 <= 3) { + if (val == 0) { + /* Nothing to do */ + return; + } else if (val >= 1 && val <= 4) { if (flags & CF_UNSIGNED) { AddCodeLine ("jsr shleax%ld", val); } else { @@ -3056,7 +2940,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"); @@ -3099,7 +2983,7 @@ void g_neg (unsigned flags) break; case CF_LONG: - AddCodeLine ("jsr negeax"); + AddCodeLine ("jsr negeax"); break; default: @@ -3170,7 +3054,7 @@ void g_inc (unsigned flags, unsigned long val) if (flags & CF_FORCECHAR) { if (CPU == CPU_65C02 && val <= 2) { while (val--) { - AddCodeLine ("ina"); + AddCodeLine ("ina"); } } else { AddCodeLine ("clc"); @@ -3182,11 +3066,11 @@ void g_inc (unsigned flags, unsigned long val) case CF_INT: if (CPU == CPU_65C02 && val == 1) { + unsigned L = GetLocalLabel(); AddCodeLine ("ina"); - AddCodeLine ("bne *+3"); + AddCodeLine ("bne %s", LocalLabelName (L)); AddCodeLine ("inx"); - /* Tell the optimizer that the X register may be invalid */ - AddCodeHint ("x:!"); + g_defcodelabel (L); } else if (CodeSizeFactor < 200) { /* Use jsr calls */ if (val <= 8) { @@ -3199,14 +3083,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(); AddCodeLine ("clc"); AddCodeLine ("adc #$%02X", (unsigned char) val); - AddCodeLine ("bcc *+3"); + AddCodeLine ("bcc %s", LocalLabelName (L)); AddCodeLine ("inx"); - /* Tell the optimizer that the X register may be invalid */ - AddCodeHint ("x:!"); + g_defcodelabel (L); } if (val >= 0x100) { AddCodeLine ("inx"); @@ -3214,12 +3098,13 @@ 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) { AddCodeLine ("adc #$%02X", (unsigned char) val); - /* Tell the optimizer that the X register may be invalid */ - AddCodeHint ("x:!"); } AddCodeLine ("pha"); AddCodeLine ("txa"); @@ -3288,12 +3173,12 @@ void g_dec (unsigned flags, unsigned long val) /* Inline the code */ if (val < 0x300) { if ((val & 0xFF) != 0) { + unsigned L = GetLocalLabel(); AddCodeLine ("sec"); AddCodeLine ("sbc #$%02X", (unsigned char) val); - AddCodeLine ("bcs *+3"); + AddCodeLine ("bcs %s", LocalLabelName (L)); AddCodeLine ("dex"); - /* Tell the optimizer that the X register may be invalid */ - AddCodeHint ("x:!"); + g_defcodelabel (L); } if (val >= 0x100) { AddCodeLine ("dex"); @@ -3305,8 +3190,6 @@ void g_dec (unsigned flags, unsigned long val) AddCodeLine ("sec"); if ((val & 0xFF) != 0) { AddCodeLine ("sbc #$%02X", (unsigned char) val); - /* Tell the optimizer that the X register may be invalid */ - AddCodeHint ("x:!"); } AddCodeLine ("pha"); AddCodeLine ("txa"); @@ -3348,10 +3231,12 @@ void g_eq (unsigned flags, unsigned long val) static char* ops [12] = { "toseq00", "toseqa0", "toseqax", "toseq00", "toseqa0", "toseqax", - 0, 0, "toseqeax", - 0, 0, "toseqeax", + 0, 0, "toseqeax", + 0, 0, "toseqeax", }; + unsigned L; + /* If the right hand side is const, the lhs is not on stack but still * in the primary register. */ @@ -3368,9 +3253,11 @@ void g_eq (unsigned flags, unsigned long val) /* FALLTHROUGH */ case CF_INT: + L = GetLocalLabel(); AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); - AddCodeLine ("bne *+4"); + AddCodeLine ("bne %s", LocalLabelName (L)); AddCodeLine ("cmp #$%02X", (unsigned char)val); + g_defcodelabel (L); AddCodeLine ("jsr booleq"); return; @@ -3404,6 +3291,7 @@ void g_ne (unsigned flags, unsigned long val) 0, 0, "tosneeax", }; + unsigned L; /* If the right hand side is const, the lhs is not on stack but still * in the primary register. @@ -3421,9 +3309,11 @@ void g_ne (unsigned flags, unsigned long val) /* FALLTHROUGH */ case CF_INT: + L = GetLocalLabel(); AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); - AddCodeLine ("bne *+4"); + AddCodeLine ("bne %s", LocalLabelName (L)); AddCodeLine ("cmp #$%02X", (unsigned char)val); + g_defcodelabel (L); AddCodeLine ("jsr boolne"); return; @@ -3451,10 +3341,10 @@ void g_lt (unsigned flags, unsigned long val) /* Test for less than */ { static char* ops [12] = { - "toslt00", "toslta0", "tosltax", - "tosult00", "tosulta0", "tosultax", - 0, 0, "toslteax", - 0, 0, "tosulteax", + "toslt00", "toslta0", "tosltax", + "tosult00", "tosulta0", "tosultax", + 0, 0, "toslteax", + 0, 0, "tosulteax", }; /* If the right hand side is const, the lhs is not on stack but still @@ -3471,37 +3361,47 @@ void g_lt (unsigned flags, unsigned long val) 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 */ + 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 ("txa"); + AddCodeLine ("lda sreg+1"); AddCodeLine ("jsr boollt"); return; } - /* Direct code only for unsigned data types */ - if (flags & CF_UNSIGNED) { - AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8)); - AddCodeLine ("bne *+4"); - AddCodeLine ("cmp #$%02X", (unsigned char)val); - AddCodeLine ("jsr boolult"); - return; - } - break; - - case CF_LONG: break; default: @@ -3537,16 +3437,31 @@ 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) { - AddCodeLine ("cmp #$%02X", (unsigned char)val); - if (flags & CF_UNSIGNED) { - AddCodeLine ("jsr boolule"); - } else { - AddCodeLine ("jsr boolle"); + case CF_CHAR: + if (flags & CF_FORCECHAR) { + if (flags & CF_UNSIGNED) { + if (val < 255) { + AddCodeLine ("cmp #$%02X", (unsigned char)val+1); + AddCodeLine ("jsr boolult"); + } else { + AddCodeLine ("cmp #$%02X", (unsigned char)val); + AddCodeLine ("jsr boolule"); + } + } else { + if (val < 127) { + AddCodeLine ("cmp #$%02X", (unsigned char)val+1); + AddCodeLine ("jsr boollt"); + } else { + AddCodeLine ("cmp #$%02X", (unsigned char)val); + AddCodeLine ("jsr boolle"); + } } return; } @@ -3554,10 +3469,17 @@ void g_le (unsigned flags, unsigned long val) 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 *+4"); - AddCodeLine ("cmp #$%02X", (unsigned char)val); - AddCodeLine ("jsr boolule"); + AddCodeLine ("bne %s", LocalLabelName (L)); + AddCodeLine ("cmp #$%02X", (unsigned char)val); + g_defcodelabel (L); + AddCodeLine ("jsr %s", Name); return; } break; @@ -3586,10 +3508,10 @@ void g_gt (unsigned flags, unsigned long val) /* Test for greater than */ { static char* ops [12] = { - "tosgt00", "tosgta0", "tosgtax", - "tosugt00", "tosugta0", "tosugtax", - 0, 0, "tosgteax", - 0, 0, "tosugteax", + "tosgt00", "tosgta0", "tosgtax", + "tosugt00", "tosugta0", "tosugtax", + 0, 0, "tosgteax", + 0, 0, "tosugteax", }; @@ -3598,54 +3520,75 @@ 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) { - AddCodeLine ("cmp #$%02X", (unsigned char)val); - 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 & 0xFF) { - AddCodeLine ("jsr boolugt"); - } else { - AddCodeLine ("jsr boolne"); - } - } else { - AddCodeLine ("jsr boolgt"); - } - return; - } - /* FALLTHROUGH */ + 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"); + } else { + AddCodeLine ("cmp #$%02X", (unsigned char)val); + AddCodeLine ("jsr boolugt"); + } + } else { + if (val < 127) { + AddCodeLine ("cmp #$%02X", (unsigned char)val+1); + AddCodeLine ("jsr boolge"); + } else { + AddCodeLine ("cmp #$%02X", (unsigned char)val); + AddCodeLine ("jsr boolgt"); + } + } + return; + } + /* FALLTHROUGH */ - 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 & 0xFFFF) == 0) { - AddCodeLine ("stx tmp1"); - AddCodeLine ("ora tmp1"); - AddCodeLine ("jsr boolne"); - } else { + 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 *+4"); - AddCodeLine ("cmp #$%02X", (unsigned char)val); - AddCodeLine ("jsr boolugt"); - } - return; + AddCodeLine ("bne %s", LocalLabelName (L)); + AddCodeLine ("cmp #$%02X", (unsigned char)val); + g_defcodelabel (L); + AddCodeLine ("jsr %s", Name); + } + return; } - break; + break; case CF_LONG: - break; + break; default: - typeerror (flags); + typeerror (flags); } /* If we go here, we didn't emit code. Push the lhs on stack and fall @@ -3698,20 +3641,39 @@ void g_ge (unsigned flags, unsigned long val) /* 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 *+4"); + AddCodeLine ("bne %s", LocalLabelName (L)); AddCodeLine ("cmp #$%02X", (unsigned char)val); + g_defcodelabel (L); AddCodeLine ("jsr booluge"); return; - } + } break; case CF_LONG: - break; + 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); + typeerror (flags); } /* If we go here, we didn't emit code. Push the lhs on stack and fall @@ -3773,7 +3735,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); } } @@ -3825,27 +3787,99 @@ void g_zerobytes (unsigned n) /*****************************************************************************/ -/* User supplied assembler code */ +/* Switch statement */ /*****************************************************************************/ -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_switch (Collection* Nodes, unsigned DefaultLabel, unsigned Depth) +/* Generate code for a switch statement */ { - if (Len >= 0) { - AddCodeLine ("%.*s", Len, Line); - } else { - AddCodeLine ("%s", Line); + 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); + } + + /* Walk over all nodes */ + for (I = 0; I < CollCount (Nodes); ++I) { + + /* Get the next case node */ + CaseNode* N = CollAtUnchecked (Nodes, I); + + /* If we have a next label, define it */ + if (NextLabel) { + g_defcodelabel (NextLabel); + NextLabel = 0; + } + + /* Do the compare */ + AddCodeLine (Compare, CN_GetValue (N)); + + /* 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)); } /*****************************************************************************/ -/* Inlined known functions */ +/* Inlined known functions */ /*****************************************************************************/