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 AddCodeLine ("bpl *+3");
624 AddCodeHint ("x:!"); /* X is invalid now */
630 AddCodeLine ("lda %s", lbuf);
631 if (flags & CF_TEST) {
632 AddCodeLine ("ora %s+1", lbuf);
634 AddCodeLine ("ldx %s+1", lbuf);
639 if (flags & CF_TEST) {
640 AddCodeLine ("lda %s+3", lbuf);
641 AddCodeLine ("ora %s+2", lbuf);
642 AddCodeLine ("ora %s+1", lbuf);
643 AddCodeLine ("ora %s+0", lbuf);
645 AddCodeLine ("lda %s+3", lbuf);
646 AddCodeLine ("sta sreg+1");
647 AddCodeLine ("lda %s+2", lbuf);
648 AddCodeLine ("sta sreg");
649 AddCodeLine ("ldx %s+1", lbuf);
650 AddCodeLine ("lda %s", lbuf);
662 void g_getlocal (unsigned flags, int offs)
663 /* Fetch specified local object (local var). */
666 CheckLocalOffs (offs);
667 switch (flags & CF_TYPE) {
670 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
671 if (CPU == CPU_65C02 && offs == 0) {
672 AddCodeLine ("lda (sp)");
675 AddCodeLine ("lda (sp),y");
679 AddCodeLine ("ldx #$00");
680 AddCodeLine ("lda (sp,x)");
683 AddCodeLine ("ldx #$00");
684 AddCodeLine ("lda (sp),y");
686 if ((flags & CF_UNSIGNED) == 0) {
687 AddCodeLine ("bpl *+3");
689 AddCodeHint ("x:!"); /* X is invalid now */
695 CheckLocalOffs (offs + 1);
696 if (flags & CF_TEST) {
698 AddCodeLine ("lda (sp),y");
700 AddCodeLine ("ora (sp),y");
702 if (CodeSizeFactor > 180) {
704 AddCodeLine ("lda (sp),y");
707 AddCodeLine ("lda (sp),y");
711 AddCodeLine ("jsr ldaxysp");
713 AddCodeLine ("jsr ldax0sp");
722 AddCodeLine ("jsr ldeaxysp");
724 AddCodeLine ("jsr ldeax0sp");
735 void g_getind (unsigned flags, unsigned offs)
736 /* Fetch the specified object type indirect through the primary register
737 * into the primary register
740 /* If the offset is greater than 255, add the part that is > 255 to
741 * the primary. This way we get an easy addition and use the low byte
744 offs = MakeByteOffs (flags, offs);
746 /* Handle the indirect fetch */
747 switch (flags & CF_TYPE) {
750 /* Character sized */
753 if (flags & CF_UNSIGNED) {
754 AddCodeLine ("jsr ldauidx");
756 AddCodeLine ("jsr ldaidx");
759 if (flags & CF_UNSIGNED) {
760 if (CodeSizeFactor > 250) {
761 AddCodeLine ("sta ptr1");
762 AddCodeLine ("stx ptr1+1");
763 AddCodeLine ("ldx #$00");
764 AddCodeLine ("lda (ptr1,x)");
766 AddCodeLine ("jsr ldaui");
769 AddCodeLine ("jsr ldai");
775 if (flags & CF_TEST) {
777 AddCodeLine ("sta ptr1");
778 AddCodeLine ("stx ptr1+1");
779 AddCodeLine ("lda (ptr1),y");
781 AddCodeLine ("ora (ptr1),y");
784 AddCodeLine ("jsr ldaxi");
787 AddCodeLine ("jsr ldaxidx");
794 AddCodeLine ("jsr ldeaxi");
797 AddCodeLine ("jsr ldeaxidx");
799 if (flags & CF_TEST) {
800 AddCodeLine ("jsr tsteax");
812 void g_leasp (int offs)
813 /* Fetch the address of the specified symbol into the primary register */
815 /* Calculate the offset relative to sp */
818 /* For value 0 we do direct code */
820 AddCodeLine ("lda sp");
821 AddCodeLine ("ldx sp+1");
823 if (CodeSizeFactor < 300) {
824 ldaconst (offs); /* Load A with offset value */
825 AddCodeLine ("jsr leaasp"); /* Load effective address */
827 if (CPU == CPU_65C02 && offs == 1) {
828 AddCodeLine ("lda sp");
829 AddCodeLine ("ldx sp+1");
831 AddCodeLine ("bne *+3");
833 AddCodeHint ("x:!"); /* Invalidate X */
837 AddCodeLine ("ldx sp+1");
838 AddCodeLine ("adc sp");
839 AddCodeLine ("bcc *+3");
841 AddCodeHint ("x:!"); /* Invalidate X */
849 void g_leavariadic (int Offs)
850 /* Fetch the address of a parameter in a variadic function into the primary
854 unsigned ArgSizeOffs;
856 /* Calculate the offset relative to sp */
859 /* Get the offset of the parameter which is stored at sp+0 on function
860 * entry and check if this offset is reachable with a byte offset.
863 ArgSizeOffs = -oursp;
864 CheckLocalOffs (ArgSizeOffs);
866 /* Get the size of all parameters. */
867 if (ArgSizeOffs == 0 && CPU == CPU_65C02) {
868 AddCodeLine ("lda (sp)");
870 ldyconst (ArgSizeOffs);
871 AddCodeLine ("lda (sp),y");
874 /* Add the value of the stackpointer */
875 if (CodeSizeFactor > 250) {
876 AddCodeLine ("ldx sp+1");
878 AddCodeLine ("adc sp");
879 AddCodeLine ("bcc *+3");
881 AddCodeHint ("x:!"); /* Invalidate X */
883 AddCodeLine ("jsr leaasp");
886 /* Add the offset to the primary */
888 g_inc (CF_INT | CF_CONST, Offs);
889 } else if (Offs < 0) {
890 g_dec (CF_INT | CF_CONST, -Offs);
896 /*****************************************************************************/
897 /* Store into memory */
898 /*****************************************************************************/
902 void g_putstatic (unsigned flags, unsigned long label, unsigned offs)
903 /* Store the primary register into the specified static memory cell */
905 /* Create the correct label name */
906 char* lbuf = GetLabelName (flags, label, offs);
908 /* Check the size and generate the correct store operation */
909 switch (flags & CF_TYPE) {
912 AddCodeLine ("sta %s", lbuf);
916 AddCodeLine ("sta %s", lbuf);
917 AddCodeLine ("stx %s+1", lbuf);
921 AddCodeLine ("sta %s", lbuf);
922 AddCodeLine ("stx %s+1", lbuf);
923 AddCodeLine ("ldy sreg");
924 AddCodeLine ("sty %s+2", lbuf);
925 AddCodeLine ("ldy sreg+1");
926 AddCodeLine ("sty %s+3", lbuf);
937 void g_putlocal (unsigned Flags, int Offs, long Val)
938 /* Put data into local object. */
941 CheckLocalOffs (Offs);
942 switch (Flags & CF_TYPE) {
945 if (Flags & CF_CONST) {
946 AddCodeLine ("lda #$%02X", (unsigned char) Val);
948 if (CPU == CPU_65C02 && Offs == 0) {
949 AddCodeLine ("sta (sp)");
952 AddCodeLine ("sta (sp),y");
957 if (Flags & CF_CONST) {
959 AddCodeLine ("lda #$%02X", (unsigned char) (Val >> 8));
960 AddCodeLine ("sta (sp),y");
961 if ((Flags & CF_NOKEEP) == 0) {
962 /* Place high byte into X */
965 if (CPU == CPU_65C02 && Offs == 0) {
966 AddCodeLine ("lda #$%02X", (unsigned char) Val);
967 AddCodeLine ("sta (sp)");
969 if ((Val & 0xFF) == Offs+1) {
970 /* The value we need is already in Y */
975 AddCodeLine ("lda #$%02X", (unsigned char) Val);
977 AddCodeLine ("sta (sp),y");
980 if ((Flags & CF_NOKEEP) == 0 || CodeSizeFactor < 160) {
983 AddCodeLine ("jsr staxysp");
985 AddCodeLine ("jsr stax0sp");
988 if (CPU == CPU_65C02 && Offs == 0) {
989 AddCodeLine ("sta (sp)");
992 AddCodeLine ("sta (sp),y");
995 AddCodeLine ("sta (sp),y");
998 AddCodeLine ("sta (sp),y");
1005 if (Flags & CF_CONST) {
1006 g_getimmed (Flags, Val, 0);
1010 AddCodeLine ("jsr steaxysp");
1012 AddCodeLine ("jsr steax0sp");
1024 void g_putind (unsigned Flags, unsigned Offs)
1025 /* Store the specified object type in the primary register at the address
1026 * on the top of the stack
1029 /* We can handle offsets below $100 directly, larger offsets must be added
1030 * to the address. Since a/x is in use, best code is achieved by adding
1031 * just the high byte. Be sure to check if the low byte will overflow while
1034 if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
1036 /* Overflow - we need to add the low byte also */
1037 AddCodeLine ("ldy #$00");
1038 AddCodeLine ("clc");
1039 AddCodeLine ("pha");
1040 AddCodeLine ("lda #$%02X", Offs & 0xFF);
1041 AddCodeLine ("adc (sp),y");
1042 AddCodeLine ("sta (sp),y");
1043 AddCodeLine ("iny");
1044 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1045 AddCodeLine ("adc (sp),y");
1046 AddCodeLine ("sta (sp),y");
1047 AddCodeLine ("pla");
1049 /* Complete address is on stack, new offset is zero */
1052 } else if ((Offs & 0xFF00) != 0) {
1054 /* We can just add the high byte */
1055 AddCodeLine ("ldy #$01");
1056 AddCodeLine ("clc");
1057 AddCodeLine ("pha");
1058 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1059 AddCodeLine ("adc (sp),y");
1060 AddCodeLine ("sta (sp),y");
1061 AddCodeLine ("pla");
1063 /* Offset is now just the low byte */
1067 /* Check the size and determine operation */
1068 switch (Flags & CF_TYPE) {
1073 AddCodeLine ("jsr staspidx");
1075 AddCodeLine ("jsr staspp");
1082 AddCodeLine ("jsr staxspidx");
1084 AddCodeLine ("jsr staxspp");
1091 AddCodeLine ("jsr steaxspidx");
1093 AddCodeLine ("jsr steaxspp");
1102 /* Pop the argument which is always a pointer */
1108 /*****************************************************************************/
1109 /* type conversion and similiar stuff */
1110 /*****************************************************************************/
1114 void g_toslong (unsigned flags)
1115 /* Make sure, the value on TOS is a long. Convert if necessary */
1117 switch (flags & CF_TYPE) {
1121 if (flags & CF_UNSIGNED) {
1122 AddCodeLine ("jsr tosulong");
1124 AddCodeLine ("jsr toslong");
1139 void g_tosint (unsigned flags)
1140 /* Make sure, the value on TOS is an int. Convert if necessary */
1142 switch (flags & CF_TYPE) {
1149 AddCodeLine ("jsr tosint");
1160 void g_reglong (unsigned flags)
1161 /* Make sure, the value in the primary register a long. Convert if necessary */
1163 switch (flags & CF_TYPE) {
1167 if (flags & CF_UNSIGNED) {
1168 if (CodeSizeFactor >= 200) {
1170 AddCodeLine ("sty sreg");
1171 AddCodeLine ("sty sreg+1");
1173 AddCodeLine ("jsr axulong");
1176 AddCodeLine ("jsr axlong");
1190 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1191 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1192 * value, that corresponds to the value on TOS, rhs corresponds to the value
1193 * in (e)ax. The return value is the the flags value for the resulting type.
1196 unsigned ltype, rtype;
1199 /* Get the type spec from the flags */
1200 ltype = lhs & CF_TYPE;
1201 rtype = rhs & CF_TYPE;
1203 /* Check if a conversion is needed */
1204 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1205 /* We must promote the primary register to long */
1207 /* Get the new rhs type */
1208 rhs = (rhs & ~CF_TYPE) | CF_LONG;
1210 } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1211 /* We must promote the lhs to long */
1217 /* Get the new rhs type */
1218 lhs = (lhs & ~CF_TYPE) | CF_LONG;
1222 /* Determine the result type for the operation:
1223 * - The result is const if both operands are const.
1224 * - The result is unsigned if one of the operands is unsigned.
1225 * - The result is long if one of the operands is long.
1226 * - Otherwise the result is int sized.
1228 result = (lhs & CF_CONST) & (rhs & CF_CONST);
1229 result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1230 if (rtype == CF_LONG || ltype == CF_LONG) {
1240 unsigned g_typecast (unsigned lhs, unsigned rhs)
1241 /* Cast the value in the primary register to the operand size that is flagged
1242 * by the lhs value. Return the result value.
1245 unsigned ltype, rtype;
1247 /* Get the type spec from the flags */
1248 ltype = lhs & CF_TYPE;
1249 rtype = rhs & CF_TYPE;
1251 /* Check if a conversion is needed */
1252 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1253 /* We must promote the primary register to long */
1257 /* Do not need any other action. If the left type is int, and the primary
1258 * register is long, it will be automagically truncated. If the right hand
1259 * side is const, it is not located in the primary register and handled by
1260 * the expression parser code.
1263 /* Result is const if the right hand side was const */
1264 lhs |= (rhs & CF_CONST);
1266 /* The resulting type is that of the left hand side (that's why you called
1274 void g_scale (unsigned flags, long val)
1275 /* Scale the value in the primary register by the given value. If val is positive,
1276 * scale up, is val is negative, scale down. This function is used to scale
1277 * the operands or results of pointer arithmetic by the size of the type, the
1278 * pointer points to.
1283 /* Value may not be zero */
1285 Internal ("Data type has no size");
1286 } else if (val > 0) {
1289 if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1291 /* Factor is 2, 4 or 8, use special function */
1292 switch (flags & CF_TYPE) {
1295 if (flags & CF_FORCECHAR) {
1297 AddCodeLine ("asl a");
1304 if (CodeSizeFactor >= (p2+1)*130U) {
1305 AddCodeLine ("stx tmp1");
1307 AddCodeLine ("asl a");
1308 AddCodeLine ("rol tmp1");
1310 AddCodeLine ("ldx tmp1");
1312 if (flags & CF_UNSIGNED) {
1313 AddCodeLine ("jsr shlax%d", p2);
1315 AddCodeLine ("jsr aslax%d", p2);
1321 if (flags & CF_UNSIGNED) {
1322 AddCodeLine ("jsr shleax%d", p2);
1324 AddCodeLine ("jsr asleax%d", p2);
1333 } else if (val != 1) {
1335 /* Use a multiplication instead */
1336 g_mul (flags | CF_CONST, val);
1344 if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1346 /* Factor is 2, 4 or 8, use special function */
1347 switch (flags & CF_TYPE) {
1350 if (flags & CF_FORCECHAR) {
1351 if (flags & CF_UNSIGNED) {
1353 AddCodeLine ("lsr a");
1356 } else if (p2 <= 2) {
1357 AddCodeLine ("cmp #$80");
1358 AddCodeLine ("ror a");
1365 if (flags & CF_UNSIGNED) {
1366 if (CodeSizeFactor >= (p2+1)*130U) {
1367 AddCodeLine ("stx tmp1");
1369 AddCodeLine ("lsr tmp1");
1370 AddCodeLine ("ror a");
1372 AddCodeLine ("ldx tmp1");
1374 AddCodeLine ("jsr lsrax%d", p2);
1377 if (CodeSizeFactor >= (p2+1)*150U) {
1378 AddCodeLine ("stx tmp1");
1380 AddCodeLine ("cpx #$80");
1381 AddCodeLine ("ror tmp1");
1382 AddCodeLine ("ror a");
1384 AddCodeLine ("ldx tmp1");
1386 AddCodeLine ("jsr asrax%d", p2);
1392 if (flags & CF_UNSIGNED) {
1393 AddCodeLine ("jsr lsreax%d", p2);
1395 AddCodeLine ("jsr asreax%d", p2);
1404 } else if (val != 1) {
1406 /* Use a division instead */
1407 g_div (flags | CF_CONST, val);
1415 /*****************************************************************************/
1416 /* Adds and subs of variables fix a fixed address */
1417 /*****************************************************************************/
1421 void g_addlocal (unsigned flags, int offs)
1422 /* Add a local variable to ax */
1424 /* Correct the offset and check it */
1426 CheckLocalOffs (offs);
1428 switch (flags & CF_TYPE) {
1431 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1432 AddCodeLine ("clc");
1433 AddCodeLine ("adc (sp),y");
1434 AddCodeLine ("bcc *+3");
1435 AddCodeLine ("inx");
1436 AddCodeHint ("x:!");
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 */
1469 /* Create the correct label name */
1470 char* lbuf = GetLabelName (flags, label, offs);
1472 switch (flags & CF_TYPE) {
1475 AddCodeLine ("clc");
1476 AddCodeLine ("adc %s", lbuf);
1477 AddCodeLine ("bcc *+3");
1478 AddCodeLine ("inx");
1479 AddCodeHint ("x:!");
1483 AddCodeLine ("clc");
1484 AddCodeLine ("adc %s", lbuf);
1485 AddCodeLine ("tay");
1486 AddCodeLine ("txa");
1487 AddCodeLine ("adc %s+1", lbuf);
1488 AddCodeLine ("tax");
1489 AddCodeLine ("tya");
1493 /* Do it the old way */
1495 g_getstatic (flags, label, offs);
1507 /*****************************************************************************/
1508 /* Compares of ax with a variable with fixed address */
1509 /*****************************************************************************/
1513 void g_cmplocal (unsigned flags, int offs)
1514 /* Compare a local variable to ax */
1516 Internal ("g_cmplocal not implemented");
1521 void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
1522 /* Compare a static variable to ax */
1524 Internal ("g_cmpstatic not implemented");
1529 /*****************************************************************************/
1530 /* Special op= functions */
1531 /*****************************************************************************/
1535 void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
1537 /* Emit += for a static variable */
1539 /* Create the correct label name */
1540 char* lbuf = GetLabelName (flags, label, offs);
1542 /* Check the size and determine operation */
1543 switch (flags & CF_TYPE) {
1546 if (flags & CF_FORCECHAR) {
1547 AddCodeLine ("ldx #$00");
1548 if (flags & CF_CONST) {
1550 AddCodeLine ("inc %s", lbuf);
1551 AddCodeLine ("lda %s", lbuf);
1553 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1554 AddCodeLine ("clc");
1555 AddCodeLine ("adc %s", lbuf);
1556 AddCodeLine ("sta %s", lbuf);
1559 AddCodeLine ("clc");
1560 AddCodeLine ("adc %s", lbuf);
1561 AddCodeLine ("sta %s", lbuf);
1563 if ((flags & CF_UNSIGNED) == 0) {
1564 AddCodeLine ("bpl *+3");
1565 AddCodeLine ("dex");
1566 AddCodeHint ("x:!"); /* Invalidate X */
1573 if (flags & CF_CONST) {
1575 unsigned L = GetLocalLabel ();
1576 AddCodeLine ("inc %s", lbuf);
1577 AddCodeLine ("bne %s", LocalLabelName (L));
1578 AddCodeLine ("inc %s+1", lbuf);
1580 AddCodeLine ("lda %s", lbuf); /* Hmmm... */
1581 AddCodeLine ("ldx %s+1", lbuf);
1583 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1584 AddCodeLine ("clc");
1585 AddCodeLine ("adc %s", lbuf);
1586 AddCodeLine ("sta %s", lbuf);
1588 unsigned L = GetLocalLabel ();
1589 AddCodeLine ("bcc %s", LocalLabelName (L));
1590 AddCodeLine ("inc %s+1", lbuf);
1592 AddCodeLine ("ldx %s+1", lbuf);
1594 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1595 AddCodeLine ("adc %s+1", lbuf);
1596 AddCodeLine ("sta %s+1", lbuf);
1597 AddCodeLine ("tax");
1598 AddCodeLine ("lda %s", lbuf);
1602 AddCodeLine ("clc");
1603 AddCodeLine ("adc %s", lbuf);
1604 AddCodeLine ("sta %s", lbuf);
1605 AddCodeLine ("txa");
1606 AddCodeLine ("adc %s+1", lbuf);
1607 AddCodeLine ("sta %s+1", lbuf);
1608 AddCodeLine ("tax");
1609 AddCodeLine ("lda %s", lbuf);
1614 if (flags & CF_CONST) {
1616 AddCodeLine ("ldy #<(%s)", lbuf);
1617 AddCodeLine ("sty ptr1");
1618 AddCodeLine ("ldy #>(%s+1)", lbuf);
1620 AddCodeLine ("jsr laddeq1");
1622 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1623 AddCodeLine ("jsr laddeqa");
1626 g_getstatic (flags, label, offs);
1628 g_putstatic (flags, label, offs);
1631 AddCodeLine ("ldy #<(%s)", lbuf);
1632 AddCodeLine ("sty ptr1");
1633 AddCodeLine ("ldy #>(%s+1)", lbuf);
1634 AddCodeLine ("jsr laddeq");
1645 void g_addeqlocal (unsigned flags, int offs, unsigned long val)
1646 /* Emit += for a local variable */
1648 /* Calculate the true offset, check it, load it into Y */
1650 CheckLocalOffs (offs);
1652 /* Check the size and determine operation */
1653 switch (flags & CF_TYPE) {
1656 if (flags & CF_FORCECHAR) {
1658 AddCodeLine ("ldx #$00");
1659 if (flags & CF_CONST) {
1660 AddCodeLine ("clc");
1661 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1662 AddCodeLine ("adc (sp,x)");
1663 AddCodeLine ("sta (sp,x)");
1665 AddCodeLine ("clc");
1666 AddCodeLine ("adc (sp,x)");
1667 AddCodeLine ("sta (sp,x)");
1671 AddCodeLine ("ldx #$00");
1672 if (flags & CF_CONST) {
1673 AddCodeLine ("clc");
1674 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1675 AddCodeLine ("adc (sp),y");
1676 AddCodeLine ("sta (sp),y");
1678 AddCodeLine ("clc");
1679 AddCodeLine ("adc (sp),y");
1680 AddCodeLine ("sta (sp),y");
1683 if ((flags & CF_UNSIGNED) == 0) {
1684 AddCodeLine ("bpl *+3");
1685 AddCodeLine ("dex");
1686 AddCodeHint ("x:!"); /* Invalidate X */
1693 if (flags & CF_CONST) {
1694 g_getimmed (flags, val, 0);
1697 AddCodeLine ("jsr addeq0sp");
1700 AddCodeLine ("jsr addeqysp");
1705 if (flags & CF_CONST) {
1706 g_getimmed (flags, val, 0);
1709 AddCodeLine ("jsr laddeq0sp");
1712 AddCodeLine ("jsr laddeqysp");
1723 void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1724 /* Emit += for the location with address in ax */
1726 /* If the offset is too large for a byte register, add the high byte
1727 * of the offset to the primary. Beware: We need a special correction
1728 * if the offset in the low byte will overflow in the operation.
1730 offs = MakeByteOffs (flags, offs);
1732 /* Check the size and determine operation */
1733 switch (flags & CF_TYPE) {
1736 AddCodeLine ("sta ptr1");
1737 AddCodeLine ("stx ptr1+1");
1739 AddCodeLine ("ldx #$00");
1740 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1741 AddCodeLine ("clc");
1742 AddCodeLine ("adc (ptr1,x)");
1743 AddCodeLine ("sta (ptr1,x)");
1745 AddCodeLine ("ldy #$%02X", offs);
1746 AddCodeLine ("ldx #$00");
1747 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1748 AddCodeLine ("clc");
1749 AddCodeLine ("adc (ptr1),y");
1750 AddCodeLine ("sta (ptr1),y");
1755 if (CodeSizeFactor >= 200) {
1756 /* Lots of code, use only if size is not important */
1757 AddCodeLine ("sta ptr1");
1758 AddCodeLine ("stx ptr1+1");
1759 AddCodeLine ("ldy #$%02X", offs);
1760 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1761 AddCodeLine ("clc");
1762 AddCodeLine ("adc (ptr1),y");
1763 AddCodeLine ("sta (ptr1),y");
1764 AddCodeLine ("pha");
1765 AddCodeLine ("iny");
1766 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1767 AddCodeLine ("adc (ptr1),y");
1768 AddCodeLine ("sta (ptr1),y");
1769 AddCodeLine ("tax");
1770 AddCodeLine ("pla");
1776 AddCodeLine ("jsr pushax"); /* Push the address */
1777 push (flags); /* Correct the internal sp */
1778 g_getind (flags, offs); /* Fetch the value */
1779 g_inc (flags, val); /* Increment value in primary */
1780 g_putind (flags, offs); /* Store the value back */
1790 void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
1792 /* Emit -= for a static variable */
1794 /* Create the correct label name */
1795 char* lbuf = GetLabelName (flags, label, offs);
1797 /* Check the size and determine operation */
1798 switch (flags & CF_TYPE) {
1801 if (flags & CF_FORCECHAR) {
1802 AddCodeLine ("ldx #$00");
1803 if (flags & CF_CONST) {
1805 AddCodeLine ("dec %s", lbuf);
1806 AddCodeLine ("lda %s", lbuf);
1808 AddCodeLine ("sec");
1809 AddCodeLine ("lda %s", lbuf);
1810 AddCodeLine ("sbc #$%02X", (int)(val & 0xFF));
1811 AddCodeLine ("sta %s", lbuf);
1814 AddCodeLine ("sec");
1815 AddCodeLine ("sta tmp1");
1816 AddCodeLine ("lda %s", lbuf);
1817 AddCodeLine ("sbc tmp1");
1818 AddCodeLine ("sta %s", lbuf);
1820 if ((flags & CF_UNSIGNED) == 0) {
1821 AddCodeLine ("bpl *+3");
1822 AddCodeLine ("dex");
1823 AddCodeHint ("x:!"); /* Invalidate X */
1830 AddCodeLine ("sec");
1831 if (flags & CF_CONST) {
1832 AddCodeLine ("lda %s", lbuf);
1833 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1834 AddCodeLine ("sta %s", lbuf);
1836 unsigned L = GetLocalLabel ();
1837 AddCodeLine ("bcs %s", LocalLabelName (L));
1838 AddCodeLine ("dec %s+1", lbuf);
1840 AddCodeLine ("ldx %s+1", lbuf);
1842 AddCodeLine ("lda %s+1", lbuf);
1843 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1844 AddCodeLine ("sta %s+1", lbuf);
1845 AddCodeLine ("tax");
1846 AddCodeLine ("lda %s", lbuf);
1849 AddCodeLine ("sta tmp1");
1850 AddCodeLine ("lda %s", lbuf);
1851 AddCodeLine ("sbc tmp1");
1852 AddCodeLine ("sta %s", lbuf);
1853 AddCodeLine ("stx tmp1");
1854 AddCodeLine ("lda %s+1", lbuf);
1855 AddCodeLine ("sbc tmp1");
1856 AddCodeLine ("sta %s+1", lbuf);
1857 AddCodeLine ("tax");
1858 AddCodeLine ("lda %s", lbuf);
1863 if (flags & CF_CONST) {
1865 AddCodeLine ("ldy #<(%s)", lbuf);
1866 AddCodeLine ("sty ptr1");
1867 AddCodeLine ("ldy #>(%s+1)", lbuf);
1869 AddCodeLine ("jsr lsubeq1");
1871 AddCodeLine ("lda #$%02X", (unsigned char)val);
1872 AddCodeLine ("jsr lsubeqa");
1875 g_getstatic (flags, label, offs);
1877 g_putstatic (flags, label, offs);
1880 AddCodeLine ("ldy #<(%s)", lbuf);
1881 AddCodeLine ("sty ptr1");
1882 AddCodeLine ("ldy #>(%s+1)", lbuf);
1883 AddCodeLine ("jsr lsubeq");
1894 void g_subeqlocal (unsigned flags, int offs, unsigned long val)
1895 /* Emit -= for a local variable */
1897 /* Calculate the true offset, check it, load it into Y */
1899 CheckLocalOffs (offs);
1901 /* Check the size and determine operation */
1902 switch (flags & CF_TYPE) {
1905 if (flags & CF_FORCECHAR) {
1907 AddCodeLine ("ldx #$00");
1908 AddCodeLine ("sec");
1909 if (flags & CF_CONST) {
1910 AddCodeLine ("lda (sp),y");
1911 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1913 AddCodeLine ("sta tmp1");
1914 AddCodeLine ("lda (sp),y");
1915 AddCodeLine ("sbc tmp1");
1917 AddCodeLine ("sta (sp),y");
1918 if ((flags & CF_UNSIGNED) == 0) {
1919 AddCodeLine ("bpl *+3");
1920 AddCodeLine ("dex");
1921 AddCodeHint ("x:!"); /* Invalidate X */
1928 if (flags & CF_CONST) {
1929 g_getimmed (flags, val, 0);
1932 AddCodeLine ("jsr subeq0sp");
1935 AddCodeLine ("jsr subeqysp");
1940 if (flags & CF_CONST) {
1941 g_getimmed (flags, val, 0);
1944 AddCodeLine ("jsr lsubeq0sp");
1947 AddCodeLine ("jsr lsubeqysp");
1958 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
1959 /* Emit -= for the location with address in ax */
1961 /* If the offset is too large for a byte register, add the high byte
1962 * of the offset to the primary. Beware: We need a special correction
1963 * if the offset in the low byte will overflow in the operation.
1965 offs = MakeByteOffs (flags, offs);
1967 /* Check the size and determine operation */
1968 switch (flags & CF_TYPE) {
1971 AddCodeLine ("sta ptr1");
1972 AddCodeLine ("stx ptr1+1");
1974 AddCodeLine ("ldx #$00");
1975 AddCodeLine ("lda (ptr1,x)");
1976 AddCodeLine ("sec");
1977 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1978 AddCodeLine ("sta (ptr1,x)");
1980 AddCodeLine ("ldy #$%02X", offs);
1981 AddCodeLine ("ldx #$00");
1982 AddCodeLine ("lda (ptr1),y");
1983 AddCodeLine ("sec");
1984 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1985 AddCodeLine ("sta (ptr1),y");
1990 if (CodeSizeFactor >= 200) {
1991 /* Lots of code, use only if size is not important */
1992 AddCodeLine ("sta ptr1");
1993 AddCodeLine ("stx ptr1+1");
1994 AddCodeLine ("ldy #$%02X", offs);
1995 AddCodeLine ("lda (ptr1),y");
1996 AddCodeLine ("sec");
1997 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1998 AddCodeLine ("sta (ptr1),y");
1999 AddCodeLine ("pha");
2000 AddCodeLine ("iny");
2001 AddCodeLine ("lda (ptr1),y");
2002 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
2003 AddCodeLine ("sta (ptr1),y");
2004 AddCodeLine ("tax");
2005 AddCodeLine ("pla");
2011 AddCodeLine ("jsr pushax"); /* Push the address */
2012 push (flags); /* Correct the internal sp */
2013 g_getind (flags, offs); /* Fetch the value */
2014 g_dec (flags, val); /* Increment value in primary */
2015 g_putind (flags, offs); /* Store the value back */
2025 /*****************************************************************************/
2026 /* Add a variable address to the value in ax */
2027 /*****************************************************************************/
2031 void g_addaddr_local (unsigned flags, int offs)
2032 /* Add the address of a local variable to ax */
2034 /* Add the offset */
2037 /* We cannot address more then 256 bytes of locals anyway */
2038 CheckLocalOffs (offs);
2039 AddCodeLine ("clc");
2040 AddCodeLine ("adc #$%02X", offs & 0xFF);
2041 AddCodeLine ("bcc *+4"); /* Do also skip the CLC insn below */
2042 AddCodeLine ("inx");
2043 AddCodeHint ("x:!"); /* Invalidate X */
2046 /* Add the current stackpointer value */
2047 AddCodeLine ("clc");
2048 AddCodeLine ("adc sp");
2049 AddCodeLine ("tay");
2050 AddCodeLine ("txa");
2051 AddCodeLine ("adc sp+1");
2052 AddCodeLine ("tax");
2053 AddCodeLine ("tya");
2058 void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
2059 /* Add the address of a static variable to ax */
2061 /* Create the correct label name */
2062 char* lbuf = GetLabelName (flags, label, offs);
2064 /* Add the address to the current ax value */
2065 AddCodeLine ("clc");
2066 AddCodeLine ("adc #<(%s)", lbuf);
2067 AddCodeLine ("tay");
2068 AddCodeLine ("txa");
2069 AddCodeLine ("adc #>(%s)", lbuf);
2070 AddCodeLine ("tax");
2071 AddCodeLine ("tya");
2076 /*****************************************************************************/
2078 /*****************************************************************************/
2082 void g_save (unsigned flags)
2083 /* Copy primary register to hold register. */
2085 /* Check the size and determine operation */
2086 switch (flags & CF_TYPE) {
2089 if (flags & CF_FORCECHAR) {
2090 AddCodeLine ("pha");
2096 AddCodeLine ("sta regsave");
2097 AddCodeLine ("stx regsave+1");
2101 AddCodeLine ("jsr saveeax");
2111 void g_restore (unsigned flags)
2112 /* Copy hold register to primary. */
2114 /* Check the size and determine operation */
2115 switch (flags & CF_TYPE) {
2118 if (flags & CF_FORCECHAR) {
2119 AddCodeLine ("pla");
2125 AddCodeLine ("lda regsave");
2126 AddCodeLine ("ldx regsave+1");
2130 AddCodeLine ("jsr resteax");
2140 void g_cmp (unsigned flags, unsigned long val)
2141 /* Immidiate compare. The primary register will not be changed, Z flag
2145 /* Check the size and determine operation */
2146 switch (flags & CF_TYPE) {
2149 if (flags & CF_FORCECHAR) {
2150 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2156 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2157 AddCodeLine ("bne *+4");
2158 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
2162 Internal ("g_cmp: Long compares not implemented");
2172 static void oper (unsigned flags, unsigned long val, char** subs)
2173 /* Encode a binary operation. subs is a pointer to four groups of three
2175 * 0-2 --> Operate on ints
2176 * 3-5 --> Operate on unsigneds
2177 * 6-8 --> Operate on longs
2178 * 9-11 --> Operate on unsigned longs
2180 * The first subroutine names in each string group is used to encode an
2181 * operation with a zero constant, the second to encode an operation with
2182 * a 8 bit constant, and the third is used in all other cases.
2187 /* Determine the offset into the array */
2188 offs = (flags & CF_UNSIGNED)? 3 : 0;
2189 switch (flags & CF_TYPE) {
2202 /* Encode the operation */
2203 if (flags & CF_CONST) {
2204 /* Constant value given */
2205 if (val == 0 && subs [offs+0]) {
2206 /* Special case: constant with value zero */
2207 AddCodeLine ("jsr %s", subs [offs+0]);
2208 } else if (val < 0x100 && subs [offs+1]) {
2209 /* Special case: constant with high byte zero */
2210 ldaconst (val); /* Load low byte */
2211 AddCodeLine ("jsr %s", subs [offs+1]);
2213 /* Others: arbitrary constant value */
2214 g_getimmed (flags, val, 0); /* Load value */
2215 AddCodeLine ("jsr %s", subs [offs+2]);
2218 /* Value not constant (is already in (e)ax) */
2219 AddCodeLine ("jsr %s", subs [offs+2]);
2222 /* The operation will pop it's argument */
2228 void g_test (unsigned flags)
2229 /* Test the value in the primary and set the condition codes */
2231 switch (flags & CF_TYPE) {
2234 if (flags & CF_FORCECHAR) {
2235 AddCodeLine ("tax");
2241 AddCodeLine ("stx tmp1");
2242 AddCodeLine ("ora tmp1");
2246 if (flags & CF_UNSIGNED) {
2247 AddCodeLine ("jsr utsteax");
2249 AddCodeLine ("jsr tsteax");
2261 void g_push (unsigned flags, unsigned long val)
2262 /* Push the primary register or a constant value onto the stack */
2266 if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2268 /* We have a constant 8 or 16 bit value */
2269 if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2271 /* Handle as 8 bit value */
2272 if (CodeSizeFactor >= 165 || val > 2) {
2274 AddCodeLine ("jsr pusha");
2276 AddCodeLine ("jsr pushc%d", (int) val);
2281 /* Handle as 16 bit value */
2282 hi = (unsigned char) (val >> 8);
2284 AddCodeLine ("jsr push%u", (unsigned) val);
2285 } else if (hi == 0 || hi == 0xFF) {
2286 /* Use special function */
2288 AddCodeLine ("jsr %s", (hi == 0)? "pusha0" : "pushaFF");
2291 g_getimmed (flags, val, 0);
2292 AddCodeLine ("jsr pushax");
2298 /* Value is not 16 bit or not constant */
2299 if (flags & CF_CONST) {
2300 /* Constant 32 bit value, load into eax */
2301 g_getimmed (flags, val, 0);
2304 /* Push the primary register */
2305 switch (flags & CF_TYPE) {
2308 if (flags & CF_FORCECHAR) {
2309 /* Handle as char */
2310 AddCodeLine ("jsr pusha");
2315 AddCodeLine ("jsr pushax");
2319 AddCodeLine ("jsr pusheax");
2329 /* Adjust the stack offset */
2335 void g_swap (unsigned flags)
2336 /* Swap the primary register and the top of the stack. flags give the type
2337 * of *both* values (must have same size).
2340 switch (flags & CF_TYPE) {
2344 AddCodeLine ("jsr swapstk");
2348 AddCodeLine ("jsr swapestk");
2359 void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2360 /* Call the specified subroutine name */
2362 if ((Flags & CF_FIXARGC) == 0) {
2363 /* Pass the argument count */
2366 AddCodeLine ("jsr _%s", Label);
2367 oursp += ArgSize; /* callee pops args */
2372 void g_callind (unsigned Flags, unsigned ArgSize)
2373 /* Call subroutine with address in AX */
2375 if ((Flags & CF_FIXARGC) == 0) {
2376 /* Pass arg count */
2379 AddCodeLine ("jsr callax"); /* do the call */
2380 oursp += ArgSize; /* callee pops args */
2385 void g_jump (unsigned Label)
2386 /* Jump to specified internal label number */
2388 AddCodeLine ("jmp %s", LocalLabelName (Label));
2393 void g_switch (unsigned Flags)
2394 /* Output switch statement preamble */
2396 switch (Flags & CF_TYPE) {
2400 AddCodeLine ("jsr switch");
2404 AddCodeLine ("jsr lswitch");
2415 void g_case (unsigned flags, unsigned label, unsigned long val)
2416 /* Create table code for one case selector */
2418 switch (flags & CF_TYPE) {
2422 AddCodeLine (".word $%04X, %s",
2423 (unsigned)(val & 0xFFFF),
2424 LocalLabelName (label));
2428 AddCodeLine (".dword $%08lX", val);
2429 AddCodeLine (".word %s", LocalLabelName (label));
2440 void g_truejump (unsigned flags, unsigned label)
2441 /* Jump to label if zero flag clear */
2443 AddCodeLine ("jne %s", LocalLabelName (label));
2448 void g_falsejump (unsigned flags, unsigned label)
2449 /* Jump to label if zero flag set */
2451 AddCodeLine ("jeq %s", LocalLabelName (label));
2456 static void mod_internal (int k, char* verb1, char* verb2)
2459 AddCodeLine ("jsr %ssp%c", verb1, k + '0');
2463 AddCodeLine ("jsr %ssp", verb2);
2469 void g_space (int space)
2470 /* Create or drop space on the stack */
2473 mod_internal (-space, "inc", "addy");
2474 } else if (space > 0) {
2475 mod_internal (space, "dec", "suby");
2481 void g_cstackcheck (void)
2482 /* Check for a C stack overflow */
2484 AddCodeLine ("jsr cstkchk");
2489 void g_stackcheck (void)
2490 /* Check for a stack overflow */
2492 AddCodeLine ("jsr stkchk");
2497 void g_add (unsigned flags, unsigned long val)
2498 /* Primary = TOS + Primary */
2500 static char* ops [12] = {
2501 0, "tosadda0", "tosaddax",
2502 0, "tosadda0", "tosaddax",
2507 if (flags & CF_CONST) {
2508 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2509 g_push (flags & ~CF_CONST, 0);
2511 oper (flags, val, ops);
2516 void g_sub (unsigned flags, unsigned long val)
2517 /* Primary = TOS - Primary */
2519 static char* ops [12] = {
2520 0, "tossuba0", "tossubax",
2521 0, "tossuba0", "tossubax",
2526 if (flags & CF_CONST) {
2527 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2528 g_push (flags & ~CF_CONST, 0);
2530 oper (flags, val, ops);
2535 void g_rsub (unsigned flags, unsigned long val)
2536 /* Primary = Primary - TOS */
2538 static char* ops [12] = {
2539 0, "tosrsuba0", "tosrsubax",
2540 0, "tosrsuba0", "tosrsubax",
2544 oper (flags, val, ops);
2549 void g_mul (unsigned flags, unsigned long val)
2550 /* Primary = TOS * Primary */
2552 static char* ops [12] = {
2553 0, "tosmula0", "tosmulax",
2554 0, "tosumula0", "tosumulax",
2561 /* Do strength reduction if the value is constant and a power of two */
2562 if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2563 /* Generate a shift instead */
2568 /* If the right hand side is const, the lhs is not on stack but still
2569 * in the primary register.
2571 if (flags & CF_CONST) {
2573 switch (flags & CF_TYPE) {
2576 if (flags & CF_FORCECHAR) {
2577 /* Handle some special cases */
2581 AddCodeLine ("sta tmp1");
2582 AddCodeLine ("asl a");
2583 AddCodeLine ("clc");
2584 AddCodeLine ("adc tmp1");
2588 AddCodeLine ("sta tmp1");
2589 AddCodeLine ("asl a");
2590 AddCodeLine ("asl a");
2591 AddCodeLine ("clc");
2592 AddCodeLine ("adc tmp1");
2596 AddCodeLine ("sta tmp1");
2597 AddCodeLine ("asl a");
2598 AddCodeLine ("asl a");
2599 AddCodeLine ("clc");
2600 AddCodeLine ("adc tmp1");
2601 AddCodeLine ("asl a");
2617 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2618 * into the normal, non-optimized stuff.
2620 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2621 g_push (flags & ~CF_CONST, 0);
2625 /* Use long way over the stack */
2626 oper (flags, val, ops);
2631 void g_div (unsigned flags, unsigned long val)
2632 /* Primary = TOS / Primary */
2634 static char* ops [12] = {
2635 0, "tosdiva0", "tosdivax",
2636 0, "tosudiva0", "tosudivax",
2641 /* Do strength reduction if the value is constant and a power of two */
2643 if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2644 /* Generate a shift instead */
2647 /* Generate a division */
2648 if (flags & CF_CONST) {
2649 /* lhs is not on stack */
2650 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2651 g_push (flags & ~CF_CONST, 0);
2653 oper (flags, val, ops);
2659 void g_mod (unsigned flags, unsigned long val)
2660 /* Primary = TOS % Primary */
2662 static char* ops [12] = {
2663 0, "tosmoda0", "tosmodax",
2664 0, "tosumoda0", "tosumodax",
2670 /* Check if we can do some cost reduction */
2671 if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2672 /* We can do that with an AND operation */
2673 g_and (flags, val - 1);
2675 /* Do it the hard way... */
2676 if (flags & CF_CONST) {
2677 /* lhs is not on stack */
2678 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2679 g_push (flags & ~CF_CONST, 0);
2681 oper (flags, val, ops);
2687 void g_or (unsigned flags, unsigned long val)
2688 /* Primary = TOS | Primary */
2690 static char* ops [12] = {
2691 0, "tosora0", "tosorax",
2692 0, "tosora0", "tosorax",
2697 /* If the right hand side is const, the lhs is not on stack but still
2698 * in the primary register.
2700 if (flags & CF_CONST) {
2702 switch (flags & CF_TYPE) {
2705 if (flags & CF_FORCECHAR) {
2706 if ((val & 0xFF) != 0xFF) {
2707 AddCodeLine ("ora #$%02X", (unsigned char)val);
2715 AddCodeLine ("ora #$%02X", (unsigned char)val);
2722 AddCodeLine ("ora #$%02X", (unsigned char)val);
2731 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2732 * into the normal, non-optimized stuff.
2734 g_push (flags & ~CF_CONST, 0);
2738 /* Use long way over the stack */
2739 oper (flags, val, ops);
2744 void g_xor (unsigned flags, unsigned long val)
2745 /* Primary = TOS ^ Primary */
2747 static char* ops [12] = {
2748 0, "tosxora0", "tosxorax",
2749 0, "tosxora0", "tosxorax",
2755 /* If the right hand side is const, the lhs is not on stack but still
2756 * in the primary register.
2758 if (flags & CF_CONST) {
2760 switch (flags & CF_TYPE) {
2763 if (flags & CF_FORCECHAR) {
2764 if ((val & 0xFF) != 0) {
2765 AddCodeLine ("eor #$%02X", (unsigned char)val);
2774 AddCodeLine ("eor #$%02X", (unsigned char)val);
2777 } else if ((val & 0xFF) == 0) {
2778 AddCodeLine ("pha");
2779 AddCodeLine ("txa");
2780 AddCodeLine ("eor #$%02X", (unsigned char)(val >> 8));
2781 AddCodeLine ("tax");
2782 AddCodeLine ("pla");
2790 AddCodeLine ("eor #$%02X", (unsigned char)val);
2800 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2801 * into the normal, non-optimized stuff.
2803 g_push (flags & ~CF_CONST, 0);
2807 /* Use long way over the stack */
2808 oper (flags, val, ops);
2813 void g_and (unsigned flags, unsigned long val)
2814 /* Primary = TOS & Primary */
2816 static char* ops [12] = {
2817 0, "tosanda0", "tosandax",
2818 0, "tosanda0", "tosandax",
2823 /* If the right hand side is const, the lhs is not on stack but still
2824 * in the primary register.
2826 if (flags & CF_CONST) {
2828 switch (flags & CF_TYPE) {
2831 if (flags & CF_FORCECHAR) {
2832 AddCodeLine ("and #$%02X", (unsigned char)val);
2837 if ((val & 0xFFFF) != 0xFFFF) {
2842 } else if (val != 0xFF) {
2843 AddCodeLine ("and #$%02X", (unsigned char)val);
2845 } else if ((val & 0xFF00) == 0xFF00) {
2846 AddCodeLine ("and #$%02X", (unsigned char)val);
2847 } else if ((val & 0x00FF) == 0x0000) {
2848 AddCodeLine ("txa");
2849 AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2850 AddCodeLine ("tax");
2853 AddCodeLine ("tay");
2854 AddCodeLine ("txa");
2855 AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2856 AddCodeLine ("tax");
2857 AddCodeLine ("tya");
2858 if ((val & 0x00FF) != 0x00FF) {
2859 AddCodeLine ("and #$%02X", (unsigned char)val);
2868 AddCodeLine ("stx sreg+1");
2869 AddCodeLine ("stx sreg");
2870 if ((val & 0xFF) != 0xFF) {
2871 AddCodeLine ("and #$%02X", (unsigned char)val);
2874 } else if (val == 0xFF00) {
2876 AddCodeLine ("sta sreg+1");
2877 AddCodeLine ("sta sreg");
2886 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2887 * into the normal, non-optimized stuff.
2889 g_push (flags & ~CF_CONST, 0);
2893 /* Use long way over the stack */
2894 oper (flags, val, ops);
2899 void g_asr (unsigned flags, unsigned long val)
2900 /* Primary = TOS >> Primary */
2902 static char* ops [12] = {
2903 0, "tosasra0", "tosasrax",
2904 0, "tosshra0", "tosshrax",
2909 /* If the right hand side is const, the lhs is not on stack but still
2910 * in the primary register.
2912 if (flags & CF_CONST) {
2914 switch (flags & CF_TYPE) {
2918 if (val >= 1 && val <= 3) {
2919 if (flags & CF_UNSIGNED) {
2920 AddCodeLine ("jsr shrax%ld", val);
2922 AddCodeLine ("jsr asrax%ld", val);
2925 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2926 AddCodeLine ("txa");
2933 if (val >= 1 && val <= 3) {
2934 if (flags & CF_UNSIGNED) {
2935 AddCodeLine ("jsr shreax%ld", val);
2937 AddCodeLine ("jsr asreax%ld", val);
2940 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2941 AddCodeLine ("txa");
2942 AddCodeLine ("ldx sreg");
2943 AddCodeLine ("ldy sreg+1");
2944 AddCodeLine ("sty sreg");
2945 AddCodeLine ("ldy #$00");
2946 AddCodeLine ("sty sreg+1");
2948 } else if (val == 16) {
2949 AddCodeLine ("ldy #$00");
2950 AddCodeLine ("ldx sreg+1");
2951 if ((flags & CF_UNSIGNED) == 0) {
2952 AddCodeLine ("bpl *+3");
2953 AddCodeLine ("dey");
2954 AddCodeHint ("y:!");
2956 AddCodeLine ("lda sreg");
2957 AddCodeLine ("sty sreg+1");
2958 AddCodeLine ("sty sreg");
2967 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2968 * into the normal, non-optimized stuff.
2970 g_push (flags & ~CF_CONST, 0);
2974 /* Use long way over the stack */
2975 oper (flags, val, ops);
2980 void g_asl (unsigned flags, unsigned long val)
2981 /* Primary = TOS << Primary */
2983 static char* ops [12] = {
2984 0, "tosasla0", "tosaslax",
2985 0, "tosshla0", "tosshlax",
2991 /* If the right hand side is const, the lhs is not on stack but still
2992 * in the primary register.
2994 if (flags & CF_CONST) {
2996 switch (flags & CF_TYPE) {
3000 if (val >= 1 && val <= 3) {
3001 if (flags & CF_UNSIGNED) {
3002 AddCodeLine ("jsr shlax%ld", val);
3004 AddCodeLine ("jsr aslax%ld", val);
3007 } else if (val == 8) {
3008 AddCodeLine ("tax");
3009 AddCodeLine ("lda #$00");
3015 if (val >= 1 && val <= 3) {
3016 if (flags & CF_UNSIGNED) {
3017 AddCodeLine ("jsr shleax%ld", val);
3019 AddCodeLine ("jsr asleax%ld", val);
3022 } else if (val == 8) {
3023 AddCodeLine ("ldy sreg");
3024 AddCodeLine ("sty sreg+1");
3025 AddCodeLine ("stx sreg");
3026 AddCodeLine ("tax");
3027 AddCodeLine ("lda #$00");
3029 } else if (val == 16) {
3030 AddCodeLine ("stx sreg+1");
3031 AddCodeLine ("sta sreg");
3032 AddCodeLine ("lda #$00");
3033 AddCodeLine ("tax");
3042 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3043 * into the normal, non-optimized stuff.
3045 g_push (flags & ~CF_CONST, 0);
3049 /* Use long way over the stack */
3050 oper (flags, val, ops);
3055 void g_neg (unsigned flags)
3056 /* Primary = -Primary */
3058 switch (flags & CF_TYPE) {
3062 AddCodeLine ("jsr negax");
3066 AddCodeLine ("jsr negeax");
3076 void g_bneg (unsigned flags)
3077 /* Primary = !Primary */
3079 switch (flags & CF_TYPE) {
3082 AddCodeLine ("jsr bnega");
3086 AddCodeLine ("jsr bnegax");
3090 AddCodeLine ("jsr bnegeax");
3100 void g_com (unsigned flags)
3101 /* Primary = ~Primary */
3103 switch (flags & CF_TYPE) {
3107 AddCodeLine ("jsr complax");
3111 AddCodeLine ("jsr compleax");
3121 void g_inc (unsigned flags, unsigned long val)
3122 /* Increment the primary register by a given number */
3124 /* Don't inc by zero */
3129 /* Generate code for the supported types */
3131 switch (flags & CF_TYPE) {
3134 if (flags & CF_FORCECHAR) {
3135 if (CPU == CPU_65C02 && val <= 2) {
3137 AddCodeLine ("ina");
3140 AddCodeLine ("clc");
3141 AddCodeLine ("adc #$%02X", (unsigned char)val);
3148 if (CPU == CPU_65C02 && val == 1) {
3149 AddCodeLine ("ina");
3150 AddCodeLine ("bne *+3");
3151 AddCodeLine ("inx");
3152 /* Tell the optimizer that the X register may be invalid */
3153 AddCodeHint ("x:!");
3154 } else if (CodeSizeFactor < 200) {
3157 AddCodeLine ("jsr incax%lu", val);
3158 } else if (val <= 255) {
3160 AddCodeLine ("jsr incaxy");
3162 g_add (flags | CF_CONST, val);
3165 /* Inline the code */
3167 if ((val & 0xFF) != 0) {
3168 AddCodeLine ("clc");
3169 AddCodeLine ("adc #$%02X", (unsigned char) val);
3170 AddCodeLine ("bcc *+3");
3171 AddCodeLine ("inx");
3172 /* Tell the optimizer that the X register may be invalid */
3173 AddCodeHint ("x:!");
3176 AddCodeLine ("inx");
3179 AddCodeLine ("inx");
3182 AddCodeLine ("clc");
3183 if ((val & 0xFF) != 0) {
3184 AddCodeLine ("adc #$%02X", (unsigned char) val);
3185 /* Tell the optimizer that the X register may be invalid */
3186 AddCodeHint ("x:!");
3188 AddCodeLine ("pha");
3189 AddCodeLine ("txa");
3190 AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3191 AddCodeLine ("tax");
3192 AddCodeLine ("pla");
3200 AddCodeLine ("jsr inceaxy");
3202 g_add (flags | CF_CONST, val);
3214 void g_dec (unsigned flags, unsigned long val)
3215 /* Decrement the primary register by a given number */
3217 /* Don't dec by zero */
3222 /* Generate code for the supported types */
3224 switch (flags & CF_TYPE) {
3227 if (flags & CF_FORCECHAR) {
3228 if (CPU == CPU_65C02 && val <= 2) {
3230 AddCodeLine ("dea");
3233 AddCodeLine ("sec");
3234 AddCodeLine ("sbc #$%02X", (unsigned char)val);
3241 if (CodeSizeFactor < 200) {
3242 /* Use subroutines */
3244 AddCodeLine ("jsr decax%d", (int) val);
3245 } else if (val <= 255) {
3247 AddCodeLine ("jsr decaxy");
3249 g_sub (flags | CF_CONST, val);
3252 /* Inline the code */
3254 if ((val & 0xFF) != 0) {
3255 AddCodeLine ("sec");
3256 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3257 AddCodeLine ("bcs *+3");
3258 AddCodeLine ("dex");
3259 /* Tell the optimizer that the X register may be invalid */
3260 AddCodeHint ("x:!");
3263 AddCodeLine ("dex");
3266 AddCodeLine ("dex");
3269 AddCodeLine ("sec");
3270 if ((val & 0xFF) != 0) {
3271 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3272 /* Tell the optimizer that the X register may be invalid */
3273 AddCodeHint ("x:!");
3275 AddCodeLine ("pha");
3276 AddCodeLine ("txa");
3277 AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3278 AddCodeLine ("tax");
3279 AddCodeLine ("pla");
3287 AddCodeLine ("jsr deceaxy");
3289 g_sub (flags | CF_CONST, val);
3302 * Following are the conditional operators. They compare the TOS against
3303 * the primary and put a literal 1 in the primary if the condition is
3304 * true, otherwise they clear the primary register
3309 void g_eq (unsigned flags, unsigned long val)
3310 /* Test for equal */
3312 static char* ops [12] = {
3313 "toseq00", "toseqa0", "toseqax",
3314 "toseq00", "toseqa0", "toseqax",
3319 /* If the right hand side is const, the lhs is not on stack but still
3320 * in the primary register.
3322 if (flags & CF_CONST) {
3324 switch (flags & CF_TYPE) {
3327 if (flags & CF_FORCECHAR) {
3328 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3329 AddCodeLine ("jsr booleq");
3335 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3336 AddCodeLine ("bne *+4");
3337 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3338 AddCodeLine ("jsr booleq");
3348 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3349 * into the normal, non-optimized stuff.
3351 g_push (flags & ~CF_CONST, 0);
3355 /* Use long way over the stack */
3356 oper (flags, val, ops);
3361 void g_ne (unsigned flags, unsigned long val)
3362 /* Test for not equal */
3364 static char* ops [12] = {
3365 "tosne00", "tosnea0", "tosneax",
3366 "tosne00", "tosnea0", "tosneax",
3372 /* If the right hand side is const, the lhs is not on stack but still
3373 * in the primary register.
3375 if (flags & CF_CONST) {
3377 switch (flags & CF_TYPE) {
3380 if (flags & CF_FORCECHAR) {
3381 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3382 AddCodeLine ("jsr boolne");
3388 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3389 AddCodeLine ("bne *+4");
3390 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3391 AddCodeLine ("jsr boolne");
3401 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3402 * into the normal, non-optimized stuff.
3404 g_push (flags & ~CF_CONST, 0);
3408 /* Use long way over the stack */
3409 oper (flags, val, ops);
3414 void g_lt (unsigned flags, unsigned long val)
3415 /* Test for less than */
3417 static char* ops [12] = {
3418 "toslt00", "toslta0", "tosltax",
3419 "tosult00", "tosulta0", "tosultax",
3424 /* If the right hand side is const, the lhs is not on stack but still
3425 * in the primary register.
3427 if (flags & CF_CONST) {
3429 /* Give a warning in some special cases */
3430 if ((flags & CF_UNSIGNED) && val == 0) {
3431 Warning ("Condition is never true");
3434 /* Look at the type */
3435 switch (flags & CF_TYPE) {
3438 if (flags & CF_FORCECHAR) {
3439 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3440 if (flags & CF_UNSIGNED) {
3441 AddCodeLine ("jsr boolult");
3443 AddCodeLine ("jsr boollt");
3450 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3451 /* If we have a signed compare against zero, we only need to
3452 * test the high byte.
3454 AddCodeLine ("txa");
3455 AddCodeLine ("jsr boollt");
3458 /* Direct code only for unsigned data types */
3459 if (flags & CF_UNSIGNED) {
3460 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3461 AddCodeLine ("bne *+4");
3462 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3463 AddCodeLine ("jsr boolult");
3469 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3470 /* If we have a signed compare against zero, we only need to
3471 * test the high byte.
3473 AddCodeLine ("lda sreg+1");
3474 AddCodeLine ("jsr boollt");
3483 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3484 * into the normal, non-optimized stuff.
3486 g_push (flags & ~CF_CONST, 0);
3490 /* Use long way over the stack */
3491 oper (flags, val, ops);
3496 void g_le (unsigned flags, unsigned long val)
3497 /* Test for less than or equal to */
3499 static char* ops [12] = {
3500 "tosle00", "toslea0", "tosleax",
3501 "tosule00", "tosulea0", "tosuleax",
3507 /* If the right hand side is const, the lhs is not on stack but still
3508 * in the primary register.
3510 if (flags & CF_CONST) {
3512 /* Look at the type */
3513 switch (flags & CF_TYPE) {
3516 if (flags & CF_FORCECHAR) {
3517 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3518 if (flags & CF_UNSIGNED) {
3519 AddCodeLine ("jsr boolule");
3521 AddCodeLine ("jsr boolle");
3528 if (flags & CF_UNSIGNED) {
3529 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3530 AddCodeLine ("bne *+4");
3531 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3532 AddCodeLine ("jsr boolule");
3544 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3545 * into the normal, non-optimized stuff.
3547 g_push (flags & ~CF_CONST, 0);
3551 /* Use long way over the stack */
3552 oper (flags, val, ops);
3557 void g_gt (unsigned flags, unsigned long val)
3558 /* Test for greater than */
3560 static char* ops [12] = {
3561 "tosgt00", "tosgta0", "tosgtax",
3562 "tosugt00", "tosugta0", "tosugtax",
3568 /* If the right hand side is const, the lhs is not on stack but still
3569 * in the primary register.
3571 if (flags & CF_CONST) {
3573 /* Look at the type */
3574 switch (flags & CF_TYPE) {
3577 if (flags & CF_FORCECHAR) {
3578 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3579 if (flags & CF_UNSIGNED) {
3580 /* If we have a compare > 0, we will replace it by
3581 * != 0 here, since both are identical but the latter
3582 * is easier to optimize.
3585 AddCodeLine ("jsr boolugt");
3587 AddCodeLine ("jsr boolne");
3590 AddCodeLine ("jsr boolgt");
3597 if (flags & CF_UNSIGNED) {
3598 /* If we have a compare > 0, we will replace it by
3599 * != 0 here, since both are identical but the latter
3600 * is easier to optimize.
3602 if ((val & 0xFFFF) == 0) {
3603 AddCodeLine ("stx tmp1");
3604 AddCodeLine ("ora tmp1");
3605 AddCodeLine ("jsr boolne");
3607 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3608 AddCodeLine ("bne *+4");
3609 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3610 AddCodeLine ("jsr boolugt");
3623 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3624 * into the normal, non-optimized stuff.
3626 g_push (flags & ~CF_CONST, 0);
3630 /* Use long way over the stack */
3631 oper (flags, val, ops);
3636 void g_ge (unsigned flags, unsigned long val)
3637 /* Test for greater than or equal to */
3639 static char* ops [12] = {
3640 "tosge00", "tosgea0", "tosgeax",
3641 "tosuge00", "tosugea0", "tosugeax",
3647 /* If the right hand side is const, the lhs is not on stack but still
3648 * in the primary register.
3650 if (flags & CF_CONST) {
3652 /* Give a warning in some special cases */
3653 if ((flags & CF_UNSIGNED) && val == 0) {
3654 Warning ("Condition is always true");
3657 /* Look at the type */
3658 switch (flags & CF_TYPE) {
3661 if (flags & CF_FORCECHAR) {
3662 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3663 if (flags & CF_UNSIGNED) {
3664 AddCodeLine ("jsr booluge");
3666 AddCodeLine ("jsr boolge");
3673 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3674 /* If we have a signed compare against zero, we only need to
3675 * test the high byte.
3677 AddCodeLine ("txa");
3678 AddCodeLine ("jsr boolge");
3681 /* Direct code only for unsigned data types */
3682 if (flags & CF_UNSIGNED) {
3683 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3684 AddCodeLine ("bne *+4");
3685 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3686 AddCodeLine ("jsr booluge");
3692 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3693 /* If we have a signed compare against zero, we only need to
3694 * test the high byte.
3696 AddCodeLine ("lda sreg+1");
3697 AddCodeLine ("jsr boolge");
3706 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3707 * into the normal, non-optimized stuff.
3709 g_push (flags & ~CF_CONST, 0);
3713 /* Use long way over the stack */
3714 oper (flags, val, ops);
3719 /*****************************************************************************/
3720 /* Allocating static storage */
3721 /*****************************************************************************/
3725 void g_res (unsigned n)
3726 /* Reserve static storage, n bytes */
3728 AddDataLine ("\t.res\t%u,$00", n);
3733 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3734 /* Define data with the size given in flags */
3736 if (flags & CF_CONST) {
3738 /* Numeric constant */
3739 switch (flags & CF_TYPE) {
3742 AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
3746 AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
3750 AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
3761 /* Create the correct label name */
3762 const char* Label = GetLabelName (flags, val, offs);
3764 /* Labels are always 16 bit */
3765 AddDataLine ("\t.word\t%s", Label);
3772 void g_defbytes (const void* Bytes, unsigned Count)
3773 /* Output a row of bytes as a constant */
3779 /* Cast the buffer pointer */
3780 const unsigned char* Data = (const unsigned char*) Bytes;
3782 /* Output the stuff */
3785 /* How many go into this line? */
3786 if ((Chunk = Count) > 16) {
3791 /* Output one line */
3792 strcpy (Buf, "\t.byte\t");
3795 B += sprintf (B, "$%02X", *Data++);
3801 /* Output the line */
3808 void g_zerobytes (unsigned n)
3809 /* Output n bytes of data initialized with zero */
3811 AddDataLine ("\t.res\t%u,$00", n);
3816 /*****************************************************************************/
3817 /* User supplied assembler code */
3818 /*****************************************************************************/
3822 void g_asmcode (const char* Line, int Len)
3823 /* Output one line of assembler code. If Len is greater than zero, it is used
3824 * as the maximum number of characters to use from Line.
3828 AddCodeLine ("%.*s", Len, Line);
3830 AddCodeLine ("%s", Line);
3836 /*****************************************************************************/
3837 /* Inlined known functions */
3838 /*****************************************************************************/
3842 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3843 /* Inline the strlen() function */
3845 /* We need a label in both cases */
3846 unsigned label = GetLocalLabel ();
3848 /* Two different encodings */
3849 if (flags & CF_CONST) {
3851 /* The address of the string is constant. Create the correct label name */
3852 char* lbuf = GetLabelName (flags, val, offs);
3854 /* Generate the strlen code */
3855 AddCodeLine ("ldy #$FF");
3856 g_defcodelabel (label);
3857 AddCodeLine ("iny");
3858 AddCodeLine ("lda %s,y", lbuf);
3859 AddCodeLine ("bne %s", LocalLabelName (label));
3860 AddCodeLine ("tax");
3861 AddCodeLine ("tya");
3865 /* Address not constant but in primary */
3866 if (CodeSizeFactor < 400) {
3867 /* This is too much code, so call strlen instead of inlining */
3868 AddCodeLine ("jsr _strlen");
3870 /* Inline the function */
3871 AddCodeLine ("sta ptr1");
3872 AddCodeLine ("stx ptr1+1");
3873 AddCodeLine ("ldy #$FF");
3874 g_defcodelabel (label);
3875 AddCodeLine ("iny");
3876 AddCodeLine ("lda (ptr1),y");
3877 AddCodeLine ("bne %s", LocalLabelName (label));
3878 AddCodeLine ("tax");
3879 AddCodeLine ("tya");