1 /*****************************************************************************/
5 /* 6502 code generator */
9 /* (C) 1998-2001 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
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 /*****************************************************************************/
62 /*****************************************************************************/
64 /*****************************************************************************/
68 /* Compiler relative stack pointer */
73 /*****************************************************************************/
75 /*****************************************************************************/
79 static void typeerror (unsigned type)
80 /* Print an error message about an invalid operand type */
82 Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPE);
87 static void CheckLocalOffs (unsigned Offs)
88 /* Check the offset into the stack for 8bit range */
91 /* Too many local vars */
92 Error ("Too many local variables");
98 static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs)
100 static char lbuf [128]; /* Label name */
102 /* Create the correct label name */
103 switch (flags & CF_ADDRMASK) {
106 /* Static memory cell */
107 sprintf (lbuf, "%s+%u", LocalLabelName (label), offs);
112 sprintf (lbuf, "_%s+%u", (char*) label, offs);
116 /* Absolute address */
117 sprintf (lbuf, "$%04X", (unsigned)((label+offs) & 0xFFFF));
121 /* Variable in register bank */
122 sprintf (lbuf, "regbank+%u", (unsigned)((label+offs) & 0xFFFF));
126 Internal ("Invalid address flags");
129 /* Return a pointer to the static buffer */
135 /*****************************************************************************/
136 /* Pre- and postamble */
137 /*****************************************************************************/
141 void g_preamble (void)
142 /* Generate the assembler code preamble */
144 /* Create a new (global) segment list and remember it */
148 /* Identify the compiler version */
150 AddTextLine ("; File generated by cc65 v %u.%u.%u",
151 VER_MAJOR, VER_MINOR, VER_PATCH);
154 /* Insert some object file options */
155 AddTextLine ("\t.fopt\t\tcompiler,\"cc65 v %u.%u.%u\"",
156 VER_MAJOR, VER_MINOR, VER_PATCH);
158 /* If we're producing code for some other CPU, switch the command set */
159 if (CPU == CPU_65C02) {
160 AddTextLine ("\t.pc02");
163 /* Allow auto import for runtime library routines */
164 AddTextLine ("\t.autoimport\ton");
166 /* Switch the assembler into case sensitive mode */
167 AddTextLine ("\t.case\t\ton");
169 /* Tell the assembler if we want to generate debug info */
170 AddTextLine ("\t.debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
172 /* Import the stack pointer for direct auto variable access */
173 AddTextLine ("\t.importzp\tsp, sreg, regsave, regbank, tmp1, ptr1");
175 /* Define long branch macros */
176 AddTextLine ("\t.macpack\tlongbranch");
181 void g_fileinfo (const char* Name, unsigned long Size, unsigned long MTime)
182 /* If debug info is enabled, place a file info into the source */
185 /* We have to place this into the global text segment, so it will
186 * appear before all .dbg line statements.
188 TS_AddLine (GS->Text, "\t.dbg\t\tfile, \"%s\", %lu, %lu", Name, Size, MTime);
194 /*****************************************************************************/
195 /* Segment support */
196 /*****************************************************************************/
200 void g_userodata (void)
201 /* Switch to the read only data segment */
203 UseDataSeg (SEG_RODATA);
208 void g_usedata (void)
209 /* Switch to the data segment */
211 UseDataSeg (SEG_DATA);
217 /* Switch to the bss segment */
219 UseDataSeg (SEG_BSS);
224 void g_segname (segment_t Seg, const char* Name)
225 /* Set the name of a segment */
229 /* Remember the new name */
230 NewSegName (Seg, Name);
232 /* Emit a segment directive for the data style segments */
234 case SEG_RODATA: S = CS->ROData; break;
235 case SEG_DATA: S = CS->Data; break;
236 case SEG_BSS: S = CS->BSS; break;
237 default: S = 0; break;
240 DS_AddLine (S, ".segment\t\"%s\"", Name);
246 /*****************************************************************************/
248 /*****************************************************************************/
252 unsigned sizeofarg (unsigned flags)
253 /* Return the size of a function argument type that is encoded in flags */
255 switch (flags & CF_TYPE) {
258 return (flags & CF_FORCECHAR)? 1 : 2;
275 int pop (unsigned flags)
276 /* Pop an argument of the given size */
278 return oursp += sizeofarg (flags);
283 int push (unsigned flags)
284 /* Push an argument of the given size */
286 return oursp -= sizeofarg (flags);
291 static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
292 /* The value in Offs is an offset to an address in a/x. Make sure, an object
293 * of the type given in Flags can be loaded or stored into this address by
294 * adding part of the offset to the address in ax, so that the remaining
295 * offset fits into an index register. Return the remaining offset.
298 /* If the offset is too large for a byte register, add the high byte
299 * of the offset to the primary. Beware: We need a special correction
300 * if the offset in the low byte will overflow in the operation.
302 unsigned O = Offs & ~0xFFU;
303 if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
304 /* We need to add the low byte also */
308 /* Do the correction if we need one */
310 g_inc (CF_INT | CF_CONST, O);
314 /* Return the new offset */
320 /*****************************************************************************/
321 /* Functions handling local labels */
322 /*****************************************************************************/
326 void g_defcodelabel (unsigned label)
327 /* Define a local code label */
329 CS_AddLabel (CS->Code, LocalLabelName (label));
334 void g_defdatalabel (unsigned label)
335 /* Define a local data label */
337 AddDataLine ("%s:", LocalLabelName (label));
342 /*****************************************************************************/
343 /* Functions handling global labels */
344 /*****************************************************************************/
348 void g_defgloblabel (const char* Name)
349 /* Define a global label with the given name */
351 /* Global labels are always data labels */
352 AddDataLine ("_%s:", Name);
357 void g_defexport (const char* Name, int ZP)
358 /* Export the given label */
361 AddTextLine ("\t.exportzp\t_%s", Name);
363 AddTextLine ("\t.export\t\t_%s", Name);
369 void g_defimport (const char* Name, int ZP)
370 /* Import the given label */
373 AddTextLine ("\t.importzp\t_%s", Name);
375 AddTextLine ("\t.import\t\t_%s", Name);
381 /*****************************************************************************/
382 /* Load functions for various registers */
383 /*****************************************************************************/
387 static void ldaconst (unsigned val)
388 /* Load a with a constant */
390 AddCodeLine ("lda #$%02X", val & 0xFF);
395 static void ldxconst (unsigned val)
396 /* Load x with a constant */
398 AddCodeLine ("ldx #$%02X", val & 0xFF);
403 static void ldyconst (unsigned val)
404 /* Load y with a constant */
406 AddCodeLine ("ldy #$%02X", val & 0xFF);
411 /*****************************************************************************/
412 /* Function entry and exit */
413 /*****************************************************************************/
417 /* Remember the argument size of a function. The variable is set by g_enter
418 * and used by g_leave. If the functions gets its argument size by the caller
419 * (variable param list or function without prototype), g_enter will set the
425 void g_enter (unsigned flags, unsigned argsize)
426 /* Function prologue */
428 if ((flags & CF_FIXARGC) != 0) {
429 /* Just remember the argument size for the leave */
433 AddCodeLine ("jsr enter");
440 /* Function epilogue */
442 /* How many bytes of locals do we have to drop? */
445 /* If we didn't have a variable argument list, don't call leave */
448 /* Drop stackframe if needed */
452 AddCodeLine ("jsr incsp%d", k);
456 AddCodeLine ("jsr addysp");
463 /* Nothing to drop */
464 AddCodeLine ("jsr leave");
466 /* We've a stack frame to drop */
468 AddCodeLine ("jsr leavey");
472 /* Add the final rts */
478 /*****************************************************************************/
479 /* Register variables */
480 /*****************************************************************************/
484 void g_save_regvars (int RegOffs, unsigned Bytes)
485 /* Save register variables */
487 /* Don't loop for up to two bytes */
490 AddCodeLine ("lda regbank%+d", RegOffs);
491 AddCodeLine ("jsr pusha");
493 } else if (Bytes == 2) {
495 AddCodeLine ("lda regbank%+d", RegOffs);
496 AddCodeLine ("ldx regbank%+d", RegOffs+1);
497 AddCodeLine ("jsr pushax");
501 /* More than two bytes - loop */
502 unsigned Label = GetLocalLabel ();
504 ldyconst (Bytes - 1);
506 g_defcodelabel (Label);
507 AddCodeLine ("lda regbank%+d,x", RegOffs-1);
508 AddCodeLine ("sta (sp),y");
511 AddCodeLine ("bne %s", LocalLabelName (Label));
515 /* We pushed stuff, correct the stack pointer */
521 void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
522 /* Restore register variables */
524 /* Calculate the actual stack offset and check it */
526 CheckLocalOffs (StackOffs);
528 /* Don't loop for up to two bytes */
531 ldyconst (StackOffs);
532 AddCodeLine ("lda (sp),y");
533 AddCodeLine ("sta regbank%+d", RegOffs);
535 } else if (Bytes == 2) {
537 ldyconst (StackOffs);
538 AddCodeLine ("lda (sp),y");
539 AddCodeLine ("sta regbank%+d", RegOffs);
541 AddCodeLine ("lda (sp),y");
542 AddCodeLine ("sta regbank%+d", RegOffs+1);
546 /* More than two bytes - loop */
547 unsigned Label = GetLocalLabel ();
548 ldyconst (StackOffs+Bytes-1);
550 g_defcodelabel (Label);
551 AddCodeLine ("lda (sp),y");
552 AddCodeLine ("sta regbank%+d,x", RegOffs-1);
555 AddCodeLine ("bne %s", LocalLabelName (Label));
562 /*****************************************************************************/
563 /* Fetching memory cells */
564 /*****************************************************************************/
568 void g_getimmed (unsigned Flags, unsigned long Val, unsigned Offs)
569 /* Load a constant into the primary register */
571 unsigned char B1, B2, B3, B4;
575 if ((Flags & CF_CONST) != 0) {
577 /* Numeric constant */
578 switch (Flags & CF_TYPE) {
581 if ((Flags & CF_FORCECHAR) != 0) {
587 ldxconst ((Val >> 8) & 0xFF);
588 ldaconst (Val & 0xFF);
592 /* Split the value into 4 bytes */
593 B1 = (unsigned char) (Val >> 0);
594 B2 = (unsigned char) (Val >> 8);
595 B3 = (unsigned char) (Val >> 16);
596 B4 = (unsigned char) (Val >> 24);
598 /* Remember which bytes are done */
602 AddCodeLine ("ldx #$%02X", B2);
605 AddCodeLine ("stx sreg");
609 AddCodeLine ("stx sreg+1");
612 if ((Done & 0x04) == 0 && B1 != B3) {
613 AddCodeLine ("lda #$%02X", B3);
614 AddCodeLine ("sta sreg");
617 if ((Done & 0x08) == 0 && B1 != B4) {
618 AddCodeLine ("lda #$%02X", B4);
619 AddCodeLine ("sta sreg+1");
622 AddCodeLine ("lda #$%02X", B1);
624 if ((Done & 0x04) == 0) {
626 AddCodeLine ("sta sreg");
628 if ((Done & 0x08) == 0) {
630 AddCodeLine ("sta sreg+1");
642 /* Some sort of label */
643 const char* Label = GetLabelName (Flags, Val, Offs);
645 /* Load the address into the primary */
646 AddCodeLine ("lda #<(%s)", Label);
647 AddCodeLine ("ldx #>(%s)", Label);
654 void g_getstatic (unsigned flags, unsigned long label, unsigned offs)
655 /* Fetch an static memory cell into the primary register */
657 /* Create the correct label name */
658 char* lbuf = GetLabelName (flags, label, offs);
660 /* Check the size and generate the correct load operation */
661 switch (flags & CF_TYPE) {
664 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
665 AddCodeLine ("lda %s", lbuf); /* load A from the label */
668 AddCodeLine ("lda %s", lbuf); /* load A from the label */
669 if (!(flags & CF_UNSIGNED)) {
670 /* Must sign extend */
671 unsigned L = GetLocalLabel ();
672 AddCodeLine ("bpl %s", LocalLabelName (L));
680 AddCodeLine ("lda %s", lbuf);
681 if (flags & CF_TEST) {
682 AddCodeLine ("ora %s+1", lbuf);
684 AddCodeLine ("ldx %s+1", lbuf);
689 if (flags & CF_TEST) {
690 AddCodeLine ("lda %s+3", lbuf);
691 AddCodeLine ("ora %s+2", lbuf);
692 AddCodeLine ("ora %s+1", lbuf);
693 AddCodeLine ("ora %s+0", lbuf);
695 AddCodeLine ("lda %s+3", lbuf);
696 AddCodeLine ("sta sreg+1");
697 AddCodeLine ("lda %s+2", lbuf);
698 AddCodeLine ("sta sreg");
699 AddCodeLine ("ldx %s+1", lbuf);
700 AddCodeLine ("lda %s", lbuf);
712 void g_getlocal (unsigned flags, int offs)
713 /* Fetch specified local object (local var). */
716 CheckLocalOffs (offs);
717 switch (flags & CF_TYPE) {
720 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
721 if (CPU == CPU_65C02 && offs == 0) {
722 AddCodeLine ("lda (sp)");
725 AddCodeLine ("lda (sp),y");
729 AddCodeLine ("ldx #$00");
730 AddCodeLine ("lda (sp),y");
731 if ((flags & CF_UNSIGNED) == 0) {
732 unsigned L = GetLocalLabel();
733 AddCodeLine ("bpl %s", LocalLabelName (L));
741 CheckLocalOffs (offs + 1);
742 if (flags & CF_TEST) {
744 AddCodeLine ("lda (sp),y");
746 AddCodeLine ("ora (sp),y");
748 if (CodeSizeFactor > 180) {
750 AddCodeLine ("lda (sp),y");
753 AddCodeLine ("lda (sp),y");
757 AddCodeLine ("jsr ldaxysp");
759 AddCodeLine ("jsr ldax0sp");
768 AddCodeLine ("jsr ldeaxysp");
770 AddCodeLine ("jsr ldeax0sp");
781 void g_getind (unsigned flags, unsigned offs)
782 /* Fetch the specified object type indirect through the primary register
783 * into the primary register
786 /* If the offset is greater than 255, add the part that is > 255 to
787 * the primary. This way we get an easy addition and use the low byte
790 offs = MakeByteOffs (flags, offs);
792 /* Handle the indirect fetch */
793 switch (flags & CF_TYPE) {
796 /* Character sized */
797 if (flags & CF_UNSIGNED) {
799 AddCodeLine ("jsr ldauidx");
802 AddCodeLine ("jsr ldaidx");
807 if (flags & CF_TEST) {
809 AddCodeLine ("sta ptr1");
810 AddCodeLine ("stx ptr1+1");
811 AddCodeLine ("lda (ptr1),y");
813 AddCodeLine ("ora (ptr1),y");
816 AddCodeLine ("jsr ldaxi");
819 AddCodeLine ("jsr ldaxidx");
826 AddCodeLine ("jsr ldeaxi");
829 AddCodeLine ("jsr ldeaxidx");
831 if (flags & CF_TEST) {
832 AddCodeLine ("jsr tsteax");
844 void g_leasp (int offs)
845 /* Fetch the address of the specified symbol into the primary register */
847 /* Calculate the offset relative to sp */
850 /* For value 0 we do direct code */
852 AddCodeLine ("lda sp");
853 AddCodeLine ("ldx sp+1");
855 if (CodeSizeFactor < 300) {
856 ldaconst (offs); /* Load A with offset value */
857 AddCodeLine ("jsr leaasp"); /* Load effective address */
859 unsigned L = GetLocalLabel ();
860 if (CPU == CPU_65C02 && offs == 1) {
861 AddCodeLine ("lda sp");
862 AddCodeLine ("ldx sp+1");
864 AddCodeLine ("bne %s", LocalLabelName (L));
869 AddCodeLine ("ldx sp+1");
870 AddCodeLine ("adc sp");
871 AddCodeLine ("bcc %s", LocalLabelName (L));
881 void g_leavariadic (int Offs)
882 /* Fetch the address of a parameter in a variadic function into the primary
886 unsigned ArgSizeOffs;
888 /* Calculate the offset relative to sp */
891 /* Get the offset of the parameter which is stored at sp+0 on function
892 * entry and check if this offset is reachable with a byte offset.
895 ArgSizeOffs = -oursp;
896 CheckLocalOffs (ArgSizeOffs);
898 /* Get the size of all parameters. */
899 if (ArgSizeOffs == 0 && CPU == CPU_65C02) {
900 AddCodeLine ("lda (sp)");
902 ldyconst (ArgSizeOffs);
903 AddCodeLine ("lda (sp),y");
906 /* Add the value of the stackpointer */
907 if (CodeSizeFactor > 250) {
908 unsigned L = GetLocalLabel();
909 AddCodeLine ("ldx sp+1");
911 AddCodeLine ("adc sp");
912 AddCodeLine ("bcc %s", LocalLabelName (L));
916 AddCodeLine ("jsr leaasp");
919 /* Add the offset to the primary */
921 g_inc (CF_INT | CF_CONST, Offs);
922 } else if (Offs < 0) {
923 g_dec (CF_INT | CF_CONST, -Offs);
929 /*****************************************************************************/
930 /* Store into memory */
931 /*****************************************************************************/
935 void g_putstatic (unsigned flags, unsigned long label, unsigned offs)
936 /* Store the primary register into the specified static memory cell */
938 /* Create the correct label name */
939 char* lbuf = GetLabelName (flags, label, offs);
941 /* Check the size and generate the correct store operation */
942 switch (flags & CF_TYPE) {
945 AddCodeLine ("sta %s", lbuf);
949 AddCodeLine ("sta %s", lbuf);
950 AddCodeLine ("stx %s+1", lbuf);
954 AddCodeLine ("sta %s", lbuf);
955 AddCodeLine ("stx %s+1", lbuf);
956 AddCodeLine ("ldy sreg");
957 AddCodeLine ("sty %s+2", lbuf);
958 AddCodeLine ("ldy sreg+1");
959 AddCodeLine ("sty %s+3", lbuf);
970 void g_putlocal (unsigned Flags, int Offs, long Val)
971 /* Put data into local object. */
974 CheckLocalOffs (Offs);
975 switch (Flags & CF_TYPE) {
978 if (Flags & CF_CONST) {
979 AddCodeLine ("lda #$%02X", (unsigned char) Val);
981 if (CPU == CPU_65C02 && Offs == 0) {
982 AddCodeLine ("sta (sp)");
985 AddCodeLine ("sta (sp),y");
990 if (Flags & CF_CONST) {
992 AddCodeLine ("lda #$%02X", (unsigned char) (Val >> 8));
993 AddCodeLine ("sta (sp),y");
994 if ((Flags & CF_NOKEEP) == 0) {
995 /* Place high byte into X */
998 if (CPU == CPU_65C02 && Offs == 0) {
999 AddCodeLine ("lda #$%02X", (unsigned char) Val);
1000 AddCodeLine ("sta (sp)");
1002 if ((Val & 0xFF) == Offs+1) {
1003 /* The value we need is already in Y */
1004 AddCodeLine ("tya");
1005 AddCodeLine ("dey");
1007 AddCodeLine ("dey");
1008 AddCodeLine ("lda #$%02X", (unsigned char) Val);
1010 AddCodeLine ("sta (sp),y");
1013 if ((Flags & CF_NOKEEP) == 0 || CodeSizeFactor < 160) {
1016 AddCodeLine ("jsr staxysp");
1018 AddCodeLine ("jsr stax0sp");
1021 if (CPU == CPU_65C02 && Offs == 0) {
1022 AddCodeLine ("sta (sp)");
1024 AddCodeLine ("txa");
1025 AddCodeLine ("sta (sp),y");
1028 AddCodeLine ("sta (sp),y");
1029 AddCodeLine ("iny");
1030 AddCodeLine ("txa");
1031 AddCodeLine ("sta (sp),y");
1038 if (Flags & CF_CONST) {
1039 g_getimmed (Flags, Val, 0);
1043 AddCodeLine ("jsr steaxysp");
1045 AddCodeLine ("jsr steax0sp");
1057 void g_putind (unsigned Flags, unsigned Offs)
1058 /* Store the specified object type in the primary register at the address
1059 * on the top of the stack
1062 /* We can handle offsets below $100 directly, larger offsets must be added
1063 * to the address. Since a/x is in use, best code is achieved by adding
1064 * just the high byte. Be sure to check if the low byte will overflow while
1067 if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
1069 /* Overflow - we need to add the low byte also */
1070 AddCodeLine ("ldy #$00");
1071 AddCodeLine ("clc");
1072 AddCodeLine ("pha");
1073 AddCodeLine ("lda #$%02X", Offs & 0xFF);
1074 AddCodeLine ("adc (sp),y");
1075 AddCodeLine ("sta (sp),y");
1076 AddCodeLine ("iny");
1077 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1078 AddCodeLine ("adc (sp),y");
1079 AddCodeLine ("sta (sp),y");
1080 AddCodeLine ("pla");
1082 /* Complete address is on stack, new offset is zero */
1085 } else if ((Offs & 0xFF00) != 0) {
1087 /* We can just add the high byte */
1088 AddCodeLine ("ldy #$01");
1089 AddCodeLine ("clc");
1090 AddCodeLine ("pha");
1091 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1092 AddCodeLine ("adc (sp),y");
1093 AddCodeLine ("sta (sp),y");
1094 AddCodeLine ("pla");
1096 /* Offset is now just the low byte */
1100 /* Check the size and determine operation */
1101 switch (Flags & CF_TYPE) {
1105 AddCodeLine ("jsr staspidx");
1110 AddCodeLine ("jsr staxspidx");
1115 AddCodeLine ("jsr steaxspidx");
1123 /* Pop the argument which is always a pointer */
1129 /*****************************************************************************/
1130 /* type conversion and similiar stuff */
1131 /*****************************************************************************/
1135 void g_toslong (unsigned flags)
1136 /* Make sure, the value on TOS is a long. Convert if necessary */
1138 switch (flags & CF_TYPE) {
1142 if (flags & CF_UNSIGNED) {
1143 AddCodeLine ("jsr tosulong");
1145 AddCodeLine ("jsr toslong");
1160 void g_tosint (unsigned flags)
1161 /* Make sure, the value on TOS is an int. Convert if necessary */
1163 switch (flags & CF_TYPE) {
1170 AddCodeLine ("jsr tosint");
1181 void g_reglong (unsigned flags)
1182 /* Make sure, the value in the primary register a long. Convert if necessary */
1184 switch (flags & CF_TYPE) {
1188 if (flags & CF_UNSIGNED) {
1189 if (CodeSizeFactor >= 200) {
1191 AddCodeLine ("sty sreg");
1192 AddCodeLine ("sty sreg+1");
1194 AddCodeLine ("jsr axulong");
1197 AddCodeLine ("jsr axlong");
1211 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1212 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1213 * value, that corresponds to the value on TOS, rhs corresponds to the value
1214 * in (e)ax. The return value is the the flags value for the resulting type.
1217 unsigned ltype, rtype;
1220 /* Get the type spec from the flags */
1221 ltype = lhs & CF_TYPE;
1222 rtype = rhs & CF_TYPE;
1224 /* Check if a conversion is needed */
1225 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1226 /* We must promote the primary register to long */
1228 /* Get the new rhs type */
1229 rhs = (rhs & ~CF_TYPE) | CF_LONG;
1231 } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1232 /* We must promote the lhs to long */
1238 /* Get the new rhs type */
1239 lhs = (lhs & ~CF_TYPE) | CF_LONG;
1243 /* Determine the result type for the operation:
1244 * - The result is const if both operands are const.
1245 * - The result is unsigned if one of the operands is unsigned.
1246 * - The result is long if one of the operands is long.
1247 * - Otherwise the result is int sized.
1249 result = (lhs & CF_CONST) & (rhs & CF_CONST);
1250 result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1251 if (rtype == CF_LONG || ltype == CF_LONG) {
1261 unsigned g_typecast (unsigned lhs, unsigned rhs)
1262 /* Cast the value in the primary register to the operand size that is flagged
1263 * by the lhs value. Return the result value.
1266 unsigned ltype, rtype;
1268 /* Get the type spec from the flags */
1269 ltype = lhs & CF_TYPE;
1270 rtype = rhs & CF_TYPE;
1272 /* Check if a conversion is needed */
1273 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1274 /* We must promote the primary register to long */
1278 /* Do not need any other action. If the left type is int, and the primary
1279 * register is long, it will be automagically truncated. If the right hand
1280 * side is const, it is not located in the primary register and handled by
1281 * the expression parser code.
1284 /* Result is const if the right hand side was const */
1285 lhs |= (rhs & CF_CONST);
1287 /* The resulting type is that of the left hand side (that's why you called
1295 void g_scale (unsigned flags, long val)
1296 /* Scale the value in the primary register by the given value. If val is positive,
1297 * scale up, is val is negative, scale down. This function is used to scale
1298 * the operands or results of pointer arithmetic by the size of the type, the
1299 * pointer points to.
1304 /* Value may not be zero */
1306 Internal ("Data type has no size");
1307 } else if (val > 0) {
1310 if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
1312 /* Factor is 2, 4, 8 and 16, use special function */
1313 switch (flags & CF_TYPE) {
1316 if (flags & CF_FORCECHAR) {
1318 AddCodeLine ("asl a");
1325 if (CodeSizeFactor >= (p2+1)*130U) {
1326 AddCodeLine ("stx tmp1");
1328 AddCodeLine ("asl a");
1329 AddCodeLine ("rol tmp1");
1331 AddCodeLine ("ldx tmp1");
1333 if (flags & CF_UNSIGNED) {
1334 AddCodeLine ("jsr shlax%d", p2);
1336 AddCodeLine ("jsr aslax%d", p2);
1342 if (flags & CF_UNSIGNED) {
1343 AddCodeLine ("jsr shleax%d", p2);
1345 AddCodeLine ("jsr asleax%d", p2);
1354 } else if (val != 1) {
1356 /* Use a multiplication instead */
1357 g_mul (flags | CF_CONST, val);
1365 if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
1367 /* Factor is 2, 4, 8 and 16 use special function */
1368 switch (flags & CF_TYPE) {
1371 if (flags & CF_FORCECHAR) {
1372 if (flags & CF_UNSIGNED) {
1374 AddCodeLine ("lsr a");
1377 } else if (p2 <= 2) {
1378 AddCodeLine ("cmp #$80");
1379 AddCodeLine ("ror a");
1386 if (flags & CF_UNSIGNED) {
1387 if (CodeSizeFactor >= (p2+1)*130U) {
1388 AddCodeLine ("stx tmp1");
1390 AddCodeLine ("lsr tmp1");
1391 AddCodeLine ("ror a");
1393 AddCodeLine ("ldx tmp1");
1395 AddCodeLine ("jsr lsrax%d", p2);
1398 if (CodeSizeFactor >= (p2+1)*150U) {
1399 AddCodeLine ("stx tmp1");
1401 AddCodeLine ("cpx #$80");
1402 AddCodeLine ("ror tmp1");
1403 AddCodeLine ("ror a");
1405 AddCodeLine ("ldx tmp1");
1407 AddCodeLine ("jsr asrax%d", p2);
1413 if (flags & CF_UNSIGNED) {
1414 AddCodeLine ("jsr lsreax%d", p2);
1416 AddCodeLine ("jsr asreax%d", p2);
1425 } else if (val != 1) {
1427 /* Use a division instead */
1428 g_div (flags | CF_CONST, val);
1436 /*****************************************************************************/
1437 /* Adds and subs of variables fix a fixed address */
1438 /*****************************************************************************/
1442 void g_addlocal (unsigned flags, int offs)
1443 /* Add a local variable to ax */
1447 /* Correct the offset and check it */
1449 CheckLocalOffs (offs);
1451 switch (flags & CF_TYPE) {
1454 L = GetLocalLabel();
1455 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1456 AddCodeLine ("clc");
1457 AddCodeLine ("adc (sp),y");
1458 AddCodeLine ("bcc %s", LocalLabelName (L));
1459 AddCodeLine ("inx");
1464 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1465 AddCodeLine ("clc");
1466 AddCodeLine ("adc (sp),y");
1467 AddCodeLine ("pha");
1468 AddCodeLine ("txa");
1469 AddCodeLine ("iny");
1470 AddCodeLine ("adc (sp),y");
1471 AddCodeLine ("tax");
1472 AddCodeLine ("pla");
1476 /* Do it the old way */
1478 g_getlocal (flags, offs);
1490 void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
1491 /* Add a static variable to ax */
1495 /* Create the correct label name */
1496 char* lbuf = GetLabelName (flags, label, offs);
1498 switch (flags & CF_TYPE) {
1501 L = GetLocalLabel();
1502 AddCodeLine ("clc");
1503 AddCodeLine ("adc %s", lbuf);
1504 AddCodeLine ("bcc %s", LocalLabelName (L));
1505 AddCodeLine ("inx");
1510 AddCodeLine ("clc");
1511 AddCodeLine ("adc %s", lbuf);
1512 AddCodeLine ("tay");
1513 AddCodeLine ("txa");
1514 AddCodeLine ("adc %s+1", lbuf);
1515 AddCodeLine ("tax");
1516 AddCodeLine ("tya");
1520 /* Do it the old way */
1522 g_getstatic (flags, label, offs);
1534 /*****************************************************************************/
1535 /* Compares of ax with a variable with fixed address */
1536 /*****************************************************************************/
1540 void g_cmplocal (unsigned flags, int offs)
1541 /* Compare a local variable to ax */
1543 Internal ("g_cmplocal not implemented");
1548 void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
1549 /* Compare a static variable to ax */
1551 Internal ("g_cmpstatic not implemented");
1556 /*****************************************************************************/
1557 /* Special op= functions */
1558 /*****************************************************************************/
1562 void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
1564 /* Emit += for a static variable */
1566 /* Create the correct label name */
1567 char* lbuf = GetLabelName (flags, label, offs);
1569 /* Check the size and determine operation */
1570 switch (flags & CF_TYPE) {
1573 if (flags & CF_FORCECHAR) {
1574 AddCodeLine ("ldx #$00");
1575 if (flags & CF_CONST) {
1577 AddCodeLine ("inc %s", lbuf);
1578 AddCodeLine ("lda %s", lbuf);
1580 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1581 AddCodeLine ("clc");
1582 AddCodeLine ("adc %s", lbuf);
1583 AddCodeLine ("sta %s", lbuf);
1586 AddCodeLine ("clc");
1587 AddCodeLine ("adc %s", lbuf);
1588 AddCodeLine ("sta %s", lbuf);
1590 if ((flags & CF_UNSIGNED) == 0) {
1591 unsigned L = GetLocalLabel();
1592 AddCodeLine ("bpl %s", LocalLabelName (L));
1593 AddCodeLine ("dex");
1601 if (flags & CF_CONST) {
1603 unsigned L = GetLocalLabel ();
1604 AddCodeLine ("inc %s", lbuf);
1605 AddCodeLine ("bne %s", LocalLabelName (L));
1606 AddCodeLine ("inc %s+1", lbuf);
1608 AddCodeLine ("lda %s", lbuf); /* Hmmm... */
1609 AddCodeLine ("ldx %s+1", lbuf);
1611 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1612 AddCodeLine ("clc");
1613 AddCodeLine ("adc %s", lbuf);
1614 AddCodeLine ("sta %s", lbuf);
1616 unsigned L = GetLocalLabel ();
1617 AddCodeLine ("bcc %s", LocalLabelName (L));
1618 AddCodeLine ("inc %s+1", lbuf);
1620 AddCodeLine ("ldx %s+1", lbuf);
1622 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1623 AddCodeLine ("adc %s+1", lbuf);
1624 AddCodeLine ("sta %s+1", lbuf);
1625 AddCodeLine ("tax");
1626 AddCodeLine ("lda %s", lbuf);
1630 AddCodeLine ("clc");
1631 AddCodeLine ("adc %s", lbuf);
1632 AddCodeLine ("sta %s", lbuf);
1633 AddCodeLine ("txa");
1634 AddCodeLine ("adc %s+1", lbuf);
1635 AddCodeLine ("sta %s+1", lbuf);
1636 AddCodeLine ("tax");
1637 AddCodeLine ("lda %s", lbuf);
1642 if (flags & CF_CONST) {
1644 AddCodeLine ("ldy #<(%s)", lbuf);
1645 AddCodeLine ("sty ptr1");
1646 AddCodeLine ("ldy #>(%s+1)", lbuf);
1648 AddCodeLine ("jsr laddeq1");
1650 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1651 AddCodeLine ("jsr laddeqa");
1654 g_getstatic (flags, label, offs);
1656 g_putstatic (flags, label, offs);
1659 AddCodeLine ("ldy #<(%s)", lbuf);
1660 AddCodeLine ("sty ptr1");
1661 AddCodeLine ("ldy #>(%s+1)", lbuf);
1662 AddCodeLine ("jsr laddeq");
1673 void g_addeqlocal (unsigned flags, int offs, unsigned long val)
1674 /* Emit += for a local variable */
1676 /* Calculate the true offset, check it, load it into Y */
1678 CheckLocalOffs (offs);
1680 /* Check the size and determine operation */
1681 switch (flags & CF_TYPE) {
1684 if (flags & CF_FORCECHAR) {
1686 AddCodeLine ("ldx #$00");
1687 if (flags & CF_CONST) {
1688 AddCodeLine ("clc");
1689 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1690 AddCodeLine ("adc (sp),y");
1691 AddCodeLine ("sta (sp),y");
1693 AddCodeLine ("clc");
1694 AddCodeLine ("adc (sp),y");
1695 AddCodeLine ("sta (sp),y");
1697 if ((flags & CF_UNSIGNED) == 0) {
1698 unsigned L = GetLocalLabel();
1699 AddCodeLine ("bpl %s", LocalLabelName (L));
1700 AddCodeLine ("dex");
1708 if (flags & CF_CONST) {
1709 g_getimmed (flags, val, 0);
1712 AddCodeLine ("jsr addeqysp");
1716 if (flags & CF_CONST) {
1717 g_getimmed (flags, val, 0);
1720 AddCodeLine ("jsr laddeq0sp");
1723 AddCodeLine ("jsr laddeqysp");
1734 void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1735 /* Emit += for the location with address in ax */
1737 /* If the offset is too large for a byte register, add the high byte
1738 * of the offset to the primary. Beware: We need a special correction
1739 * if the offset in the low byte will overflow in the operation.
1741 offs = MakeByteOffs (flags, offs);
1743 /* Check the size and determine operation */
1744 switch (flags & CF_TYPE) {
1747 AddCodeLine ("sta ptr1");
1748 AddCodeLine ("stx ptr1+1");
1749 AddCodeLine ("ldy #$%02X", offs);
1750 AddCodeLine ("ldx #$00");
1751 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1752 AddCodeLine ("clc");
1753 AddCodeLine ("adc (ptr1),y");
1754 AddCodeLine ("sta (ptr1),y");
1758 if (CodeSizeFactor >= 200) {
1759 /* Lots of code, use only if size is not important */
1760 AddCodeLine ("sta ptr1");
1761 AddCodeLine ("stx ptr1+1");
1762 AddCodeLine ("ldy #$%02X", offs);
1763 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1764 AddCodeLine ("clc");
1765 AddCodeLine ("adc (ptr1),y");
1766 AddCodeLine ("sta (ptr1),y");
1767 AddCodeLine ("pha");
1768 AddCodeLine ("iny");
1769 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1770 AddCodeLine ("adc (ptr1),y");
1771 AddCodeLine ("sta (ptr1),y");
1772 AddCodeLine ("tax");
1773 AddCodeLine ("pla");
1779 AddCodeLine ("jsr pushax"); /* Push the address */
1780 push (CF_PTR); /* Correct the internal sp */
1781 g_getind (flags, offs); /* Fetch the value */
1782 g_inc (flags, val); /* Increment value in primary */
1783 g_putind (flags, offs); /* Store the value back */
1793 void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
1795 /* Emit -= for a static variable */
1797 /* Create the correct label name */
1798 char* lbuf = GetLabelName (flags, label, offs);
1800 /* Check the size and determine operation */
1801 switch (flags & CF_TYPE) {
1804 if (flags & CF_FORCECHAR) {
1805 AddCodeLine ("ldx #$00");
1806 if (flags & CF_CONST) {
1808 AddCodeLine ("dec %s", lbuf);
1809 AddCodeLine ("lda %s", lbuf);
1811 AddCodeLine ("sec");
1812 AddCodeLine ("lda %s", lbuf);
1813 AddCodeLine ("sbc #$%02X", (int)(val & 0xFF));
1814 AddCodeLine ("sta %s", lbuf);
1817 AddCodeLine ("sec");
1818 AddCodeLine ("sta tmp1");
1819 AddCodeLine ("lda %s", lbuf);
1820 AddCodeLine ("sbc tmp1");
1821 AddCodeLine ("sta %s", lbuf);
1823 if ((flags & CF_UNSIGNED) == 0) {
1824 unsigned L = GetLocalLabel();
1825 AddCodeLine ("bpl %s", LocalLabelName (L));
1826 AddCodeLine ("dex");
1834 AddCodeLine ("sec");
1835 if (flags & CF_CONST) {
1836 AddCodeLine ("lda %s", lbuf);
1837 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1838 AddCodeLine ("sta %s", lbuf);
1840 unsigned L = GetLocalLabel ();
1841 AddCodeLine ("bcs %s", LocalLabelName (L));
1842 AddCodeLine ("dec %s+1", lbuf);
1844 AddCodeLine ("ldx %s+1", lbuf);
1846 AddCodeLine ("lda %s+1", lbuf);
1847 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1848 AddCodeLine ("sta %s+1", lbuf);
1849 AddCodeLine ("tax");
1850 AddCodeLine ("lda %s", lbuf);
1853 AddCodeLine ("sta tmp1");
1854 AddCodeLine ("lda %s", lbuf);
1855 AddCodeLine ("sbc tmp1");
1856 AddCodeLine ("sta %s", lbuf);
1857 AddCodeLine ("stx tmp1");
1858 AddCodeLine ("lda %s+1", lbuf);
1859 AddCodeLine ("sbc tmp1");
1860 AddCodeLine ("sta %s+1", lbuf);
1861 AddCodeLine ("tax");
1862 AddCodeLine ("lda %s", lbuf);
1867 if (flags & CF_CONST) {
1869 AddCodeLine ("ldy #<(%s)", lbuf);
1870 AddCodeLine ("sty ptr1");
1871 AddCodeLine ("ldy #>(%s+1)", lbuf);
1873 AddCodeLine ("jsr lsubeq1");
1875 AddCodeLine ("lda #$%02X", (unsigned char)val);
1876 AddCodeLine ("jsr lsubeqa");
1879 g_getstatic (flags, label, offs);
1881 g_putstatic (flags, label, offs);
1884 AddCodeLine ("ldy #<(%s)", lbuf);
1885 AddCodeLine ("sty ptr1");
1886 AddCodeLine ("ldy #>(%s+1)", lbuf);
1887 AddCodeLine ("jsr lsubeq");
1898 void g_subeqlocal (unsigned flags, int offs, unsigned long val)
1899 /* Emit -= for a local variable */
1901 /* Calculate the true offset, check it, load it into Y */
1903 CheckLocalOffs (offs);
1905 /* Check the size and determine operation */
1906 switch (flags & CF_TYPE) {
1909 if (flags & CF_FORCECHAR) {
1911 AddCodeLine ("ldx #$00");
1912 AddCodeLine ("sec");
1913 if (flags & CF_CONST) {
1914 AddCodeLine ("lda (sp),y");
1915 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1917 AddCodeLine ("sta tmp1");
1918 AddCodeLine ("lda (sp),y");
1919 AddCodeLine ("sbc tmp1");
1921 AddCodeLine ("sta (sp),y");
1922 if ((flags & CF_UNSIGNED) == 0) {
1923 unsigned L = GetLocalLabel();
1924 AddCodeLine ("bpl %s", LocalLabelName (L));
1925 AddCodeLine ("dex");
1933 if (flags & CF_CONST) {
1934 g_getimmed (flags, val, 0);
1937 AddCodeLine ("jsr subeq0sp");
1940 AddCodeLine ("jsr subeqysp");
1945 if (flags & CF_CONST) {
1946 g_getimmed (flags, val, 0);
1949 AddCodeLine ("jsr lsubeq0sp");
1952 AddCodeLine ("jsr lsubeqysp");
1963 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
1964 /* Emit -= for the location with address in ax */
1966 /* If the offset is too large for a byte register, add the high byte
1967 * of the offset to the primary. Beware: We need a special correction
1968 * if the offset in the low byte will overflow in the operation.
1970 offs = MakeByteOffs (flags, offs);
1972 /* Check the size and determine operation */
1973 switch (flags & CF_TYPE) {
1976 AddCodeLine ("sta ptr1");
1977 AddCodeLine ("stx ptr1+1");
1978 AddCodeLine ("ldy #$%02X", offs);
1979 AddCodeLine ("ldx #$00");
1980 AddCodeLine ("lda (ptr1),y");
1981 AddCodeLine ("sec");
1982 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1983 AddCodeLine ("sta (ptr1),y");
1987 if (CodeSizeFactor >= 200) {
1988 /* Lots of code, use only if size is not important */
1989 AddCodeLine ("sta ptr1");
1990 AddCodeLine ("stx ptr1+1");
1991 AddCodeLine ("ldy #$%02X", offs);
1992 AddCodeLine ("lda (ptr1),y");
1993 AddCodeLine ("sec");
1994 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1995 AddCodeLine ("sta (ptr1),y");
1996 AddCodeLine ("pha");
1997 AddCodeLine ("iny");
1998 AddCodeLine ("lda (ptr1),y");
1999 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
2000 AddCodeLine ("sta (ptr1),y");
2001 AddCodeLine ("tax");
2002 AddCodeLine ("pla");
2008 AddCodeLine ("jsr pushax"); /* Push the address */
2009 push (CF_PTR); /* Correct the internal sp */
2010 g_getind (flags, offs); /* Fetch the value */
2011 g_dec (flags, val); /* Increment value in primary */
2012 g_putind (flags, offs); /* Store the value back */
2022 /*****************************************************************************/
2023 /* Add a variable address to the value in ax */
2024 /*****************************************************************************/
2028 void g_addaddr_local (unsigned flags, int offs)
2029 /* Add the address of a local variable to ax */
2033 /* Add the offset */
2036 /* We cannot address more then 256 bytes of locals anyway */
2037 L = GetLocalLabel();
2038 CheckLocalOffs (offs);
2039 AddCodeLine ("clc");
2040 AddCodeLine ("adc #$%02X", offs & 0xFF);
2041 /* Do also skip the CLC insn below */
2042 AddCodeLine ("bcc %s", LocalLabelName (L));
2043 AddCodeLine ("inx");
2046 /* Add the current stackpointer value */
2047 AddCodeLine ("clc");
2049 /* Label was used above */
2052 AddCodeLine ("adc sp");
2053 AddCodeLine ("tay");
2054 AddCodeLine ("txa");
2055 AddCodeLine ("adc sp+1");
2056 AddCodeLine ("tax");
2057 AddCodeLine ("tya");
2062 void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
2063 /* Add the address of a static variable to ax */
2065 /* Create the correct label name */
2066 char* lbuf = GetLabelName (flags, label, offs);
2068 /* Add the address to the current ax value */
2069 AddCodeLine ("clc");
2070 AddCodeLine ("adc #<(%s)", lbuf);
2071 AddCodeLine ("tay");
2072 AddCodeLine ("txa");
2073 AddCodeLine ("adc #>(%s)", lbuf);
2074 AddCodeLine ("tax");
2075 AddCodeLine ("tya");
2080 /*****************************************************************************/
2082 /*****************************************************************************/
2086 void g_save (unsigned flags)
2087 /* Copy primary register to hold register. */
2089 /* Check the size and determine operation */
2090 switch (flags & CF_TYPE) {
2093 if (flags & CF_FORCECHAR) {
2094 AddCodeLine ("pha");
2100 AddCodeLine ("sta regsave");
2101 AddCodeLine ("stx regsave+1");
2105 AddCodeLine ("jsr saveeax");
2115 void g_restore (unsigned flags)
2116 /* Copy hold register to primary. */
2118 /* Check the size and determine operation */
2119 switch (flags & CF_TYPE) {
2122 if (flags & CF_FORCECHAR) {
2123 AddCodeLine ("pla");
2129 AddCodeLine ("lda regsave");
2130 AddCodeLine ("ldx regsave+1");
2134 AddCodeLine ("jsr resteax");
2144 void g_cmp (unsigned flags, unsigned long val)
2145 /* Immidiate compare. The primary register will not be changed, Z flag
2151 /* Check the size and determine operation */
2152 switch (flags & CF_TYPE) {
2155 if (flags & CF_FORCECHAR) {
2156 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2162 L = GetLocalLabel();
2163 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2164 AddCodeLine ("bne %s", LocalLabelName (L));
2165 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
2170 Internal ("g_cmp: Long compares not implemented");
2180 static void oper (unsigned flags, unsigned long val, char** subs)
2181 /* Encode a binary operation. subs is a pointer to four groups of three
2183 * 0-2 --> Operate on ints
2184 * 3-5 --> Operate on unsigneds
2185 * 6-8 --> Operate on longs
2186 * 9-11 --> Operate on unsigned longs
2188 * The first subroutine names in each string group is used to encode an
2189 * operation with a zero constant, the second to encode an operation with
2190 * a 8 bit constant, and the third is used in all other cases.
2195 /* Determine the offset into the array */
2196 offs = (flags & CF_UNSIGNED)? 3 : 0;
2197 switch (flags & CF_TYPE) {
2210 /* Encode the operation */
2211 if (flags & CF_CONST) {
2212 /* Constant value given */
2213 if (val == 0 && subs [offs+0]) {
2214 /* Special case: constant with value zero */
2215 AddCodeLine ("jsr %s", subs [offs+0]);
2216 } else if (val < 0x100 && subs [offs+1]) {
2217 /* Special case: constant with high byte zero */
2218 ldaconst (val); /* Load low byte */
2219 AddCodeLine ("jsr %s", subs [offs+1]);
2221 /* Others: arbitrary constant value */
2222 g_getimmed (flags, val, 0); /* Load value */
2223 AddCodeLine ("jsr %s", subs [offs+2]);
2226 /* Value not constant (is already in (e)ax) */
2227 AddCodeLine ("jsr %s", subs [offs+2]);
2230 /* The operation will pop it's argument */
2236 void g_test (unsigned flags)
2237 /* Test the value in the primary and set the condition codes */
2239 switch (flags & CF_TYPE) {
2242 if (flags & CF_FORCECHAR) {
2243 AddCodeLine ("tax");
2249 AddCodeLine ("stx tmp1");
2250 AddCodeLine ("ora tmp1");
2254 if (flags & CF_UNSIGNED) {
2255 AddCodeLine ("jsr utsteax");
2257 AddCodeLine ("jsr tsteax");
2269 void g_push (unsigned flags, unsigned long val)
2270 /* Push the primary register or a constant value onto the stack */
2274 if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2276 /* We have a constant 8 or 16 bit value */
2277 if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2279 /* Handle as 8 bit value */
2280 if (CodeSizeFactor >= 165 || val > 2) {
2282 AddCodeLine ("jsr pusha");
2284 AddCodeLine ("jsr pushc%d", (int) val);
2289 /* Handle as 16 bit value */
2290 hi = (unsigned char) (val >> 8);
2292 AddCodeLine ("jsr push%u", (unsigned) val);
2293 } else if (hi == 0 || hi == 0xFF) {
2294 /* Use special function */
2296 AddCodeLine ("jsr %s", (hi == 0)? "pusha0" : "pushaFF");
2299 g_getimmed (flags, val, 0);
2300 AddCodeLine ("jsr pushax");
2306 /* Value is not 16 bit or not constant */
2307 if (flags & CF_CONST) {
2308 /* Constant 32 bit value, load into eax */
2309 g_getimmed (flags, val, 0);
2312 /* Push the primary register */
2313 switch (flags & CF_TYPE) {
2316 if (flags & CF_FORCECHAR) {
2317 /* Handle as char */
2318 AddCodeLine ("jsr pusha");
2323 AddCodeLine ("jsr pushax");
2327 AddCodeLine ("jsr pusheax");
2337 /* Adjust the stack offset */
2343 void g_swap (unsigned flags)
2344 /* Swap the primary register and the top of the stack. flags give the type
2345 * of *both* values (must have same size).
2348 switch (flags & CF_TYPE) {
2352 AddCodeLine ("jsr swapstk");
2356 AddCodeLine ("jsr swapestk");
2367 void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2368 /* Call the specified subroutine name */
2370 if ((Flags & CF_FIXARGC) == 0) {
2371 /* Pass the argument count */
2374 AddCodeLine ("jsr _%s", Label);
2375 oursp += ArgSize; /* callee pops args */
2380 void g_callind (unsigned Flags, unsigned ArgSize)
2381 /* Call subroutine with address in AX */
2383 if ((Flags & CF_FIXARGC) == 0) {
2384 /* Pass arg count */
2387 AddCodeLine ("jsr callax"); /* do the call */
2388 oursp += ArgSize; /* callee pops args */
2393 void g_jump (unsigned Label)
2394 /* Jump to specified internal label number */
2396 AddCodeLine ("jmp %s", LocalLabelName (Label));
2401 void g_switch (unsigned Flags)
2402 /* Output switch statement preamble */
2404 switch (Flags & CF_TYPE) {
2408 AddCodeLine ("jsr switch");
2412 AddCodeLine ("jsr lswitch");
2423 void g_case (unsigned flags, unsigned label, unsigned long val)
2424 /* Create table code for one case selector */
2426 switch (flags & CF_TYPE) {
2430 AddCodeLine (".word $%04X, %s",
2431 (unsigned)(val & 0xFFFF),
2432 LocalLabelName (label));
2436 AddCodeLine (".dword $%08lX", val);
2437 AddCodeLine (".word %s", LocalLabelName (label));
2448 void g_truejump (unsigned flags, unsigned label)
2449 /* Jump to label if zero flag clear */
2451 AddCodeLine ("jne %s", LocalLabelName (label));
2456 void g_falsejump (unsigned flags, unsigned label)
2457 /* Jump to label if zero flag set */
2459 AddCodeLine ("jeq %s", LocalLabelName (label));
2464 static void mod_internal (int k, char* verb1, char* verb2)
2467 AddCodeLine ("jsr %ssp%c", verb1, k + '0');
2471 AddCodeLine ("jsr %ssp", verb2);
2477 void g_space (int space)
2478 /* Create or drop space on the stack */
2481 mod_internal (-space, "inc", "addy");
2482 } else if (space > 0) {
2483 mod_internal (space, "dec", "suby");
2489 void g_cstackcheck (void)
2490 /* Check for a C stack overflow */
2492 AddCodeLine ("jsr cstkchk");
2497 void g_stackcheck (void)
2498 /* Check for a stack overflow */
2500 AddCodeLine ("jsr stkchk");
2505 void g_add (unsigned flags, unsigned long val)
2506 /* Primary = TOS + Primary */
2508 static char* ops [12] = {
2509 0, "tosadda0", "tosaddax",
2510 0, "tosadda0", "tosaddax",
2515 if (flags & CF_CONST) {
2516 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2517 g_push (flags & ~CF_CONST, 0);
2519 oper (flags, val, ops);
2524 void g_sub (unsigned flags, unsigned long val)
2525 /* Primary = TOS - Primary */
2527 static char* ops [12] = {
2528 0, "tossuba0", "tossubax",
2529 0, "tossuba0", "tossubax",
2534 if (flags & CF_CONST) {
2535 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2536 g_push (flags & ~CF_CONST, 0);
2538 oper (flags, val, ops);
2543 void g_rsub (unsigned flags, unsigned long val)
2544 /* Primary = Primary - TOS */
2546 static char* ops [12] = {
2547 0, "tosrsuba0", "tosrsubax",
2548 0, "tosrsuba0", "tosrsubax",
2552 oper (flags, val, ops);
2557 void g_mul (unsigned flags, unsigned long val)
2558 /* Primary = TOS * Primary */
2560 static char* ops [12] = {
2561 0, "tosmula0", "tosmulax",
2562 0, "tosumula0", "tosumulax",
2569 /* Do strength reduction if the value is constant and a power of two */
2570 if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2571 /* Generate a shift instead */
2576 /* If the right hand side is const, the lhs is not on stack but still
2577 * in the primary register.
2579 if (flags & CF_CONST) {
2581 switch (flags & CF_TYPE) {
2584 if (flags & CF_FORCECHAR) {
2585 /* Handle some special cases */
2589 AddCodeLine ("sta tmp1");
2590 AddCodeLine ("asl a");
2591 AddCodeLine ("clc");
2592 AddCodeLine ("adc tmp1");
2596 AddCodeLine ("sta tmp1");
2597 AddCodeLine ("asl a");
2598 AddCodeLine ("asl a");
2599 AddCodeLine ("clc");
2600 AddCodeLine ("adc tmp1");
2604 AddCodeLine ("sta tmp1");
2605 AddCodeLine ("asl a");
2606 AddCodeLine ("asl a");
2607 AddCodeLine ("clc");
2608 AddCodeLine ("adc tmp1");
2609 AddCodeLine ("asl a");
2625 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2626 * into the normal, non-optimized stuff.
2628 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2629 g_push (flags & ~CF_CONST, 0);
2633 /* Use long way over the stack */
2634 oper (flags, val, ops);
2639 void g_div (unsigned flags, unsigned long val)
2640 /* Primary = TOS / Primary */
2642 static char* ops [12] = {
2643 0, "tosdiva0", "tosdivax",
2644 0, "tosudiva0", "tosudivax",
2649 /* Do strength reduction if the value is constant and a power of two */
2651 if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2652 /* Generate a shift instead */
2655 /* Generate a division */
2656 if (flags & CF_CONST) {
2657 /* lhs is not on stack */
2658 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2659 g_push (flags & ~CF_CONST, 0);
2661 oper (flags, val, ops);
2667 void g_mod (unsigned flags, unsigned long val)
2668 /* Primary = TOS % Primary */
2670 static char* ops [12] = {
2671 0, "tosmoda0", "tosmodax",
2672 0, "tosumoda0", "tosumodax",
2678 /* Check if we can do some cost reduction */
2679 if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2680 /* We can do that with an AND operation */
2681 g_and (flags, val - 1);
2683 /* Do it the hard way... */
2684 if (flags & CF_CONST) {
2685 /* lhs is not on stack */
2686 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2687 g_push (flags & ~CF_CONST, 0);
2689 oper (flags, val, ops);
2695 void g_or (unsigned flags, unsigned long val)
2696 /* Primary = TOS | Primary */
2698 static char* ops [12] = {
2699 0, "tosora0", "tosorax",
2700 0, "tosora0", "tosorax",
2705 /* If the right hand side is const, the lhs is not on stack but still
2706 * in the primary register.
2708 if (flags & CF_CONST) {
2710 switch (flags & CF_TYPE) {
2713 if (flags & CF_FORCECHAR) {
2714 if ((val & 0xFF) != 0xFF) {
2715 AddCodeLine ("ora #$%02X", (unsigned char)val);
2723 AddCodeLine ("ora #$%02X", (unsigned char)val);
2730 AddCodeLine ("ora #$%02X", (unsigned char)val);
2739 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2740 * into the normal, non-optimized stuff.
2742 g_push (flags & ~CF_CONST, 0);
2746 /* Use long way over the stack */
2747 oper (flags, val, ops);
2752 void g_xor (unsigned flags, unsigned long val)
2753 /* Primary = TOS ^ Primary */
2755 static char* ops [12] = {
2756 0, "tosxora0", "tosxorax",
2757 0, "tosxora0", "tosxorax",
2763 /* If the right hand side is const, the lhs is not on stack but still
2764 * in the primary register.
2766 if (flags & CF_CONST) {
2768 switch (flags & CF_TYPE) {
2771 if (flags & CF_FORCECHAR) {
2772 if ((val & 0xFF) != 0) {
2773 AddCodeLine ("eor #$%02X", (unsigned char)val);
2782 AddCodeLine ("eor #$%02X", (unsigned char)val);
2785 } else if ((val & 0xFF) == 0) {
2786 AddCodeLine ("pha");
2787 AddCodeLine ("txa");
2788 AddCodeLine ("eor #$%02X", (unsigned char)(val >> 8));
2789 AddCodeLine ("tax");
2790 AddCodeLine ("pla");
2798 AddCodeLine ("eor #$%02X", (unsigned char)val);
2808 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2809 * into the normal, non-optimized stuff.
2811 g_push (flags & ~CF_CONST, 0);
2815 /* Use long way over the stack */
2816 oper (flags, val, ops);
2821 void g_and (unsigned flags, unsigned long val)
2822 /* Primary = TOS & Primary */
2824 static char* ops [12] = {
2825 0, "tosanda0", "tosandax",
2826 0, "tosanda0", "tosandax",
2831 /* If the right hand side is const, the lhs is not on stack but still
2832 * in the primary register.
2834 if (flags & CF_CONST) {
2836 switch (flags & CF_TYPE) {
2839 if (flags & CF_FORCECHAR) {
2840 AddCodeLine ("and #$%02X", (unsigned char)val);
2845 if ((val & 0xFFFF) != 0xFFFF) {
2850 } else if (val != 0xFF) {
2851 AddCodeLine ("and #$%02X", (unsigned char)val);
2853 } else if ((val & 0xFF00) == 0xFF00) {
2854 AddCodeLine ("and #$%02X", (unsigned char)val);
2855 } else if ((val & 0x00FF) == 0x0000) {
2856 AddCodeLine ("txa");
2857 AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2858 AddCodeLine ("tax");
2861 AddCodeLine ("tay");
2862 AddCodeLine ("txa");
2863 AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2864 AddCodeLine ("tax");
2865 AddCodeLine ("tya");
2866 if ((val & 0x00FF) != 0x00FF) {
2867 AddCodeLine ("and #$%02X", (unsigned char)val);
2876 AddCodeLine ("stx sreg+1");
2877 AddCodeLine ("stx sreg");
2878 if ((val & 0xFF) != 0xFF) {
2879 AddCodeLine ("and #$%02X", (unsigned char)val);
2882 } else if (val == 0xFF00) {
2884 AddCodeLine ("sta sreg+1");
2885 AddCodeLine ("sta sreg");
2894 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2895 * into the normal, non-optimized stuff.
2897 g_push (flags & ~CF_CONST, 0);
2901 /* Use long way over the stack */
2902 oper (flags, val, ops);
2907 void g_asr (unsigned flags, unsigned long val)
2908 /* Primary = TOS >> Primary */
2910 static char* ops [12] = {
2911 0, "tosasra0", "tosasrax",
2912 0, "tosshra0", "tosshrax",
2917 /* If the right hand side is const, the lhs is not on stack but still
2918 * in the primary register.
2920 if (flags & CF_CONST) {
2922 switch (flags & CF_TYPE) {
2926 if (val >= 1 && val <= 4) {
2927 if (flags & CF_UNSIGNED) {
2928 AddCodeLine ("jsr shrax%ld", val);
2930 AddCodeLine ("jsr asrax%ld", val);
2933 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2934 AddCodeLine ("txa");
2941 if (val >= 1 && val <= 4) {
2942 if (flags & CF_UNSIGNED) {
2943 AddCodeLine ("jsr shreax%ld", val);
2945 AddCodeLine ("jsr asreax%ld", val);
2948 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2949 AddCodeLine ("txa");
2950 AddCodeLine ("ldx sreg");
2951 AddCodeLine ("ldy sreg+1");
2952 AddCodeLine ("sty sreg");
2953 AddCodeLine ("ldy #$00");
2954 AddCodeLine ("sty sreg+1");
2956 } else if (val == 16) {
2957 AddCodeLine ("ldy #$00");
2958 AddCodeLine ("ldx sreg+1");
2959 if ((flags & CF_UNSIGNED) == 0) {
2960 unsigned L = GetLocalLabel();
2961 AddCodeLine ("bpl %s", LocalLabelName (L));
2962 AddCodeLine ("dey");
2965 AddCodeLine ("lda sreg");
2966 AddCodeLine ("sty sreg+1");
2967 AddCodeLine ("sty 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.
2979 g_push (flags & ~CF_CONST, 0);
2983 /* Use long way over the stack */
2984 oper (flags, val, ops);
2989 void g_asl (unsigned flags, unsigned long val)
2990 /* Primary = TOS << Primary */
2992 static char* ops [12] = {
2993 0, "tosasla0", "tosaslax",
2994 0, "tosshla0", "tosshlax",
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 >= 1 && val <= 4) {
3010 if (flags & CF_UNSIGNED) {
3011 AddCodeLine ("jsr shlax%ld", val);
3013 AddCodeLine ("jsr aslax%ld", val);
3016 } else if (val == 8) {
3017 AddCodeLine ("tax");
3018 AddCodeLine ("lda #$00");
3024 if (val >= 1 && val <= 4) {
3025 if (flags & CF_UNSIGNED) {
3026 AddCodeLine ("jsr shleax%ld", val);
3028 AddCodeLine ("jsr asleax%ld", val);
3031 } else if (val == 8) {
3032 AddCodeLine ("ldy sreg");
3033 AddCodeLine ("sty sreg+1");
3034 AddCodeLine ("stx sreg");
3035 AddCodeLine ("tax");
3036 AddCodeLine ("lda #$00");
3038 } else if (val == 16) {
3039 AddCodeLine ("stx sreg+1");
3040 AddCodeLine ("sta sreg");
3041 AddCodeLine ("lda #$00");
3042 AddCodeLine ("tax");
3051 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3052 * into the normal, non-optimized stuff.
3054 g_push (flags & ~CF_CONST, 0);
3058 /* Use long way over the stack */
3059 oper (flags, val, ops);
3064 void g_neg (unsigned flags)
3065 /* Primary = -Primary */
3067 switch (flags & CF_TYPE) {
3071 AddCodeLine ("jsr negax");
3075 AddCodeLine ("jsr negeax");
3085 void g_bneg (unsigned flags)
3086 /* Primary = !Primary */
3088 switch (flags & CF_TYPE) {
3091 AddCodeLine ("jsr bnega");
3095 AddCodeLine ("jsr bnegax");
3099 AddCodeLine ("jsr bnegeax");
3109 void g_com (unsigned flags)
3110 /* Primary = ~Primary */
3112 switch (flags & CF_TYPE) {
3116 AddCodeLine ("jsr complax");
3120 AddCodeLine ("jsr compleax");
3130 void g_inc (unsigned flags, unsigned long val)
3131 /* Increment the primary register by a given number */
3133 /* Don't inc by zero */
3138 /* Generate code for the supported types */
3140 switch (flags & CF_TYPE) {
3143 if (flags & CF_FORCECHAR) {
3144 if (CPU == CPU_65C02 && val <= 2) {
3146 AddCodeLine ("ina");
3149 AddCodeLine ("clc");
3150 AddCodeLine ("adc #$%02X", (unsigned char)val);
3157 if (CPU == CPU_65C02 && val == 1) {
3158 unsigned L = GetLocalLabel();
3159 AddCodeLine ("ina");
3160 AddCodeLine ("bne %s", LocalLabelName (L));
3161 AddCodeLine ("inx");
3163 } else if (CodeSizeFactor < 200) {
3166 AddCodeLine ("jsr incax%lu", val);
3167 } else if (val <= 255) {
3169 AddCodeLine ("jsr incaxy");
3171 g_add (flags | CF_CONST, val);
3174 /* Inline the code */
3176 if ((val & 0xFF) != 0) {
3177 unsigned L = GetLocalLabel();
3178 AddCodeLine ("clc");
3179 AddCodeLine ("adc #$%02X", (unsigned char) val);
3180 AddCodeLine ("bcc %s", LocalLabelName (L));
3181 AddCodeLine ("inx");
3185 AddCodeLine ("inx");
3188 AddCodeLine ("inx");
3191 AddCodeLine ("clc");
3192 if ((val & 0xFF) != 0) {
3193 AddCodeLine ("adc #$%02X", (unsigned char) val);
3195 AddCodeLine ("pha");
3196 AddCodeLine ("txa");
3197 AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3198 AddCodeLine ("tax");
3199 AddCodeLine ("pla");
3207 AddCodeLine ("jsr inceaxy");
3209 g_add (flags | CF_CONST, val);
3221 void g_dec (unsigned flags, unsigned long val)
3222 /* Decrement the primary register by a given number */
3224 /* Don't dec by zero */
3229 /* Generate code for the supported types */
3231 switch (flags & CF_TYPE) {
3234 if (flags & CF_FORCECHAR) {
3235 if (CPU == CPU_65C02 && val <= 2) {
3237 AddCodeLine ("dea");
3240 AddCodeLine ("sec");
3241 AddCodeLine ("sbc #$%02X", (unsigned char)val);
3248 if (CodeSizeFactor < 200) {
3249 /* Use subroutines */
3251 AddCodeLine ("jsr decax%d", (int) val);
3252 } else if (val <= 255) {
3254 AddCodeLine ("jsr decaxy");
3256 g_sub (flags | CF_CONST, val);
3259 /* Inline the code */
3261 if ((val & 0xFF) != 0) {
3262 unsigned L = GetLocalLabel();
3263 AddCodeLine ("sec");
3264 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3265 AddCodeLine ("bcs %s", LocalLabelName (L));
3266 AddCodeLine ("dex");
3270 AddCodeLine ("dex");
3273 AddCodeLine ("dex");
3276 AddCodeLine ("sec");
3277 if ((val & 0xFF) != 0) {
3278 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3280 AddCodeLine ("pha");
3281 AddCodeLine ("txa");
3282 AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3283 AddCodeLine ("tax");
3284 AddCodeLine ("pla");
3292 AddCodeLine ("jsr deceaxy");
3294 g_sub (flags | CF_CONST, val);
3307 * Following are the conditional operators. They compare the TOS against
3308 * the primary and put a literal 1 in the primary if the condition is
3309 * true, otherwise they clear the primary register
3314 void g_eq (unsigned flags, unsigned long val)
3315 /* Test for equal */
3317 static char* ops [12] = {
3318 "toseq00", "toseqa0", "toseqax",
3319 "toseq00", "toseqa0", "toseqax",
3326 /* If the right hand side is const, the lhs is not on stack but still
3327 * in the primary register.
3329 if (flags & CF_CONST) {
3331 switch (flags & CF_TYPE) {
3334 if (flags & CF_FORCECHAR) {
3335 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3336 AddCodeLine ("jsr booleq");
3342 L = GetLocalLabel();
3343 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3344 AddCodeLine ("bne %s", LocalLabelName (L));
3345 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3347 AddCodeLine ("jsr booleq");
3357 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3358 * into the normal, non-optimized stuff.
3360 g_push (flags & ~CF_CONST, 0);
3364 /* Use long way over the stack */
3365 oper (flags, val, ops);
3370 void g_ne (unsigned flags, unsigned long val)
3371 /* Test for not equal */
3373 static char* ops [12] = {
3374 "tosne00", "tosnea0", "tosneax",
3375 "tosne00", "tosnea0", "tosneax",
3382 /* If the right hand side is const, the lhs is not on stack but still
3383 * in the primary register.
3385 if (flags & CF_CONST) {
3387 switch (flags & CF_TYPE) {
3390 if (flags & CF_FORCECHAR) {
3391 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3392 AddCodeLine ("jsr boolne");
3398 L = GetLocalLabel();
3399 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3400 AddCodeLine ("bne %s", LocalLabelName (L));
3401 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3403 AddCodeLine ("jsr boolne");
3413 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3414 * into the normal, non-optimized stuff.
3416 g_push (flags & ~CF_CONST, 0);
3420 /* Use long way over the stack */
3421 oper (flags, val, ops);
3426 void g_lt (unsigned flags, unsigned long val)
3427 /* Test for less than */
3429 static char* ops [12] = {
3430 "toslt00", "toslta0", "tosltax",
3431 "tosult00", "tosulta0", "tosultax",
3436 /* If the right hand side is const, the lhs is not on stack but still
3437 * in the primary register.
3439 if (flags & CF_CONST) {
3441 /* Give a warning in some special cases */
3442 if ((flags & CF_UNSIGNED) && val == 0) {
3443 Warning ("Condition is never true");
3446 /* Look at the type */
3447 switch (flags & CF_TYPE) {
3450 if (flags & CF_FORCECHAR) {
3451 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3452 if (flags & CF_UNSIGNED) {
3453 AddCodeLine ("jsr boolult");
3455 AddCodeLine ("jsr boollt");
3462 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3463 /* If we have a signed compare against zero, we only need to
3464 * test the high byte.
3466 AddCodeLine ("txa");
3467 AddCodeLine ("jsr boollt");
3470 /* Direct code only for unsigned data types */
3471 if (flags & CF_UNSIGNED) {
3472 unsigned L = GetLocalLabel();
3473 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3474 AddCodeLine ("bne %s", LocalLabelName (L));
3475 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3477 AddCodeLine ("jsr boolult");
3483 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3484 /* If we have a signed compare against zero, we only need to
3485 * test the high byte.
3487 AddCodeLine ("lda sreg+1");
3488 AddCodeLine ("jsr boollt");
3497 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3498 * into the normal, non-optimized stuff.
3500 g_push (flags & ~CF_CONST, 0);
3504 /* Use long way over the stack */
3505 oper (flags, val, ops);
3510 void g_le (unsigned flags, unsigned long val)
3511 /* Test for less than or equal to */
3513 static char* ops [12] = {
3514 "tosle00", "toslea0", "tosleax",
3515 "tosule00", "tosulea0", "tosuleax",
3521 /* If the right hand side is const, the lhs is not on stack but still
3522 * in the primary register.
3524 if (flags & CF_CONST) {
3526 /* <= is not very effective on the 6502, so try to convert
3527 * it into < if the value is in a valid range.
3530 /* Look at the type */
3531 switch (flags & CF_TYPE) {
3534 if (flags & CF_FORCECHAR) {
3535 if (flags & CF_UNSIGNED) {
3537 AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3538 AddCodeLine ("jsr boolult");
3540 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3541 AddCodeLine ("jsr boolule");
3545 AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3546 AddCodeLine ("jsr boollt");
3548 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3549 AddCodeLine ("jsr boolle");
3557 if (flags & CF_UNSIGNED) {
3558 unsigned L = GetLocalLabel();
3559 const char* Name = "boolule";
3564 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3565 AddCodeLine ("bne %s", LocalLabelName (L));
3566 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3568 AddCodeLine ("jsr %s", Name);
3580 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3581 * into the normal, non-optimized stuff.
3583 g_push (flags & ~CF_CONST, 0);
3587 /* Use long way over the stack */
3588 oper (flags, val, ops);
3593 void g_gt (unsigned flags, unsigned long val)
3594 /* Test for greater than */
3596 static char* ops [12] = {
3597 "tosgt00", "tosgta0", "tosgtax",
3598 "tosugt00", "tosugta0", "tosugtax",
3604 /* If the right hand side is const, the lhs is not on stack but still
3605 * in the primary register.
3607 if (flags & CF_CONST) {
3609 /* > is not very effective on the 6502, so try to convert
3610 * it into >= if the value is in a valid range.
3613 /* Look at the type */
3614 switch (flags & CF_TYPE) {
3617 if (flags & CF_FORCECHAR) {
3618 if (flags & CF_UNSIGNED) {
3619 /* If we have a compare > 0, we will replace it by
3620 * != 0 here, since both are identical but the latter
3621 * is easier to optimize.
3624 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3625 AddCodeLine ("jsr boolne");
3626 } else if (val < 255) {
3627 AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3628 AddCodeLine ("jsr booluge");
3630 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3631 AddCodeLine ("jsr boolugt");
3635 AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3636 AddCodeLine ("jsr boolge");
3638 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3639 AddCodeLine ("jsr boolgt");
3647 if (flags & CF_UNSIGNED) {
3648 /* If we have a compare > 0, we will replace it by
3649 * != 0 here, since both are identical but the latter
3650 * is easier to optimize.
3653 AddCodeLine ("stx tmp1");
3654 AddCodeLine ("ora tmp1");
3655 AddCodeLine ("jsr boolne");
3657 unsigned L = GetLocalLabel();
3658 const char* Name = "boolugt";
3663 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3664 AddCodeLine ("bne %s", LocalLabelName (L));
3665 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3667 AddCodeLine ("jsr %s", Name);
3680 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3681 * into the normal, non-optimized stuff.
3683 g_push (flags & ~CF_CONST, 0);
3687 /* Use long way over the stack */
3688 oper (flags, val, ops);
3693 void g_ge (unsigned flags, unsigned long val)
3694 /* Test for greater than or equal to */
3696 static char* ops [12] = {
3697 "tosge00", "tosgea0", "tosgeax",
3698 "tosuge00", "tosugea0", "tosugeax",
3704 /* If the right hand side is const, the lhs is not on stack but still
3705 * in the primary register.
3707 if (flags & CF_CONST) {
3709 /* Give a warning in some special cases */
3710 if ((flags & CF_UNSIGNED) && val == 0) {
3711 Warning ("Condition is always true");
3714 /* Look at the type */
3715 switch (flags & CF_TYPE) {
3718 if (flags & CF_FORCECHAR) {
3719 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3720 if (flags & CF_UNSIGNED) {
3721 AddCodeLine ("jsr booluge");
3723 AddCodeLine ("jsr boolge");
3730 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3731 /* If we have a signed compare against zero, we only need to
3732 * test the high byte.
3734 AddCodeLine ("txa");
3735 AddCodeLine ("jsr boolge");
3738 /* Direct code only for unsigned data types */
3739 if (flags & CF_UNSIGNED) {
3740 unsigned L = GetLocalLabel();
3741 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3742 AddCodeLine ("bne %s", LocalLabelName (L));
3743 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3745 AddCodeLine ("jsr booluge");
3751 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3752 /* If we have a signed compare against zero, we only need to
3753 * test the high byte.
3755 AddCodeLine ("lda sreg+1");
3756 AddCodeLine ("jsr boolge");
3765 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3766 * into the normal, non-optimized stuff.
3768 g_push (flags & ~CF_CONST, 0);
3772 /* Use long way over the stack */
3773 oper (flags, val, ops);
3778 /*****************************************************************************/
3779 /* Allocating static storage */
3780 /*****************************************************************************/
3784 void g_res (unsigned n)
3785 /* Reserve static storage, n bytes */
3787 AddDataLine ("\t.res\t%u,$00", n);
3792 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3793 /* Define data with the size given in flags */
3795 if (flags & CF_CONST) {
3797 /* Numeric constant */
3798 switch (flags & CF_TYPE) {
3801 AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
3805 AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
3809 AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
3820 /* Create the correct label name */
3821 const char* Label = GetLabelName (flags, val, offs);
3823 /* Labels are always 16 bit */
3824 AddDataLine ("\t.word\t%s", Label);
3831 void g_defbytes (const void* Bytes, unsigned Count)
3832 /* Output a row of bytes as a constant */
3838 /* Cast the buffer pointer */
3839 const unsigned char* Data = (const unsigned char*) Bytes;
3841 /* Output the stuff */
3844 /* How many go into this line? */
3845 if ((Chunk = Count) > 16) {
3850 /* Output one line */
3851 strcpy (Buf, "\t.byte\t");
3854 B += sprintf (B, "$%02X", *Data++);
3860 /* Output the line */
3867 void g_zerobytes (unsigned n)
3868 /* Output n bytes of data initialized with zero */
3870 AddDataLine ("\t.res\t%u,$00", n);
3875 /*****************************************************************************/
3876 /* User supplied assembler code */
3877 /*****************************************************************************/
3881 void g_asmcode (struct StrBuf* B)
3882 /* Output one line of assembler code. */
3884 AddCodeLine ("%.*s", SB_GetLen (B), SB_GetConstBuf (B));
3889 /*****************************************************************************/
3890 /* Inlined known functions */
3891 /*****************************************************************************/
3895 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3896 /* Inline the strlen() function */
3898 /* We need a label in both cases */
3899 unsigned label = GetLocalLabel ();
3901 /* Two different encodings */
3902 if (flags & CF_CONST) {
3904 /* The address of the string is constant. Create the correct label name */
3905 char* lbuf = GetLabelName (flags, val, offs);
3907 /* Generate the strlen code */
3908 AddCodeLine ("ldy #$FF");
3909 g_defcodelabel (label);
3910 AddCodeLine ("iny");
3911 AddCodeLine ("lda %s,y", lbuf);
3912 AddCodeLine ("bne %s", LocalLabelName (label));
3913 AddCodeLine ("tax");
3914 AddCodeLine ("tya");
3918 /* Address not constant but in primary */
3919 if (CodeSizeFactor < 400) {
3920 /* This is too much code, so call strlen instead of inlining */
3921 AddCodeLine ("jsr _strlen");
3923 /* Inline the function */
3924 AddCodeLine ("sta ptr1");
3925 AddCodeLine ("stx ptr1+1");
3926 AddCodeLine ("ldy #$FF");
3927 g_defcodelabel (label);
3928 AddCodeLine ("iny");
3929 AddCodeLine ("lda (ptr1),y");
3930 AddCodeLine ("bne %s", LocalLabelName (label));
3931 AddCodeLine ("tax");
3932 AddCodeLine ("tya");