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 /*****************************************************************************/
60 /*****************************************************************************/
62 /*****************************************************************************/
66 /* Compiler relative stack pointer */
71 /*****************************************************************************/
73 /*****************************************************************************/
77 static void typeerror (unsigned type)
78 /* Print an error message about an invalid operand type */
80 Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPE);
85 static void CheckLocalOffs (unsigned Offs)
86 /* Check the offset into the stack for 8bit range */
89 /* Too many local vars */
90 Error ("Too many local variables");
96 static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs)
98 static char lbuf [128]; /* Label name */
100 /* Create the correct label name */
101 switch (flags & CF_ADDRMASK) {
104 /* Static memory cell */
105 sprintf (lbuf, "%s+%u", LocalLabelName (label), offs);
110 sprintf (lbuf, "_%s+%u", (char*) label, offs);
114 /* Absolute address */
115 sprintf (lbuf, "$%04X", (unsigned)((label+offs) & 0xFFFF));
119 /* Variable in register bank */
120 sprintf (lbuf, "regbank+%u", (unsigned)((label+offs) & 0xFFFF));
124 Internal ("Invalid address flags");
127 /* Return a pointer to the static buffer */
133 /*****************************************************************************/
134 /* Pre- and postamble */
135 /*****************************************************************************/
139 void g_preamble (void)
140 /* Generate the assembler code preamble */
142 /* Create a new segment list */
145 /* Identify the compiler version */
146 AddTextLine ("; File generated by cc65 v %u.%u.%u",
147 VER_MAJOR, VER_MINOR, VER_PATCH);
149 /* Insert some object file options */
150 AddTextLine (".fopt\t\tcompiler,\"cc65 v %u.%u.%u\"",
151 VER_MAJOR, VER_MINOR, VER_PATCH);
153 /* If we're producing code for some other CPU, switch the command set */
154 if (CPU == CPU_65C02) {
155 AddTextLine (".pc02");
158 /* Allow auto import for runtime library routines */
159 AddTextLine (".autoimport\ton");
161 /* Switch the assembler into case sensitive mode */
162 AddTextLine (".case\t\ton");
164 /* Tell the assembler if we want to generate debug info */
165 AddTextLine (".debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
167 /* Import the stack pointer for direct auto variable access */
168 AddTextLine (".importzp\tsp, sreg, regsave, regbank, tmp1, ptr1");
170 /* Define long branch macros */
171 AddTextLine (".macpack\tlongbranch");
176 /*****************************************************************************/
177 /* Segment support */
178 /*****************************************************************************/
182 void g_userodata (void)
183 /* Switch to the read only data segment */
185 UseDataSeg (SEG_RODATA);
190 void g_usedata (void)
191 /* Switch to the data segment */
193 UseDataSeg (SEG_DATA);
199 /* Switch to the bss segment */
201 UseDataSeg (SEG_BSS);
206 /*****************************************************************************/
208 /*****************************************************************************/
212 unsigned sizeofarg (unsigned flags)
213 /* Return the size of a function argument type that is encoded in flags */
215 switch (flags & CF_TYPE) {
218 return (flags & CF_FORCECHAR)? 1 : 2;
235 int pop (unsigned flags)
236 /* Pop an argument of the given size */
238 return oursp += sizeofarg (flags);
243 int push (unsigned flags)
244 /* Push an argument of the given size */
246 return oursp -= sizeofarg (flags);
251 static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
252 /* The value in Offs is an offset to an address in a/x. Make sure, an object
253 * of the type given in Flags can be loaded or stored into this address by
254 * adding part of the offset to the address in ax, so that the remaining
255 * offset fits into an index register. Return the remaining offset.
258 /* If the offset is too large for a byte register, add the high byte
259 * of the offset to the primary. Beware: We need a special correction
260 * if the offset in the low byte will overflow in the operation.
262 unsigned O = Offs & ~0xFFU;
263 if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
264 /* We need to add the low byte also */
268 /* Do the correction if we need one */
270 g_inc (CF_INT | CF_CONST, O);
274 /* Return the new offset */
280 /*****************************************************************************/
281 /* Functions handling local labels */
282 /*****************************************************************************/
286 void g_defcodelabel (unsigned label)
287 /* Define a local code label */
289 AddCodeLabel (CS->Code, LocalLabelName (label));
294 void g_defdatalabel (unsigned label)
295 /* Define a local data label */
297 AddDataLine ("%s:", LocalLabelName (label));
302 /*****************************************************************************/
303 /* Functions handling global labels */
304 /*****************************************************************************/
308 void g_defgloblabel (const char* Name)
309 /* Define a global label with the given name */
311 /* Global labels are always data labels */
312 AddDataLine ("_%s:", Name);
317 void g_defexport (const char* Name, int ZP)
318 /* Export the given label */
321 AddTextLine ("\t.exportzp\t_%s", Name);
323 AddTextLine ("\t.export\t\t_%s", Name);
329 void g_defimport (const char* Name, int ZP)
330 /* Import the given label */
333 AddTextLine ("\t.importzp\t_%s", Name);
335 AddTextLine ("\t.import\t\t_%s", Name);
341 /*****************************************************************************/
342 /* Load functions for various registers */
343 /*****************************************************************************/
347 static void ldaconst (unsigned val)
348 /* Load a with a constant */
350 AddCodeLine ("lda #$%02X", val & 0xFF);
355 static void ldxconst (unsigned val)
356 /* Load x with a constant */
358 AddCodeLine ("ldx #$%02X", val & 0xFF);
363 static void ldyconst (unsigned val)
364 /* Load y with a constant */
366 AddCodeLine ("ldy #$%02X", val & 0xFF);
371 /*****************************************************************************/
372 /* Function entry and exit */
373 /*****************************************************************************/
377 /* Remember the argument size of a function. The variable is set by g_enter
378 * and used by g_leave. If the functions gets its argument size by the caller
379 * (variable param list or function without prototype), g_enter will set the
385 void g_enter (unsigned flags, unsigned argsize)
386 /* Function prologue */
388 if ((flags & CF_FIXARGC) != 0) {
389 /* Just remember the argument size for the leave */
393 AddCodeLine ("jsr enter");
400 /* Function epilogue */
402 /* How many bytes of locals do we have to drop? */
405 /* If we didn't have a variable argument list, don't call leave */
408 /* Drop stackframe if needed */
412 AddCodeLine ("jsr incsp%d", k);
416 AddCodeLine ("jsr addysp");
423 /* Nothing to drop */
424 AddCodeLine ("jsr leave");
426 /* We've a stack frame to drop */
428 AddCodeLine ("jsr leavey");
432 /* Add the final rts */
438 /*****************************************************************************/
439 /* Register variables */
440 /*****************************************************************************/
444 void g_save_regvars (int RegOffs, unsigned Bytes)
445 /* Save register variables */
447 /* Don't loop for up to two bytes */
450 AddCodeLine ("lda regbank%+d", RegOffs);
451 AddCodeLine ("jsr pusha");
453 } else if (Bytes == 2) {
455 AddCodeLine ("lda regbank%+d", RegOffs);
456 AddCodeLine ("ldx regbank%+d", RegOffs+1);
457 AddCodeLine ("jsr pushax");
461 /* More than two bytes - loop */
462 unsigned Label = GetLocalLabel ();
464 ldyconst (Bytes - 1);
466 g_defcodelabel (Label);
467 AddCodeLine ("lda regbank%+d,x", RegOffs-1);
468 AddCodeLine ("sta (sp),y");
471 AddCodeLine ("bne %s", LocalLabelName (Label));
475 /* We pushed stuff, correct the stack pointer */
481 void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
482 /* Restore register variables */
484 /* Calculate the actual stack offset and check it */
486 CheckLocalOffs (StackOffs);
488 /* Don't loop for up to two bytes */
491 ldyconst (StackOffs);
492 AddCodeLine ("lda (sp),y");
493 AddCodeLine ("sta regbank%+d", RegOffs);
495 } else if (Bytes == 2) {
497 ldyconst (StackOffs);
498 AddCodeLine ("lda (sp),y");
499 AddCodeLine ("sta regbank%+d", RegOffs);
501 AddCodeLine ("lda (sp),y");
502 AddCodeLine ("sta regbank%+d", RegOffs+1);
506 /* More than two bytes - loop */
507 unsigned Label = GetLocalLabel ();
508 ldyconst (StackOffs+Bytes-1);
510 g_defcodelabel (Label);
511 AddCodeLine ("lda (sp),y");
512 AddCodeLine ("sta regbank%+d,x", RegOffs-1);
515 AddCodeLine ("bne %s", LocalLabelName (Label));
522 /*****************************************************************************/
523 /* Fetching memory cells */
524 /*****************************************************************************/
528 void g_getimmed (unsigned flags, unsigned long val, unsigned offs)
529 /* Load a constant into the primary register */
531 if ((flags & CF_CONST) != 0) {
533 /* Numeric constant */
534 switch (flags & CF_TYPE) {
537 if ((flags & CF_FORCECHAR) != 0) {
543 ldxconst ((val >> 8) & 0xFF);
544 ldaconst (val & 0xFF);
549 AddCodeLine ("ldx #$00");
550 AddCodeLine ("stx sreg+1");
551 AddCodeLine ("stx sreg");
552 AddCodeLine ("lda #$%02X", (unsigned char) val);
553 } else if ((val & 0xFFFF00FF) == 0) {
554 AddCodeLine ("lda #$00");
555 AddCodeLine ("sta sreg+1");
556 AddCodeLine ("sta sreg");
557 AddCodeLine ("ldx #$%02X", (unsigned char) (val >> 8));
558 } else if ((val & 0xFFFF0000) == 0 && CodeSizeFactor > 140) {
559 AddCodeLine ("lda #$00");
560 AddCodeLine ("sta sreg+1");
561 AddCodeLine ("sta sreg");
562 AddCodeLine ("lda #$%02X", (unsigned char) val);
563 AddCodeLine ("ldx #$%02X", (unsigned char) (val >> 8));
564 } else if ((val & 0xFFFFFF00) == 0xFFFFFF00) {
565 AddCodeLine ("ldx #$FF");
566 AddCodeLine ("stx sreg+1");
567 AddCodeLine ("stx sreg");
568 if ((val & 0xFF) == 0xFF) {
571 AddCodeLine ("lda #$%02X", (unsigned char) val);
573 } else if ((val & 0xFFFF00FF) == 0xFFFF00FF) {
574 AddCodeLine ("lda #$FF");
575 AddCodeLine ("sta sreg+1");
576 AddCodeLine ("sta sreg");
577 AddCodeLine ("ldx #$%02X", (unsigned char) (val >> 8));
579 /* Call a subroutine that will load following value */
580 AddCodeLine ("jsr ldeax");
581 AddCodeLine (".dword $%08lX", val & 0xFFFFFFFF);
593 /* Some sort of label */
594 const char* Label = GetLabelName (flags, val, offs);
596 /* Load the address into the primary */
597 AddCodeLine ("lda #<(%s)", Label);
598 AddCodeLine ("ldx #>(%s)", Label);
605 void g_getstatic (unsigned flags, unsigned long label, unsigned offs)
606 /* Fetch an static memory cell into the primary register */
608 /* Create the correct label name */
609 char* lbuf = GetLabelName (flags, label, offs);
611 /* Check the size and generate the correct load operation */
612 switch (flags & CF_TYPE) {
615 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
616 AddCodeLine ("lda %s", lbuf); /* load A from the label */
619 AddCodeLine ("lda %s", lbuf); /* load A from the label */
620 if (!(flags & CF_UNSIGNED)) {
621 /* Must sign extend */
622 unsigned L = GetLocalLabel ();
623 AddCodeLine ("bpl %s", LocalLabelName (L));
631 AddCodeLine ("lda %s", lbuf);
632 if (flags & CF_TEST) {
633 AddCodeLine ("ora %s+1", lbuf);
635 AddCodeLine ("ldx %s+1", lbuf);
640 if (flags & CF_TEST) {
641 AddCodeLine ("lda %s+3", lbuf);
642 AddCodeLine ("ora %s+2", lbuf);
643 AddCodeLine ("ora %s+1", lbuf);
644 AddCodeLine ("ora %s+0", lbuf);
646 AddCodeLine ("lda %s+3", lbuf);
647 AddCodeLine ("sta sreg+1");
648 AddCodeLine ("lda %s+2", lbuf);
649 AddCodeLine ("sta sreg");
650 AddCodeLine ("ldx %s+1", lbuf);
651 AddCodeLine ("lda %s", lbuf);
663 void g_getlocal (unsigned flags, int offs)
664 /* Fetch specified local object (local var). */
667 CheckLocalOffs (offs);
668 switch (flags & CF_TYPE) {
671 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
672 if (CPU == CPU_65C02 && offs == 0) {
673 AddCodeLine ("lda (sp)");
676 AddCodeLine ("lda (sp),y");
680 AddCodeLine ("ldx #$00");
681 AddCodeLine ("lda (sp,x)");
684 AddCodeLine ("ldx #$00");
685 AddCodeLine ("lda (sp),y");
687 if ((flags & CF_UNSIGNED) == 0) {
688 unsigned L = GetLocalLabel();
689 AddCodeLine ("bpl %s", LocalLabelName (L));
697 CheckLocalOffs (offs + 1);
698 if (flags & CF_TEST) {
700 AddCodeLine ("lda (sp),y");
702 AddCodeLine ("ora (sp),y");
704 if (CodeSizeFactor > 180) {
706 AddCodeLine ("lda (sp),y");
709 AddCodeLine ("lda (sp),y");
713 AddCodeLine ("jsr ldaxysp");
715 AddCodeLine ("jsr ldax0sp");
724 AddCodeLine ("jsr ldeaxysp");
726 AddCodeLine ("jsr ldeax0sp");
737 void g_getind (unsigned flags, unsigned offs)
738 /* Fetch the specified object type indirect through the primary register
739 * into the primary register
742 /* If the offset is greater than 255, add the part that is > 255 to
743 * the primary. This way we get an easy addition and use the low byte
746 offs = MakeByteOffs (flags, offs);
748 /* Handle the indirect fetch */
749 switch (flags & CF_TYPE) {
752 /* Character sized */
755 if (flags & CF_UNSIGNED) {
756 AddCodeLine ("jsr ldauidx");
758 AddCodeLine ("jsr ldaidx");
761 if (flags & CF_UNSIGNED) {
762 if (CodeSizeFactor > 250) {
763 AddCodeLine ("sta ptr1");
764 AddCodeLine ("stx ptr1+1");
765 AddCodeLine ("ldx #$00");
766 AddCodeLine ("lda (ptr1,x)");
768 AddCodeLine ("jsr ldaui");
771 AddCodeLine ("jsr ldai");
777 if (flags & CF_TEST) {
779 AddCodeLine ("sta ptr1");
780 AddCodeLine ("stx ptr1+1");
781 AddCodeLine ("lda (ptr1),y");
783 AddCodeLine ("ora (ptr1),y");
786 AddCodeLine ("jsr ldaxi");
789 AddCodeLine ("jsr ldaxidx");
796 AddCodeLine ("jsr ldeaxi");
799 AddCodeLine ("jsr ldeaxidx");
801 if (flags & CF_TEST) {
802 AddCodeLine ("jsr tsteax");
814 void g_leasp (int offs)
815 /* Fetch the address of the specified symbol into the primary register */
817 /* Calculate the offset relative to sp */
820 /* For value 0 we do direct code */
822 AddCodeLine ("lda sp");
823 AddCodeLine ("ldx sp+1");
825 if (CodeSizeFactor < 300) {
826 ldaconst (offs); /* Load A with offset value */
827 AddCodeLine ("jsr leaasp"); /* Load effective address */
829 unsigned L = GetLocalLabel ();
830 if (CPU == CPU_65C02 && offs == 1) {
831 AddCodeLine ("lda sp");
832 AddCodeLine ("ldx sp+1");
834 AddCodeLine ("bne %s", LocalLabelName (L));
839 AddCodeLine ("ldx sp+1");
840 AddCodeLine ("adc sp");
841 AddCodeLine ("bcc %s", LocalLabelName (L));
851 void g_leavariadic (int Offs)
852 /* Fetch the address of a parameter in a variadic function into the primary
856 unsigned ArgSizeOffs;
858 /* Calculate the offset relative to sp */
861 /* Get the offset of the parameter which is stored at sp+0 on function
862 * entry and check if this offset is reachable with a byte offset.
865 ArgSizeOffs = -oursp;
866 CheckLocalOffs (ArgSizeOffs);
868 /* Get the size of all parameters. */
869 if (ArgSizeOffs == 0 && CPU == CPU_65C02) {
870 AddCodeLine ("lda (sp)");
872 ldyconst (ArgSizeOffs);
873 AddCodeLine ("lda (sp),y");
876 /* Add the value of the stackpointer */
877 if (CodeSizeFactor > 250) {
878 unsigned L = GetLocalLabel();
879 AddCodeLine ("ldx sp+1");
881 AddCodeLine ("adc sp");
882 AddCodeLine ("bcc %s", LocalLabelName (L));
886 AddCodeLine ("jsr leaasp");
889 /* Add the offset to the primary */
891 g_inc (CF_INT | CF_CONST, Offs);
892 } else if (Offs < 0) {
893 g_dec (CF_INT | CF_CONST, -Offs);
899 /*****************************************************************************/
900 /* Store into memory */
901 /*****************************************************************************/
905 void g_putstatic (unsigned flags, unsigned long label, unsigned offs)
906 /* Store the primary register into the specified static memory cell */
908 /* Create the correct label name */
909 char* lbuf = GetLabelName (flags, label, offs);
911 /* Check the size and generate the correct store operation */
912 switch (flags & CF_TYPE) {
915 AddCodeLine ("sta %s", lbuf);
919 AddCodeLine ("sta %s", lbuf);
920 AddCodeLine ("stx %s+1", lbuf);
924 AddCodeLine ("sta %s", lbuf);
925 AddCodeLine ("stx %s+1", lbuf);
926 AddCodeLine ("ldy sreg");
927 AddCodeLine ("sty %s+2", lbuf);
928 AddCodeLine ("ldy sreg+1");
929 AddCodeLine ("sty %s+3", lbuf);
940 void g_putlocal (unsigned Flags, int Offs, long Val)
941 /* Put data into local object. */
944 CheckLocalOffs (Offs);
945 switch (Flags & CF_TYPE) {
948 if (Flags & CF_CONST) {
949 AddCodeLine ("lda #$%02X", (unsigned char) Val);
951 if (CPU == CPU_65C02 && Offs == 0) {
952 AddCodeLine ("sta (sp)");
955 AddCodeLine ("sta (sp),y");
960 if (Flags & CF_CONST) {
962 AddCodeLine ("lda #$%02X", (unsigned char) (Val >> 8));
963 AddCodeLine ("sta (sp),y");
964 if ((Flags & CF_NOKEEP) == 0) {
965 /* Place high byte into X */
968 if (CPU == CPU_65C02 && Offs == 0) {
969 AddCodeLine ("lda #$%02X", (unsigned char) Val);
970 AddCodeLine ("sta (sp)");
972 if ((Val & 0xFF) == Offs+1) {
973 /* The value we need is already in Y */
978 AddCodeLine ("lda #$%02X", (unsigned char) Val);
980 AddCodeLine ("sta (sp),y");
983 if ((Flags & CF_NOKEEP) == 0 || CodeSizeFactor < 160) {
986 AddCodeLine ("jsr staxysp");
988 AddCodeLine ("jsr stax0sp");
991 if (CPU == CPU_65C02 && Offs == 0) {
992 AddCodeLine ("sta (sp)");
995 AddCodeLine ("sta (sp),y");
998 AddCodeLine ("sta (sp),y");
1000 AddCodeLine ("txa");
1001 AddCodeLine ("sta (sp),y");
1008 if (Flags & CF_CONST) {
1009 g_getimmed (Flags, Val, 0);
1013 AddCodeLine ("jsr steaxysp");
1015 AddCodeLine ("jsr steax0sp");
1027 void g_putind (unsigned Flags, unsigned Offs)
1028 /* Store the specified object type in the primary register at the address
1029 * on the top of the stack
1032 /* We can handle offsets below $100 directly, larger offsets must be added
1033 * to the address. Since a/x is in use, best code is achieved by adding
1034 * just the high byte. Be sure to check if the low byte will overflow while
1037 if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
1039 /* Overflow - we need to add the low byte also */
1040 AddCodeLine ("ldy #$00");
1041 AddCodeLine ("clc");
1042 AddCodeLine ("pha");
1043 AddCodeLine ("lda #$%02X", Offs & 0xFF);
1044 AddCodeLine ("adc (sp),y");
1045 AddCodeLine ("sta (sp),y");
1046 AddCodeLine ("iny");
1047 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1048 AddCodeLine ("adc (sp),y");
1049 AddCodeLine ("sta (sp),y");
1050 AddCodeLine ("pla");
1052 /* Complete address is on stack, new offset is zero */
1055 } else if ((Offs & 0xFF00) != 0) {
1057 /* We can just add the high byte */
1058 AddCodeLine ("ldy #$01");
1059 AddCodeLine ("clc");
1060 AddCodeLine ("pha");
1061 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1062 AddCodeLine ("adc (sp),y");
1063 AddCodeLine ("sta (sp),y");
1064 AddCodeLine ("pla");
1066 /* Offset is now just the low byte */
1070 /* Check the size and determine operation */
1071 switch (Flags & CF_TYPE) {
1076 AddCodeLine ("jsr staspidx");
1078 AddCodeLine ("jsr staspp");
1085 AddCodeLine ("jsr staxspidx");
1087 AddCodeLine ("jsr staxspp");
1094 AddCodeLine ("jsr steaxspidx");
1096 AddCodeLine ("jsr steaxspp");
1105 /* Pop the argument which is always a pointer */
1111 /*****************************************************************************/
1112 /* type conversion and similiar stuff */
1113 /*****************************************************************************/
1117 void g_toslong (unsigned flags)
1118 /* Make sure, the value on TOS is a long. Convert if necessary */
1120 switch (flags & CF_TYPE) {
1124 if (flags & CF_UNSIGNED) {
1125 AddCodeLine ("jsr tosulong");
1127 AddCodeLine ("jsr toslong");
1142 void g_tosint (unsigned flags)
1143 /* Make sure, the value on TOS is an int. Convert if necessary */
1145 switch (flags & CF_TYPE) {
1152 AddCodeLine ("jsr tosint");
1163 void g_reglong (unsigned flags)
1164 /* Make sure, the value in the primary register a long. Convert if necessary */
1166 switch (flags & CF_TYPE) {
1170 if (flags & CF_UNSIGNED) {
1171 if (CodeSizeFactor >= 200) {
1173 AddCodeLine ("sty sreg");
1174 AddCodeLine ("sty sreg+1");
1176 AddCodeLine ("jsr axulong");
1179 AddCodeLine ("jsr axlong");
1193 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1194 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1195 * value, that corresponds to the value on TOS, rhs corresponds to the value
1196 * in (e)ax. The return value is the the flags value for the resulting type.
1199 unsigned ltype, rtype;
1202 /* Get the type spec from the flags */
1203 ltype = lhs & CF_TYPE;
1204 rtype = rhs & CF_TYPE;
1206 /* Check if a conversion is needed */
1207 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1208 /* We must promote the primary register to long */
1210 /* Get the new rhs type */
1211 rhs = (rhs & ~CF_TYPE) | CF_LONG;
1213 } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1214 /* We must promote the lhs to long */
1220 /* Get the new rhs type */
1221 lhs = (lhs & ~CF_TYPE) | CF_LONG;
1225 /* Determine the result type for the operation:
1226 * - The result is const if both operands are const.
1227 * - The result is unsigned if one of the operands is unsigned.
1228 * - The result is long if one of the operands is long.
1229 * - Otherwise the result is int sized.
1231 result = (lhs & CF_CONST) & (rhs & CF_CONST);
1232 result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1233 if (rtype == CF_LONG || ltype == CF_LONG) {
1243 unsigned g_typecast (unsigned lhs, unsigned rhs)
1244 /* Cast the value in the primary register to the operand size that is flagged
1245 * by the lhs value. Return the result value.
1248 unsigned ltype, rtype;
1250 /* Get the type spec from the flags */
1251 ltype = lhs & CF_TYPE;
1252 rtype = rhs & CF_TYPE;
1254 /* Check if a conversion is needed */
1255 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1256 /* We must promote the primary register to long */
1260 /* Do not need any other action. If the left type is int, and the primary
1261 * register is long, it will be automagically truncated. If the right hand
1262 * side is const, it is not located in the primary register and handled by
1263 * the expression parser code.
1266 /* Result is const if the right hand side was const */
1267 lhs |= (rhs & CF_CONST);
1269 /* The resulting type is that of the left hand side (that's why you called
1277 void g_scale (unsigned flags, long val)
1278 /* Scale the value in the primary register by the given value. If val is positive,
1279 * scale up, is val is negative, scale down. This function is used to scale
1280 * the operands or results of pointer arithmetic by the size of the type, the
1281 * pointer points to.
1286 /* Value may not be zero */
1288 Internal ("Data type has no size");
1289 } else if (val > 0) {
1292 if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1294 /* Factor is 2, 4 or 8, use special function */
1295 switch (flags & CF_TYPE) {
1298 if (flags & CF_FORCECHAR) {
1300 AddCodeLine ("asl a");
1307 if (CodeSizeFactor >= (p2+1)*130U) {
1308 AddCodeLine ("stx tmp1");
1310 AddCodeLine ("asl a");
1311 AddCodeLine ("rol tmp1");
1313 AddCodeLine ("ldx tmp1");
1315 if (flags & CF_UNSIGNED) {
1316 AddCodeLine ("jsr shlax%d", p2);
1318 AddCodeLine ("jsr aslax%d", p2);
1324 if (flags & CF_UNSIGNED) {
1325 AddCodeLine ("jsr shleax%d", p2);
1327 AddCodeLine ("jsr asleax%d", p2);
1336 } else if (val != 1) {
1338 /* Use a multiplication instead */
1339 g_mul (flags | CF_CONST, val);
1347 if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1349 /* Factor is 2, 4 or 8, use special function */
1350 switch (flags & CF_TYPE) {
1353 if (flags & CF_FORCECHAR) {
1354 if (flags & CF_UNSIGNED) {
1356 AddCodeLine ("lsr a");
1359 } else if (p2 <= 2) {
1360 AddCodeLine ("cmp #$80");
1361 AddCodeLine ("ror a");
1368 if (flags & CF_UNSIGNED) {
1369 if (CodeSizeFactor >= (p2+1)*130U) {
1370 AddCodeLine ("stx tmp1");
1372 AddCodeLine ("lsr tmp1");
1373 AddCodeLine ("ror a");
1375 AddCodeLine ("ldx tmp1");
1377 AddCodeLine ("jsr lsrax%d", p2);
1380 if (CodeSizeFactor >= (p2+1)*150U) {
1381 AddCodeLine ("stx tmp1");
1383 AddCodeLine ("cpx #$80");
1384 AddCodeLine ("ror tmp1");
1385 AddCodeLine ("ror a");
1387 AddCodeLine ("ldx tmp1");
1389 AddCodeLine ("jsr asrax%d", p2);
1395 if (flags & CF_UNSIGNED) {
1396 AddCodeLine ("jsr lsreax%d", p2);
1398 AddCodeLine ("jsr asreax%d", p2);
1407 } else if (val != 1) {
1409 /* Use a division instead */
1410 g_div (flags | CF_CONST, val);
1418 /*****************************************************************************/
1419 /* Adds and subs of variables fix a fixed address */
1420 /*****************************************************************************/
1424 void g_addlocal (unsigned flags, int offs)
1425 /* Add a local variable to ax */
1429 /* Correct the offset and check it */
1431 CheckLocalOffs (offs);
1433 switch (flags & CF_TYPE) {
1436 L = GetLocalLabel();
1437 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1438 AddCodeLine ("clc");
1439 AddCodeLine ("adc (sp),y");
1440 AddCodeLine ("bcc %s", LocalLabelName (L));
1441 AddCodeLine ("inx");
1446 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1447 AddCodeLine ("clc");
1448 AddCodeLine ("adc (sp),y");
1449 AddCodeLine ("pha");
1450 AddCodeLine ("txa");
1451 AddCodeLine ("iny");
1452 AddCodeLine ("adc (sp),y");
1453 AddCodeLine ("tax");
1454 AddCodeLine ("pla");
1458 /* Do it the old way */
1460 g_getlocal (flags, offs);
1472 void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
1473 /* Add a static variable to ax */
1477 /* Create the correct label name */
1478 char* lbuf = GetLabelName (flags, label, offs);
1480 switch (flags & CF_TYPE) {
1483 L = GetLocalLabel();
1484 AddCodeLine ("clc");
1485 AddCodeLine ("adc %s", lbuf);
1486 AddCodeLine ("bcc %s", LocalLabelName (L));
1487 AddCodeLine ("inx");
1492 AddCodeLine ("clc");
1493 AddCodeLine ("adc %s", lbuf);
1494 AddCodeLine ("tay");
1495 AddCodeLine ("txa");
1496 AddCodeLine ("adc %s+1", lbuf);
1497 AddCodeLine ("tax");
1498 AddCodeLine ("tya");
1502 /* Do it the old way */
1504 g_getstatic (flags, label, offs);
1516 /*****************************************************************************/
1517 /* Compares of ax with a variable with fixed address */
1518 /*****************************************************************************/
1522 void g_cmplocal (unsigned flags, int offs)
1523 /* Compare a local variable to ax */
1525 Internal ("g_cmplocal not implemented");
1530 void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
1531 /* Compare a static variable to ax */
1533 Internal ("g_cmpstatic not implemented");
1538 /*****************************************************************************/
1539 /* Special op= functions */
1540 /*****************************************************************************/
1544 void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
1546 /* Emit += for a static variable */
1548 /* Create the correct label name */
1549 char* lbuf = GetLabelName (flags, label, offs);
1551 /* Check the size and determine operation */
1552 switch (flags & CF_TYPE) {
1555 if (flags & CF_FORCECHAR) {
1556 AddCodeLine ("ldx #$00");
1557 if (flags & CF_CONST) {
1559 AddCodeLine ("inc %s", lbuf);
1560 AddCodeLine ("lda %s", lbuf);
1562 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1563 AddCodeLine ("clc");
1564 AddCodeLine ("adc %s", lbuf);
1565 AddCodeLine ("sta %s", lbuf);
1568 AddCodeLine ("clc");
1569 AddCodeLine ("adc %s", lbuf);
1570 AddCodeLine ("sta %s", lbuf);
1572 if ((flags & CF_UNSIGNED) == 0) {
1573 unsigned L = GetLocalLabel();
1574 AddCodeLine ("bpl %s", LocalLabelName (L));
1575 AddCodeLine ("dex");
1583 if (flags & CF_CONST) {
1585 unsigned L = GetLocalLabel ();
1586 AddCodeLine ("inc %s", lbuf);
1587 AddCodeLine ("bne %s", LocalLabelName (L));
1588 AddCodeLine ("inc %s+1", lbuf);
1590 AddCodeLine ("lda %s", lbuf); /* Hmmm... */
1591 AddCodeLine ("ldx %s+1", lbuf);
1593 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1594 AddCodeLine ("clc");
1595 AddCodeLine ("adc %s", lbuf);
1596 AddCodeLine ("sta %s", lbuf);
1598 unsigned L = GetLocalLabel ();
1599 AddCodeLine ("bcc %s", LocalLabelName (L));
1600 AddCodeLine ("inc %s+1", lbuf);
1602 AddCodeLine ("ldx %s+1", lbuf);
1604 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1605 AddCodeLine ("adc %s+1", lbuf);
1606 AddCodeLine ("sta %s+1", lbuf);
1607 AddCodeLine ("tax");
1608 AddCodeLine ("lda %s", lbuf);
1612 AddCodeLine ("clc");
1613 AddCodeLine ("adc %s", lbuf);
1614 AddCodeLine ("sta %s", lbuf);
1615 AddCodeLine ("txa");
1616 AddCodeLine ("adc %s+1", lbuf);
1617 AddCodeLine ("sta %s+1", lbuf);
1618 AddCodeLine ("tax");
1619 AddCodeLine ("lda %s", lbuf);
1624 if (flags & CF_CONST) {
1626 AddCodeLine ("ldy #<(%s)", lbuf);
1627 AddCodeLine ("sty ptr1");
1628 AddCodeLine ("ldy #>(%s+1)", lbuf);
1630 AddCodeLine ("jsr laddeq1");
1632 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1633 AddCodeLine ("jsr laddeqa");
1636 g_getstatic (flags, label, offs);
1638 g_putstatic (flags, label, offs);
1641 AddCodeLine ("ldy #<(%s)", lbuf);
1642 AddCodeLine ("sty ptr1");
1643 AddCodeLine ("ldy #>(%s+1)", lbuf);
1644 AddCodeLine ("jsr laddeq");
1655 void g_addeqlocal (unsigned flags, int offs, unsigned long val)
1656 /* Emit += for a local variable */
1658 /* Calculate the true offset, check it, load it into Y */
1660 CheckLocalOffs (offs);
1662 /* Check the size and determine operation */
1663 switch (flags & CF_TYPE) {
1666 if (flags & CF_FORCECHAR) {
1668 AddCodeLine ("ldx #$00");
1669 if (flags & CF_CONST) {
1670 AddCodeLine ("clc");
1671 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1672 AddCodeLine ("adc (sp,x)");
1673 AddCodeLine ("sta (sp,x)");
1675 AddCodeLine ("clc");
1676 AddCodeLine ("adc (sp,x)");
1677 AddCodeLine ("sta (sp,x)");
1681 AddCodeLine ("ldx #$00");
1682 if (flags & CF_CONST) {
1683 AddCodeLine ("clc");
1684 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1685 AddCodeLine ("adc (sp),y");
1686 AddCodeLine ("sta (sp),y");
1688 AddCodeLine ("clc");
1689 AddCodeLine ("adc (sp),y");
1690 AddCodeLine ("sta (sp),y");
1693 if ((flags & CF_UNSIGNED) == 0) {
1694 unsigned L = GetLocalLabel();
1695 AddCodeLine ("bpl %s", LocalLabelName (L));
1696 AddCodeLine ("dex");
1704 if (flags & CF_CONST) {
1705 g_getimmed (flags, val, 0);
1708 AddCodeLine ("jsr addeq0sp");
1711 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");
1750 AddCodeLine ("ldx #$00");
1751 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1752 AddCodeLine ("clc");
1753 AddCodeLine ("adc (ptr1,x)");
1754 AddCodeLine ("sta (ptr1,x)");
1756 AddCodeLine ("ldy #$%02X", offs);
1757 AddCodeLine ("ldx #$00");
1758 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1759 AddCodeLine ("clc");
1760 AddCodeLine ("adc (ptr1),y");
1761 AddCodeLine ("sta (ptr1),y");
1766 if (CodeSizeFactor >= 200) {
1767 /* Lots of code, use only if size is not important */
1768 AddCodeLine ("sta ptr1");
1769 AddCodeLine ("stx ptr1+1");
1770 AddCodeLine ("ldy #$%02X", offs);
1771 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1772 AddCodeLine ("clc");
1773 AddCodeLine ("adc (ptr1),y");
1774 AddCodeLine ("sta (ptr1),y");
1775 AddCodeLine ("pha");
1776 AddCodeLine ("iny");
1777 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1778 AddCodeLine ("adc (ptr1),y");
1779 AddCodeLine ("sta (ptr1),y");
1780 AddCodeLine ("tax");
1781 AddCodeLine ("pla");
1787 AddCodeLine ("jsr pushax"); /* Push the address */
1788 push (flags); /* Correct the internal sp */
1789 g_getind (flags, offs); /* Fetch the value */
1790 g_inc (flags, val); /* Increment value in primary */
1791 g_putind (flags, offs); /* Store the value back */
1801 void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
1803 /* Emit -= for a static variable */
1805 /* Create the correct label name */
1806 char* lbuf = GetLabelName (flags, label, offs);
1808 /* Check the size and determine operation */
1809 switch (flags & CF_TYPE) {
1812 if (flags & CF_FORCECHAR) {
1813 AddCodeLine ("ldx #$00");
1814 if (flags & CF_CONST) {
1816 AddCodeLine ("dec %s", lbuf);
1817 AddCodeLine ("lda %s", lbuf);
1819 AddCodeLine ("sec");
1820 AddCodeLine ("lda %s", lbuf);
1821 AddCodeLine ("sbc #$%02X", (int)(val & 0xFF));
1822 AddCodeLine ("sta %s", lbuf);
1825 AddCodeLine ("sec");
1826 AddCodeLine ("sta tmp1");
1827 AddCodeLine ("lda %s", lbuf);
1828 AddCodeLine ("sbc tmp1");
1829 AddCodeLine ("sta %s", lbuf);
1831 if ((flags & CF_UNSIGNED) == 0) {
1832 unsigned L = GetLocalLabel();
1833 AddCodeLine ("bpl %s", LocalLabelName (L));
1834 AddCodeLine ("dex");
1842 AddCodeLine ("sec");
1843 if (flags & CF_CONST) {
1844 AddCodeLine ("lda %s", lbuf);
1845 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1846 AddCodeLine ("sta %s", lbuf);
1848 unsigned L = GetLocalLabel ();
1849 AddCodeLine ("bcs %s", LocalLabelName (L));
1850 AddCodeLine ("dec %s+1", lbuf);
1852 AddCodeLine ("ldx %s+1", lbuf);
1854 AddCodeLine ("lda %s+1", lbuf);
1855 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1856 AddCodeLine ("sta %s+1", lbuf);
1857 AddCodeLine ("tax");
1858 AddCodeLine ("lda %s", lbuf);
1861 AddCodeLine ("sta tmp1");
1862 AddCodeLine ("lda %s", lbuf);
1863 AddCodeLine ("sbc tmp1");
1864 AddCodeLine ("sta %s", lbuf);
1865 AddCodeLine ("stx tmp1");
1866 AddCodeLine ("lda %s+1", lbuf);
1867 AddCodeLine ("sbc tmp1");
1868 AddCodeLine ("sta %s+1", lbuf);
1869 AddCodeLine ("tax");
1870 AddCodeLine ("lda %s", lbuf);
1875 if (flags & CF_CONST) {
1877 AddCodeLine ("ldy #<(%s)", lbuf);
1878 AddCodeLine ("sty ptr1");
1879 AddCodeLine ("ldy #>(%s+1)", lbuf);
1881 AddCodeLine ("jsr lsubeq1");
1883 AddCodeLine ("lda #$%02X", (unsigned char)val);
1884 AddCodeLine ("jsr lsubeqa");
1887 g_getstatic (flags, label, offs);
1889 g_putstatic (flags, label, offs);
1892 AddCodeLine ("ldy #<(%s)", lbuf);
1893 AddCodeLine ("sty ptr1");
1894 AddCodeLine ("ldy #>(%s+1)", lbuf);
1895 AddCodeLine ("jsr lsubeq");
1906 void g_subeqlocal (unsigned flags, int offs, unsigned long val)
1907 /* Emit -= for a local variable */
1909 /* Calculate the true offset, check it, load it into Y */
1911 CheckLocalOffs (offs);
1913 /* Check the size and determine operation */
1914 switch (flags & CF_TYPE) {
1917 if (flags & CF_FORCECHAR) {
1919 AddCodeLine ("ldx #$00");
1920 AddCodeLine ("sec");
1921 if (flags & CF_CONST) {
1922 AddCodeLine ("lda (sp),y");
1923 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1925 AddCodeLine ("sta tmp1");
1926 AddCodeLine ("lda (sp),y");
1927 AddCodeLine ("sbc tmp1");
1929 AddCodeLine ("sta (sp),y");
1930 if ((flags & CF_UNSIGNED) == 0) {
1931 unsigned L = GetLocalLabel();
1932 AddCodeLine ("bpl %s", LocalLabelName (L));
1933 AddCodeLine ("dex");
1941 if (flags & CF_CONST) {
1942 g_getimmed (flags, val, 0);
1945 AddCodeLine ("jsr subeq0sp");
1948 AddCodeLine ("jsr subeqysp");
1953 if (flags & CF_CONST) {
1954 g_getimmed (flags, val, 0);
1957 AddCodeLine ("jsr lsubeq0sp");
1960 AddCodeLine ("jsr lsubeqysp");
1971 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
1972 /* Emit -= for the location with address in ax */
1974 /* If the offset is too large for a byte register, add the high byte
1975 * of the offset to the primary. Beware: We need a special correction
1976 * if the offset in the low byte will overflow in the operation.
1978 offs = MakeByteOffs (flags, offs);
1980 /* Check the size and determine operation */
1981 switch (flags & CF_TYPE) {
1984 AddCodeLine ("sta ptr1");
1985 AddCodeLine ("stx ptr1+1");
1987 AddCodeLine ("ldx #$00");
1988 AddCodeLine ("lda (ptr1,x)");
1989 AddCodeLine ("sec");
1990 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1991 AddCodeLine ("sta (ptr1,x)");
1993 AddCodeLine ("ldy #$%02X", offs);
1994 AddCodeLine ("ldx #$00");
1995 AddCodeLine ("lda (ptr1),y");
1996 AddCodeLine ("sec");
1997 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1998 AddCodeLine ("sta (ptr1),y");
2003 if (CodeSizeFactor >= 200) {
2004 /* Lots of code, use only if size is not important */
2005 AddCodeLine ("sta ptr1");
2006 AddCodeLine ("stx ptr1+1");
2007 AddCodeLine ("ldy #$%02X", offs);
2008 AddCodeLine ("lda (ptr1),y");
2009 AddCodeLine ("sec");
2010 AddCodeLine ("sbc #$%02X", (unsigned char)val);
2011 AddCodeLine ("sta (ptr1),y");
2012 AddCodeLine ("pha");
2013 AddCodeLine ("iny");
2014 AddCodeLine ("lda (ptr1),y");
2015 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
2016 AddCodeLine ("sta (ptr1),y");
2017 AddCodeLine ("tax");
2018 AddCodeLine ("pla");
2024 AddCodeLine ("jsr pushax"); /* Push the address */
2025 push (flags); /* Correct the internal sp */
2026 g_getind (flags, offs); /* Fetch the value */
2027 g_dec (flags, val); /* Increment value in primary */
2028 g_putind (flags, offs); /* Store the value back */
2038 /*****************************************************************************/
2039 /* Add a variable address to the value in ax */
2040 /*****************************************************************************/
2044 void g_addaddr_local (unsigned flags, int offs)
2045 /* Add the address of a local variable to ax */
2049 /* Add the offset */
2052 /* We cannot address more then 256 bytes of locals anyway */
2053 L = GetLocalLabel();
2054 CheckLocalOffs (offs);
2055 AddCodeLine ("clc");
2056 AddCodeLine ("adc #$%02X", offs & 0xFF);
2057 /* Do also skip the CLC insn below */
2058 AddCodeLine ("bcc %s", LocalLabelName (L));
2059 AddCodeLine ("inx");
2062 /* Add the current stackpointer value */
2063 AddCodeLine ("clc");
2065 /* Label was used above */
2068 AddCodeLine ("adc sp");
2069 AddCodeLine ("tay");
2070 AddCodeLine ("txa");
2071 AddCodeLine ("adc sp+1");
2072 AddCodeLine ("tax");
2073 AddCodeLine ("tya");
2078 void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
2079 /* Add the address of a static variable to ax */
2081 /* Create the correct label name */
2082 char* lbuf = GetLabelName (flags, label, offs);
2084 /* Add the address to the current ax value */
2085 AddCodeLine ("clc");
2086 AddCodeLine ("adc #<(%s)", lbuf);
2087 AddCodeLine ("tay");
2088 AddCodeLine ("txa");
2089 AddCodeLine ("adc #>(%s)", lbuf);
2090 AddCodeLine ("tax");
2091 AddCodeLine ("tya");
2096 /*****************************************************************************/
2098 /*****************************************************************************/
2102 void g_save (unsigned flags)
2103 /* Copy primary register to hold register. */
2105 /* Check the size and determine operation */
2106 switch (flags & CF_TYPE) {
2109 if (flags & CF_FORCECHAR) {
2110 AddCodeLine ("pha");
2116 AddCodeLine ("sta regsave");
2117 AddCodeLine ("stx regsave+1");
2121 AddCodeLine ("jsr saveeax");
2131 void g_restore (unsigned flags)
2132 /* Copy hold register to primary. */
2134 /* Check the size and determine operation */
2135 switch (flags & CF_TYPE) {
2138 if (flags & CF_FORCECHAR) {
2139 AddCodeLine ("pla");
2145 AddCodeLine ("lda regsave");
2146 AddCodeLine ("ldx regsave+1");
2150 AddCodeLine ("jsr resteax");
2160 void g_cmp (unsigned flags, unsigned long val)
2161 /* Immidiate compare. The primary register will not be changed, Z flag
2167 /* Check the size and determine operation */
2168 switch (flags & CF_TYPE) {
2171 if (flags & CF_FORCECHAR) {
2172 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2178 L = GetLocalLabel();
2179 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2180 AddCodeLine ("bne %s", LocalLabelName (L));
2181 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
2186 Internal ("g_cmp: Long compares not implemented");
2196 static void oper (unsigned flags, unsigned long val, char** subs)
2197 /* Encode a binary operation. subs is a pointer to four groups of three
2199 * 0-2 --> Operate on ints
2200 * 3-5 --> Operate on unsigneds
2201 * 6-8 --> Operate on longs
2202 * 9-11 --> Operate on unsigned longs
2204 * The first subroutine names in each string group is used to encode an
2205 * operation with a zero constant, the second to encode an operation with
2206 * a 8 bit constant, and the third is used in all other cases.
2211 /* Determine the offset into the array */
2212 offs = (flags & CF_UNSIGNED)? 3 : 0;
2213 switch (flags & CF_TYPE) {
2226 /* Encode the operation */
2227 if (flags & CF_CONST) {
2228 /* Constant value given */
2229 if (val == 0 && subs [offs+0]) {
2230 /* Special case: constant with value zero */
2231 AddCodeLine ("jsr %s", subs [offs+0]);
2232 } else if (val < 0x100 && subs [offs+1]) {
2233 /* Special case: constant with high byte zero */
2234 ldaconst (val); /* Load low byte */
2235 AddCodeLine ("jsr %s", subs [offs+1]);
2237 /* Others: arbitrary constant value */
2238 g_getimmed (flags, val, 0); /* Load value */
2239 AddCodeLine ("jsr %s", subs [offs+2]);
2242 /* Value not constant (is already in (e)ax) */
2243 AddCodeLine ("jsr %s", subs [offs+2]);
2246 /* The operation will pop it's argument */
2252 void g_test (unsigned flags)
2253 /* Test the value in the primary and set the condition codes */
2255 switch (flags & CF_TYPE) {
2258 if (flags & CF_FORCECHAR) {
2259 AddCodeLine ("tax");
2265 AddCodeLine ("stx tmp1");
2266 AddCodeLine ("ora tmp1");
2270 if (flags & CF_UNSIGNED) {
2271 AddCodeLine ("jsr utsteax");
2273 AddCodeLine ("jsr tsteax");
2285 void g_push (unsigned flags, unsigned long val)
2286 /* Push the primary register or a constant value onto the stack */
2290 if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2292 /* We have a constant 8 or 16 bit value */
2293 if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2295 /* Handle as 8 bit value */
2296 if (CodeSizeFactor >= 165 || val > 2) {
2298 AddCodeLine ("jsr pusha");
2300 AddCodeLine ("jsr pushc%d", (int) val);
2305 /* Handle as 16 bit value */
2306 hi = (unsigned char) (val >> 8);
2308 AddCodeLine ("jsr push%u", (unsigned) val);
2309 } else if (hi == 0 || hi == 0xFF) {
2310 /* Use special function */
2312 AddCodeLine ("jsr %s", (hi == 0)? "pusha0" : "pushaFF");
2315 g_getimmed (flags, val, 0);
2316 AddCodeLine ("jsr pushax");
2322 /* Value is not 16 bit or not constant */
2323 if (flags & CF_CONST) {
2324 /* Constant 32 bit value, load into eax */
2325 g_getimmed (flags, val, 0);
2328 /* Push the primary register */
2329 switch (flags & CF_TYPE) {
2332 if (flags & CF_FORCECHAR) {
2333 /* Handle as char */
2334 AddCodeLine ("jsr pusha");
2339 AddCodeLine ("jsr pushax");
2343 AddCodeLine ("jsr pusheax");
2353 /* Adjust the stack offset */
2359 void g_swap (unsigned flags)
2360 /* Swap the primary register and the top of the stack. flags give the type
2361 * of *both* values (must have same size).
2364 switch (flags & CF_TYPE) {
2368 AddCodeLine ("jsr swapstk");
2372 AddCodeLine ("jsr swapestk");
2383 void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2384 /* Call the specified subroutine name */
2386 if ((Flags & CF_FIXARGC) == 0) {
2387 /* Pass the argument count */
2390 AddCodeLine ("jsr _%s", Label);
2391 oursp += ArgSize; /* callee pops args */
2396 void g_callind (unsigned Flags, unsigned ArgSize)
2397 /* Call subroutine with address in AX */
2399 if ((Flags & CF_FIXARGC) == 0) {
2400 /* Pass arg count */
2403 AddCodeLine ("jsr callax"); /* do the call */
2404 oursp += ArgSize; /* callee pops args */
2409 void g_jump (unsigned Label)
2410 /* Jump to specified internal label number */
2412 AddCodeLine ("jmp %s", LocalLabelName (Label));
2417 void g_switch (unsigned Flags)
2418 /* Output switch statement preamble */
2420 switch (Flags & CF_TYPE) {
2424 AddCodeLine ("jsr switch");
2428 AddCodeLine ("jsr lswitch");
2439 void g_case (unsigned flags, unsigned label, unsigned long val)
2440 /* Create table code for one case selector */
2442 switch (flags & CF_TYPE) {
2446 AddCodeLine (".word $%04X, %s",
2447 (unsigned)(val & 0xFFFF),
2448 LocalLabelName (label));
2452 AddCodeLine (".dword $%08lX", val);
2453 AddCodeLine (".word %s", LocalLabelName (label));
2464 void g_truejump (unsigned flags, unsigned label)
2465 /* Jump to label if zero flag clear */
2467 AddCodeLine ("jne %s", LocalLabelName (label));
2472 void g_falsejump (unsigned flags, unsigned label)
2473 /* Jump to label if zero flag set */
2475 AddCodeLine ("jeq %s", LocalLabelName (label));
2480 static void mod_internal (int k, char* verb1, char* verb2)
2483 AddCodeLine ("jsr %ssp%c", verb1, k + '0');
2487 AddCodeLine ("jsr %ssp", verb2);
2493 void g_space (int space)
2494 /* Create or drop space on the stack */
2497 mod_internal (-space, "inc", "addy");
2498 } else if (space > 0) {
2499 mod_internal (space, "dec", "suby");
2505 void g_cstackcheck (void)
2506 /* Check for a C stack overflow */
2508 AddCodeLine ("jsr cstkchk");
2513 void g_stackcheck (void)
2514 /* Check for a stack overflow */
2516 AddCodeLine ("jsr stkchk");
2521 void g_add (unsigned flags, unsigned long val)
2522 /* Primary = TOS + Primary */
2524 static char* ops [12] = {
2525 0, "tosadda0", "tosaddax",
2526 0, "tosadda0", "tosaddax",
2531 if (flags & CF_CONST) {
2532 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2533 g_push (flags & ~CF_CONST, 0);
2535 oper (flags, val, ops);
2540 void g_sub (unsigned flags, unsigned long val)
2541 /* Primary = TOS - Primary */
2543 static char* ops [12] = {
2544 0, "tossuba0", "tossubax",
2545 0, "tossuba0", "tossubax",
2550 if (flags & CF_CONST) {
2551 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2552 g_push (flags & ~CF_CONST, 0);
2554 oper (flags, val, ops);
2559 void g_rsub (unsigned flags, unsigned long val)
2560 /* Primary = Primary - TOS */
2562 static char* ops [12] = {
2563 0, "tosrsuba0", "tosrsubax",
2564 0, "tosrsuba0", "tosrsubax",
2568 oper (flags, val, ops);
2573 void g_mul (unsigned flags, unsigned long val)
2574 /* Primary = TOS * Primary */
2576 static char* ops [12] = {
2577 0, "tosmula0", "tosmulax",
2578 0, "tosumula0", "tosumulax",
2585 /* Do strength reduction if the value is constant and a power of two */
2586 if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2587 /* Generate a shift instead */
2592 /* If the right hand side is const, the lhs is not on stack but still
2593 * in the primary register.
2595 if (flags & CF_CONST) {
2597 switch (flags & CF_TYPE) {
2600 if (flags & CF_FORCECHAR) {
2601 /* Handle some special cases */
2605 AddCodeLine ("sta tmp1");
2606 AddCodeLine ("asl a");
2607 AddCodeLine ("clc");
2608 AddCodeLine ("adc tmp1");
2612 AddCodeLine ("sta tmp1");
2613 AddCodeLine ("asl a");
2614 AddCodeLine ("asl a");
2615 AddCodeLine ("clc");
2616 AddCodeLine ("adc tmp1");
2620 AddCodeLine ("sta tmp1");
2621 AddCodeLine ("asl a");
2622 AddCodeLine ("asl a");
2623 AddCodeLine ("clc");
2624 AddCodeLine ("adc tmp1");
2625 AddCodeLine ("asl a");
2641 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2642 * into the normal, non-optimized stuff.
2644 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2645 g_push (flags & ~CF_CONST, 0);
2649 /* Use long way over the stack */
2650 oper (flags, val, ops);
2655 void g_div (unsigned flags, unsigned long val)
2656 /* Primary = TOS / Primary */
2658 static char* ops [12] = {
2659 0, "tosdiva0", "tosdivax",
2660 0, "tosudiva0", "tosudivax",
2665 /* Do strength reduction if the value is constant and a power of two */
2667 if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2668 /* Generate a shift instead */
2671 /* Generate a division */
2672 if (flags & CF_CONST) {
2673 /* lhs is not on stack */
2674 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2675 g_push (flags & ~CF_CONST, 0);
2677 oper (flags, val, ops);
2683 void g_mod (unsigned flags, unsigned long val)
2684 /* Primary = TOS % Primary */
2686 static char* ops [12] = {
2687 0, "tosmoda0", "tosmodax",
2688 0, "tosumoda0", "tosumodax",
2694 /* Check if we can do some cost reduction */
2695 if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2696 /* We can do that with an AND operation */
2697 g_and (flags, val - 1);
2699 /* Do it the hard way... */
2700 if (flags & CF_CONST) {
2701 /* lhs is not on stack */
2702 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2703 g_push (flags & ~CF_CONST, 0);
2705 oper (flags, val, ops);
2711 void g_or (unsigned flags, unsigned long val)
2712 /* Primary = TOS | Primary */
2714 static char* ops [12] = {
2715 0, "tosora0", "tosorax",
2716 0, "tosora0", "tosorax",
2721 /* If the right hand side is const, the lhs is not on stack but still
2722 * in the primary register.
2724 if (flags & CF_CONST) {
2726 switch (flags & CF_TYPE) {
2729 if (flags & CF_FORCECHAR) {
2730 if ((val & 0xFF) != 0xFF) {
2731 AddCodeLine ("ora #$%02X", (unsigned char)val);
2739 AddCodeLine ("ora #$%02X", (unsigned char)val);
2746 AddCodeLine ("ora #$%02X", (unsigned char)val);
2755 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2756 * into the normal, non-optimized stuff.
2758 g_push (flags & ~CF_CONST, 0);
2762 /* Use long way over the stack */
2763 oper (flags, val, ops);
2768 void g_xor (unsigned flags, unsigned long val)
2769 /* Primary = TOS ^ Primary */
2771 static char* ops [12] = {
2772 0, "tosxora0", "tosxorax",
2773 0, "tosxora0", "tosxorax",
2779 /* If the right hand side is const, the lhs is not on stack but still
2780 * in the primary register.
2782 if (flags & CF_CONST) {
2784 switch (flags & CF_TYPE) {
2787 if (flags & CF_FORCECHAR) {
2788 if ((val & 0xFF) != 0) {
2789 AddCodeLine ("eor #$%02X", (unsigned char)val);
2798 AddCodeLine ("eor #$%02X", (unsigned char)val);
2801 } else if ((val & 0xFF) == 0) {
2802 AddCodeLine ("pha");
2803 AddCodeLine ("txa");
2804 AddCodeLine ("eor #$%02X", (unsigned char)(val >> 8));
2805 AddCodeLine ("tax");
2806 AddCodeLine ("pla");
2814 AddCodeLine ("eor #$%02X", (unsigned char)val);
2824 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2825 * into the normal, non-optimized stuff.
2827 g_push (flags & ~CF_CONST, 0);
2831 /* Use long way over the stack */
2832 oper (flags, val, ops);
2837 void g_and (unsigned flags, unsigned long val)
2838 /* Primary = TOS & Primary */
2840 static char* ops [12] = {
2841 0, "tosanda0", "tosandax",
2842 0, "tosanda0", "tosandax",
2847 /* If the right hand side is const, the lhs is not on stack but still
2848 * in the primary register.
2850 if (flags & CF_CONST) {
2852 switch (flags & CF_TYPE) {
2855 if (flags & CF_FORCECHAR) {
2856 AddCodeLine ("and #$%02X", (unsigned char)val);
2861 if ((val & 0xFFFF) != 0xFFFF) {
2866 } else if (val != 0xFF) {
2867 AddCodeLine ("and #$%02X", (unsigned char)val);
2869 } else if ((val & 0xFF00) == 0xFF00) {
2870 AddCodeLine ("and #$%02X", (unsigned char)val);
2871 } else if ((val & 0x00FF) == 0x0000) {
2872 AddCodeLine ("txa");
2873 AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2874 AddCodeLine ("tax");
2877 AddCodeLine ("tay");
2878 AddCodeLine ("txa");
2879 AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2880 AddCodeLine ("tax");
2881 AddCodeLine ("tya");
2882 if ((val & 0x00FF) != 0x00FF) {
2883 AddCodeLine ("and #$%02X", (unsigned char)val);
2892 AddCodeLine ("stx sreg+1");
2893 AddCodeLine ("stx sreg");
2894 if ((val & 0xFF) != 0xFF) {
2895 AddCodeLine ("and #$%02X", (unsigned char)val);
2898 } else if (val == 0xFF00) {
2900 AddCodeLine ("sta sreg+1");
2901 AddCodeLine ("sta sreg");
2910 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2911 * into the normal, non-optimized stuff.
2913 g_push (flags & ~CF_CONST, 0);
2917 /* Use long way over the stack */
2918 oper (flags, val, ops);
2923 void g_asr (unsigned flags, unsigned long val)
2924 /* Primary = TOS >> Primary */
2926 static char* ops [12] = {
2927 0, "tosasra0", "tosasrax",
2928 0, "tosshra0", "tosshrax",
2933 /* If the right hand side is const, the lhs is not on stack but still
2934 * in the primary register.
2936 if (flags & CF_CONST) {
2938 switch (flags & CF_TYPE) {
2942 if (val >= 1 && val <= 3) {
2943 if (flags & CF_UNSIGNED) {
2944 AddCodeLine ("jsr shrax%ld", val);
2946 AddCodeLine ("jsr asrax%ld", val);
2949 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2950 AddCodeLine ("txa");
2957 if (val >= 1 && val <= 3) {
2958 if (flags & CF_UNSIGNED) {
2959 AddCodeLine ("jsr shreax%ld", val);
2961 AddCodeLine ("jsr asreax%ld", val);
2964 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2965 AddCodeLine ("txa");
2966 AddCodeLine ("ldx sreg");
2967 AddCodeLine ("ldy sreg+1");
2968 AddCodeLine ("sty sreg");
2969 AddCodeLine ("ldy #$00");
2970 AddCodeLine ("sty sreg+1");
2972 } else if (val == 16) {
2973 AddCodeLine ("ldy #$00");
2974 AddCodeLine ("ldx sreg+1");
2975 if ((flags & CF_UNSIGNED) == 0) {
2976 unsigned L = GetLocalLabel();
2977 AddCodeLine ("bpl %s", LocalLabelName (L));
2978 AddCodeLine ("dey");
2981 AddCodeLine ("lda sreg");
2982 AddCodeLine ("sty sreg+1");
2983 AddCodeLine ("sty sreg");
2992 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2993 * into the normal, non-optimized stuff.
2995 g_push (flags & ~CF_CONST, 0);
2999 /* Use long way over the stack */
3000 oper (flags, val, ops);
3005 void g_asl (unsigned flags, unsigned long val)
3006 /* Primary = TOS << Primary */
3008 static char* ops [12] = {
3009 0, "tosasla0", "tosaslax",
3010 0, "tosshla0", "tosshlax",
3016 /* If the right hand side is const, the lhs is not on stack but still
3017 * in the primary register.
3019 if (flags & CF_CONST) {
3021 switch (flags & CF_TYPE) {
3025 if (val >= 1 && val <= 3) {
3026 if (flags & CF_UNSIGNED) {
3027 AddCodeLine ("jsr shlax%ld", val);
3029 AddCodeLine ("jsr aslax%ld", val);
3032 } else if (val == 8) {
3033 AddCodeLine ("tax");
3034 AddCodeLine ("lda #$00");
3040 if (val >= 1 && val <= 3) {
3041 if (flags & CF_UNSIGNED) {
3042 AddCodeLine ("jsr shleax%ld", val);
3044 AddCodeLine ("jsr asleax%ld", val);
3047 } else if (val == 8) {
3048 AddCodeLine ("ldy sreg");
3049 AddCodeLine ("sty sreg+1");
3050 AddCodeLine ("stx sreg");
3051 AddCodeLine ("tax");
3052 AddCodeLine ("lda #$00");
3054 } else if (val == 16) {
3055 AddCodeLine ("stx sreg+1");
3056 AddCodeLine ("sta sreg");
3057 AddCodeLine ("lda #$00");
3058 AddCodeLine ("tax");
3067 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3068 * into the normal, non-optimized stuff.
3070 g_push (flags & ~CF_CONST, 0);
3074 /* Use long way over the stack */
3075 oper (flags, val, ops);
3080 void g_neg (unsigned flags)
3081 /* Primary = -Primary */
3083 switch (flags & CF_TYPE) {
3087 AddCodeLine ("jsr negax");
3091 AddCodeLine ("jsr negeax");
3101 void g_bneg (unsigned flags)
3102 /* Primary = !Primary */
3104 switch (flags & CF_TYPE) {
3107 AddCodeLine ("jsr bnega");
3111 AddCodeLine ("jsr bnegax");
3115 AddCodeLine ("jsr bnegeax");
3125 void g_com (unsigned flags)
3126 /* Primary = ~Primary */
3128 switch (flags & CF_TYPE) {
3132 AddCodeLine ("jsr complax");
3136 AddCodeLine ("jsr compleax");
3146 void g_inc (unsigned flags, unsigned long val)
3147 /* Increment the primary register by a given number */
3149 /* Don't inc by zero */
3154 /* Generate code for the supported types */
3156 switch (flags & CF_TYPE) {
3159 if (flags & CF_FORCECHAR) {
3160 if (CPU == CPU_65C02 && val <= 2) {
3162 AddCodeLine ("ina");
3165 AddCodeLine ("clc");
3166 AddCodeLine ("adc #$%02X", (unsigned char)val);
3173 if (CPU == CPU_65C02 && val == 1) {
3174 unsigned L = GetLocalLabel();
3175 AddCodeLine ("ina");
3176 AddCodeLine ("bne %s", LocalLabelName (L));
3177 AddCodeLine ("inx");
3179 } else if (CodeSizeFactor < 200) {
3182 AddCodeLine ("jsr incax%lu", val);
3183 } else if (val <= 255) {
3185 AddCodeLine ("jsr incaxy");
3187 g_add (flags | CF_CONST, val);
3190 /* Inline the code */
3192 if ((val & 0xFF) != 0) {
3193 unsigned L = GetLocalLabel();
3194 AddCodeLine ("clc");
3195 AddCodeLine ("adc #$%02X", (unsigned char) val);
3196 AddCodeLine ("bcc %s", LocalLabelName (L));
3197 AddCodeLine ("inx");
3201 AddCodeLine ("inx");
3204 AddCodeLine ("inx");
3207 AddCodeLine ("clc");
3208 if ((val & 0xFF) != 0) {
3209 AddCodeLine ("adc #$%02X", (unsigned char) val);
3210 /* Tell the optimizer that the X register may be invalid */
3211 AddCodeHint ("x:!");
3213 AddCodeLine ("pha");
3214 AddCodeLine ("txa");
3215 AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3216 AddCodeLine ("tax");
3217 AddCodeLine ("pla");
3225 AddCodeLine ("jsr inceaxy");
3227 g_add (flags | CF_CONST, val);
3239 void g_dec (unsigned flags, unsigned long val)
3240 /* Decrement the primary register by a given number */
3242 /* Don't dec by zero */
3247 /* Generate code for the supported types */
3249 switch (flags & CF_TYPE) {
3252 if (flags & CF_FORCECHAR) {
3253 if (CPU == CPU_65C02 && val <= 2) {
3255 AddCodeLine ("dea");
3258 AddCodeLine ("sec");
3259 AddCodeLine ("sbc #$%02X", (unsigned char)val);
3266 if (CodeSizeFactor < 200) {
3267 /* Use subroutines */
3269 AddCodeLine ("jsr decax%d", (int) val);
3270 } else if (val <= 255) {
3272 AddCodeLine ("jsr decaxy");
3274 g_sub (flags | CF_CONST, val);
3277 /* Inline the code */
3279 if ((val & 0xFF) != 0) {
3280 unsigned L = GetLocalLabel();
3281 AddCodeLine ("sec");
3282 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3283 AddCodeLine ("bcs %s", LocalLabelName (L));
3284 AddCodeLine ("dex");
3288 AddCodeLine ("dex");
3291 AddCodeLine ("dex");
3294 AddCodeLine ("sec");
3295 if ((val & 0xFF) != 0) {
3296 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3297 /* Tell the optimizer that the X register may be invalid */
3298 AddCodeHint ("x:!");
3300 AddCodeLine ("pha");
3301 AddCodeLine ("txa");
3302 AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3303 AddCodeLine ("tax");
3304 AddCodeLine ("pla");
3312 AddCodeLine ("jsr deceaxy");
3314 g_sub (flags | CF_CONST, val);
3327 * Following are the conditional operators. They compare the TOS against
3328 * the primary and put a literal 1 in the primary if the condition is
3329 * true, otherwise they clear the primary register
3334 void g_eq (unsigned flags, unsigned long val)
3335 /* Test for equal */
3337 static char* ops [12] = {
3338 "toseq00", "toseqa0", "toseqax",
3339 "toseq00", "toseqa0", "toseqax",
3346 /* If the right hand side is const, the lhs is not on stack but still
3347 * in the primary register.
3349 if (flags & CF_CONST) {
3351 switch (flags & CF_TYPE) {
3354 if (flags & CF_FORCECHAR) {
3355 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3356 AddCodeLine ("jsr booleq");
3362 L = GetLocalLabel();
3363 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3364 AddCodeLine ("bne %s", LocalLabelName (L));
3365 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3367 AddCodeLine ("jsr booleq");
3377 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3378 * into the normal, non-optimized stuff.
3380 g_push (flags & ~CF_CONST, 0);
3384 /* Use long way over the stack */
3385 oper (flags, val, ops);
3390 void g_ne (unsigned flags, unsigned long val)
3391 /* Test for not equal */
3393 static char* ops [12] = {
3394 "tosne00", "tosnea0", "tosneax",
3395 "tosne00", "tosnea0", "tosneax",
3402 /* If the right hand side is const, the lhs is not on stack but still
3403 * in the primary register.
3405 if (flags & CF_CONST) {
3407 switch (flags & CF_TYPE) {
3410 if (flags & CF_FORCECHAR) {
3411 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3412 AddCodeLine ("jsr boolne");
3418 L = GetLocalLabel();
3419 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3420 AddCodeLine ("bne %s", LocalLabelName (L));
3421 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3423 AddCodeLine ("jsr boolne");
3433 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3434 * into the normal, non-optimized stuff.
3436 g_push (flags & ~CF_CONST, 0);
3440 /* Use long way over the stack */
3441 oper (flags, val, ops);
3446 void g_lt (unsigned flags, unsigned long val)
3447 /* Test for less than */
3449 static char* ops [12] = {
3450 "toslt00", "toslta0", "tosltax",
3451 "tosult00", "tosulta0", "tosultax",
3456 /* If the right hand side is const, the lhs is not on stack but still
3457 * in the primary register.
3459 if (flags & CF_CONST) {
3461 /* Give a warning in some special cases */
3462 if ((flags & CF_UNSIGNED) && val == 0) {
3463 Warning ("Condition is never true");
3466 /* Look at the type */
3467 switch (flags & CF_TYPE) {
3470 if (flags & CF_FORCECHAR) {
3471 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3472 if (flags & CF_UNSIGNED) {
3473 AddCodeLine ("jsr boolult");
3475 AddCodeLine ("jsr boollt");
3482 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3483 /* If we have a signed compare against zero, we only need to
3484 * test the high byte.
3486 AddCodeLine ("txa");
3487 AddCodeLine ("jsr boollt");
3490 /* Direct code only for unsigned data types */
3491 if (flags & CF_UNSIGNED) {
3492 unsigned L = GetLocalLabel();
3493 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3494 AddCodeLine ("bne %s", LocalLabelName (L));
3495 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3497 AddCodeLine ("jsr boolult");
3503 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3504 /* If we have a signed compare against zero, we only need to
3505 * test the high byte.
3507 AddCodeLine ("lda sreg+1");
3508 AddCodeLine ("jsr boollt");
3517 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3518 * into the normal, non-optimized stuff.
3520 g_push (flags & ~CF_CONST, 0);
3524 /* Use long way over the stack */
3525 oper (flags, val, ops);
3530 void g_le (unsigned flags, unsigned long val)
3531 /* Test for less than or equal to */
3533 static char* ops [12] = {
3534 "tosle00", "toslea0", "tosleax",
3535 "tosule00", "tosulea0", "tosuleax",
3541 /* If the right hand side is const, the lhs is not on stack but still
3542 * in the primary register.
3544 if (flags & CF_CONST) {
3546 /* Look at the type */
3547 switch (flags & CF_TYPE) {
3550 if (flags & CF_FORCECHAR) {
3551 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3552 if (flags & CF_UNSIGNED) {
3553 AddCodeLine ("jsr boolule");
3555 AddCodeLine ("jsr boolle");
3562 if (flags & CF_UNSIGNED) {
3563 unsigned L = GetLocalLabel();
3564 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3565 AddCodeLine ("bne %s", LocalLabelName (L));
3566 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3568 AddCodeLine ("jsr boolule");
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 /* Look at the type */
3610 switch (flags & CF_TYPE) {
3613 if (flags & CF_FORCECHAR) {
3614 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3615 if (flags & CF_UNSIGNED) {
3616 /* If we have a compare > 0, we will replace it by
3617 * != 0 here, since both are identical but the latter
3618 * is easier to optimize.
3621 AddCodeLine ("jsr boolugt");
3623 AddCodeLine ("jsr boolne");
3626 AddCodeLine ("jsr boolgt");
3633 if (flags & CF_UNSIGNED) {
3634 /* If we have a compare > 0, we will replace it by
3635 * != 0 here, since both are identical but the latter
3636 * is easier to optimize.
3638 if ((val & 0xFFFF) == 0) {
3639 AddCodeLine ("stx tmp1");
3640 AddCodeLine ("ora tmp1");
3641 AddCodeLine ("jsr boolne");
3643 unsigned L = GetLocalLabel();
3644 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3645 AddCodeLine ("bne %s", LocalLabelName (L));
3646 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3648 AddCodeLine ("jsr boolugt");
3661 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3662 * into the normal, non-optimized stuff.
3664 g_push (flags & ~CF_CONST, 0);
3668 /* Use long way over the stack */
3669 oper (flags, val, ops);
3674 void g_ge (unsigned flags, unsigned long val)
3675 /* Test for greater than or equal to */
3677 static char* ops [12] = {
3678 "tosge00", "tosgea0", "tosgeax",
3679 "tosuge00", "tosugea0", "tosugeax",
3685 /* If the right hand side is const, the lhs is not on stack but still
3686 * in the primary register.
3688 if (flags & CF_CONST) {
3690 /* Give a warning in some special cases */
3691 if ((flags & CF_UNSIGNED) && val == 0) {
3692 Warning ("Condition is always true");
3695 /* Look at the type */
3696 switch (flags & CF_TYPE) {
3699 if (flags & CF_FORCECHAR) {
3700 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3701 if (flags & CF_UNSIGNED) {
3702 AddCodeLine ("jsr booluge");
3704 AddCodeLine ("jsr boolge");
3711 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3712 /* If we have a signed compare against zero, we only need to
3713 * test the high byte.
3715 AddCodeLine ("txa");
3716 AddCodeLine ("jsr boolge");
3719 /* Direct code only for unsigned data types */
3720 if (flags & CF_UNSIGNED) {
3721 unsigned L = GetLocalLabel();
3722 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3723 AddCodeLine ("bne %s", LocalLabelName (L));
3724 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3726 AddCodeLine ("jsr booluge");
3732 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3733 /* If we have a signed compare against zero, we only need to
3734 * test the high byte.
3736 AddCodeLine ("lda sreg+1");
3737 AddCodeLine ("jsr boolge");
3746 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3747 * into the normal, non-optimized stuff.
3749 g_push (flags & ~CF_CONST, 0);
3753 /* Use long way over the stack */
3754 oper (flags, val, ops);
3759 /*****************************************************************************/
3760 /* Allocating static storage */
3761 /*****************************************************************************/
3765 void g_res (unsigned n)
3766 /* Reserve static storage, n bytes */
3768 AddDataLine ("\t.res\t%u,$00", n);
3773 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3774 /* Define data with the size given in flags */
3776 if (flags & CF_CONST) {
3778 /* Numeric constant */
3779 switch (flags & CF_TYPE) {
3782 AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
3786 AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
3790 AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
3801 /* Create the correct label name */
3802 const char* Label = GetLabelName (flags, val, offs);
3804 /* Labels are always 16 bit */
3805 AddDataLine ("\t.word\t%s", Label);
3812 void g_defbytes (const void* Bytes, unsigned Count)
3813 /* Output a row of bytes as a constant */
3819 /* Cast the buffer pointer */
3820 const unsigned char* Data = (const unsigned char*) Bytes;
3822 /* Output the stuff */
3825 /* How many go into this line? */
3826 if ((Chunk = Count) > 16) {
3831 /* Output one line */
3832 strcpy (Buf, "\t.byte\t");
3835 B += sprintf (B, "$%02X", *Data++);
3841 /* Output the line */
3848 void g_zerobytes (unsigned n)
3849 /* Output n bytes of data initialized with zero */
3851 AddDataLine ("\t.res\t%u,$00", n);
3856 /*****************************************************************************/
3857 /* User supplied assembler code */
3858 /*****************************************************************************/
3862 void g_asmcode (const char* Line, int Len)
3863 /* Output one line of assembler code. If Len is greater than zero, it is used
3864 * as the maximum number of characters to use from Line.
3868 AddCodeLine ("%.*s", Len, Line);
3870 AddCodeLine ("%s", Line);
3876 /*****************************************************************************/
3877 /* Inlined known functions */
3878 /*****************************************************************************/
3882 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3883 /* Inline the strlen() function */
3885 /* We need a label in both cases */
3886 unsigned label = GetLocalLabel ();
3888 /* Two different encodings */
3889 if (flags & CF_CONST) {
3891 /* The address of the string is constant. Create the correct label name */
3892 char* lbuf = GetLabelName (flags, val, offs);
3894 /* Generate the strlen code */
3895 AddCodeLine ("ldy #$FF");
3896 g_defcodelabel (label);
3897 AddCodeLine ("iny");
3898 AddCodeLine ("lda %s,y", lbuf);
3899 AddCodeLine ("bne %s", LocalLabelName (label));
3900 AddCodeLine ("tax");
3901 AddCodeLine ("tya");
3905 /* Address not constant but in primary */
3906 if (CodeSizeFactor < 400) {
3907 /* This is too much code, so call strlen instead of inlining */
3908 AddCodeLine ("jsr _strlen");
3910 /* Inline the function */
3911 AddCodeLine ("sta ptr1");
3912 AddCodeLine ("stx ptr1+1");
3913 AddCodeLine ("ldy #$FF");
3914 g_defcodelabel (label);
3915 AddCodeLine ("iny");
3916 AddCodeLine ("lda (ptr1),y");
3917 AddCodeLine ("bne %s", LocalLabelName (label));
3918 AddCodeLine ("tax");
3919 AddCodeLine ("tya");