1 /*****************************************************************************/
5 /* 6502 code generator */
9 /* (C) 1998-2003 Ullrich von Bassewitz */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
63 /*****************************************************************************/
65 /*****************************************************************************/
69 /* Compiler relative stack pointer */
74 /*****************************************************************************/
76 /*****************************************************************************/
80 static void typeerror (unsigned type)
81 /* Print an error message about an invalid operand type */
83 Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPE);
88 static void CheckLocalOffs (unsigned Offs)
89 /* Check the offset into the stack for 8bit range */
92 /* Too many local vars */
93 Error ("Too many local variables");
99 static const char* GetLabelName (unsigned Flags, unsigned long Label, long Offs)
101 static char Buf [256]; /* Label name */
103 /* Create the correct label name */
104 switch (Flags & CF_ADDRMASK) {
107 /* Static memory cell */
109 xsprintf (Buf, sizeof (Buf), "%s%+ld", LocalLabelName (Label), Offs);
111 xsprintf (Buf, sizeof (Buf), "%s", LocalLabelName (Label));
118 xsprintf (Buf, sizeof (Buf), "_%s%+ld", (char*) Label, Offs);
120 xsprintf (Buf, sizeof (Buf), "_%s", (char*) Label);
125 /* Absolute address */
126 xsprintf (Buf, sizeof (Buf), "$%04X", (int)((Label+Offs) & 0xFFFF));
130 /* Variable in register bank */
131 xsprintf (Buf, sizeof (Buf), "regbank+%u", (unsigned)((Label+Offs) & 0xFFFF));
135 Internal ("Invalid address flags: %04X", Flags);
138 /* Return a pointer to the static buffer */
144 /*****************************************************************************/
145 /* Pre- and postamble */
146 /*****************************************************************************/
150 void g_preamble (void)
151 /* Generate the assembler code preamble */
153 /* Create a new (global) segment list and remember it */
157 /* Identify the compiler version */
159 AddTextLine ("; File generated by cc65 v %u.%u.%u",
160 VER_MAJOR, VER_MINOR, VER_PATCH);
163 /* Insert some object file options */
164 AddTextLine ("\t.fopt\t\tcompiler,\"cc65 v %u.%u.%u\"",
165 VER_MAJOR, VER_MINOR, VER_PATCH);
167 /* If we're producing code for some other CPU, switch the command set */
169 case CPU_6502: AddTextLine ("\t.setcpu\t\t\"6502\""); break;
170 case CPU_65SC02: AddTextLine ("\t.setcpu\t\t\"65SC02\""); break;
171 case CPU_65C02: AddTextLine ("\t.setcpu\t\t\"65C02\""); break;
172 case CPU_65816: AddTextLine ("\t.setcpu\t\t\"65816\""); break;
173 default: Internal ("Unknown CPU: %d", CPU);
177 AddTextLine ("\t.smart\t\ton");
179 /* Allow auto import for runtime library routines */
180 AddTextLine ("\t.autoimport\ton");
182 /* Switch the assembler into case sensitive mode */
183 AddTextLine ("\t.case\t\ton");
185 /* Tell the assembler if we want to generate debug info */
186 AddTextLine ("\t.debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
188 /* Import the stack pointer for direct auto variable access */
189 AddTextLine ("\t.importzp\tsp, sreg, regsave, regbank, tmp1, ptr1, ptr2");
191 /* Define long branch macros */
192 AddTextLine ("\t.macpack\tlongbranch");
197 void g_fileinfo (const char* Name, unsigned long Size, unsigned long MTime)
198 /* If debug info is enabled, place a file info into the source */
201 /* We have to place this into the global text segment, so it will
202 * appear before all .dbg line statements.
204 TS_AddLine (GS->Text, "\t.dbg\t\tfile, \"%s\", %lu, %lu", Name, Size, MTime);
210 /*****************************************************************************/
211 /* Segment support */
212 /*****************************************************************************/
216 void g_userodata (void)
217 /* Switch to the read only data segment */
219 UseDataSeg (SEG_RODATA);
224 void g_usedata (void)
225 /* Switch to the data segment */
227 UseDataSeg (SEG_DATA);
233 /* Switch to the bss segment */
235 UseDataSeg (SEG_BSS);
240 void g_segname (segment_t Seg, const char* Name)
241 /* Set the name of a segment */
245 /* Remember the new name */
246 NewSegName (Seg, Name);
248 /* Emit a segment directive for the data style segments */
250 case SEG_RODATA: S = CS->ROData; break;
251 case SEG_DATA: S = CS->Data; break;
252 case SEG_BSS: S = CS->BSS; break;
253 default: S = 0; break;
256 DS_AddLine (S, ".segment\t\"%s\"", Name);
262 /*****************************************************************************/
264 /*****************************************************************************/
268 unsigned sizeofarg (unsigned flags)
269 /* Return the size of a function argument type that is encoded in flags */
271 switch (flags & CF_TYPE) {
274 return (flags & CF_FORCECHAR)? 1 : 2;
294 int pop (unsigned flags)
295 /* Pop an argument of the given size */
297 return oursp += sizeofarg (flags);
302 int push (unsigned flags)
303 /* Push an argument of the given size */
305 return oursp -= sizeofarg (flags);
310 static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
311 /* The value in Offs is an offset to an address in a/x. Make sure, an object
312 * of the type given in Flags can be loaded or stored into this address by
313 * adding part of the offset to the address in ax, so that the remaining
314 * offset fits into an index register. Return the remaining offset.
317 /* If the offset is too large for a byte register, add the high byte
318 * of the offset to the primary. Beware: We need a special correction
319 * if the offset in the low byte will overflow in the operation.
321 unsigned O = Offs & ~0xFFU;
322 if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
323 /* We need to add the low byte also */
327 /* Do the correction if we need one */
329 g_inc (CF_INT | CF_CONST, O);
333 /* Return the new offset */
339 /*****************************************************************************/
340 /* Functions handling local labels */
341 /*****************************************************************************/
345 void g_defcodelabel (unsigned label)
346 /* Define a local code label */
348 CS_AddLabel (CS->Code, LocalLabelName (label));
353 void g_defdatalabel (unsigned label)
354 /* Define a local data label */
356 AddDataLine ("%s:", LocalLabelName (label));
361 /*****************************************************************************/
362 /* Functions handling global labels */
363 /*****************************************************************************/
367 void g_defgloblabel (const char* Name)
368 /* Define a global label with the given name */
370 /* Global labels are always data labels */
371 AddDataLine ("_%s:", Name);
376 void g_defexport (const char* Name, int ZP)
377 /* Export the given label */
380 AddTextLine ("\t.exportzp\t_%s", Name);
382 AddTextLine ("\t.export\t\t_%s", Name);
388 void g_defimport (const char* Name, int ZP)
389 /* Import the given label */
392 AddTextLine ("\t.importzp\t_%s", Name);
394 AddTextLine ("\t.import\t\t_%s", Name);
400 void g_importmainargs (void)
401 /* Forced import of a special symbol that handles arguments to main */
403 AddTextLine ("\t.forceimport\tinitmainargs");
408 /*****************************************************************************/
409 /* Load functions for various registers */
410 /*****************************************************************************/
414 static void ldaconst (unsigned val)
415 /* Load a with a constant */
417 AddCodeLine ("lda #$%02X", val & 0xFF);
422 static void ldxconst (unsigned val)
423 /* Load x with a constant */
425 AddCodeLine ("ldx #$%02X", val & 0xFF);
430 static void ldyconst (unsigned val)
431 /* Load y with a constant */
433 AddCodeLine ("ldy #$%02X", val & 0xFF);
438 /*****************************************************************************/
439 /* Function entry and exit */
440 /*****************************************************************************/
444 /* Remember the argument size of a function. The variable is set by g_enter
445 * and used by g_leave. If the functions gets its argument size by the caller
446 * (variable param list or function without prototype), g_enter will set the
452 void g_enter (unsigned flags, unsigned argsize)
453 /* Function prologue */
455 if ((flags & CF_FIXARGC) != 0) {
456 /* Just remember the argument size for the leave */
460 AddCodeLine ("jsr enter");
467 /* Function epilogue */
469 /* How many bytes of locals do we have to drop? */
472 /* If we didn't have a variable argument list, don't call leave */
475 /* Drop stackframe if needed */
479 AddCodeLine ("jsr incsp%d", k);
483 AddCodeLine ("jsr addysp");
490 /* Nothing to drop */
491 AddCodeLine ("jsr leave");
493 /* We've a stack frame to drop */
495 AddCodeLine ("jsr leavey");
499 /* Add the final rts */
505 /*****************************************************************************/
506 /* Register variables */
507 /*****************************************************************************/
511 void g_swap_regvars (int StackOffs, int RegOffs, unsigned Bytes)
512 /* Swap a register variable with a location on the stack */
514 /* Calculate the actual stack offset and check it */
516 CheckLocalOffs (StackOffs);
521 if (CodeSizeFactor < 165) {
522 ldyconst (StackOffs);
524 AddCodeLine ("jsr regswap1");
526 ldyconst (StackOffs);
527 AddCodeLine ("lda (sp),y");
528 AddCodeLine ("ldx regbank%+d", RegOffs);
529 AddCodeLine ("sta regbank%+d", RegOffs);
531 AddCodeLine ("sta (sp),y");
534 } else if (Bytes == 2) {
536 ldyconst (StackOffs);
538 AddCodeLine ("jsr regswap2");
542 ldyconst (StackOffs);
545 AddCodeLine ("jsr regswap");
551 void g_save_regvars (int RegOffs, unsigned Bytes)
552 /* Save register variables */
554 /* Don't loop for up to two bytes */
557 AddCodeLine ("lda regbank%+d", RegOffs);
558 AddCodeLine ("jsr pusha");
560 } else if (Bytes == 2) {
562 AddCodeLine ("lda regbank%+d", RegOffs);
563 AddCodeLine ("ldx regbank%+d", RegOffs+1);
564 AddCodeLine ("jsr pushax");
568 /* More than two bytes - loop */
569 unsigned Label = GetLocalLabel ();
571 ldyconst (Bytes - 1);
573 g_defcodelabel (Label);
574 AddCodeLine ("lda regbank%+d,x", RegOffs-1);
575 AddCodeLine ("sta (sp),y");
578 AddCodeLine ("bne %s", LocalLabelName (Label));
582 /* We pushed stuff, correct the stack pointer */
588 void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
589 /* Restore register variables */
591 /* Calculate the actual stack offset and check it */
593 CheckLocalOffs (StackOffs);
595 /* Don't loop for up to two bytes */
598 ldyconst (StackOffs);
599 AddCodeLine ("lda (sp),y");
600 AddCodeLine ("sta regbank%+d", RegOffs);
602 } else if (Bytes == 2) {
604 ldyconst (StackOffs);
605 AddCodeLine ("lda (sp),y");
606 AddCodeLine ("sta regbank%+d", RegOffs);
608 AddCodeLine ("lda (sp),y");
609 AddCodeLine ("sta regbank%+d", RegOffs+1);
611 } else if (Bytes == 3 && CodeSizeFactor >= 133) {
613 ldyconst (StackOffs);
614 AddCodeLine ("lda (sp),y");
615 AddCodeLine ("sta regbank%+d", RegOffs);
617 AddCodeLine ("lda (sp),y");
618 AddCodeLine ("sta regbank%+d", RegOffs+1);
620 AddCodeLine ("lda (sp),y");
621 AddCodeLine ("sta regbank%+d", RegOffs+2);
623 } else if (StackOffs <= RegOffs) {
625 /* More bytes, but the relation between the register offset in the
626 * register bank and the stack offset allows us to generate short
627 * code that uses just one index register.
629 unsigned Label = GetLocalLabel ();
630 ldyconst (StackOffs);
631 g_defcodelabel (Label);
632 AddCodeLine ("lda (sp),y");
633 AddCodeLine ("sta regbank%+d,y", RegOffs - StackOffs);
635 AddCodeLine ("cpy #$%02X", StackOffs + Bytes);
636 AddCodeLine ("bne %s", LocalLabelName (Label));
640 /* Ok, this is the generic code. We need to save X because the
641 * caller will only save A.
643 unsigned Label = GetLocalLabel ();
644 AddCodeLine ("stx tmp1");
645 ldyconst (StackOffs + Bytes - 1);
646 ldxconst (Bytes - 1);
647 g_defcodelabel (Label);
648 AddCodeLine ("lda (sp),y");
649 AddCodeLine ("sta regbank%+d,x", RegOffs);
652 AddCodeLine ("bpl %s", LocalLabelName (Label));
653 AddCodeLine ("ldx tmp1");
660 /*****************************************************************************/
661 /* Fetching memory cells */
662 /*****************************************************************************/
666 void g_getimmed (unsigned Flags, unsigned long Val, long Offs)
667 /* Load a constant into the primary register */
669 unsigned char B1, B2, B3, B4;
673 if ((Flags & CF_CONST) != 0) {
675 /* Numeric constant */
676 switch (Flags & CF_TYPE) {
679 if ((Flags & CF_FORCECHAR) != 0) {
685 ldxconst ((Val >> 8) & 0xFF);
686 ldaconst (Val & 0xFF);
690 /* Split the value into 4 bytes */
691 B1 = (unsigned char) (Val >> 0);
692 B2 = (unsigned char) (Val >> 8);
693 B3 = (unsigned char) (Val >> 16);
694 B4 = (unsigned char) (Val >> 24);
696 /* Remember which bytes are done */
700 AddCodeLine ("ldx #$%02X", B2);
703 AddCodeLine ("stx sreg");
707 AddCodeLine ("stx sreg+1");
710 if ((Done & 0x04) == 0 && B1 != B3) {
711 AddCodeLine ("lda #$%02X", B3);
712 AddCodeLine ("sta sreg");
715 if ((Done & 0x08) == 0 && B1 != B4) {
716 AddCodeLine ("lda #$%02X", B4);
717 AddCodeLine ("sta sreg+1");
720 AddCodeLine ("lda #$%02X", B1);
722 if ((Done & 0x04) == 0) {
724 AddCodeLine ("sta sreg");
726 if ((Done & 0x08) == 0) {
728 AddCodeLine ("sta sreg+1");
740 /* Some sort of label */
741 const char* Label = GetLabelName (Flags, Val, Offs);
743 /* Load the address into the primary */
744 AddCodeLine ("lda #<(%s)", Label);
745 AddCodeLine ("ldx #>(%s)", Label);
752 void g_getstatic (unsigned flags, unsigned long label, long offs)
753 /* Fetch an static memory cell into the primary register */
755 /* Create the correct label name */
756 const char* lbuf = GetLabelName (flags, label, offs);
758 /* Check the size and generate the correct load operation */
759 switch (flags & CF_TYPE) {
762 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
763 AddCodeLine ("lda %s", lbuf); /* load A from the label */
766 AddCodeLine ("lda %s", lbuf); /* load A from the label */
767 if (!(flags & CF_UNSIGNED)) {
768 /* Must sign extend */
769 unsigned L = GetLocalLabel ();
770 AddCodeLine ("bpl %s", LocalLabelName (L));
778 AddCodeLine ("lda %s", lbuf);
779 if (flags & CF_TEST) {
780 AddCodeLine ("ora %s+1", lbuf);
782 AddCodeLine ("ldx %s+1", lbuf);
787 if (flags & CF_TEST) {
788 AddCodeLine ("lda %s+3", lbuf);
789 AddCodeLine ("ora %s+2", lbuf);
790 AddCodeLine ("ora %s+1", lbuf);
791 AddCodeLine ("ora %s+0", lbuf);
793 AddCodeLine ("lda %s+3", lbuf);
794 AddCodeLine ("sta sreg+1");
795 AddCodeLine ("lda %s+2", lbuf);
796 AddCodeLine ("sta sreg");
797 AddCodeLine ("ldx %s+1", lbuf);
798 AddCodeLine ("lda %s", lbuf);
810 void g_getlocal (unsigned flags, int offs)
811 /* Fetch specified local object (local var). */
814 CheckLocalOffs (offs);
815 switch (flags & CF_TYPE) {
818 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
820 AddCodeLine ("lda (sp),y");
823 AddCodeLine ("ldx #$00");
824 AddCodeLine ("lda (sp),y");
825 if ((flags & CF_UNSIGNED) == 0) {
826 unsigned L = GetLocalLabel();
827 AddCodeLine ("bpl %s", LocalLabelName (L));
835 CheckLocalOffs (offs + 1);
836 if (flags & CF_TEST) {
838 AddCodeLine ("lda (sp),y");
840 AddCodeLine ("ora (sp),y");
843 AddCodeLine ("jsr ldaxysp");
849 AddCodeLine ("jsr ldeaxysp");
859 void g_getind (unsigned flags, unsigned offs)
860 /* Fetch the specified object type indirect through the primary register
861 * into the primary register
864 /* If the offset is greater than 255, add the part that is > 255 to
865 * the primary. This way we get an easy addition and use the low byte
868 offs = MakeByteOffs (flags, offs);
870 /* Handle the indirect fetch */
871 switch (flags & CF_TYPE) {
874 /* Character sized */
875 if (flags & CF_UNSIGNED) {
877 AddCodeLine ("jsr ldauidx");
880 AddCodeLine ("jsr ldaidx");
885 if (flags & CF_TEST) {
887 AddCodeLine ("sta ptr1");
888 AddCodeLine ("stx ptr1+1");
889 AddCodeLine ("lda (ptr1),y");
891 AddCodeLine ("ora (ptr1),y");
894 AddCodeLine ("jsr ldaxidx");
900 AddCodeLine ("jsr ldeaxidx");
901 if (flags & CF_TEST) {
902 AddCodeLine ("jsr tsteax");
914 void g_leasp (int offs)
915 /* Fetch the address of the specified symbol into the primary register */
917 /* Calculate the offset relative to sp */
920 /* For value 0 we do direct code */
922 AddCodeLine ("lda sp");
923 AddCodeLine ("ldx sp+1");
925 if (CodeSizeFactor < 300) {
926 ldaconst (offs); /* Load A with offset value */
927 AddCodeLine ("jsr leaasp"); /* Load effective address */
929 unsigned L = GetLocalLabel ();
930 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && offs == 1) {
931 AddCodeLine ("lda sp");
932 AddCodeLine ("ldx sp+1");
934 AddCodeLine ("bne %s", LocalLabelName (L));
939 AddCodeLine ("ldx sp+1");
940 AddCodeLine ("adc sp");
941 AddCodeLine ("bcc %s", LocalLabelName (L));
951 void g_leavariadic (int Offs)
952 /* Fetch the address of a parameter in a variadic function into the primary
956 unsigned ArgSizeOffs;
958 /* Calculate the offset relative to sp */
961 /* Get the offset of the parameter which is stored at sp+0 on function
962 * entry and check if this offset is reachable with a byte offset.
965 ArgSizeOffs = -oursp;
966 CheckLocalOffs (ArgSizeOffs);
968 /* Get the size of all parameters. */
969 ldyconst (ArgSizeOffs);
970 AddCodeLine ("lda (sp),y");
972 /* Add the value of the stackpointer */
973 if (CodeSizeFactor > 250) {
974 unsigned L = GetLocalLabel();
975 AddCodeLine ("ldx sp+1");
977 AddCodeLine ("adc sp");
978 AddCodeLine ("bcc %s", LocalLabelName (L));
982 AddCodeLine ("jsr leaasp");
985 /* Add the offset to the primary */
987 g_inc (CF_INT | CF_CONST, Offs);
988 } else if (Offs < 0) {
989 g_dec (CF_INT | CF_CONST, -Offs);
995 /*****************************************************************************/
996 /* Store into memory */
997 /*****************************************************************************/
1001 void g_putstatic (unsigned flags, unsigned long label, long offs)
1002 /* Store the primary register into the specified static memory cell */
1004 /* Create the correct label name */
1005 const char* lbuf = GetLabelName (flags, label, offs);
1007 /* Check the size and generate the correct store operation */
1008 switch (flags & CF_TYPE) {
1011 AddCodeLine ("sta %s", lbuf);
1015 AddCodeLine ("sta %s", lbuf);
1016 AddCodeLine ("stx %s+1", lbuf);
1020 AddCodeLine ("sta %s", lbuf);
1021 AddCodeLine ("stx %s+1", lbuf);
1022 AddCodeLine ("ldy sreg");
1023 AddCodeLine ("sty %s+2", lbuf);
1024 AddCodeLine ("ldy sreg+1");
1025 AddCodeLine ("sty %s+3", lbuf);
1036 void g_putlocal (unsigned Flags, int Offs, long Val)
1037 /* Put data into local object. */
1040 CheckLocalOffs (Offs);
1041 switch (Flags & CF_TYPE) {
1044 if (Flags & CF_CONST) {
1045 AddCodeLine ("lda #$%02X", (unsigned char) Val);
1048 AddCodeLine ("sta (sp),y");
1052 if (Flags & CF_CONST) {
1054 AddCodeLine ("lda #$%02X", (unsigned char) (Val >> 8));
1055 AddCodeLine ("sta (sp),y");
1056 if ((Flags & CF_NOKEEP) == 0) {
1057 /* Place high byte into X */
1058 AddCodeLine ("tax");
1060 if ((Val & 0xFF) == Offs+1) {
1061 /* The value we need is already in Y */
1062 AddCodeLine ("tya");
1063 AddCodeLine ("dey");
1065 AddCodeLine ("dey");
1066 AddCodeLine ("lda #$%02X", (unsigned char) Val);
1068 AddCodeLine ("sta (sp),y");
1070 if ((Flags & CF_NOKEEP) == 0 || CodeSizeFactor < 160) {
1072 AddCodeLine ("jsr staxysp");
1075 AddCodeLine ("sta (sp),y");
1076 AddCodeLine ("iny");
1077 AddCodeLine ("txa");
1078 AddCodeLine ("sta (sp),y");
1084 if (Flags & CF_CONST) {
1085 g_getimmed (Flags, Val, 0);
1088 AddCodeLine ("jsr steaxysp");
1099 void g_putind (unsigned Flags, unsigned Offs)
1100 /* Store the specified object type in the primary register at the address
1101 * on the top of the stack
1104 /* We can handle offsets below $100 directly, larger offsets must be added
1105 * to the address. Since a/x is in use, best code is achieved by adding
1106 * just the high byte. Be sure to check if the low byte will overflow while
1109 if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
1111 /* Overflow - we need to add the low byte also */
1112 AddCodeLine ("ldy #$00");
1113 AddCodeLine ("clc");
1114 AddCodeLine ("pha");
1115 AddCodeLine ("lda #$%02X", Offs & 0xFF);
1116 AddCodeLine ("adc (sp),y");
1117 AddCodeLine ("sta (sp),y");
1118 AddCodeLine ("iny");
1119 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1120 AddCodeLine ("adc (sp),y");
1121 AddCodeLine ("sta (sp),y");
1122 AddCodeLine ("pla");
1124 /* Complete address is on stack, new offset is zero */
1127 } else if ((Offs & 0xFF00) != 0) {
1129 /* We can just add the high byte */
1130 AddCodeLine ("ldy #$01");
1131 AddCodeLine ("clc");
1132 AddCodeLine ("pha");
1133 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1134 AddCodeLine ("adc (sp),y");
1135 AddCodeLine ("sta (sp),y");
1136 AddCodeLine ("pla");
1138 /* Offset is now just the low byte */
1142 /* Check the size and determine operation */
1143 switch (Flags & CF_TYPE) {
1147 AddCodeLine ("jsr staspidx");
1152 AddCodeLine ("jsr staxspidx");
1157 AddCodeLine ("jsr steaxspidx");
1165 /* Pop the argument which is always a pointer */
1171 /*****************************************************************************/
1172 /* type conversion and similiar stuff */
1173 /*****************************************************************************/
1177 void g_toslong (unsigned flags)
1178 /* Make sure, the value on TOS is a long. Convert if necessary */
1180 switch (flags & CF_TYPE) {
1184 if (flags & CF_UNSIGNED) {
1185 AddCodeLine ("jsr tosulong");
1187 AddCodeLine ("jsr toslong");
1202 void g_tosint (unsigned flags)
1203 /* Make sure, the value on TOS is an int. Convert if necessary */
1205 switch (flags & CF_TYPE) {
1212 AddCodeLine ("jsr tosint");
1223 void g_regint (unsigned Flags)
1224 /* Make sure, the value in the primary register an int. Convert if necessary */
1228 switch (Flags & CF_TYPE) {
1231 if (Flags & CF_FORCECHAR) {
1232 /* Conversion is from char */
1233 if (Flags & CF_UNSIGNED) {
1234 AddCodeLine ("ldx #$00");
1236 L = GetLocalLabel();
1237 AddCodeLine ("ldx #$00");
1238 AddCodeLine ("cmp #$80");
1239 AddCodeLine ("bcc %s", LocalLabelName (L));
1240 AddCodeLine ("dex");
1257 void g_reglong (unsigned Flags)
1258 /* Make sure, the value in the primary register a long. Convert if necessary */
1262 switch (Flags & CF_TYPE) {
1265 if (Flags & CF_FORCECHAR) {
1266 /* Conversion is from char */
1267 if (Flags & CF_UNSIGNED) {
1268 if (CodeSizeFactor >= 200) {
1269 AddCodeLine ("ldx #$00");
1270 AddCodeLine ("stx sreg");
1271 AddCodeLine ("stx sreg+1");
1273 AddCodeLine ("jsr aulong");
1276 if (CodeSizeFactor >= 366) {
1277 L = GetLocalLabel();
1278 AddCodeLine ("ldx #$00");
1279 AddCodeLine ("cmp #$80");
1280 AddCodeLine ("bcc %s", LocalLabelName (L));
1281 AddCodeLine ("dex");
1283 AddCodeLine ("stx sreg");
1284 AddCodeLine ("stx sreg+1");
1286 AddCodeLine ("jsr along");
1293 if (Flags & CF_UNSIGNED) {
1294 if (CodeSizeFactor >= 200) {
1296 AddCodeLine ("sty sreg");
1297 AddCodeLine ("sty sreg+1");
1299 AddCodeLine ("jsr axulong");
1302 AddCodeLine ("jsr axlong");
1316 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1317 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1318 * value, that corresponds to the value on TOS, rhs corresponds to the value
1319 * in (e)ax. The return value is the the flags value for the resulting type.
1322 unsigned ltype, rtype;
1325 /* Get the type spec from the flags */
1326 ltype = lhs & CF_TYPE;
1327 rtype = rhs & CF_TYPE;
1329 /* Check if a conversion is needed */
1330 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1331 /* We must promote the primary register to long */
1333 /* Get the new rhs type */
1334 rhs = (rhs & ~CF_TYPE) | CF_LONG;
1336 } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1337 /* We must promote the lhs to long */
1343 /* Get the new rhs type */
1344 lhs = (lhs & ~CF_TYPE) | CF_LONG;
1348 /* Determine the result type for the operation:
1349 * - The result is const if both operands are const.
1350 * - The result is unsigned if one of the operands is unsigned.
1351 * - The result is long if one of the operands is long.
1352 * - Otherwise the result is int sized.
1354 result = (lhs & CF_CONST) & (rhs & CF_CONST);
1355 result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1356 if (rtype == CF_LONG || ltype == CF_LONG) {
1366 unsigned g_typecast (unsigned lhs, unsigned rhs)
1367 /* Cast the value in the primary register to the operand size that is flagged
1368 * by the lhs value. Return the result value.
1371 unsigned ltype, rtype;
1373 /* Get the type spec from the flags */
1374 ltype = lhs & CF_TYPE;
1375 rtype = rhs & CF_TYPE;
1377 /* Check if a conversion is needed */
1378 if ((rhs & CF_CONST) == 0) {
1379 if (ltype == CF_LONG && rtype != CF_LONG) {
1380 /* We must promote the primary register to long */
1382 } else if (ltype == CF_INT && rtype != CF_INT) {
1383 /* We must promote the primary register to int */
1388 /* Do not need any other action. If the left type is int, and the primary
1389 * register is long, it will be automagically truncated. If the right hand
1390 * side is const, it is not located in the primary register and handled by
1391 * the expression parser code.
1394 /* Result is const if the right hand side was const */
1395 lhs |= (rhs & CF_CONST);
1397 /* The resulting type is that of the left hand side (that's why you called
1405 void g_scale (unsigned flags, long val)
1406 /* Scale the value in the primary register by the given value. If val is positive,
1407 * scale up, is val is negative, scale down. This function is used to scale
1408 * the operands or results of pointer arithmetic by the size of the type, the
1409 * pointer points to.
1414 /* Value may not be zero */
1416 Internal ("Data type has no size");
1417 } else if (val > 0) {
1420 if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
1422 /* Factor is 2, 4, 8 and 16, use special function */
1423 switch (flags & CF_TYPE) {
1426 if (flags & CF_FORCECHAR) {
1428 AddCodeLine ("asl a");
1435 if (CodeSizeFactor >= (p2+1)*130U) {
1436 AddCodeLine ("stx tmp1");
1438 AddCodeLine ("asl a");
1439 AddCodeLine ("rol tmp1");
1441 AddCodeLine ("ldx tmp1");
1443 if (flags & CF_UNSIGNED) {
1444 AddCodeLine ("jsr shlax%d", p2);
1446 AddCodeLine ("jsr aslax%d", p2);
1452 if (flags & CF_UNSIGNED) {
1453 AddCodeLine ("jsr shleax%d", p2);
1455 AddCodeLine ("jsr asleax%d", p2);
1464 } else if (val != 1) {
1466 /* Use a multiplication instead */
1467 g_mul (flags | CF_CONST, val);
1475 if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
1477 /* Factor is 2, 4, 8 and 16 use special function */
1478 switch (flags & CF_TYPE) {
1481 if (flags & CF_FORCECHAR) {
1482 if (flags & CF_UNSIGNED) {
1484 AddCodeLine ("lsr a");
1487 } else if (p2 <= 2) {
1488 AddCodeLine ("cmp #$80");
1489 AddCodeLine ("ror a");
1496 if (flags & CF_UNSIGNED) {
1497 if (CodeSizeFactor >= (p2+1)*130U) {
1498 AddCodeLine ("stx tmp1");
1500 AddCodeLine ("lsr tmp1");
1501 AddCodeLine ("ror a");
1503 AddCodeLine ("ldx tmp1");
1505 AddCodeLine ("jsr lsrax%d", p2);
1508 if (CodeSizeFactor >= (p2+1)*150U) {
1509 AddCodeLine ("stx tmp1");
1511 AddCodeLine ("cpx #$80");
1512 AddCodeLine ("ror tmp1");
1513 AddCodeLine ("ror a");
1515 AddCodeLine ("ldx tmp1");
1517 AddCodeLine ("jsr asrax%d", p2);
1523 if (flags & CF_UNSIGNED) {
1524 AddCodeLine ("jsr lsreax%d", p2);
1526 AddCodeLine ("jsr asreax%d", p2);
1535 } else if (val != 1) {
1537 /* Use a division instead */
1538 g_div (flags | CF_CONST, val);
1546 /*****************************************************************************/
1547 /* Adds and subs of variables fix a fixed address */
1548 /*****************************************************************************/
1552 void g_addlocal (unsigned flags, int offs)
1553 /* Add a local variable to ax */
1557 /* Correct the offset and check it */
1559 CheckLocalOffs (offs);
1561 switch (flags & CF_TYPE) {
1564 L = GetLocalLabel();
1565 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1566 AddCodeLine ("clc");
1567 AddCodeLine ("adc (sp),y");
1568 AddCodeLine ("bcc %s", LocalLabelName (L));
1569 AddCodeLine ("inx");
1574 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1575 AddCodeLine ("clc");
1576 AddCodeLine ("adc (sp),y");
1577 AddCodeLine ("pha");
1578 AddCodeLine ("txa");
1579 AddCodeLine ("iny");
1580 AddCodeLine ("adc (sp),y");
1581 AddCodeLine ("tax");
1582 AddCodeLine ("pla");
1586 /* Do it the old way */
1588 g_getlocal (flags, offs);
1600 void g_addstatic (unsigned flags, unsigned long label, long offs)
1601 /* Add a static variable to ax */
1605 /* Create the correct label name */
1606 const char* lbuf = GetLabelName (flags, label, offs);
1608 switch (flags & CF_TYPE) {
1611 L = GetLocalLabel();
1612 AddCodeLine ("clc");
1613 AddCodeLine ("adc %s", lbuf);
1614 AddCodeLine ("bcc %s", LocalLabelName (L));
1615 AddCodeLine ("inx");
1620 AddCodeLine ("clc");
1621 AddCodeLine ("adc %s", lbuf);
1622 AddCodeLine ("tay");
1623 AddCodeLine ("txa");
1624 AddCodeLine ("adc %s+1", lbuf);
1625 AddCodeLine ("tax");
1626 AddCodeLine ("tya");
1630 /* Do it the old way */
1632 g_getstatic (flags, label, offs);
1644 /*****************************************************************************/
1645 /* Special op= functions */
1646 /*****************************************************************************/
1650 void g_addeqstatic (unsigned flags, unsigned long label, long offs,
1652 /* Emit += for a static variable */
1654 /* Create the correct label name */
1655 const char* lbuf = GetLabelName (flags, label, offs);
1657 /* Check the size and determine operation */
1658 switch (flags & CF_TYPE) {
1661 if (flags & CF_FORCECHAR) {
1662 AddCodeLine ("ldx #$00");
1663 if (flags & CF_CONST) {
1665 AddCodeLine ("inc %s", lbuf);
1666 AddCodeLine ("lda %s", lbuf);
1668 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1669 AddCodeLine ("clc");
1670 AddCodeLine ("adc %s", lbuf);
1671 AddCodeLine ("sta %s", lbuf);
1674 AddCodeLine ("clc");
1675 AddCodeLine ("adc %s", lbuf);
1676 AddCodeLine ("sta %s", lbuf);
1678 if ((flags & CF_UNSIGNED) == 0) {
1679 unsigned L = GetLocalLabel();
1680 AddCodeLine ("bpl %s", LocalLabelName (L));
1681 AddCodeLine ("dex");
1689 if (flags & CF_CONST) {
1691 unsigned L = GetLocalLabel ();
1692 AddCodeLine ("inc %s", lbuf);
1693 AddCodeLine ("bne %s", LocalLabelName (L));
1694 AddCodeLine ("inc %s+1", lbuf);
1696 AddCodeLine ("lda %s", lbuf); /* Hmmm... */
1697 AddCodeLine ("ldx %s+1", lbuf);
1699 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1700 AddCodeLine ("clc");
1701 AddCodeLine ("adc %s", lbuf);
1702 AddCodeLine ("sta %s", lbuf);
1704 unsigned L = GetLocalLabel ();
1705 AddCodeLine ("bcc %s", LocalLabelName (L));
1706 AddCodeLine ("inc %s+1", lbuf);
1708 AddCodeLine ("ldx %s+1", lbuf);
1710 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1711 AddCodeLine ("adc %s+1", lbuf);
1712 AddCodeLine ("sta %s+1", lbuf);
1713 AddCodeLine ("tax");
1714 AddCodeLine ("lda %s", lbuf);
1718 AddCodeLine ("clc");
1719 AddCodeLine ("adc %s", lbuf);
1720 AddCodeLine ("sta %s", lbuf);
1721 AddCodeLine ("txa");
1722 AddCodeLine ("adc %s+1", lbuf);
1723 AddCodeLine ("sta %s+1", lbuf);
1724 AddCodeLine ("tax");
1725 AddCodeLine ("lda %s", lbuf);
1730 if (flags & CF_CONST) {
1732 AddCodeLine ("ldy #<(%s)", lbuf);
1733 AddCodeLine ("sty ptr1");
1734 AddCodeLine ("ldy #>(%s)", lbuf);
1736 AddCodeLine ("jsr laddeq1");
1738 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1739 AddCodeLine ("jsr laddeqa");
1742 g_getstatic (flags, label, offs);
1744 g_putstatic (flags, label, offs);
1747 AddCodeLine ("ldy #<(%s)", lbuf);
1748 AddCodeLine ("sty ptr1");
1749 AddCodeLine ("ldy #>(%s)", lbuf);
1750 AddCodeLine ("jsr laddeq");
1761 void g_addeqlocal (unsigned flags, int offs, unsigned long val)
1762 /* Emit += for a local variable */
1764 /* Calculate the true offset, check it, load it into Y */
1766 CheckLocalOffs (offs);
1768 /* Check the size and determine operation */
1769 switch (flags & CF_TYPE) {
1772 if (flags & CF_FORCECHAR) {
1774 AddCodeLine ("ldx #$00");
1775 if (flags & CF_CONST) {
1776 AddCodeLine ("clc");
1777 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1778 AddCodeLine ("adc (sp),y");
1779 AddCodeLine ("sta (sp),y");
1781 AddCodeLine ("clc");
1782 AddCodeLine ("adc (sp),y");
1783 AddCodeLine ("sta (sp),y");
1785 if ((flags & CF_UNSIGNED) == 0) {
1786 unsigned L = GetLocalLabel();
1787 AddCodeLine ("bpl %s", LocalLabelName (L));
1788 AddCodeLine ("dex");
1797 if (flags & CF_CONST) {
1798 if (CodeSizeFactor >= 400) {
1799 AddCodeLine ("clc");
1800 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1801 AddCodeLine ("adc (sp),y");
1802 AddCodeLine ("sta (sp),y");
1803 AddCodeLine ("iny");
1804 AddCodeLine ("lda #$%02X", (int) ((val >> 8) & 0xFF));
1805 AddCodeLine ("adc (sp),y");
1806 AddCodeLine ("sta (sp),y");
1807 AddCodeLine ("tax");
1808 AddCodeLine ("dey");
1809 AddCodeLine ("lda (sp),y");
1811 g_getimmed (flags, val, 0);
1812 AddCodeLine ("jsr addeqysp");
1815 AddCodeLine ("jsr addeqysp");
1820 if (flags & CF_CONST) {
1821 g_getimmed (flags, val, 0);
1824 AddCodeLine ("jsr laddeqysp");
1834 void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1835 /* Emit += for the location with address in ax */
1837 /* If the offset is too large for a byte register, add the high byte
1838 * of the offset to the primary. Beware: We need a special correction
1839 * if the offset in the low byte will overflow in the operation.
1841 offs = MakeByteOffs (flags, offs);
1843 /* Check the size and determine operation */
1844 switch (flags & CF_TYPE) {
1847 AddCodeLine ("sta ptr1");
1848 AddCodeLine ("stx ptr1+1");
1849 AddCodeLine ("ldy #$%02X", offs);
1850 AddCodeLine ("ldx #$00");
1851 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1852 AddCodeLine ("clc");
1853 AddCodeLine ("adc (ptr1),y");
1854 AddCodeLine ("sta (ptr1),y");
1858 if (CodeSizeFactor >= 200) {
1859 /* Lots of code, use only if size is not important */
1860 AddCodeLine ("sta ptr1");
1861 AddCodeLine ("stx ptr1+1");
1862 AddCodeLine ("ldy #$%02X", offs);
1863 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1864 AddCodeLine ("clc");
1865 AddCodeLine ("adc (ptr1),y");
1866 AddCodeLine ("sta (ptr1),y");
1867 AddCodeLine ("pha");
1868 AddCodeLine ("iny");
1869 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1870 AddCodeLine ("adc (ptr1),y");
1871 AddCodeLine ("sta (ptr1),y");
1872 AddCodeLine ("tax");
1873 AddCodeLine ("pla");
1879 AddCodeLine ("jsr pushax"); /* Push the address */
1880 push (CF_PTR); /* Correct the internal sp */
1881 g_getind (flags, offs); /* Fetch the value */
1882 g_inc (flags, val); /* Increment value in primary */
1883 g_putind (flags, offs); /* Store the value back */
1893 void g_subeqstatic (unsigned flags, unsigned long label, long offs,
1895 /* Emit -= for a static variable */
1897 /* Create the correct label name */
1898 const char* lbuf = GetLabelName (flags, label, offs);
1900 /* Check the size and determine operation */
1901 switch (flags & CF_TYPE) {
1904 if (flags & CF_FORCECHAR) {
1905 AddCodeLine ("ldx #$00");
1906 if (flags & CF_CONST) {
1908 AddCodeLine ("dec %s", lbuf);
1909 AddCodeLine ("lda %s", lbuf);
1911 AddCodeLine ("sec");
1912 AddCodeLine ("lda %s", lbuf);
1913 AddCodeLine ("sbc #$%02X", (int)(val & 0xFF));
1914 AddCodeLine ("sta %s", lbuf);
1917 AddCodeLine ("eor #$FF");
1918 AddCodeLine ("sec");
1919 AddCodeLine ("adc %s", lbuf);
1920 AddCodeLine ("sta %s", lbuf);
1922 if ((flags & CF_UNSIGNED) == 0) {
1923 unsigned L = GetLocalLabel();
1924 AddCodeLine ("bpl %s", LocalLabelName (L));
1925 AddCodeLine ("dex");
1933 AddCodeLine ("sec");
1934 if (flags & CF_CONST) {
1935 AddCodeLine ("lda %s", lbuf);
1936 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1937 AddCodeLine ("sta %s", lbuf);
1939 unsigned L = GetLocalLabel ();
1940 AddCodeLine ("bcs %s", LocalLabelName (L));
1941 AddCodeLine ("dec %s+1", lbuf);
1943 AddCodeLine ("ldx %s+1", lbuf);
1945 AddCodeLine ("lda %s+1", lbuf);
1946 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1947 AddCodeLine ("sta %s+1", lbuf);
1948 AddCodeLine ("tax");
1949 AddCodeLine ("lda %s", lbuf);
1952 AddCodeLine ("eor #$FF");
1953 AddCodeLine ("adc %s", lbuf);
1954 AddCodeLine ("sta %s", lbuf);
1955 AddCodeLine ("txa");
1956 AddCodeLine ("eor #$FF");
1957 AddCodeLine ("adc %s+1", lbuf);
1958 AddCodeLine ("sta %s+1", lbuf);
1959 AddCodeLine ("tax");
1960 AddCodeLine ("lda %s", lbuf);
1965 if (flags & CF_CONST) {
1967 AddCodeLine ("ldy #<(%s)", lbuf);
1968 AddCodeLine ("sty ptr1");
1969 AddCodeLine ("ldy #>(%s)", lbuf);
1970 AddCodeLine ("lda #$%02X", (unsigned char)val);
1971 AddCodeLine ("jsr lsubeqa");
1973 g_getstatic (flags, label, offs);
1975 g_putstatic (flags, label, offs);
1978 AddCodeLine ("ldy #<(%s)", lbuf);
1979 AddCodeLine ("sty ptr1");
1980 AddCodeLine ("ldy #>(%s)", lbuf);
1981 AddCodeLine ("jsr lsubeq");
1992 void g_subeqlocal (unsigned flags, int offs, unsigned long val)
1993 /* Emit -= for a local variable */
1995 /* Calculate the true offset, check it, load it into Y */
1997 CheckLocalOffs (offs);
1999 /* Check the size and determine operation */
2000 switch (flags & CF_TYPE) {
2003 if (flags & CF_FORCECHAR) {
2005 AddCodeLine ("ldx #$00");
2006 AddCodeLine ("sec");
2007 if (flags & CF_CONST) {
2008 AddCodeLine ("lda (sp),y");
2009 AddCodeLine ("sbc #$%02X", (unsigned char)val);
2011 AddCodeLine ("eor #$FF");
2012 AddCodeLine ("adc (sp),y");
2014 AddCodeLine ("sta (sp),y");
2015 if ((flags & CF_UNSIGNED) == 0) {
2016 unsigned L = GetLocalLabel();
2017 AddCodeLine ("bpl %s", LocalLabelName (L));
2018 AddCodeLine ("dex");
2026 if (flags & CF_CONST) {
2027 g_getimmed (flags, val, 0);
2030 AddCodeLine ("jsr subeqysp");
2034 if (flags & CF_CONST) {
2035 g_getimmed (flags, val, 0);
2038 AddCodeLine ("jsr lsubeqysp");
2048 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
2049 /* Emit -= for the location with address in ax */
2051 /* If the offset is too large for a byte register, add the high byte
2052 * of the offset to the primary. Beware: We need a special correction
2053 * if the offset in the low byte will overflow in the operation.
2055 offs = MakeByteOffs (flags, offs);
2057 /* Check the size and determine operation */
2058 switch (flags & CF_TYPE) {
2061 AddCodeLine ("sta ptr1");
2062 AddCodeLine ("stx ptr1+1");
2063 AddCodeLine ("ldy #$%02X", offs);
2064 AddCodeLine ("ldx #$00");
2065 AddCodeLine ("lda (ptr1),y");
2066 AddCodeLine ("sec");
2067 AddCodeLine ("sbc #$%02X", (unsigned char)val);
2068 AddCodeLine ("sta (ptr1),y");
2072 if (CodeSizeFactor >= 200) {
2073 /* Lots of code, use only if size is not important */
2074 AddCodeLine ("sta ptr1");
2075 AddCodeLine ("stx ptr1+1");
2076 AddCodeLine ("ldy #$%02X", offs);
2077 AddCodeLine ("lda (ptr1),y");
2078 AddCodeLine ("sec");
2079 AddCodeLine ("sbc #$%02X", (unsigned char)val);
2080 AddCodeLine ("sta (ptr1),y");
2081 AddCodeLine ("pha");
2082 AddCodeLine ("iny");
2083 AddCodeLine ("lda (ptr1),y");
2084 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
2085 AddCodeLine ("sta (ptr1),y");
2086 AddCodeLine ("tax");
2087 AddCodeLine ("pla");
2093 AddCodeLine ("jsr pushax"); /* Push the address */
2094 push (CF_PTR); /* Correct the internal sp */
2095 g_getind (flags, offs); /* Fetch the value */
2096 g_dec (flags, val); /* Increment value in primary */
2097 g_putind (flags, offs); /* Store the value back */
2107 /*****************************************************************************/
2108 /* Add a variable address to the value in ax */
2109 /*****************************************************************************/
2113 void g_addaddr_local (unsigned flags attribute ((unused)), int offs)
2114 /* Add the address of a local variable to ax */
2118 /* Add the offset */
2121 /* We cannot address more then 256 bytes of locals anyway */
2122 L = GetLocalLabel();
2123 CheckLocalOffs (offs);
2124 AddCodeLine ("clc");
2125 AddCodeLine ("adc #$%02X", offs & 0xFF);
2126 /* Do also skip the CLC insn below */
2127 AddCodeLine ("bcc %s", LocalLabelName (L));
2128 AddCodeLine ("inx");
2131 /* Add the current stackpointer value */
2132 AddCodeLine ("clc");
2134 /* Label was used above */
2137 AddCodeLine ("adc sp");
2138 AddCodeLine ("tay");
2139 AddCodeLine ("txa");
2140 AddCodeLine ("adc sp+1");
2141 AddCodeLine ("tax");
2142 AddCodeLine ("tya");
2147 void g_addaddr_static (unsigned flags, unsigned long label, long offs)
2148 /* Add the address of a static variable to ax */
2150 /* Create the correct label name */
2151 const char* lbuf = GetLabelName (flags, label, offs);
2153 /* Add the address to the current ax value */
2154 AddCodeLine ("clc");
2155 AddCodeLine ("adc #<(%s)", lbuf);
2156 AddCodeLine ("tay");
2157 AddCodeLine ("txa");
2158 AddCodeLine ("adc #>(%s)", lbuf);
2159 AddCodeLine ("tax");
2160 AddCodeLine ("tya");
2165 /*****************************************************************************/
2167 /*****************************************************************************/
2171 void g_save (unsigned flags)
2172 /* Copy primary register to hold register. */
2174 /* Check the size and determine operation */
2175 switch (flags & CF_TYPE) {
2178 if (flags & CF_FORCECHAR) {
2179 AddCodeLine ("pha");
2185 AddCodeLine ("sta regsave");
2186 AddCodeLine ("stx regsave+1");
2190 AddCodeLine ("jsr saveeax");
2200 void g_restore (unsigned flags)
2201 /* Copy hold register to primary. */
2203 /* Check the size and determine operation */
2204 switch (flags & CF_TYPE) {
2207 if (flags & CF_FORCECHAR) {
2208 AddCodeLine ("pla");
2214 AddCodeLine ("lda regsave");
2215 AddCodeLine ("ldx regsave+1");
2219 AddCodeLine ("jsr resteax");
2229 void g_cmp (unsigned flags, unsigned long val)
2230 /* Immidiate compare. The primary register will not be changed, Z flag
2236 /* Check the size and determine operation */
2237 switch (flags & CF_TYPE) {
2240 if (flags & CF_FORCECHAR) {
2241 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2247 L = GetLocalLabel();
2248 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2249 AddCodeLine ("bne %s", LocalLabelName (L));
2250 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
2255 Internal ("g_cmp: Long compares not implemented");
2265 static void oper (unsigned flags, unsigned long val, char** subs)
2266 /* Encode a binary operation. subs is a pointer to four groups of three
2268 * 0-2 --> Operate on ints
2269 * 3-5 --> Operate on unsigneds
2270 * 6-8 --> Operate on longs
2271 * 9-11 --> Operate on unsigned longs
2273 * The first subroutine names in each string group is used to encode an
2274 * operation with a zero constant, the second to encode an operation with
2275 * a 8 bit constant, and the third is used in all other cases.
2280 /* Determine the offset into the array */
2281 offs = (flags & CF_UNSIGNED)? 3 : 0;
2282 switch (flags & CF_TYPE) {
2295 /* Encode the operation */
2296 if (flags & CF_CONST) {
2297 /* Constant value given */
2298 if (val == 0 && subs [offs+0]) {
2299 /* Special case: constant with value zero */
2300 AddCodeLine ("jsr %s", subs [offs+0]);
2301 } else if (val < 0x100 && subs [offs+1]) {
2302 /* Special case: constant with high byte zero */
2303 ldaconst (val); /* Load low byte */
2304 AddCodeLine ("jsr %s", subs [offs+1]);
2306 /* Others: arbitrary constant value */
2307 g_getimmed (flags, val, 0); /* Load value */
2308 AddCodeLine ("jsr %s", subs [offs+2]);
2311 /* Value not constant (is already in (e)ax) */
2312 AddCodeLine ("jsr %s", subs [offs+2]);
2315 /* The operation will pop it's argument */
2321 void g_test (unsigned flags)
2322 /* Test the value in the primary and set the condition codes */
2324 switch (flags & CF_TYPE) {
2327 if (flags & CF_FORCECHAR) {
2328 AddCodeLine ("tax");
2334 AddCodeLine ("stx tmp1");
2335 AddCodeLine ("ora tmp1");
2339 if (flags & CF_UNSIGNED) {
2340 AddCodeLine ("jsr utsteax");
2342 AddCodeLine ("jsr tsteax");
2354 void g_push (unsigned flags, unsigned long val)
2355 /* Push the primary register or a constant value onto the stack */
2357 if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2359 /* We have a constant 8 or 16 bit value */
2360 if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2362 /* Handle as 8 bit value */
2364 AddCodeLine ("jsr pusha");
2368 /* Handle as 16 bit value */
2369 g_getimmed (flags, val, 0);
2370 AddCodeLine ("jsr pushax");
2375 /* Value is not 16 bit or not constant */
2376 if (flags & CF_CONST) {
2377 /* Constant 32 bit value, load into eax */
2378 g_getimmed (flags, val, 0);
2381 /* Push the primary register */
2382 switch (flags & CF_TYPE) {
2385 if (flags & CF_FORCECHAR) {
2386 /* Handle as char */
2387 AddCodeLine ("jsr pusha");
2392 AddCodeLine ("jsr pushax");
2396 AddCodeLine ("jsr pusheax");
2406 /* Adjust the stack offset */
2412 void g_swap (unsigned flags)
2413 /* Swap the primary register and the top of the stack. flags give the type
2414 * of *both* values (must have same size).
2417 switch (flags & CF_TYPE) {
2421 AddCodeLine ("jsr swapstk");
2425 AddCodeLine ("jsr swapestk");
2436 void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2437 /* Call the specified subroutine name */
2439 if ((Flags & CF_FIXARGC) == 0) {
2440 /* Pass the argument count */
2443 AddCodeLine ("jsr _%s", Label);
2444 oursp += ArgSize; /* callee pops args */
2449 void g_callind (unsigned Flags, unsigned ArgSize, int Offs)
2450 /* Call subroutine indirect */
2452 if ((Flags & CF_LOCAL) == 0) {
2453 /* Address is in a/x */
2454 if ((Flags & CF_FIXARGC) == 0) {
2455 /* Pass arg count */
2458 AddCodeLine ("jsr callax");
2460 /* The address is on stack, offset is on Val */
2462 CheckLocalOffs (Offs);
2463 AddCodeLine ("pha");
2464 AddCodeLine ("ldy #$%02X", Offs);
2465 AddCodeLine ("lda (sp),y");
2466 AddCodeLine ("sta jmpvec+1");
2467 AddCodeLine ("iny");
2468 AddCodeLine ("lda (sp),y");
2469 AddCodeLine ("sta jmpvec+2");
2470 AddCodeLine ("pla");
2471 AddCodeLine ("jsr jmpvec");
2474 /* Callee pops args */
2480 void g_jump (unsigned Label)
2481 /* Jump to specified internal label number */
2483 AddCodeLine ("jmp %s", LocalLabelName (Label));
2488 void g_truejump (unsigned flags attribute ((unused)), unsigned label)
2489 /* Jump to label if zero flag clear */
2491 AddCodeLine ("jne %s", LocalLabelName (label));
2496 void g_falsejump (unsigned flags attribute ((unused)), unsigned label)
2497 /* Jump to label if zero flag set */
2499 AddCodeLine ("jeq %s", LocalLabelName (label));
2504 static void mod_internal (int k, char* verb1, char* verb2)
2507 AddCodeLine ("jsr %ssp%c", verb1, k + '0');
2511 AddCodeLine ("jsr %ssp", verb2);
2517 void g_space (int space)
2518 /* Create or drop space on the stack */
2521 mod_internal (-space, "inc", "addy");
2522 } else if (space > 0) {
2523 mod_internal (space, "dec", "suby");
2529 void g_cstackcheck (void)
2530 /* Check for a C stack overflow */
2532 AddCodeLine ("jsr cstkchk");
2537 void g_stackcheck (void)
2538 /* Check for a stack overflow */
2540 AddCodeLine ("jsr stkchk");
2545 void g_add (unsigned flags, unsigned long val)
2546 /* Primary = TOS + Primary */
2548 static char* ops [12] = {
2549 0, "tosadda0", "tosaddax",
2550 0, "tosadda0", "tosaddax",
2555 if (flags & CF_CONST) {
2556 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2557 g_push (flags & ~CF_CONST, 0);
2559 oper (flags, val, ops);
2564 void g_sub (unsigned flags, unsigned long val)
2565 /* Primary = TOS - Primary */
2567 static char* ops [12] = {
2568 0, "tossuba0", "tossubax",
2569 0, "tossuba0", "tossubax",
2574 if (flags & CF_CONST) {
2575 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2576 g_push (flags & ~CF_CONST, 0);
2578 oper (flags, val, ops);
2583 void g_rsub (unsigned flags, unsigned long val)
2584 /* Primary = Primary - TOS */
2586 static char* ops [12] = {
2587 0, "tosrsuba0", "tosrsubax",
2588 0, "tosrsuba0", "tosrsubax",
2592 oper (flags, val, ops);
2597 void g_mul (unsigned flags, unsigned long val)
2598 /* Primary = TOS * Primary */
2600 static char* ops [12] = {
2601 0, "tosmula0", "tosmulax",
2602 0, "tosumula0", "tosumulax",
2609 /* Do strength reduction if the value is constant and a power of two */
2610 if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2611 /* Generate a shift instead */
2616 /* If the right hand side is const, the lhs is not on stack but still
2617 * in the primary register.
2619 if (flags & CF_CONST) {
2621 switch (flags & CF_TYPE) {
2624 if (flags & CF_FORCECHAR) {
2625 /* Handle some special cases */
2629 AddCodeLine ("sta tmp1");
2630 AddCodeLine ("asl a");
2631 AddCodeLine ("clc");
2632 AddCodeLine ("adc tmp1");
2636 AddCodeLine ("sta tmp1");
2637 AddCodeLine ("asl a");
2638 AddCodeLine ("asl a");
2639 AddCodeLine ("clc");
2640 AddCodeLine ("adc tmp1");
2644 AddCodeLine ("sta tmp1");
2645 AddCodeLine ("asl a");
2646 AddCodeLine ("clc");
2647 AddCodeLine ("adc tmp1");
2648 AddCodeLine ("asl a");
2652 AddCodeLine ("sta tmp1");
2653 AddCodeLine ("asl a");
2654 AddCodeLine ("asl a");
2655 AddCodeLine ("clc");
2656 AddCodeLine ("adc tmp1");
2657 AddCodeLine ("asl a");
2666 AddCodeLine ("jsr mulax3");
2669 AddCodeLine ("jsr mulax5");
2672 AddCodeLine ("jsr mulax6");
2675 AddCodeLine ("jsr mulax7");
2678 AddCodeLine ("jsr mulax9");
2681 AddCodeLine ("jsr mulax10");
2693 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2694 * into the normal, non-optimized stuff.
2696 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2697 g_push (flags & ~CF_CONST, 0);
2701 /* Use long way over the stack */
2702 oper (flags, val, ops);
2707 void g_div (unsigned flags, unsigned long val)
2708 /* Primary = TOS / Primary */
2710 static char* ops [12] = {
2711 0, "tosdiva0", "tosdivax",
2712 0, "tosudiva0", "tosudivax",
2717 /* Do strength reduction if the value is constant and a power of two */
2719 if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2720 /* Generate a shift instead */
2723 /* Generate a division */
2724 if (flags & CF_CONST) {
2725 /* lhs is not on stack */
2726 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2727 g_push (flags & ~CF_CONST, 0);
2729 oper (flags, val, ops);
2735 void g_mod (unsigned flags, unsigned long val)
2736 /* Primary = TOS % Primary */
2738 static char* ops [12] = {
2739 0, "tosmoda0", "tosmodax",
2740 0, "tosumoda0", "tosumodax",
2746 /* Check if we can do some cost reduction */
2747 if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2748 /* We can do that with an AND operation */
2749 g_and (flags, val - 1);
2751 /* Do it the hard way... */
2752 if (flags & CF_CONST) {
2753 /* lhs is not on stack */
2754 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2755 g_push (flags & ~CF_CONST, 0);
2757 oper (flags, val, ops);
2763 void g_or (unsigned flags, unsigned long val)
2764 /* Primary = TOS | Primary */
2766 static char* ops [12] = {
2767 0, "tosora0", "tosorax",
2768 0, "tosora0", "tosorax",
2773 /* If the right hand side is const, the lhs is not on stack but still
2774 * in the primary register.
2776 if (flags & CF_CONST) {
2778 switch (flags & CF_TYPE) {
2781 if (flags & CF_FORCECHAR) {
2782 if ((val & 0xFF) != 0) {
2783 AddCodeLine ("ora #$%02X", (unsigned char)val);
2791 if ((val & 0xFF) != 0) {
2792 AddCodeLine ("ora #$%02X", (unsigned char)val);
2795 } else if ((val & 0xFF00) == 0xFF00) {
2796 if ((val & 0xFF) != 0) {
2797 AddCodeLine ("ora #$%02X", (unsigned char)val);
2806 if ((val & 0xFF) != 0) {
2807 AddCodeLine ("ora #$%02X", (unsigned char)val);
2817 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2818 * into the normal, non-optimized stuff. Note: The standard stuff will
2819 * always work with ints.
2821 flags &= ~CF_FORCECHAR;
2822 g_push (flags & ~CF_CONST, 0);
2825 /* Use long way over the stack */
2826 oper (flags, val, ops);
2831 void g_xor (unsigned flags, unsigned long val)
2832 /* Primary = TOS ^ Primary */
2834 static char* ops [12] = {
2835 0, "tosxora0", "tosxorax",
2836 0, "tosxora0", "tosxorax",
2842 /* If the right hand side is const, the lhs is not on stack but still
2843 * in the primary register.
2845 if (flags & CF_CONST) {
2847 switch (flags & CF_TYPE) {
2850 if (flags & CF_FORCECHAR) {
2851 if ((val & 0xFF) != 0) {
2852 AddCodeLine ("eor #$%02X", (unsigned char)val);
2861 AddCodeLine ("eor #$%02X", (unsigned char)val);
2864 } else if ((val & 0xFF) == 0) {
2865 AddCodeLine ("pha");
2866 AddCodeLine ("txa");
2867 AddCodeLine ("eor #$%02X", (unsigned char)(val >> 8));
2868 AddCodeLine ("tax");
2869 AddCodeLine ("pla");
2877 AddCodeLine ("eor #$%02X", (unsigned char)val);
2887 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2888 * into the normal, non-optimized stuff. Note: The standard stuff will
2889 * always work with ints.
2891 flags &= ~CF_FORCECHAR;
2892 g_push (flags & ~CF_CONST, 0);
2895 /* Use long way over the stack */
2896 oper (flags, val, ops);
2901 void g_and (unsigned Flags, unsigned long Val)
2902 /* Primary = TOS & Primary */
2904 static char* ops [12] = {
2905 0, "tosanda0", "tosandax",
2906 0, "tosanda0", "tosandax",
2911 /* If the right hand side is const, the lhs is not on stack but still
2912 * in the primary register.
2914 if (Flags & CF_CONST) {
2916 switch (Flags & CF_TYPE) {
2919 if (Flags & CF_FORCECHAR) {
2920 if ((Val & 0xFF) != 0xFF) {
2921 AddCodeLine ("and #$%02X", (unsigned char)Val);
2927 if ((Val & 0xFFFF) != 0xFFFF) {
2932 } else if (Val != 0xFF) {
2933 AddCodeLine ("and #$%02X", (unsigned char)Val);
2935 } else if ((Val & 0xFF00) == 0xFF00) {
2936 AddCodeLine ("and #$%02X", (unsigned char)Val);
2937 } else if ((Val & 0x00FF) == 0x0000) {
2938 AddCodeLine ("txa");
2939 AddCodeLine ("and #$%02X", (unsigned char)(Val >> 8));
2940 AddCodeLine ("tax");
2943 AddCodeLine ("tay");
2944 AddCodeLine ("txa");
2945 AddCodeLine ("and #$%02X", (unsigned char)(Val >> 8));
2946 AddCodeLine ("tax");
2947 AddCodeLine ("tya");
2948 if ((Val & 0x00FF) != 0x00FF) {
2949 AddCodeLine ("and #$%02X", (unsigned char)Val);
2958 AddCodeLine ("stx sreg+1");
2959 AddCodeLine ("stx sreg");
2960 if ((Val & 0xFF) != 0xFF) {
2961 AddCodeLine ("and #$%02X", (unsigned char)Val);
2964 } else if (Val == 0xFF00) {
2966 AddCodeLine ("sta sreg+1");
2967 AddCodeLine ("sta sreg");
2976 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2977 * into the normal, non-optimized stuff. Note: The standard stuff will
2978 * always work with ints.
2980 Flags &= ~CF_FORCECHAR;
2981 g_push (Flags & ~CF_CONST, 0);
2984 /* Use long way over the stack */
2985 oper (Flags, Val, ops);
2990 void g_asr (unsigned flags, unsigned long val)
2991 /* Primary = TOS >> Primary */
2993 static char* ops [12] = {
2994 0, "tosasra0", "tosasrax",
2995 0, "tosshra0", "tosshrax",
3000 /* If the right hand side is const, the lhs is not on stack but still
3001 * in the primary register.
3003 if (flags & CF_CONST) {
3005 switch (flags & CF_TYPE) {
3009 if (val >= 8 && (flags & CF_UNSIGNED)) {
3010 AddCodeLine ("txa");
3017 } else if (val >= 1 && val <= 4) {
3018 if (flags & CF_UNSIGNED) {
3019 AddCodeLine ("jsr shrax%ld", val);
3021 AddCodeLine ("jsr asrax%ld", val);
3031 } else if (val >= 1 && val <= 4) {
3032 if (flags & CF_UNSIGNED) {
3033 AddCodeLine ("jsr shreax%ld", val);
3035 AddCodeLine ("jsr asreax%ld", val);
3038 } else if (val == 8 && (flags & CF_UNSIGNED)) {
3039 AddCodeLine ("txa");
3040 AddCodeLine ("ldx sreg");
3041 AddCodeLine ("ldy sreg+1");
3042 AddCodeLine ("sty sreg");
3043 AddCodeLine ("ldy #$00");
3044 AddCodeLine ("sty sreg+1");
3046 } else if (val == 16) {
3047 AddCodeLine ("ldy #$00");
3048 AddCodeLine ("ldx sreg+1");
3049 if ((flags & CF_UNSIGNED) == 0) {
3050 unsigned L = GetLocalLabel();
3051 AddCodeLine ("bpl %s", LocalLabelName (L));
3052 AddCodeLine ("dey");
3055 AddCodeLine ("lda sreg");
3056 AddCodeLine ("sty sreg+1");
3057 AddCodeLine ("sty sreg");
3066 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3067 * into the normal, non-optimized stuff. Note: The standard stuff will
3068 * always work with ints.
3070 flags &= ~CF_FORCECHAR;
3071 g_push (flags & ~CF_CONST, 0);
3074 /* Use long way over the stack */
3075 oper (flags, val, ops);
3080 void g_asl (unsigned flags, unsigned long val)
3081 /* Primary = TOS << Primary */
3083 static char* ops [12] = {
3084 0, "tosasla0", "tosaslax",
3085 0, "tosshla0", "tosshlax",
3091 /* If the right hand side is const, the lhs is not on stack but still
3092 * in the primary register.
3094 if (flags & CF_CONST) {
3096 switch (flags & CF_TYPE) {
3101 AddCodeLine ("tax");
3102 AddCodeLine ("lda #$00");
3108 } else if (val >= 1 && val <= 4) {
3109 if (flags & CF_UNSIGNED) {
3110 AddCodeLine ("jsr shlax%ld", val);
3112 AddCodeLine ("jsr aslax%ld", val);
3122 } else if (val >= 1 && val <= 4) {
3123 if (flags & CF_UNSIGNED) {
3124 AddCodeLine ("jsr shleax%ld", val);
3126 AddCodeLine ("jsr asleax%ld", val);
3129 } else if (val == 8) {
3130 AddCodeLine ("ldy sreg");
3131 AddCodeLine ("sty sreg+1");
3132 AddCodeLine ("stx sreg");
3133 AddCodeLine ("tax");
3134 AddCodeLine ("lda #$00");
3136 } else if (val == 16) {
3137 AddCodeLine ("stx sreg+1");
3138 AddCodeLine ("sta sreg");
3139 AddCodeLine ("lda #$00");
3140 AddCodeLine ("tax");
3149 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3150 * into the normal, non-optimized stuff. Note: The standard stuff will
3151 * always work with ints.
3153 flags &= ~CF_FORCECHAR;
3154 g_push (flags & ~CF_CONST, 0);
3157 /* Use long way over the stack */
3158 oper (flags, val, ops);
3163 void g_neg (unsigned Flags)
3164 /* Primary = -Primary */
3166 switch (Flags & CF_TYPE) {
3169 if (Flags & CF_FORCECHAR) {
3170 AddCodeLine ("eor #$FF");
3171 AddCodeLine ("clc");
3172 AddCodeLine ("adc #$01");
3178 AddCodeLine ("jsr negax");
3182 AddCodeLine ("jsr negeax");
3192 void g_bneg (unsigned flags)
3193 /* Primary = !Primary */
3195 switch (flags & CF_TYPE) {
3198 AddCodeLine ("jsr bnega");
3202 AddCodeLine ("jsr bnegax");
3206 AddCodeLine ("jsr bnegeax");
3216 void g_com (unsigned Flags)
3217 /* Primary = ~Primary */
3219 switch (Flags & CF_TYPE) {
3222 if (Flags & CF_FORCECHAR) {
3223 AddCodeLine ("eor #$FF");
3229 AddCodeLine ("jsr complax");
3233 AddCodeLine ("jsr compleax");
3243 void g_inc (unsigned flags, unsigned long val)
3244 /* Increment the primary register by a given number */
3246 /* Don't inc by zero */
3251 /* Generate code for the supported types */
3253 switch (flags & CF_TYPE) {
3256 if (flags & CF_FORCECHAR) {
3257 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val <= 2) {
3259 AddCodeLine ("ina");
3262 AddCodeLine ("clc");
3263 AddCodeLine ("adc #$%02X", (unsigned char)val);
3270 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val == 1) {
3271 unsigned L = GetLocalLabel();
3272 AddCodeLine ("ina");
3273 AddCodeLine ("bne %s", LocalLabelName (L));
3274 AddCodeLine ("inx");
3276 } else if (CodeSizeFactor < 200) {
3279 AddCodeLine ("jsr incax%lu", val);
3280 } else if (val <= 255) {
3282 AddCodeLine ("jsr incaxy");
3284 g_add (flags | CF_CONST, val);
3287 /* Inline the code */
3289 if ((val & 0xFF) != 0) {
3290 unsigned L = GetLocalLabel();
3291 AddCodeLine ("clc");
3292 AddCodeLine ("adc #$%02X", (unsigned char) val);
3293 AddCodeLine ("bcc %s", LocalLabelName (L));
3294 AddCodeLine ("inx");
3298 AddCodeLine ("inx");
3301 AddCodeLine ("inx");
3304 AddCodeLine ("inx");
3307 AddCodeLine ("clc");
3308 if ((val & 0xFF) != 0) {
3309 AddCodeLine ("adc #$%02X", (unsigned char) val);
3311 AddCodeLine ("pha");
3312 AddCodeLine ("txa");
3313 AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3314 AddCodeLine ("tax");
3315 AddCodeLine ("pla");
3323 AddCodeLine ("jsr inceaxy");
3325 g_add (flags | CF_CONST, val);
3337 void g_dec (unsigned flags, unsigned long val)
3338 /* Decrement the primary register by a given number */
3340 /* Don't dec by zero */
3345 /* Generate code for the supported types */
3347 switch (flags & CF_TYPE) {
3350 if (flags & CF_FORCECHAR) {
3351 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && val <= 2) {
3353 AddCodeLine ("dea");
3356 AddCodeLine ("sec");
3357 AddCodeLine ("sbc #$%02X", (unsigned char)val);
3364 if (CodeSizeFactor < 200) {
3365 /* Use subroutines */
3367 AddCodeLine ("jsr decax%d", (int) val);
3368 } else if (val <= 255) {
3370 AddCodeLine ("jsr decaxy");
3372 g_sub (flags | CF_CONST, val);
3375 /* Inline the code */
3377 if ((val & 0xFF) != 0) {
3378 unsigned L = GetLocalLabel();
3379 AddCodeLine ("sec");
3380 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3381 AddCodeLine ("bcs %s", LocalLabelName (L));
3382 AddCodeLine ("dex");
3386 AddCodeLine ("dex");
3389 AddCodeLine ("dex");
3392 AddCodeLine ("sec");
3393 if ((val & 0xFF) != 0) {
3394 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3396 AddCodeLine ("pha");
3397 AddCodeLine ("txa");
3398 AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3399 AddCodeLine ("tax");
3400 AddCodeLine ("pla");
3408 AddCodeLine ("jsr deceaxy");
3410 g_sub (flags | CF_CONST, val);
3423 * Following are the conditional operators. They compare the TOS against
3424 * the primary and put a literal 1 in the primary if the condition is
3425 * true, otherwise they clear the primary register
3430 void g_eq (unsigned flags, unsigned long val)
3431 /* Test for equal */
3433 static char* ops [12] = {
3434 "toseq00", "toseqa0", "toseqax",
3435 "toseq00", "toseqa0", "toseqax",
3442 /* If the right hand side is const, the lhs is not on stack but still
3443 * in the primary register.
3445 if (flags & CF_CONST) {
3447 switch (flags & CF_TYPE) {
3450 if (flags & CF_FORCECHAR) {
3451 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3452 AddCodeLine ("jsr booleq");
3458 L = GetLocalLabel();
3459 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3460 AddCodeLine ("bne %s", LocalLabelName (L));
3461 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3463 AddCodeLine ("jsr booleq");
3473 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3474 * into the normal, non-optimized stuff. Note: The standard stuff will
3475 * always work with ints.
3477 flags &= ~CF_FORCECHAR;
3478 g_push (flags & ~CF_CONST, 0);
3481 /* Use long way over the stack */
3482 oper (flags, val, ops);
3487 void g_ne (unsigned flags, unsigned long val)
3488 /* Test for not equal */
3490 static char* ops [12] = {
3491 "tosne00", "tosnea0", "tosneax",
3492 "tosne00", "tosnea0", "tosneax",
3499 /* If the right hand side is const, the lhs is not on stack but still
3500 * in the primary register.
3502 if (flags & CF_CONST) {
3504 switch (flags & CF_TYPE) {
3507 if (flags & CF_FORCECHAR) {
3508 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3509 AddCodeLine ("jsr boolne");
3515 L = GetLocalLabel();
3516 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3517 AddCodeLine ("bne %s", LocalLabelName (L));
3518 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3520 AddCodeLine ("jsr boolne");
3530 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3531 * into the normal, non-optimized stuff. Note: The standard stuff will
3532 * always work with ints.
3534 flags &= ~CF_FORCECHAR;
3535 g_push (flags & ~CF_CONST, 0);
3538 /* Use long way over the stack */
3539 oper (flags, val, ops);
3544 void g_lt (unsigned flags, unsigned long val)
3545 /* Test for less than */
3547 static char* ops [12] = {
3548 "toslt00", "toslta0", "tosltax",
3549 "tosult00", "tosulta0", "tosultax",
3554 /* If the right hand side is const, the lhs is not on stack but still
3555 * in the primary register.
3557 if (flags & CF_CONST) {
3559 /* Because the handling of the overflow flag is too complex for
3560 * inlining, we can handle only unsigned compares, and signed
3561 * compares against zero here.
3563 if (flags & CF_UNSIGNED) {
3565 /* Give a warning in some special cases */
3567 Warning ("Condition is never true");
3568 AddCodeLine ("jsr return0");
3572 /* Look at the type */
3573 switch (flags & CF_TYPE) {
3576 if (flags & CF_FORCECHAR) {
3577 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3578 AddCodeLine ("jsr boolult");
3584 /* If the low byte is zero, we must only test the high byte */
3585 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3586 if ((val & 0xFF) != 0) {
3587 unsigned L = GetLocalLabel();
3588 AddCodeLine ("bne %s", LocalLabelName (L));
3589 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3592 AddCodeLine ("jsr boolult");
3596 /* Do a subtraction */
3597 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3598 AddCodeLine ("txa");
3599 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
3600 AddCodeLine ("lda sreg");
3601 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 16));
3602 AddCodeLine ("lda sreg+1");
3603 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 24));
3604 AddCodeLine ("jsr boolult");
3611 } else if (val == 0) {
3613 /* Look at the type */
3614 switch (flags & CF_TYPE) {
3617 if (flags & CF_FORCECHAR) {
3618 AddCodeLine ("tax");
3619 AddCodeLine ("jsr boollt");
3625 /* Just check the high byte */
3626 AddCodeLine ("txa");
3627 AddCodeLine ("jsr boollt");
3631 /* Just check the high byte */
3632 AddCodeLine ("lda sreg+1");
3633 AddCodeLine ("jsr boollt");
3641 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3642 * into the normal, non-optimized stuff. Note: The standard stuff will
3643 * always work with ints.
3645 flags &= ~CF_FORCECHAR;
3646 g_push (flags & ~CF_CONST, 0);
3649 /* Use long way over the stack */
3650 oper (flags, val, ops);
3655 void g_le (unsigned flags, unsigned long val)
3656 /* Test for less than or equal to */
3658 static char* ops [12] = {
3659 "tosle00", "toslea0", "tosleax",
3660 "tosule00", "tosulea0", "tosuleax",
3666 /* If the right hand side is const, the lhs is not on stack but still
3667 * in the primary register.
3669 if (flags & CF_CONST) {
3671 /* Look at the type */
3672 switch (flags & CF_TYPE) {
3675 if (flags & CF_FORCECHAR) {
3676 if (flags & CF_UNSIGNED) {
3677 /* Unsigned compare */
3679 /* Use < instead of <= because the former gives
3680 * better code on the 6502 than the latter.
3682 g_lt (flags, val+1);
3685 Warning ("Condition is always true");
3686 AddCodeLine ("jsr return1");
3689 /* Signed compare */
3690 if ((long) val < 0x7F) {
3691 /* Use < instead of <= because the former gives
3692 * better code on the 6502 than the latter.
3694 g_lt (flags, val+1);
3697 Warning ("Condition is always true");
3698 AddCodeLine ("jsr return1");
3706 if (flags & CF_UNSIGNED) {
3707 /* Unsigned compare */
3709 /* Use < instead of <= because the former gives
3710 * better code on the 6502 than the latter.
3712 g_lt (flags, val+1);
3715 Warning ("Condition is always true");
3716 AddCodeLine ("jsr return1");
3719 /* Signed compare */
3720 if ((long) val < 0x7FFF) {
3721 g_lt (flags, val+1);
3724 Warning ("Condition is always true");
3725 AddCodeLine ("jsr return1");
3731 if (flags & CF_UNSIGNED) {
3732 /* Unsigned compare */
3733 if (val < 0xFFFFFFFF) {
3734 /* Use < instead of <= because the former gives
3735 * better code on the 6502 than the latter.
3737 g_lt (flags, val+1);
3740 Warning ("Condition is always true");
3741 AddCodeLine ("jsr return1");
3744 /* Signed compare */
3745 if ((long) val < 0x7FFFFFFF) {
3746 g_lt (flags, val+1);
3749 Warning ("Condition is always true");
3750 AddCodeLine ("jsr return1");
3759 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3760 * into the normal, non-optimized stuff. Note: The standard stuff will
3761 * always work with ints.
3763 flags &= ~CF_FORCECHAR;
3764 g_push (flags & ~CF_CONST, 0);
3767 /* Use long way over the stack */
3768 oper (flags, val, ops);
3773 void g_gt (unsigned flags, unsigned long val)
3774 /* Test for greater than */
3776 static char* ops [12] = {
3777 "tosgt00", "tosgta0", "tosgtax",
3778 "tosugt00", "tosugta0", "tosugtax",
3784 /* If the right hand side is const, the lhs is not on stack but still
3785 * in the primary register.
3787 if (flags & CF_CONST) {
3789 /* Look at the type */
3790 switch (flags & CF_TYPE) {
3793 if (flags & CF_FORCECHAR) {
3794 if (flags & CF_UNSIGNED) {
3796 /* If we have a compare > 0, we will replace it by
3797 * != 0 here, since both are identical but the
3798 * latter is easier to optimize.
3801 } else if (val < 0xFF) {
3802 /* Use >= instead of > because the former gives
3803 * better code on the 6502 than the latter.
3805 g_ge (flags, val+1);
3808 Warning ("Condition is never true");
3809 AddCodeLine ("jsr return0");
3812 if ((long) val < 0x7F) {
3813 /* Use >= instead of > because the former gives
3814 * better code on the 6502 than the latter.
3816 g_ge (flags, val+1);
3819 Warning ("Condition is never true");
3820 AddCodeLine ("jsr return0");
3828 if (flags & CF_UNSIGNED) {
3829 /* Unsigned compare */
3831 /* If we have a compare > 0, we will replace it by
3832 * != 0 here, since both are identical but the latter
3833 * is easier to optimize.
3836 } else if (val < 0xFFFF) {
3837 /* Use >= instead of > because the former gives better
3838 * code on the 6502 than the latter.
3840 g_ge (flags, val+1);
3843 Warning ("Condition is never true");
3844 AddCodeLine ("jsr return0");
3847 /* Signed compare */
3848 if ((long) val < 0x7FFF) {
3849 g_ge (flags, val+1);
3852 Warning ("Condition is never true");
3853 AddCodeLine ("jsr return0");
3859 if (flags & CF_UNSIGNED) {
3860 /* Unsigned compare */
3862 /* If we have a compare > 0, we will replace it by
3863 * != 0 here, since both are identical but the latter
3864 * is easier to optimize.
3867 } else if (val < 0xFFFFFFFF) {
3868 /* Use >= instead of > because the former gives better
3869 * code on the 6502 than the latter.
3871 g_ge (flags, val+1);
3874 Warning ("Condition is never true");
3875 AddCodeLine ("jsr return0");
3878 /* Signed compare */
3879 if ((long) val < 0x7FFFFFFF) {
3880 g_ge (flags, val+1);
3883 Warning ("Condition is never true");
3884 AddCodeLine ("jsr return0");
3893 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3894 * into the normal, non-optimized stuff. Note: The standard stuff will
3895 * always work with ints.
3897 flags &= ~CF_FORCECHAR;
3898 g_push (flags & ~CF_CONST, 0);
3901 /* Use long way over the stack */
3902 oper (flags, val, ops);
3907 void g_ge (unsigned flags, unsigned long val)
3908 /* Test for greater than or equal to */
3910 static char* ops [12] = {
3911 "tosge00", "tosgea0", "tosgeax",
3912 "tosuge00", "tosugea0", "tosugeax",
3918 /* If the right hand side is const, the lhs is not on stack but still
3919 * in the primary register.
3921 if (flags & CF_CONST) {
3923 /* Because the handling of the overflow flag is too complex for
3924 * inlining, we can handle only unsigned compares, and signed
3925 * compares against zero here.
3927 if (flags & CF_UNSIGNED) {
3929 /* Give a warning in some special cases */
3931 Warning ("Condition is always true");
3932 AddCodeLine ("jsr return1");
3936 /* Look at the type */
3937 switch (flags & CF_TYPE) {
3940 if (flags & CF_FORCECHAR) {
3941 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3942 AddCodeLine ("jsr booluge");
3948 /* If the low byte is zero, we must only test the high byte */
3949 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3950 if ((val & 0xFF) != 0) {
3951 unsigned L = GetLocalLabel();
3952 AddCodeLine ("bne %s", LocalLabelName (L));
3953 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3956 AddCodeLine ("jsr booluge");
3960 /* Do a subtraction */
3961 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3962 AddCodeLine ("txa");
3963 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
3964 AddCodeLine ("lda sreg");
3965 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 16));
3966 AddCodeLine ("lda sreg+1");
3967 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 24));
3968 AddCodeLine ("jsr booluge");
3975 } else if (val == 0) {
3977 /* Look at the type */
3978 switch (flags & CF_TYPE) {
3981 if (flags & CF_FORCECHAR) {
3982 AddCodeLine ("tax");
3983 AddCodeLine ("jsr boolge");
3989 /* Just test the high byte */
3990 AddCodeLine ("txa");
3991 AddCodeLine ("jsr boolge");
3995 /* Just test the high byte */
3996 AddCodeLine ("lda sreg+1");
3997 AddCodeLine ("jsr boolge");
4006 /* If we go here, we didn't emit code. Push the lhs on stack and fall
4007 * into the normal, non-optimized stuff. Note: The standard stuff will
4008 * always work with ints.
4010 flags &= ~CF_FORCECHAR;
4011 g_push (flags & ~CF_CONST, 0);
4014 /* Use long way over the stack */
4015 oper (flags, val, ops);
4020 /*****************************************************************************/
4021 /* Allocating static storage */
4022 /*****************************************************************************/
4026 void g_res (unsigned n)
4027 /* Reserve static storage, n bytes */
4029 AddDataLine ("\t.res\t%u,$00", n);
4034 void g_defdata (unsigned flags, unsigned long val, long offs)
4035 /* Define data with the size given in flags */
4037 if (flags & CF_CONST) {
4039 /* Numeric constant */
4040 switch (flags & CF_TYPE) {
4043 AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
4047 AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
4051 AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
4062 /* Create the correct label name */
4063 const char* Label = GetLabelName (flags, val, offs);
4065 /* Labels are always 16 bit */
4066 AddDataLine ("\t.addr\t%s", Label);
4073 void g_defbytes (const void* Bytes, unsigned Count)
4074 /* Output a row of bytes as a constant */
4080 /* Cast the buffer pointer */
4081 const unsigned char* Data = (const unsigned char*) Bytes;
4083 /* Output the stuff */
4086 /* How many go into this line? */
4087 if ((Chunk = Count) > 16) {
4092 /* Output one line */
4093 strcpy (Buf, "\t.byte\t");
4096 B += sprintf (B, "$%02X", *Data++);
4102 /* Output the line */
4109 void g_zerobytes (unsigned Count)
4110 /* Output Count bytes of data initialized with zero */
4113 AddDataLine ("\t.res\t%u,$00", Count);
4119 void g_initregister (unsigned Label, unsigned Reg, unsigned Size)
4120 /* Initialize a register variable from static initialization data */
4122 /* Register variables do always have less than 128 bytes */
4123 unsigned CodeLabel = GetLocalLabel ();
4125 g_defcodelabel (CodeLabel);
4126 AddCodeLine ("lda %s,x", GetLabelName (CF_STATIC, Label, 0));
4127 AddCodeLine ("sta %s,x", GetLabelName (CF_REGVAR, Reg, 0));
4128 AddCodeLine ("dex");
4129 AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4134 void g_initauto (unsigned Label, unsigned Size)
4135 /* Initialize a local variable at stack offset zero from static data */
4137 unsigned CodeLabel = GetLocalLabel ();
4139 CheckLocalOffs (Size);
4142 g_defcodelabel (CodeLabel);
4143 AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0));
4144 AddCodeLine ("sta (sp),y");
4145 AddCodeLine ("dey");
4146 AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4147 } else if (Size <= 256) {
4149 g_defcodelabel (CodeLabel);
4150 AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, Label, 0));
4151 AddCodeLine ("sta (sp),y");
4152 AddCodeLine ("iny");
4153 AddCodeLine ("cpy #$%02X", (unsigned char) Size);
4154 AddCodeLine ("bne %s", LocalLabelName (CodeLabel));
4160 void g_initstatic (unsigned InitLabel, unsigned VarLabel, unsigned Size)
4161 /* Initialize a static local variable from static initialization data */
4164 unsigned CodeLabel = GetLocalLabel ();
4166 g_defcodelabel (CodeLabel);
4167 AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0));
4168 AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0));
4169 AddCodeLine ("dey");
4170 AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
4171 } else if (Size <= 256) {
4172 unsigned CodeLabel = GetLocalLabel ();
4174 g_defcodelabel (CodeLabel);
4175 AddCodeLine ("lda %s,y", GetLabelName (CF_STATIC, InitLabel, 0));
4176 AddCodeLine ("sta %s,y", GetLabelName (CF_STATIC, VarLabel, 0));
4177 AddCodeLine ("iny");
4178 AddCodeLine ("cpy #$%02X", (unsigned char) Size);
4179 AddCodeLine ("bne %s", LocalLabelName (CodeLabel));
4181 /* Use the easy way here: memcpy */
4182 g_getimmed (CF_STATIC, VarLabel, 0);
4183 AddCodeLine ("jsr pushax");
4184 g_getimmed (CF_STATIC, InitLabel, 0);
4185 AddCodeLine ("jsr pushax");
4186 g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, Size, 0);
4187 AddCodeLine ("jsr %s", GetLabelName (CF_EXTERNAL, (unsigned long) "memcpy", 0));
4193 /*****************************************************************************/
4194 /* Switch statement */
4195 /*****************************************************************************/
4199 void g_switch (Collection* Nodes, unsigned DefaultLabel, unsigned Depth)
4200 /* Generate code for a switch statement */
4202 unsigned NextLabel = 0;
4205 /* Setup registers and determine which compare insn to use */
4206 const char* Compare;
4209 Compare = "cmp #$%02X";
4212 Compare = "cpx #$%02X";
4215 AddCodeLine ("ldy sreg");
4216 Compare = "cpy #$%02X";
4219 AddCodeLine ("ldy sreg+1");
4220 Compare = "cpy #$%02X";
4223 Internal ("Invalid depth in g_switch: %u", Depth);
4226 /* Walk over all nodes */
4227 for (I = 0; I < CollCount (Nodes); ++I) {
4229 /* Get the next case node */
4230 CaseNode* N = CollAtUnchecked (Nodes, I);
4232 /* If we have a next label, define it */
4234 g_defcodelabel (NextLabel);
4238 /* Do the compare */
4239 AddCodeLine (Compare, CN_GetValue (N));
4241 /* If this is the last level, jump directly to the case code if found */
4244 /* Branch if equal */
4245 g_falsejump (0, CN_GetLabel (N));
4249 /* Determine the next label */
4250 if (I == CollCount (Nodes) - 1) {
4251 /* Last node means not found */
4252 g_truejump (0, DefaultLabel);
4254 /* Jump to the next check */
4255 NextLabel = GetLocalLabel ();
4256 g_truejump (0, NextLabel);
4259 /* Check the next level */
4260 g_switch (N->Nodes, DefaultLabel, Depth-1);
4265 /* If we go here, we haven't found the label */
4266 g_jump (DefaultLabel);
4271 /*****************************************************************************/
4272 /* User supplied assembler code */
4273 /*****************************************************************************/
4277 void g_asmcode (struct StrBuf* B)
4278 /* Output one line of assembler code. */
4280 AddCodeLine ("%.*s", SB_GetLen (B), SB_GetConstBuf (B));
4285 /*****************************************************************************/
4286 /* Inlined known functions */
4287 /*****************************************************************************/
4291 void g_strlen (unsigned flags, unsigned long val, long offs)
4292 /* Inline the strlen() function */
4294 /* We need a label in both cases */
4295 unsigned label = GetLocalLabel ();
4297 /* Two different encodings */
4298 if (flags & CF_CONST) {
4300 /* The address of the string is constant. Create the correct label name */
4301 const char* lbuf = GetLabelName (flags, val, offs);
4303 /* Generate the strlen code */
4304 AddCodeLine ("ldy #$FF");
4305 g_defcodelabel (label);
4306 AddCodeLine ("iny");
4307 AddCodeLine ("lda %s,y", lbuf);
4308 AddCodeLine ("bne %s", LocalLabelName (label));
4309 AddCodeLine ("tax");
4310 AddCodeLine ("tya");
4314 /* Address not constant but in primary */
4315 if (CodeSizeFactor < 400) {
4316 /* This is too much code, so call strlen instead of inlining */
4317 AddCodeLine ("jsr _strlen");
4319 /* Inline the function */
4320 AddCodeLine ("sta ptr1");
4321 AddCodeLine ("stx ptr1+1");
4322 AddCodeLine ("ldy #$FF");
4323 g_defcodelabel (label);
4324 AddCodeLine ("iny");
4325 AddCodeLine ("lda (ptr1),y");
4326 AddCodeLine ("bne %s", LocalLabelName (label));
4327 AddCodeLine ("tax");
4328 AddCodeLine ("tya");