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, ptr2");
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");
756 AddCodeLine ("jsr ldaxysp");
763 AddCodeLine ("jsr ldeaxysp");
773 void g_getind (unsigned flags, unsigned offs)
774 /* Fetch the specified object type indirect through the primary register
775 * into the primary register
778 /* If the offset is greater than 255, add the part that is > 255 to
779 * the primary. This way we get an easy addition and use the low byte
782 offs = MakeByteOffs (flags, offs);
784 /* Handle the indirect fetch */
785 switch (flags & CF_TYPE) {
788 /* Character sized */
789 if (flags & CF_UNSIGNED) {
791 AddCodeLine ("jsr ldauidx");
794 AddCodeLine ("jsr ldaidx");
799 if (flags & CF_TEST) {
801 AddCodeLine ("sta ptr1");
802 AddCodeLine ("stx ptr1+1");
803 AddCodeLine ("lda (ptr1),y");
805 AddCodeLine ("ora (ptr1),y");
808 AddCodeLine ("jsr ldaxidx");
814 AddCodeLine ("jsr ldeaxidx");
815 if (flags & CF_TEST) {
816 AddCodeLine ("jsr tsteax");
828 void g_leasp (int offs)
829 /* Fetch the address of the specified symbol into the primary register */
831 /* Calculate the offset relative to sp */
834 /* For value 0 we do direct code */
836 AddCodeLine ("lda sp");
837 AddCodeLine ("ldx sp+1");
839 if (CodeSizeFactor < 300) {
840 ldaconst (offs); /* Load A with offset value */
841 AddCodeLine ("jsr leaasp"); /* Load effective address */
843 unsigned L = GetLocalLabel ();
844 if (CPU == CPU_65C02 && offs == 1) {
845 AddCodeLine ("lda sp");
846 AddCodeLine ("ldx sp+1");
848 AddCodeLine ("bne %s", LocalLabelName (L));
853 AddCodeLine ("ldx sp+1");
854 AddCodeLine ("adc sp");
855 AddCodeLine ("bcc %s", LocalLabelName (L));
865 void g_leavariadic (int Offs)
866 /* Fetch the address of a parameter in a variadic function into the primary
870 unsigned ArgSizeOffs;
872 /* Calculate the offset relative to sp */
875 /* Get the offset of the parameter which is stored at sp+0 on function
876 * entry and check if this offset is reachable with a byte offset.
879 ArgSizeOffs = -oursp;
880 CheckLocalOffs (ArgSizeOffs);
882 /* Get the size of all parameters. */
883 if (ArgSizeOffs == 0 && CPU == CPU_65C02) {
884 AddCodeLine ("lda (sp)");
886 ldyconst (ArgSizeOffs);
887 AddCodeLine ("lda (sp),y");
890 /* Add the value of the stackpointer */
891 if (CodeSizeFactor > 250) {
892 unsigned L = GetLocalLabel();
893 AddCodeLine ("ldx sp+1");
895 AddCodeLine ("adc sp");
896 AddCodeLine ("bcc %s", LocalLabelName (L));
900 AddCodeLine ("jsr leaasp");
903 /* Add the offset to the primary */
905 g_inc (CF_INT | CF_CONST, Offs);
906 } else if (Offs < 0) {
907 g_dec (CF_INT | CF_CONST, -Offs);
913 /*****************************************************************************/
914 /* Store into memory */
915 /*****************************************************************************/
919 void g_putstatic (unsigned flags, unsigned long label, unsigned offs)
920 /* Store the primary register into the specified static memory cell */
922 /* Create the correct label name */
923 char* lbuf = GetLabelName (flags, label, offs);
925 /* Check the size and generate the correct store operation */
926 switch (flags & CF_TYPE) {
929 AddCodeLine ("sta %s", lbuf);
933 AddCodeLine ("sta %s", lbuf);
934 AddCodeLine ("stx %s+1", lbuf);
938 AddCodeLine ("sta %s", lbuf);
939 AddCodeLine ("stx %s+1", lbuf);
940 AddCodeLine ("ldy sreg");
941 AddCodeLine ("sty %s+2", lbuf);
942 AddCodeLine ("ldy sreg+1");
943 AddCodeLine ("sty %s+3", lbuf);
954 void g_putlocal (unsigned Flags, int Offs, long Val)
955 /* Put data into local object. */
958 CheckLocalOffs (Offs);
959 switch (Flags & CF_TYPE) {
962 if (Flags & CF_CONST) {
963 AddCodeLine ("lda #$%02X", (unsigned char) Val);
965 if (CPU == CPU_65C02 && Offs == 0) {
966 AddCodeLine ("sta (sp)");
969 AddCodeLine ("sta (sp),y");
974 if (Flags & CF_CONST) {
976 AddCodeLine ("lda #$%02X", (unsigned char) (Val >> 8));
977 AddCodeLine ("sta (sp),y");
978 if ((Flags & CF_NOKEEP) == 0) {
979 /* Place high byte into X */
982 if (CPU == CPU_65C02 && Offs == 0) {
983 AddCodeLine ("lda #$%02X", (unsigned char) Val);
984 AddCodeLine ("sta (sp)");
986 if ((Val & 0xFF) == Offs+1) {
987 /* The value we need is already in Y */
992 AddCodeLine ("lda #$%02X", (unsigned char) Val);
994 AddCodeLine ("sta (sp),y");
997 if ((Flags & CF_NOKEEP) == 0 || CodeSizeFactor < 160) {
999 AddCodeLine ("jsr staxysp");
1001 if (CPU == CPU_65C02 && Offs == 0) {
1002 AddCodeLine ("sta (sp)");
1004 AddCodeLine ("txa");
1005 AddCodeLine ("sta (sp),y");
1008 AddCodeLine ("sta (sp),y");
1009 AddCodeLine ("iny");
1010 AddCodeLine ("txa");
1011 AddCodeLine ("sta (sp),y");
1018 if (Flags & CF_CONST) {
1019 g_getimmed (Flags, Val, 0);
1022 AddCodeLine ("jsr steaxysp");
1033 void g_putind (unsigned Flags, unsigned Offs)
1034 /* Store the specified object type in the primary register at the address
1035 * on the top of the stack
1038 /* We can handle offsets below $100 directly, larger offsets must be added
1039 * to the address. Since a/x is in use, best code is achieved by adding
1040 * just the high byte. Be sure to check if the low byte will overflow while
1043 if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
1045 /* Overflow - we need to add the low byte also */
1046 AddCodeLine ("ldy #$00");
1047 AddCodeLine ("clc");
1048 AddCodeLine ("pha");
1049 AddCodeLine ("lda #$%02X", Offs & 0xFF);
1050 AddCodeLine ("adc (sp),y");
1051 AddCodeLine ("sta (sp),y");
1052 AddCodeLine ("iny");
1053 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1054 AddCodeLine ("adc (sp),y");
1055 AddCodeLine ("sta (sp),y");
1056 AddCodeLine ("pla");
1058 /* Complete address is on stack, new offset is zero */
1061 } else if ((Offs & 0xFF00) != 0) {
1063 /* We can just add the high byte */
1064 AddCodeLine ("ldy #$01");
1065 AddCodeLine ("clc");
1066 AddCodeLine ("pha");
1067 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1068 AddCodeLine ("adc (sp),y");
1069 AddCodeLine ("sta (sp),y");
1070 AddCodeLine ("pla");
1072 /* Offset is now just the low byte */
1076 /* Check the size and determine operation */
1077 switch (Flags & CF_TYPE) {
1081 AddCodeLine ("jsr staspidx");
1086 AddCodeLine ("jsr staxspidx");
1091 AddCodeLine ("jsr steaxspidx");
1099 /* Pop the argument which is always a pointer */
1105 /*****************************************************************************/
1106 /* type conversion and similiar stuff */
1107 /*****************************************************************************/
1111 void g_toslong (unsigned flags)
1112 /* Make sure, the value on TOS is a long. Convert if necessary */
1114 switch (flags & CF_TYPE) {
1118 if (flags & CF_UNSIGNED) {
1119 AddCodeLine ("jsr tosulong");
1121 AddCodeLine ("jsr toslong");
1136 void g_tosint (unsigned flags)
1137 /* Make sure, the value on TOS is an int. Convert if necessary */
1139 switch (flags & CF_TYPE) {
1146 AddCodeLine ("jsr tosint");
1157 void g_reglong (unsigned flags)
1158 /* Make sure, the value in the primary register a long. Convert if necessary */
1160 switch (flags & CF_TYPE) {
1164 if (flags & CF_UNSIGNED) {
1165 if (CodeSizeFactor >= 200) {
1167 AddCodeLine ("sty sreg");
1168 AddCodeLine ("sty sreg+1");
1170 AddCodeLine ("jsr axulong");
1173 AddCodeLine ("jsr axlong");
1187 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1188 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1189 * value, that corresponds to the value on TOS, rhs corresponds to the value
1190 * in (e)ax. The return value is the the flags value for the resulting type.
1193 unsigned ltype, rtype;
1196 /* Get the type spec from the flags */
1197 ltype = lhs & CF_TYPE;
1198 rtype = rhs & CF_TYPE;
1200 /* Check if a conversion is needed */
1201 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1202 /* We must promote the primary register to long */
1204 /* Get the new rhs type */
1205 rhs = (rhs & ~CF_TYPE) | CF_LONG;
1207 } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1208 /* We must promote the lhs to long */
1214 /* Get the new rhs type */
1215 lhs = (lhs & ~CF_TYPE) | CF_LONG;
1219 /* Determine the result type for the operation:
1220 * - The result is const if both operands are const.
1221 * - The result is unsigned if one of the operands is unsigned.
1222 * - The result is long if one of the operands is long.
1223 * - Otherwise the result is int sized.
1225 result = (lhs & CF_CONST) & (rhs & CF_CONST);
1226 result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1227 if (rtype == CF_LONG || ltype == CF_LONG) {
1237 unsigned g_typecast (unsigned lhs, unsigned rhs)
1238 /* Cast the value in the primary register to the operand size that is flagged
1239 * by the lhs value. Return the result value.
1242 unsigned ltype, rtype;
1244 /* Get the type spec from the flags */
1245 ltype = lhs & CF_TYPE;
1246 rtype = rhs & CF_TYPE;
1248 /* Check if a conversion is needed */
1249 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1250 /* We must promote the primary register to long */
1254 /* Do not need any other action. If the left type is int, and the primary
1255 * register is long, it will be automagically truncated. If the right hand
1256 * side is const, it is not located in the primary register and handled by
1257 * the expression parser code.
1260 /* Result is const if the right hand side was const */
1261 lhs |= (rhs & CF_CONST);
1263 /* The resulting type is that of the left hand side (that's why you called
1271 void g_scale (unsigned flags, long val)
1272 /* Scale the value in the primary register by the given value. If val is positive,
1273 * scale up, is val is negative, scale down. This function is used to scale
1274 * the operands or results of pointer arithmetic by the size of the type, the
1275 * pointer points to.
1280 /* Value may not be zero */
1282 Internal ("Data type has no size");
1283 } else if (val > 0) {
1286 if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
1288 /* Factor is 2, 4, 8 and 16, use special function */
1289 switch (flags & CF_TYPE) {
1292 if (flags & CF_FORCECHAR) {
1294 AddCodeLine ("asl a");
1301 if (CodeSizeFactor >= (p2+1)*130U) {
1302 AddCodeLine ("stx tmp1");
1304 AddCodeLine ("asl a");
1305 AddCodeLine ("rol tmp1");
1307 AddCodeLine ("ldx tmp1");
1309 if (flags & CF_UNSIGNED) {
1310 AddCodeLine ("jsr shlax%d", p2);
1312 AddCodeLine ("jsr aslax%d", p2);
1318 if (flags & CF_UNSIGNED) {
1319 AddCodeLine ("jsr shleax%d", p2);
1321 AddCodeLine ("jsr asleax%d", p2);
1330 } else if (val != 1) {
1332 /* Use a multiplication instead */
1333 g_mul (flags | CF_CONST, val);
1341 if ((p2 = powerof2 (val)) > 0 && p2 <= 4) {
1343 /* Factor is 2, 4, 8 and 16 use special function */
1344 switch (flags & CF_TYPE) {
1347 if (flags & CF_FORCECHAR) {
1348 if (flags & CF_UNSIGNED) {
1350 AddCodeLine ("lsr a");
1353 } else if (p2 <= 2) {
1354 AddCodeLine ("cmp #$80");
1355 AddCodeLine ("ror a");
1362 if (flags & CF_UNSIGNED) {
1363 if (CodeSizeFactor >= (p2+1)*130U) {
1364 AddCodeLine ("stx tmp1");
1366 AddCodeLine ("lsr tmp1");
1367 AddCodeLine ("ror a");
1369 AddCodeLine ("ldx tmp1");
1371 AddCodeLine ("jsr lsrax%d", p2);
1374 if (CodeSizeFactor >= (p2+1)*150U) {
1375 AddCodeLine ("stx tmp1");
1377 AddCodeLine ("cpx #$80");
1378 AddCodeLine ("ror tmp1");
1379 AddCodeLine ("ror a");
1381 AddCodeLine ("ldx tmp1");
1383 AddCodeLine ("jsr asrax%d", p2);
1389 if (flags & CF_UNSIGNED) {
1390 AddCodeLine ("jsr lsreax%d", p2);
1392 AddCodeLine ("jsr asreax%d", p2);
1401 } else if (val != 1) {
1403 /* Use a division instead */
1404 g_div (flags | CF_CONST, val);
1412 /*****************************************************************************/
1413 /* Adds and subs of variables fix a fixed address */
1414 /*****************************************************************************/
1418 void g_addlocal (unsigned flags, int offs)
1419 /* Add a local variable to ax */
1423 /* Correct the offset and check it */
1425 CheckLocalOffs (offs);
1427 switch (flags & CF_TYPE) {
1430 L = GetLocalLabel();
1431 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1432 AddCodeLine ("clc");
1433 AddCodeLine ("adc (sp),y");
1434 AddCodeLine ("bcc %s", LocalLabelName (L));
1435 AddCodeLine ("inx");
1440 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1441 AddCodeLine ("clc");
1442 AddCodeLine ("adc (sp),y");
1443 AddCodeLine ("pha");
1444 AddCodeLine ("txa");
1445 AddCodeLine ("iny");
1446 AddCodeLine ("adc (sp),y");
1447 AddCodeLine ("tax");
1448 AddCodeLine ("pla");
1452 /* Do it the old way */
1454 g_getlocal (flags, offs);
1466 void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
1467 /* Add a static variable to ax */
1471 /* Create the correct label name */
1472 char* lbuf = GetLabelName (flags, label, offs);
1474 switch (flags & CF_TYPE) {
1477 L = GetLocalLabel();
1478 AddCodeLine ("clc");
1479 AddCodeLine ("adc %s", lbuf);
1480 AddCodeLine ("bcc %s", LocalLabelName (L));
1481 AddCodeLine ("inx");
1486 AddCodeLine ("clc");
1487 AddCodeLine ("adc %s", lbuf);
1488 AddCodeLine ("tay");
1489 AddCodeLine ("txa");
1490 AddCodeLine ("adc %s+1", lbuf);
1491 AddCodeLine ("tax");
1492 AddCodeLine ("tya");
1496 /* Do it the old way */
1498 g_getstatic (flags, label, offs);
1510 /*****************************************************************************/
1511 /* Special op= functions */
1512 /*****************************************************************************/
1516 void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
1518 /* Emit += for a static variable */
1520 /* Create the correct label name */
1521 char* lbuf = GetLabelName (flags, label, offs);
1523 /* Check the size and determine operation */
1524 switch (flags & CF_TYPE) {
1527 if (flags & CF_FORCECHAR) {
1528 AddCodeLine ("ldx #$00");
1529 if (flags & CF_CONST) {
1531 AddCodeLine ("inc %s", lbuf);
1532 AddCodeLine ("lda %s", lbuf);
1534 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1535 AddCodeLine ("clc");
1536 AddCodeLine ("adc %s", lbuf);
1537 AddCodeLine ("sta %s", lbuf);
1540 AddCodeLine ("clc");
1541 AddCodeLine ("adc %s", lbuf);
1542 AddCodeLine ("sta %s", lbuf);
1544 if ((flags & CF_UNSIGNED) == 0) {
1545 unsigned L = GetLocalLabel();
1546 AddCodeLine ("bpl %s", LocalLabelName (L));
1547 AddCodeLine ("dex");
1555 if (flags & CF_CONST) {
1557 unsigned L = GetLocalLabel ();
1558 AddCodeLine ("inc %s", lbuf);
1559 AddCodeLine ("bne %s", LocalLabelName (L));
1560 AddCodeLine ("inc %s+1", lbuf);
1562 AddCodeLine ("lda %s", lbuf); /* Hmmm... */
1563 AddCodeLine ("ldx %s+1", lbuf);
1565 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1566 AddCodeLine ("clc");
1567 AddCodeLine ("adc %s", lbuf);
1568 AddCodeLine ("sta %s", lbuf);
1570 unsigned L = GetLocalLabel ();
1571 AddCodeLine ("bcc %s", LocalLabelName (L));
1572 AddCodeLine ("inc %s+1", lbuf);
1574 AddCodeLine ("ldx %s+1", lbuf);
1576 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1577 AddCodeLine ("adc %s+1", lbuf);
1578 AddCodeLine ("sta %s+1", lbuf);
1579 AddCodeLine ("tax");
1580 AddCodeLine ("lda %s", lbuf);
1584 AddCodeLine ("clc");
1585 AddCodeLine ("adc %s", lbuf);
1586 AddCodeLine ("sta %s", lbuf);
1587 AddCodeLine ("txa");
1588 AddCodeLine ("adc %s+1", lbuf);
1589 AddCodeLine ("sta %s+1", lbuf);
1590 AddCodeLine ("tax");
1591 AddCodeLine ("lda %s", lbuf);
1596 if (flags & CF_CONST) {
1598 AddCodeLine ("ldy #<(%s)", lbuf);
1599 AddCodeLine ("sty ptr1");
1600 AddCodeLine ("ldy #>(%s+1)", lbuf);
1602 AddCodeLine ("jsr laddeq1");
1604 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1605 AddCodeLine ("jsr laddeqa");
1608 g_getstatic (flags, label, offs);
1610 g_putstatic (flags, label, offs);
1613 AddCodeLine ("ldy #<(%s)", lbuf);
1614 AddCodeLine ("sty ptr1");
1615 AddCodeLine ("ldy #>(%s+1)", lbuf);
1616 AddCodeLine ("jsr laddeq");
1627 void g_addeqlocal (unsigned flags, int offs, unsigned long val)
1628 /* Emit += for a local variable */
1630 /* Calculate the true offset, check it, load it into Y */
1632 CheckLocalOffs (offs);
1634 /* Check the size and determine operation */
1635 switch (flags & CF_TYPE) {
1638 if (flags & CF_FORCECHAR) {
1640 AddCodeLine ("ldx #$00");
1641 if (flags & CF_CONST) {
1642 AddCodeLine ("clc");
1643 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1644 AddCodeLine ("adc (sp),y");
1645 AddCodeLine ("sta (sp),y");
1647 AddCodeLine ("clc");
1648 AddCodeLine ("adc (sp),y");
1649 AddCodeLine ("sta (sp),y");
1651 if ((flags & CF_UNSIGNED) == 0) {
1652 unsigned L = GetLocalLabel();
1653 AddCodeLine ("bpl %s", LocalLabelName (L));
1654 AddCodeLine ("dex");
1663 if (flags & CF_CONST) {
1664 if (CodeSizeFactor >= 400) {
1665 AddCodeLine ("clc");
1666 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1667 AddCodeLine ("adc (sp),y");
1668 AddCodeLine ("sta (sp),y");
1669 AddCodeLine ("iny");
1670 AddCodeLine ("lda #$%02X", (int) ((val >> 8) & 0xFF));
1671 AddCodeLine ("adc (sp),y");
1672 AddCodeLine ("sta (sp),y");
1673 AddCodeLine ("tax");
1674 AddCodeLine ("dey");
1675 AddCodeLine ("lda (sp),y");
1677 g_getimmed (flags, val, 0);
1678 AddCodeLine ("jsr addeqysp");
1681 AddCodeLine ("jsr addeqysp");
1686 if (flags & CF_CONST) {
1687 g_getimmed (flags, val, 0);
1690 AddCodeLine ("jsr laddeqysp");
1700 void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1701 /* Emit += for the location with address in ax */
1703 /* If the offset is too large for a byte register, add the high byte
1704 * of the offset to the primary. Beware: We need a special correction
1705 * if the offset in the low byte will overflow in the operation.
1707 offs = MakeByteOffs (flags, offs);
1709 /* Check the size and determine operation */
1710 switch (flags & CF_TYPE) {
1713 AddCodeLine ("sta ptr1");
1714 AddCodeLine ("stx ptr1+1");
1715 AddCodeLine ("ldy #$%02X", offs);
1716 AddCodeLine ("ldx #$00");
1717 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1718 AddCodeLine ("clc");
1719 AddCodeLine ("adc (ptr1),y");
1720 AddCodeLine ("sta (ptr1),y");
1724 if (CodeSizeFactor >= 200) {
1725 /* Lots of code, use only if size is not important */
1726 AddCodeLine ("sta ptr1");
1727 AddCodeLine ("stx ptr1+1");
1728 AddCodeLine ("ldy #$%02X", offs);
1729 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1730 AddCodeLine ("clc");
1731 AddCodeLine ("adc (ptr1),y");
1732 AddCodeLine ("sta (ptr1),y");
1733 AddCodeLine ("pha");
1734 AddCodeLine ("iny");
1735 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1736 AddCodeLine ("adc (ptr1),y");
1737 AddCodeLine ("sta (ptr1),y");
1738 AddCodeLine ("tax");
1739 AddCodeLine ("pla");
1745 AddCodeLine ("jsr pushax"); /* Push the address */
1746 push (CF_PTR); /* Correct the internal sp */
1747 g_getind (flags, offs); /* Fetch the value */
1748 g_inc (flags, val); /* Increment value in primary */
1749 g_putind (flags, offs); /* Store the value back */
1759 void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
1761 /* Emit -= for a static variable */
1763 /* Create the correct label name */
1764 char* lbuf = GetLabelName (flags, label, offs);
1766 /* Check the size and determine operation */
1767 switch (flags & CF_TYPE) {
1770 if (flags & CF_FORCECHAR) {
1771 AddCodeLine ("ldx #$00");
1772 if (flags & CF_CONST) {
1774 AddCodeLine ("dec %s", lbuf);
1775 AddCodeLine ("lda %s", lbuf);
1777 AddCodeLine ("sec");
1778 AddCodeLine ("lda %s", lbuf);
1779 AddCodeLine ("sbc #$%02X", (int)(val & 0xFF));
1780 AddCodeLine ("sta %s", lbuf);
1783 AddCodeLine ("sec");
1784 AddCodeLine ("sta tmp1");
1785 AddCodeLine ("lda %s", lbuf);
1786 AddCodeLine ("sbc tmp1");
1787 AddCodeLine ("sta %s", lbuf);
1789 if ((flags & CF_UNSIGNED) == 0) {
1790 unsigned L = GetLocalLabel();
1791 AddCodeLine ("bpl %s", LocalLabelName (L));
1792 AddCodeLine ("dex");
1800 AddCodeLine ("sec");
1801 if (flags & CF_CONST) {
1802 AddCodeLine ("lda %s", lbuf);
1803 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1804 AddCodeLine ("sta %s", lbuf);
1806 unsigned L = GetLocalLabel ();
1807 AddCodeLine ("bcs %s", LocalLabelName (L));
1808 AddCodeLine ("dec %s+1", lbuf);
1810 AddCodeLine ("ldx %s+1", lbuf);
1812 AddCodeLine ("lda %s+1", lbuf);
1813 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1814 AddCodeLine ("sta %s+1", lbuf);
1815 AddCodeLine ("tax");
1816 AddCodeLine ("lda %s", lbuf);
1819 AddCodeLine ("sta tmp1");
1820 AddCodeLine ("lda %s", lbuf);
1821 AddCodeLine ("sbc tmp1");
1822 AddCodeLine ("sta %s", lbuf);
1823 AddCodeLine ("stx tmp1");
1824 AddCodeLine ("lda %s+1", lbuf);
1825 AddCodeLine ("sbc tmp1");
1826 AddCodeLine ("sta %s+1", lbuf);
1827 AddCodeLine ("tax");
1828 AddCodeLine ("lda %s", lbuf);
1833 if (flags & CF_CONST) {
1835 AddCodeLine ("ldy #<(%s)", lbuf);
1836 AddCodeLine ("sty ptr1");
1837 AddCodeLine ("ldy #>(%s+1)", lbuf);
1838 AddCodeLine ("lda #$%02X", (unsigned char)val);
1839 AddCodeLine ("jsr lsubeqa");
1841 g_getstatic (flags, label, offs);
1843 g_putstatic (flags, label, offs);
1846 AddCodeLine ("ldy #<(%s)", lbuf);
1847 AddCodeLine ("sty ptr1");
1848 AddCodeLine ("ldy #>(%s+1)", lbuf);
1849 AddCodeLine ("jsr lsubeq");
1860 void g_subeqlocal (unsigned flags, int offs, unsigned long val)
1861 /* Emit -= for a local variable */
1863 /* Calculate the true offset, check it, load it into Y */
1865 CheckLocalOffs (offs);
1867 /* Check the size and determine operation */
1868 switch (flags & CF_TYPE) {
1871 if (flags & CF_FORCECHAR) {
1873 AddCodeLine ("ldx #$00");
1874 AddCodeLine ("sec");
1875 if (flags & CF_CONST) {
1876 AddCodeLine ("lda (sp),y");
1877 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1879 AddCodeLine ("sta tmp1");
1880 AddCodeLine ("lda (sp),y");
1881 AddCodeLine ("sbc tmp1");
1883 AddCodeLine ("sta (sp),y");
1884 if ((flags & CF_UNSIGNED) == 0) {
1885 unsigned L = GetLocalLabel();
1886 AddCodeLine ("bpl %s", LocalLabelName (L));
1887 AddCodeLine ("dex");
1895 if (flags & CF_CONST) {
1896 g_getimmed (flags, val, 0);
1899 AddCodeLine ("jsr subeqysp");
1903 if (flags & CF_CONST) {
1904 g_getimmed (flags, val, 0);
1907 AddCodeLine ("jsr lsubeqysp");
1917 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
1918 /* Emit -= for the location with address in ax */
1920 /* If the offset is too large for a byte register, add the high byte
1921 * of the offset to the primary. Beware: We need a special correction
1922 * if the offset in the low byte will overflow in the operation.
1924 offs = MakeByteOffs (flags, offs);
1926 /* Check the size and determine operation */
1927 switch (flags & CF_TYPE) {
1930 AddCodeLine ("sta ptr1");
1931 AddCodeLine ("stx ptr1+1");
1932 AddCodeLine ("ldy #$%02X", offs);
1933 AddCodeLine ("ldx #$00");
1934 AddCodeLine ("lda (ptr1),y");
1935 AddCodeLine ("sec");
1936 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1937 AddCodeLine ("sta (ptr1),y");
1941 if (CodeSizeFactor >= 200) {
1942 /* Lots of code, use only if size is not important */
1943 AddCodeLine ("sta ptr1");
1944 AddCodeLine ("stx ptr1+1");
1945 AddCodeLine ("ldy #$%02X", offs);
1946 AddCodeLine ("lda (ptr1),y");
1947 AddCodeLine ("sec");
1948 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1949 AddCodeLine ("sta (ptr1),y");
1950 AddCodeLine ("pha");
1951 AddCodeLine ("iny");
1952 AddCodeLine ("lda (ptr1),y");
1953 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1954 AddCodeLine ("sta (ptr1),y");
1955 AddCodeLine ("tax");
1956 AddCodeLine ("pla");
1962 AddCodeLine ("jsr pushax"); /* Push the address */
1963 push (CF_PTR); /* Correct the internal sp */
1964 g_getind (flags, offs); /* Fetch the value */
1965 g_dec (flags, val); /* Increment value in primary */
1966 g_putind (flags, offs); /* Store the value back */
1976 /*****************************************************************************/
1977 /* Add a variable address to the value in ax */
1978 /*****************************************************************************/
1982 void g_addaddr_local (unsigned flags attribute ((unused)), int offs)
1983 /* Add the address of a local variable to ax */
1987 /* Add the offset */
1990 /* We cannot address more then 256 bytes of locals anyway */
1991 L = GetLocalLabel();
1992 CheckLocalOffs (offs);
1993 AddCodeLine ("clc");
1994 AddCodeLine ("adc #$%02X", offs & 0xFF);
1995 /* Do also skip the CLC insn below */
1996 AddCodeLine ("bcc %s", LocalLabelName (L));
1997 AddCodeLine ("inx");
2000 /* Add the current stackpointer value */
2001 AddCodeLine ("clc");
2003 /* Label was used above */
2006 AddCodeLine ("adc sp");
2007 AddCodeLine ("tay");
2008 AddCodeLine ("txa");
2009 AddCodeLine ("adc sp+1");
2010 AddCodeLine ("tax");
2011 AddCodeLine ("tya");
2016 void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
2017 /* Add the address of a static variable to ax */
2019 /* Create the correct label name */
2020 char* lbuf = GetLabelName (flags, label, offs);
2022 /* Add the address to the current ax value */
2023 AddCodeLine ("clc");
2024 AddCodeLine ("adc #<(%s)", lbuf);
2025 AddCodeLine ("tay");
2026 AddCodeLine ("txa");
2027 AddCodeLine ("adc #>(%s)", lbuf);
2028 AddCodeLine ("tax");
2029 AddCodeLine ("tya");
2034 /*****************************************************************************/
2036 /*****************************************************************************/
2040 void g_save (unsigned flags)
2041 /* Copy primary register to hold register. */
2043 /* Check the size and determine operation */
2044 switch (flags & CF_TYPE) {
2047 if (flags & CF_FORCECHAR) {
2048 AddCodeLine ("pha");
2054 AddCodeLine ("sta regsave");
2055 AddCodeLine ("stx regsave+1");
2059 AddCodeLine ("jsr saveeax");
2069 void g_restore (unsigned flags)
2070 /* Copy hold register to primary. */
2072 /* Check the size and determine operation */
2073 switch (flags & CF_TYPE) {
2076 if (flags & CF_FORCECHAR) {
2077 AddCodeLine ("pla");
2083 AddCodeLine ("lda regsave");
2084 AddCodeLine ("ldx regsave+1");
2088 AddCodeLine ("jsr resteax");
2098 void g_cmp (unsigned flags, unsigned long val)
2099 /* Immidiate compare. The primary register will not be changed, Z flag
2105 /* Check the size and determine operation */
2106 switch (flags & CF_TYPE) {
2109 if (flags & CF_FORCECHAR) {
2110 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2116 L = GetLocalLabel();
2117 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2118 AddCodeLine ("bne %s", LocalLabelName (L));
2119 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
2124 Internal ("g_cmp: Long compares not implemented");
2134 static void oper (unsigned flags, unsigned long val, char** subs)
2135 /* Encode a binary operation. subs is a pointer to four groups of three
2137 * 0-2 --> Operate on ints
2138 * 3-5 --> Operate on unsigneds
2139 * 6-8 --> Operate on longs
2140 * 9-11 --> Operate on unsigned longs
2142 * The first subroutine names in each string group is used to encode an
2143 * operation with a zero constant, the second to encode an operation with
2144 * a 8 bit constant, and the third is used in all other cases.
2149 /* Determine the offset into the array */
2150 offs = (flags & CF_UNSIGNED)? 3 : 0;
2151 switch (flags & CF_TYPE) {
2164 /* Encode the operation */
2165 if (flags & CF_CONST) {
2166 /* Constant value given */
2167 if (val == 0 && subs [offs+0]) {
2168 /* Special case: constant with value zero */
2169 AddCodeLine ("jsr %s", subs [offs+0]);
2170 } else if (val < 0x100 && subs [offs+1]) {
2171 /* Special case: constant with high byte zero */
2172 ldaconst (val); /* Load low byte */
2173 AddCodeLine ("jsr %s", subs [offs+1]);
2175 /* Others: arbitrary constant value */
2176 g_getimmed (flags, val, 0); /* Load value */
2177 AddCodeLine ("jsr %s", subs [offs+2]);
2180 /* Value not constant (is already in (e)ax) */
2181 AddCodeLine ("jsr %s", subs [offs+2]);
2184 /* The operation will pop it's argument */
2190 void g_test (unsigned flags)
2191 /* Test the value in the primary and set the condition codes */
2193 switch (flags & CF_TYPE) {
2196 if (flags & CF_FORCECHAR) {
2197 AddCodeLine ("tax");
2203 AddCodeLine ("stx tmp1");
2204 AddCodeLine ("ora tmp1");
2208 if (flags & CF_UNSIGNED) {
2209 AddCodeLine ("jsr utsteax");
2211 AddCodeLine ("jsr tsteax");
2223 void g_push (unsigned flags, unsigned long val)
2224 /* Push the primary register or a constant value onto the stack */
2226 if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2228 /* We have a constant 8 or 16 bit value */
2229 if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2231 /* Handle as 8 bit value */
2233 AddCodeLine ("jsr pusha");
2237 /* Handle as 16 bit value */
2238 g_getimmed (flags, val, 0);
2239 AddCodeLine ("jsr pushax");
2244 /* Value is not 16 bit or not constant */
2245 if (flags & CF_CONST) {
2246 /* Constant 32 bit value, load into eax */
2247 g_getimmed (flags, val, 0);
2250 /* Push the primary register */
2251 switch (flags & CF_TYPE) {
2254 if (flags & CF_FORCECHAR) {
2255 /* Handle as char */
2256 AddCodeLine ("jsr pusha");
2261 AddCodeLine ("jsr pushax");
2265 AddCodeLine ("jsr pusheax");
2275 /* Adjust the stack offset */
2281 void g_swap (unsigned flags)
2282 /* Swap the primary register and the top of the stack. flags give the type
2283 * of *both* values (must have same size).
2286 switch (flags & CF_TYPE) {
2290 AddCodeLine ("jsr swapstk");
2294 AddCodeLine ("jsr swapestk");
2305 void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2306 /* Call the specified subroutine name */
2308 if ((Flags & CF_FIXARGC) == 0) {
2309 /* Pass the argument count */
2312 AddCodeLine ("jsr _%s", Label);
2313 oursp += ArgSize; /* callee pops args */
2318 void g_callind (unsigned Flags, unsigned ArgSize, int Offs)
2319 /* Call subroutine indirect */
2321 if ((Flags & CF_LOCAL) == 0) {
2322 /* Address is in a/x */
2323 if ((Flags & CF_FIXARGC) == 0) {
2324 /* Pass arg count */
2327 AddCodeLine ("jsr callax");
2329 /* The address is on stack, offset is on Val */
2331 CheckLocalOffs (Offs);
2332 AddCodeLine ("pha");
2333 AddCodeLine ("ldy #$%02X", Offs);
2334 AddCodeLine ("lda (sp),y");
2335 AddCodeLine ("sta jmpvec+1");
2336 AddCodeLine ("iny");
2337 AddCodeLine ("lda (sp),y");
2338 AddCodeLine ("sta jmpvec+2");
2339 AddCodeLine ("pla");
2340 AddCodeLine ("jsr jmpvec");
2343 /* Callee pops args */
2349 void g_jump (unsigned Label)
2350 /* Jump to specified internal label number */
2352 AddCodeLine ("jmp %s", LocalLabelName (Label));
2357 void g_switch (unsigned Flags)
2358 /* Output switch statement preamble */
2360 switch (Flags & CF_TYPE) {
2364 AddCodeLine ("jsr switch");
2368 AddCodeLine ("jsr lswitch");
2379 void g_case (unsigned flags, unsigned label, unsigned long val)
2380 /* Create table code for one case selector */
2382 switch (flags & CF_TYPE) {
2386 AddCodeLine (".word $%04X, %s",
2387 (unsigned)(val & 0xFFFF),
2388 LocalLabelName (label));
2392 AddCodeLine (".dword $%08lX", val);
2393 AddCodeLine (".word %s", LocalLabelName (label));
2404 void g_truejump (unsigned flags attribute ((unused)), unsigned label)
2405 /* Jump to label if zero flag clear */
2407 AddCodeLine ("jne %s", LocalLabelName (label));
2412 void g_falsejump (unsigned flags attribute ((unused)), unsigned label)
2413 /* Jump to label if zero flag set */
2415 AddCodeLine ("jeq %s", LocalLabelName (label));
2420 static void mod_internal (int k, char* verb1, char* verb2)
2423 AddCodeLine ("jsr %ssp%c", verb1, k + '0');
2427 AddCodeLine ("jsr %ssp", verb2);
2433 void g_space (int space)
2434 /* Create or drop space on the stack */
2437 mod_internal (-space, "inc", "addy");
2438 } else if (space > 0) {
2439 mod_internal (space, "dec", "suby");
2445 void g_cstackcheck (void)
2446 /* Check for a C stack overflow */
2448 AddCodeLine ("jsr cstkchk");
2453 void g_stackcheck (void)
2454 /* Check for a stack overflow */
2456 AddCodeLine ("jsr stkchk");
2461 void g_add (unsigned flags, unsigned long val)
2462 /* Primary = TOS + Primary */
2464 static char* ops [12] = {
2465 0, "tosadda0", "tosaddax",
2466 0, "tosadda0", "tosaddax",
2471 if (flags & CF_CONST) {
2472 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2473 g_push (flags & ~CF_CONST, 0);
2475 oper (flags, val, ops);
2480 void g_sub (unsigned flags, unsigned long val)
2481 /* Primary = TOS - Primary */
2483 static char* ops [12] = {
2484 0, "tossuba0", "tossubax",
2485 0, "tossuba0", "tossubax",
2490 if (flags & CF_CONST) {
2491 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2492 g_push (flags & ~CF_CONST, 0);
2494 oper (flags, val, ops);
2499 void g_rsub (unsigned flags, unsigned long val)
2500 /* Primary = Primary - TOS */
2502 static char* ops [12] = {
2503 0, "tosrsuba0", "tosrsubax",
2504 0, "tosrsuba0", "tosrsubax",
2508 oper (flags, val, ops);
2513 void g_mul (unsigned flags, unsigned long val)
2514 /* Primary = TOS * Primary */
2516 static char* ops [12] = {
2517 0, "tosmula0", "tosmulax",
2518 0, "tosumula0", "tosumulax",
2525 /* Do strength reduction if the value is constant and a power of two */
2526 if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2527 /* Generate a shift instead */
2532 /* If the right hand side is const, the lhs is not on stack but still
2533 * in the primary register.
2535 if (flags & CF_CONST) {
2537 switch (flags & CF_TYPE) {
2540 if (flags & CF_FORCECHAR) {
2541 /* Handle some special cases */
2545 AddCodeLine ("sta tmp1");
2546 AddCodeLine ("asl a");
2547 AddCodeLine ("clc");
2548 AddCodeLine ("adc tmp1");
2552 AddCodeLine ("sta tmp1");
2553 AddCodeLine ("asl a");
2554 AddCodeLine ("asl a");
2555 AddCodeLine ("clc");
2556 AddCodeLine ("adc tmp1");
2560 AddCodeLine ("sta tmp1");
2561 AddCodeLine ("asl a");
2562 AddCodeLine ("asl a");
2563 AddCodeLine ("clc");
2564 AddCodeLine ("adc tmp1");
2565 AddCodeLine ("asl a");
2581 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2582 * into the normal, non-optimized stuff.
2584 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2585 g_push (flags & ~CF_CONST, 0);
2589 /* Use long way over the stack */
2590 oper (flags, val, ops);
2595 void g_div (unsigned flags, unsigned long val)
2596 /* Primary = TOS / Primary */
2598 static char* ops [12] = {
2599 0, "tosdiva0", "tosdivax",
2600 0, "tosudiva0", "tosudivax",
2605 /* Do strength reduction if the value is constant and a power of two */
2607 if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2608 /* Generate a shift instead */
2611 /* Generate a division */
2612 if (flags & CF_CONST) {
2613 /* lhs is not on stack */
2614 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2615 g_push (flags & ~CF_CONST, 0);
2617 oper (flags, val, ops);
2623 void g_mod (unsigned flags, unsigned long val)
2624 /* Primary = TOS % Primary */
2626 static char* ops [12] = {
2627 0, "tosmoda0", "tosmodax",
2628 0, "tosumoda0", "tosumodax",
2634 /* Check if we can do some cost reduction */
2635 if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2636 /* We can do that with an AND operation */
2637 g_and (flags, val - 1);
2639 /* Do it the hard way... */
2640 if (flags & CF_CONST) {
2641 /* lhs is not on stack */
2642 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2643 g_push (flags & ~CF_CONST, 0);
2645 oper (flags, val, ops);
2651 void g_or (unsigned flags, unsigned long val)
2652 /* Primary = TOS | Primary */
2654 static char* ops [12] = {
2655 0, "tosora0", "tosorax",
2656 0, "tosora0", "tosorax",
2661 /* If the right hand side is const, the lhs is not on stack but still
2662 * in the primary register.
2664 if (flags & CF_CONST) {
2666 switch (flags & CF_TYPE) {
2669 if (flags & CF_FORCECHAR) {
2670 if ((val & 0xFF) != 0xFF) {
2671 AddCodeLine ("ora #$%02X", (unsigned char)val);
2679 AddCodeLine ("ora #$%02X", (unsigned char)val);
2686 AddCodeLine ("ora #$%02X", (unsigned char)val);
2695 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2696 * into the normal, non-optimized stuff.
2698 g_push (flags & ~CF_CONST, 0);
2702 /* Use long way over the stack */
2703 oper (flags, val, ops);
2708 void g_xor (unsigned flags, unsigned long val)
2709 /* Primary = TOS ^ Primary */
2711 static char* ops [12] = {
2712 0, "tosxora0", "tosxorax",
2713 0, "tosxora0", "tosxorax",
2719 /* If the right hand side is const, the lhs is not on stack but still
2720 * in the primary register.
2722 if (flags & CF_CONST) {
2724 switch (flags & CF_TYPE) {
2727 if (flags & CF_FORCECHAR) {
2728 if ((val & 0xFF) != 0) {
2729 AddCodeLine ("eor #$%02X", (unsigned char)val);
2738 AddCodeLine ("eor #$%02X", (unsigned char)val);
2741 } else if ((val & 0xFF) == 0) {
2742 AddCodeLine ("pha");
2743 AddCodeLine ("txa");
2744 AddCodeLine ("eor #$%02X", (unsigned char)(val >> 8));
2745 AddCodeLine ("tax");
2746 AddCodeLine ("pla");
2754 AddCodeLine ("eor #$%02X", (unsigned char)val);
2764 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2765 * into the normal, non-optimized stuff.
2767 g_push (flags & ~CF_CONST, 0);
2771 /* Use long way over the stack */
2772 oper (flags, val, ops);
2777 void g_and (unsigned flags, unsigned long val)
2778 /* Primary = TOS & Primary */
2780 static char* ops [12] = {
2781 0, "tosanda0", "tosandax",
2782 0, "tosanda0", "tosandax",
2787 /* If the right hand side is const, the lhs is not on stack but still
2788 * in the primary register.
2790 if (flags & CF_CONST) {
2792 switch (flags & CF_TYPE) {
2795 if (flags & CF_FORCECHAR) {
2796 AddCodeLine ("and #$%02X", (unsigned char)val);
2801 if ((val & 0xFFFF) != 0xFFFF) {
2806 } else if (val != 0xFF) {
2807 AddCodeLine ("and #$%02X", (unsigned char)val);
2809 } else if ((val & 0xFF00) == 0xFF00) {
2810 AddCodeLine ("and #$%02X", (unsigned char)val);
2811 } else if ((val & 0x00FF) == 0x0000) {
2812 AddCodeLine ("txa");
2813 AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2814 AddCodeLine ("tax");
2817 AddCodeLine ("tay");
2818 AddCodeLine ("txa");
2819 AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2820 AddCodeLine ("tax");
2821 AddCodeLine ("tya");
2822 if ((val & 0x00FF) != 0x00FF) {
2823 AddCodeLine ("and #$%02X", (unsigned char)val);
2832 AddCodeLine ("stx sreg+1");
2833 AddCodeLine ("stx sreg");
2834 if ((val & 0xFF) != 0xFF) {
2835 AddCodeLine ("and #$%02X", (unsigned char)val);
2838 } else if (val == 0xFF00) {
2840 AddCodeLine ("sta sreg+1");
2841 AddCodeLine ("sta sreg");
2850 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2851 * into the normal, non-optimized stuff.
2853 g_push (flags & ~CF_CONST, 0);
2857 /* Use long way over the stack */
2858 oper (flags, val, ops);
2863 void g_asr (unsigned flags, unsigned long val)
2864 /* Primary = TOS >> Primary */
2866 static char* ops [12] = {
2867 0, "tosasra0", "tosasrax",
2868 0, "tosshra0", "tosshrax",
2873 /* If the right hand side is const, the lhs is not on stack but still
2874 * in the primary register.
2876 if (flags & CF_CONST) {
2878 switch (flags & CF_TYPE) {
2882 if (val >= 1 && val <= 4) {
2883 if (flags & CF_UNSIGNED) {
2884 AddCodeLine ("jsr shrax%ld", val);
2886 AddCodeLine ("jsr asrax%ld", val);
2889 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2890 AddCodeLine ("txa");
2897 if (val >= 1 && val <= 4) {
2898 if (flags & CF_UNSIGNED) {
2899 AddCodeLine ("jsr shreax%ld", val);
2901 AddCodeLine ("jsr asreax%ld", val);
2904 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2905 AddCodeLine ("txa");
2906 AddCodeLine ("ldx sreg");
2907 AddCodeLine ("ldy sreg+1");
2908 AddCodeLine ("sty sreg");
2909 AddCodeLine ("ldy #$00");
2910 AddCodeLine ("sty sreg+1");
2912 } else if (val == 16) {
2913 AddCodeLine ("ldy #$00");
2914 AddCodeLine ("ldx sreg+1");
2915 if ((flags & CF_UNSIGNED) == 0) {
2916 unsigned L = GetLocalLabel();
2917 AddCodeLine ("bpl %s", LocalLabelName (L));
2918 AddCodeLine ("dey");
2921 AddCodeLine ("lda sreg");
2922 AddCodeLine ("sty sreg+1");
2923 AddCodeLine ("sty sreg");
2932 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2933 * into the normal, non-optimized stuff.
2935 g_push (flags & ~CF_CONST, 0);
2939 /* Use long way over the stack */
2940 oper (flags, val, ops);
2945 void g_asl (unsigned flags, unsigned long val)
2946 /* Primary = TOS << Primary */
2948 static char* ops [12] = {
2949 0, "tosasla0", "tosaslax",
2950 0, "tosshla0", "tosshlax",
2956 /* If the right hand side is const, the lhs is not on stack but still
2957 * in the primary register.
2959 if (flags & CF_CONST) {
2961 switch (flags & CF_TYPE) {
2965 if (val >= 1 && val <= 4) {
2966 if (flags & CF_UNSIGNED) {
2967 AddCodeLine ("jsr shlax%ld", val);
2969 AddCodeLine ("jsr aslax%ld", val);
2972 } else if (val == 8) {
2973 AddCodeLine ("tax");
2974 AddCodeLine ("lda #$00");
2980 if (val >= 1 && val <= 4) {
2981 if (flags & CF_UNSIGNED) {
2982 AddCodeLine ("jsr shleax%ld", val);
2984 AddCodeLine ("jsr asleax%ld", val);
2987 } else if (val == 8) {
2988 AddCodeLine ("ldy sreg");
2989 AddCodeLine ("sty sreg+1");
2990 AddCodeLine ("stx sreg");
2991 AddCodeLine ("tax");
2992 AddCodeLine ("lda #$00");
2994 } else if (val == 16) {
2995 AddCodeLine ("stx sreg+1");
2996 AddCodeLine ("sta sreg");
2997 AddCodeLine ("lda #$00");
2998 AddCodeLine ("tax");
3007 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3008 * into the normal, non-optimized stuff.
3010 g_push (flags & ~CF_CONST, 0);
3014 /* Use long way over the stack */
3015 oper (flags, val, ops);
3020 void g_neg (unsigned flags)
3021 /* Primary = -Primary */
3023 switch (flags & CF_TYPE) {
3027 AddCodeLine ("jsr negax");
3031 AddCodeLine ("jsr negeax");
3041 void g_bneg (unsigned flags)
3042 /* Primary = !Primary */
3044 switch (flags & CF_TYPE) {
3047 AddCodeLine ("jsr bnega");
3051 AddCodeLine ("jsr bnegax");
3055 AddCodeLine ("jsr bnegeax");
3065 void g_com (unsigned flags)
3066 /* Primary = ~Primary */
3068 switch (flags & CF_TYPE) {
3072 AddCodeLine ("jsr complax");
3076 AddCodeLine ("jsr compleax");
3086 void g_inc (unsigned flags, unsigned long val)
3087 /* Increment the primary register by a given number */
3089 /* Don't inc by zero */
3094 /* Generate code for the supported types */
3096 switch (flags & CF_TYPE) {
3099 if (flags & CF_FORCECHAR) {
3100 if (CPU == CPU_65C02 && val <= 2) {
3102 AddCodeLine ("ina");
3105 AddCodeLine ("clc");
3106 AddCodeLine ("adc #$%02X", (unsigned char)val);
3113 if (CPU == CPU_65C02 && val == 1) {
3114 unsigned L = GetLocalLabel();
3115 AddCodeLine ("ina");
3116 AddCodeLine ("bne %s", LocalLabelName (L));
3117 AddCodeLine ("inx");
3119 } else if (CodeSizeFactor < 200) {
3122 AddCodeLine ("jsr incax%lu", val);
3123 } else if (val <= 255) {
3125 AddCodeLine ("jsr incaxy");
3127 g_add (flags | CF_CONST, val);
3130 /* Inline the code */
3132 if ((val & 0xFF) != 0) {
3133 unsigned L = GetLocalLabel();
3134 AddCodeLine ("clc");
3135 AddCodeLine ("adc #$%02X", (unsigned char) val);
3136 AddCodeLine ("bcc %s", LocalLabelName (L));
3137 AddCodeLine ("inx");
3141 AddCodeLine ("inx");
3144 AddCodeLine ("inx");
3147 AddCodeLine ("clc");
3148 if ((val & 0xFF) != 0) {
3149 AddCodeLine ("adc #$%02X", (unsigned char) val);
3151 AddCodeLine ("pha");
3152 AddCodeLine ("txa");
3153 AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3154 AddCodeLine ("tax");
3155 AddCodeLine ("pla");
3163 AddCodeLine ("jsr inceaxy");
3165 g_add (flags | CF_CONST, val);
3177 void g_dec (unsigned flags, unsigned long val)
3178 /* Decrement the primary register by a given number */
3180 /* Don't dec by zero */
3185 /* Generate code for the supported types */
3187 switch (flags & CF_TYPE) {
3190 if (flags & CF_FORCECHAR) {
3191 if (CPU == CPU_65C02 && val <= 2) {
3193 AddCodeLine ("dea");
3196 AddCodeLine ("sec");
3197 AddCodeLine ("sbc #$%02X", (unsigned char)val);
3204 if (CodeSizeFactor < 200) {
3205 /* Use subroutines */
3207 AddCodeLine ("jsr decax%d", (int) val);
3208 } else if (val <= 255) {
3210 AddCodeLine ("jsr decaxy");
3212 g_sub (flags | CF_CONST, val);
3215 /* Inline the code */
3217 if ((val & 0xFF) != 0) {
3218 unsigned L = GetLocalLabel();
3219 AddCodeLine ("sec");
3220 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3221 AddCodeLine ("bcs %s", LocalLabelName (L));
3222 AddCodeLine ("dex");
3226 AddCodeLine ("dex");
3229 AddCodeLine ("dex");
3232 AddCodeLine ("sec");
3233 if ((val & 0xFF) != 0) {
3234 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3236 AddCodeLine ("pha");
3237 AddCodeLine ("txa");
3238 AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3239 AddCodeLine ("tax");
3240 AddCodeLine ("pla");
3248 AddCodeLine ("jsr deceaxy");
3250 g_sub (flags | CF_CONST, val);
3263 * Following are the conditional operators. They compare the TOS against
3264 * the primary and put a literal 1 in the primary if the condition is
3265 * true, otherwise they clear the primary register
3270 void g_eq (unsigned flags, unsigned long val)
3271 /* Test for equal */
3273 static char* ops [12] = {
3274 "toseq00", "toseqa0", "toseqax",
3275 "toseq00", "toseqa0", "toseqax",
3282 /* If the right hand side is const, the lhs is not on stack but still
3283 * in the primary register.
3285 if (flags & CF_CONST) {
3287 switch (flags & CF_TYPE) {
3290 if (flags & CF_FORCECHAR) {
3291 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3292 AddCodeLine ("jsr booleq");
3298 L = GetLocalLabel();
3299 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3300 AddCodeLine ("bne %s", LocalLabelName (L));
3301 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3303 AddCodeLine ("jsr booleq");
3313 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3314 * into the normal, non-optimized stuff.
3316 g_push (flags & ~CF_CONST, 0);
3320 /* Use long way over the stack */
3321 oper (flags, val, ops);
3326 void g_ne (unsigned flags, unsigned long val)
3327 /* Test for not equal */
3329 static char* ops [12] = {
3330 "tosne00", "tosnea0", "tosneax",
3331 "tosne00", "tosnea0", "tosneax",
3338 /* If the right hand side is const, the lhs is not on stack but still
3339 * in the primary register.
3341 if (flags & CF_CONST) {
3343 switch (flags & CF_TYPE) {
3346 if (flags & CF_FORCECHAR) {
3347 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3348 AddCodeLine ("jsr boolne");
3354 L = GetLocalLabel();
3355 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3356 AddCodeLine ("bne %s", LocalLabelName (L));
3357 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3359 AddCodeLine ("jsr boolne");
3369 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3370 * into the normal, non-optimized stuff.
3372 g_push (flags & ~CF_CONST, 0);
3376 /* Use long way over the stack */
3377 oper (flags, val, ops);
3382 void g_lt (unsigned flags, unsigned long val)
3383 /* Test for less than */
3385 static char* ops [12] = {
3386 "toslt00", "toslta0", "tosltax",
3387 "tosult00", "tosulta0", "tosultax",
3392 /* If the right hand side is const, the lhs is not on stack but still
3393 * in the primary register.
3395 if (flags & CF_CONST) {
3397 /* Give a warning in some special cases */
3398 if ((flags & CF_UNSIGNED) && val == 0) {
3399 Warning ("Condition is never true");
3402 /* Look at the type */
3403 switch (flags & CF_TYPE) {
3406 if (flags & CF_FORCECHAR) {
3407 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3408 if (flags & CF_UNSIGNED) {
3409 AddCodeLine ("jsr boolult");
3411 AddCodeLine ("jsr boollt");
3418 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3419 /* If we have a signed compare against zero, we only need to
3420 * test the high byte.
3422 AddCodeLine ("txa");
3423 AddCodeLine ("jsr boollt");
3426 /* Direct code only for unsigned data types */
3427 if (flags & CF_UNSIGNED) {
3428 unsigned L = GetLocalLabel();
3429 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3430 AddCodeLine ("bne %s", LocalLabelName (L));
3431 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3433 AddCodeLine ("jsr boolult");
3439 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3440 /* If we have a signed compare against zero, we only need to
3441 * test the high byte.
3443 AddCodeLine ("lda sreg+1");
3444 AddCodeLine ("jsr boollt");
3453 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3454 * into the normal, non-optimized stuff.
3456 g_push (flags & ~CF_CONST, 0);
3460 /* Use long way over the stack */
3461 oper (flags, val, ops);
3466 void g_le (unsigned flags, unsigned long val)
3467 /* Test for less than or equal to */
3469 static char* ops [12] = {
3470 "tosle00", "toslea0", "tosleax",
3471 "tosule00", "tosulea0", "tosuleax",
3477 /* If the right hand side is const, the lhs is not on stack but still
3478 * in the primary register.
3480 if (flags & CF_CONST) {
3482 /* <= is not very effective on the 6502, so try to convert
3483 * it into < if the value is in a valid range.
3486 /* Look at the type */
3487 switch (flags & CF_TYPE) {
3490 if (flags & CF_FORCECHAR) {
3491 if (flags & CF_UNSIGNED) {
3493 AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3494 AddCodeLine ("jsr boolult");
3496 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3497 AddCodeLine ("jsr boolule");
3501 AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3502 AddCodeLine ("jsr boollt");
3504 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3505 AddCodeLine ("jsr boolle");
3513 if (flags & CF_UNSIGNED) {
3514 unsigned L = GetLocalLabel();
3515 const char* Name = "boolule";
3520 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3521 AddCodeLine ("bne %s", LocalLabelName (L));
3522 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3524 AddCodeLine ("jsr %s", Name);
3536 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3537 * into the normal, non-optimized stuff.
3539 g_push (flags & ~CF_CONST, 0);
3543 /* Use long way over the stack */
3544 oper (flags, val, ops);
3549 void g_gt (unsigned flags, unsigned long val)
3550 /* Test for greater than */
3552 static char* ops [12] = {
3553 "tosgt00", "tosgta0", "tosgtax",
3554 "tosugt00", "tosugta0", "tosugtax",
3560 /* If the right hand side is const, the lhs is not on stack but still
3561 * in the primary register.
3563 if (flags & CF_CONST) {
3565 /* > is not very effective on the 6502, so try to convert
3566 * it into >= if the value is in a valid range.
3569 /* Look at the type */
3570 switch (flags & CF_TYPE) {
3573 if (flags & CF_FORCECHAR) {
3574 if (flags & CF_UNSIGNED) {
3575 /* If we have a compare > 0, we will replace it by
3576 * != 0 here, since both are identical but the latter
3577 * is easier to optimize.
3580 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3581 AddCodeLine ("jsr boolne");
3582 } else if (val < 255) {
3583 AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3584 AddCodeLine ("jsr booluge");
3586 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3587 AddCodeLine ("jsr boolugt");
3591 AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
3592 AddCodeLine ("jsr boolge");
3594 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3595 AddCodeLine ("jsr boolgt");
3603 if (flags & CF_UNSIGNED) {
3604 /* If we have a compare > 0, we will replace it by
3605 * != 0 here, since both are identical but the latter
3606 * is easier to optimize.
3609 AddCodeLine ("stx tmp1");
3610 AddCodeLine ("ora tmp1");
3611 AddCodeLine ("jsr boolne");
3613 unsigned L = GetLocalLabel();
3614 const char* Name = "boolugt";
3619 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3620 AddCodeLine ("bne %s", LocalLabelName (L));
3621 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3623 AddCodeLine ("jsr %s", Name);
3636 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3637 * into the normal, non-optimized stuff.
3639 g_push (flags & ~CF_CONST, 0);
3643 /* Use long way over the stack */
3644 oper (flags, val, ops);
3649 void g_ge (unsigned flags, unsigned long val)
3650 /* Test for greater than or equal to */
3652 static char* ops [12] = {
3653 "tosge00", "tosgea0", "tosgeax",
3654 "tosuge00", "tosugea0", "tosugeax",
3660 /* If the right hand side is const, the lhs is not on stack but still
3661 * in the primary register.
3663 if (flags & CF_CONST) {
3665 /* Give a warning in some special cases */
3666 if ((flags & CF_UNSIGNED) && val == 0) {
3667 Warning ("Condition is always true");
3670 /* Look at the type */
3671 switch (flags & CF_TYPE) {
3674 if (flags & CF_FORCECHAR) {
3675 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3676 if (flags & CF_UNSIGNED) {
3677 AddCodeLine ("jsr booluge");
3679 AddCodeLine ("jsr boolge");
3686 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3687 /* If we have a signed compare against zero, we only need to
3688 * test the high byte.
3690 AddCodeLine ("txa");
3691 AddCodeLine ("jsr boolge");
3694 /* Direct code only for unsigned data types */
3695 if (flags & CF_UNSIGNED) {
3696 unsigned L = GetLocalLabel();
3697 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3698 AddCodeLine ("bne %s", LocalLabelName (L));
3699 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3701 AddCodeLine ("jsr booluge");
3707 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3708 /* If we have a signed compare against zero, we only need to
3709 * test the high byte.
3711 AddCodeLine ("lda sreg+1");
3712 AddCodeLine ("jsr boolge");
3721 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3722 * into the normal, non-optimized stuff.
3724 g_push (flags & ~CF_CONST, 0);
3728 /* Use long way over the stack */
3729 oper (flags, val, ops);
3734 /*****************************************************************************/
3735 /* Allocating static storage */
3736 /*****************************************************************************/
3740 void g_res (unsigned n)
3741 /* Reserve static storage, n bytes */
3743 AddDataLine ("\t.res\t%u,$00", n);
3748 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3749 /* Define data with the size given in flags */
3751 if (flags & CF_CONST) {
3753 /* Numeric constant */
3754 switch (flags & CF_TYPE) {
3757 AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
3761 AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
3765 AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
3776 /* Create the correct label name */
3777 const char* Label = GetLabelName (flags, val, offs);
3779 /* Labels are always 16 bit */
3780 AddDataLine ("\t.word\t%s", Label);
3787 void g_defbytes (const void* Bytes, unsigned Count)
3788 /* Output a row of bytes as a constant */
3794 /* Cast the buffer pointer */
3795 const unsigned char* Data = (const unsigned char*) Bytes;
3797 /* Output the stuff */
3800 /* How many go into this line? */
3801 if ((Chunk = Count) > 16) {
3806 /* Output one line */
3807 strcpy (Buf, "\t.byte\t");
3810 B += sprintf (B, "$%02X", *Data++);
3816 /* Output the line */
3823 void g_zerobytes (unsigned n)
3824 /* Output n bytes of data initialized with zero */
3826 AddDataLine ("\t.res\t%u,$00", n);
3831 /*****************************************************************************/
3832 /* User supplied assembler code */
3833 /*****************************************************************************/
3837 void g_asmcode (struct StrBuf* B)
3838 /* Output one line of assembler code. */
3840 AddCodeLine ("%.*s", SB_GetLen (B), SB_GetConstBuf (B));
3845 /*****************************************************************************/
3846 /* Inlined known functions */
3847 /*****************************************************************************/
3851 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3852 /* Inline the strlen() function */
3854 /* We need a label in both cases */
3855 unsigned label = GetLocalLabel ();
3857 /* Two different encodings */
3858 if (flags & CF_CONST) {
3860 /* The address of the string is constant. Create the correct label name */
3861 char* lbuf = GetLabelName (flags, val, offs);
3863 /* Generate the strlen code */
3864 AddCodeLine ("ldy #$FF");
3865 g_defcodelabel (label);
3866 AddCodeLine ("iny");
3867 AddCodeLine ("lda %s,y", lbuf);
3868 AddCodeLine ("bne %s", LocalLabelName (label));
3869 AddCodeLine ("tax");
3870 AddCodeLine ("tya");
3874 /* Address not constant but in primary */
3875 if (CodeSizeFactor < 400) {
3876 /* This is too much code, so call strlen instead of inlining */
3877 AddCodeLine ("jsr _strlen");
3879 /* Inline the function */
3880 AddCodeLine ("sta ptr1");
3881 AddCodeLine ("stx ptr1+1");
3882 AddCodeLine ("ldy #$FF");
3883 g_defcodelabel (label);
3884 AddCodeLine ("iny");
3885 AddCodeLine ("lda (ptr1),y");
3886 AddCodeLine ("bne %s", LocalLabelName (label));
3887 AddCodeLine ("tax");
3888 AddCodeLine ("tya");