1 /*****************************************************************************/
5 /* 6502 code generator */
9 /* (C) 1998-2001 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
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 /*****************************************************************************/
53 /* ### #include "optimize.h" */
60 /*****************************************************************************/
62 /*****************************************************************************/
66 /* Compiler relative stack pointer */
74 segment_t CurSeg = SEG_INV;
78 /*****************************************************************************/
80 /*****************************************************************************/
84 static void AddCodeLine (const char* Format, ...)
88 va_start (ap, Format);
89 xvsprintf (Buf, sizeof (Buf), Format, ap);
91 if (CurSeg == SEG_CODE) {
92 AddCodeSegLine (CS, "%s", Buf);
94 AddDataSegLine (DS, "%s", Buf);
100 static void typeerror (unsigned type)
101 /* Print an error message about an invalid operand type */
103 Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPE);
108 static void CheckLocalOffs (unsigned Offs)
109 /* Check the offset into the stack for 8bit range */
112 /* Too many local vars */
113 AddCodeLine (";*** Too many locals");
114 Error ("Too many local variables");
120 static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs)
122 static char lbuf [128]; /* Label name */
124 /* Create the correct label name */
125 switch (flags & CF_ADDRMASK) {
128 /* Static memory cell */
129 sprintf (lbuf, "L%04X+%u", (unsigned)(label & 0xFFFF), offs);
134 sprintf (lbuf, "_%s+%u", (char*) label, offs);
138 /* Absolute address */
139 sprintf (lbuf, "$%04X", (unsigned)((label+offs) & 0xFFFF));
143 /* Variable in register bank */
144 sprintf (lbuf, "regbank+%u", (unsigned)((label+offs) & 0xFFFF));
148 Internal ("Invalid address flags");
151 /* Return a pointer to the static buffer */
157 /*****************************************************************************/
158 /* Pre- and postamble */
159 /*****************************************************************************/
163 void g_preamble (void)
164 /* Generate the assembler code preamble */
167 CS = NewCodeSeg ("CODE");
170 AddCodeLine ("; File generated by cc65 v %u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
172 /* Insert some object file options */
173 AddCodeLine (".fopt\t\tcompiler,\"cc65 v %u.%u.%u\"", VER_MAJOR, VER_MINOR, VER_PATCH);
175 /* If we're producing code for some other CPU, switch the command set */
176 if (CPU == CPU_65C02) {
177 AddCodeLine (".pc02");
180 /* Allow auto import for runtime library routines */
181 AddCodeLine (".autoimport\ton");
183 /* Switch the assembler into case sensitive mode */
184 AddCodeLine (".case\t\ton");
186 /* Tell the assembler if we want to generate debug info */
187 AddCodeLine (".debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
189 /* Import the stack pointer for direct auto variable access */
190 AddCodeLine (".importzp\tsp, sreg, regsave, regbank, tmp1, ptr1");
192 /* Define long branch macros */
193 AddCodeLine (".macpack\tlongbranch");
195 /* Tell the optimizer that this is the end of the preamble */
196 AddCodeHint ("end_of_preamble");
201 void g_postamble (void)
202 /* Generate assembler code postamble */
204 /* Tell the optimizer that this is the start of the postamble */
205 AddCodeHint ("start_of_postamble");
210 /*****************************************************************************/
211 /* Segment support */
212 /*****************************************************************************/
216 static void UseSeg (int NewSeg)
217 /* Switch to a specific segment */
219 if (CurSeg != NewSeg) {
220 CurSeg = (segment_t) NewSeg;
221 if (CurSeg != SEG_CODE) {
222 AddCodeLine (".segment\t\"%s\"", SegmentNames [CurSeg]);
229 void g_usecode (void)
230 /* Switch to the code segment */
237 void g_userodata (void)
238 /* Switch to the read only data segment */
245 void g_usedata (void)
246 /* Switch to the data segment */
254 /* Switch to the bss segment */
261 static void SegName (segment_t Seg, const char* Name)
262 /* Set the name of a segment */
264 /* Free the old name and set a new one */
265 NewSegName (Seg, Name);
267 /* If the new segment is the current segment, emit a segment directive
271 CurSeg = SEG_INV; /* Invalidate */
278 void g_codename (const char* Name)
279 /* Set the name of the CODE segment */
281 SegName (SEG_CODE, Name);
286 void g_rodataname (const char* Name)
287 /* Set the name of the RODATA segment */
289 SegName (SEG_RODATA, Name);
294 void g_dataname (const char* Name)
295 /* Set the name of the DATA segment */
297 SegName (SEG_DATA, Name);
302 void g_bssname (const char* Name)
303 /* Set the name of the BSS segment */
305 SegName (SEG_BSS, Name);
310 /*****************************************************************************/
312 /*****************************************************************************/
316 unsigned sizeofarg (unsigned flags)
317 /* Return the size of a function argument type that is encoded in flags */
319 switch (flags & CF_TYPE) {
322 return (flags & CF_FORCECHAR)? 1 : 2;
339 int pop (unsigned flags)
340 /* Pop an argument of the given size */
342 return oursp += sizeofarg (flags);
347 int push (unsigned flags)
348 /* Push an argument of the given size */
350 return oursp -= sizeofarg (flags);
355 static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
356 /* The value in Offs is an offset to an address in a/x. Make sure, an object
357 * of the type given in Flags can be loaded or stored into this address by
358 * adding part of the offset to the address in ax, so that the remaining
359 * offset fits into an index register. Return the remaining offset.
362 /* If the offset is too large for a byte register, add the high byte
363 * of the offset to the primary. Beware: We need a special correction
364 * if the offset in the low byte will overflow in the operation.
366 unsigned O = Offs & ~0xFFU;
367 if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
368 /* We need to add the low byte also */
372 /* Do the correction if we need one */
374 g_inc (CF_INT | CF_CONST, O);
378 /* Return the new offset */
384 /*****************************************************************************/
385 /* Functions handling local labels */
386 /*****************************************************************************/
390 void g_defloclabel (unsigned label)
391 /* Define a local label */
393 if (CurSeg == SEG_CODE) {
394 AddCodeSegLabel (CS, LocalLabelName (label));
396 AddDataSegLine (DS, "%s:", LocalLabelName (label));
402 /*****************************************************************************/
403 /* Functions handling global labels */
404 /*****************************************************************************/
408 void g_defgloblabel (const char* Name)
409 /* Define a global label with the given name */
411 if (CurSeg == SEG_CODE) {
414 xsprintf (Buf, sizeof (Buf), "_%s", Name);
415 AddCodeSegLabel (CS, Buf);
417 AddDataSegLine (DS, "_%s:", Name);
423 void g_defexport (const char* Name, int ZP)
424 /* Export the given label */
427 AddDataSegLine (DS, "\t.exportzp\t_%s", Name);
429 AddDataSegLine (DS, "\t.export\t\t_%s", Name);
435 void g_defimport (const char* Name, int ZP)
436 /* Import the given label */
439 AddDataSegLine (DS, "\t.importzp\t_%s", Name);
441 AddDataSegLine (DS, "\t.import\t\t_%s", Name);
447 /*****************************************************************************/
448 /* Load functions for various registers */
449 /*****************************************************************************/
453 static void ldaconst (unsigned val)
454 /* Load a with a constant */
456 AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
461 static void ldxconst (unsigned val)
462 /* Load x with a constant */
464 AddCodeLine ("\tldx\t#$%02X", val & 0xFF);
469 static void ldyconst (unsigned val)
470 /* Load y with a constant */
472 AddCodeLine ("\tldy\t#$%02X", val & 0xFF);
477 /*****************************************************************************/
478 /* Function entry and exit */
479 /*****************************************************************************/
483 /* Remember the argument size of a function. The variable is set by g_enter
484 * and used by g_leave. If the functions gets its argument size by the caller
485 * (variable param list or function without prototype), g_enter will set the
491 void g_enter (unsigned flags, unsigned argsize)
492 /* Function prologue */
494 if ((flags & CF_FIXARGC) != 0) {
495 /* Just remember the argument size for the leave */
499 AddCodeLine ("\tjsr\tenter");
505 void g_leave (int flags, int val)
506 /* Function epilogue */
511 /* CF_REG is set if we're returning a value from the function */
512 if ((flags & CF_REG) == 0) {
517 /* How many bytes of locals do we have to drop? */
520 /* If we didn't have a variable argument list, don't call leave */
523 /* Load a function return code if needed */
524 if ((flags & CF_CONST) != 0) {
525 g_getimmed (flags, val, 0);
528 /* Drop stackframe or leave with rts */
531 AddCodeHint ("y:-"); /* Y register no longer used */
532 AddCodeLine ("\trts");
534 AddCodeHint ("y:-"); /* Y register no longer used */
535 AddCodeLine ("\tjmp\tincsp%d", k);
539 AddCodeLine ("\tjmp\taddysp");
544 strcpy (buf, "\tjmp\tleave");
546 /* We've a stack frame to drop */
550 /* Y register no longer used */
553 if (flags & CF_CONST) {
554 if ((flags & CF_TYPE) != CF_LONG) {
555 /* Constant int sized value given for return code */
557 /* Special case: return 0 */
559 } else if (((val >> 8) & 0xFF) == 0) {
560 /* Special case: constant with high byte zero */
561 ldaconst (val); /* Load low byte */
564 /* Others: arbitrary constant value */
565 g_getimmed (flags, val, 0); /* Load value */
568 /* Constant long value: No shortcut possible */
569 g_getimmed (flags, val, 0);
573 /* Output the jump */
580 /*****************************************************************************/
581 /* Register variables */
582 /*****************************************************************************/
586 void g_save_regvars (int RegOffs, unsigned Bytes)
587 /* Save register variables */
589 /* Don't loop for up to two bytes */
592 AddCodeLine ("\tlda\tregbank%+d", RegOffs);
593 AddCodeLine ("\tjsr\tpusha");
595 } else if (Bytes == 2) {
597 AddCodeLine ("\tlda\tregbank%+d", RegOffs);
598 AddCodeLine ("\tldx\tregbank%+d", RegOffs+1);
599 AddCodeLine ("\tjsr\tpushax");
603 /* More than two bytes - loop */
604 unsigned Label = GetLocalLabel ();
606 ldyconst (Bytes - 1);
608 g_defloclabel (Label);
609 AddCodeLine ("\tlda\tregbank%+d,x", RegOffs-1);
610 AddCodeLine ("\tsta\t(sp),y");
611 AddCodeLine ("\tdey");
612 AddCodeLine ("\tdex");
613 AddCodeLine ("\tbne\tL%04X", Label);
617 /* We pushed stuff, correct the stack pointer */
623 void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
624 /* Restore register variables */
626 /* Calculate the actual stack offset and check it */
628 CheckLocalOffs (StackOffs);
630 /* Don't loop for up to two bytes */
633 ldyconst (StackOffs);
634 AddCodeLine ("\tlda\t(sp),y");
635 AddCodeLine ("\tsta\tregbank%+d", RegOffs);
637 } else if (Bytes == 2) {
639 ldyconst (StackOffs);
640 AddCodeLine ("\tlda\t(sp),y");
641 AddCodeLine ("\tsta\tregbank%+d", RegOffs);
642 AddCodeLine ("\tiny");
643 AddCodeLine ("\tlda\t(sp),y");
644 AddCodeLine ("\tsta\tregbank%+d", RegOffs+1);
648 /* More than two bytes - loop */
649 unsigned Label = GetLocalLabel ();
650 ldyconst (StackOffs+Bytes-1);
652 g_defloclabel (Label);
653 AddCodeLine ("\tlda\t(sp),y");
654 AddCodeLine ("\tsta\tregbank%+d,x", RegOffs-1);
655 AddCodeLine ("\tdey");
656 AddCodeLine ("\tdex");
657 AddCodeLine ("\tbne\tL%04X", Label);
664 /*****************************************************************************/
665 /* Fetching memory cells */
666 /*****************************************************************************/
670 void g_getimmed (unsigned flags, unsigned long val, unsigned offs)
671 /* Load a constant into the primary register */
673 if ((flags & CF_CONST) != 0) {
675 /* Numeric constant */
676 switch (flags & CF_TYPE) {
679 if ((flags & CF_FORCECHAR) != 0) {
685 ldxconst ((val >> 8) & 0xFF);
686 ldaconst (val & 0xFF);
691 AddCodeLine ("\tldx\t#$00");
692 AddCodeLine ("\tstx\tsreg+1");
693 AddCodeLine ("\tstx\tsreg");
694 AddCodeLine ("\tlda\t#$%02X", (unsigned char) val);
695 } else if ((val & 0xFFFF00FF) == 0) {
696 AddCodeLine ("\tlda\t#$00");
697 AddCodeLine ("\tsta\tsreg+1");
698 AddCodeLine ("\tsta\tsreg");
699 AddCodeLine ("\tldx\t#$%02X", (unsigned char) (val >> 8));
700 } else if ((val & 0xFFFF0000) == 0 && CodeSizeFactor > 140) {
701 AddCodeLine ("\tlda\t#$00");
702 AddCodeLine ("\tsta\tsreg+1");
703 AddCodeLine ("\tsta\tsreg");
704 AddCodeLine ("\tlda\t#$%02X", (unsigned char) val);
705 AddCodeLine ("\tldx\t#$%02X", (unsigned char) (val >> 8));
706 } else if ((val & 0xFFFFFF00) == 0xFFFFFF00) {
707 AddCodeLine ("\tldx\t#$FF");
708 AddCodeLine ("\tstx\tsreg+1");
709 AddCodeLine ("\tstx\tsreg");
710 if ((val & 0xFF) == 0xFF) {
711 AddCodeLine ("\ttxa");
713 AddCodeLine ("\tlda\t#$%02X", (unsigned char) val);
715 } else if ((val & 0xFFFF00FF) == 0xFFFF00FF) {
716 AddCodeLine ("\tlda\t#$FF");
717 AddCodeLine ("\tsta\tsreg+1");
718 AddCodeLine ("\tsta\tsreg");
719 AddCodeLine ("\tldx\t#$%02X", (unsigned char) (val >> 8));
721 /* Call a subroutine that will load following value */
722 AddCodeLine ("\tjsr\tldeax");
723 AddCodeLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
735 /* Some sort of label */
736 const char* Label = GetLabelName (flags, val, offs);
738 /* Load the address into the primary */
739 AddCodeLine ("\tlda\t#<(%s)", Label);
740 AddCodeLine ("\tldx\t#>(%s)", Label);
747 void g_getstatic (unsigned flags, unsigned long label, unsigned offs)
748 /* Fetch an static memory cell into the primary register */
750 /* Create the correct label name */
751 char* lbuf = GetLabelName (flags, label, offs);
753 /* Check the size and generate the correct load operation */
754 switch (flags & CF_TYPE) {
757 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
758 AddCodeLine ("\tlda\t%s", lbuf); /* load A from the label */
761 AddCodeLine ("\tlda\t%s", lbuf); /* load A from the label */
762 if (!(flags & CF_UNSIGNED)) {
763 /* Must sign extend */
764 AddCodeLine ("\tbpl\t*+3");
765 AddCodeLine ("\tdex");
766 AddCodeHint ("x:!"); /* X is invalid now */
772 AddCodeLine ("\tlda\t%s", lbuf);
773 if (flags & CF_TEST) {
774 AddCodeLine ("\tora\t%s+1", lbuf);
776 AddCodeLine ("\tldx\t%s+1", lbuf);
781 if (flags & CF_TEST) {
782 AddCodeLine ("\tlda\t%s+3", lbuf);
783 AddCodeLine ("\tora\t%s+2", lbuf);
784 AddCodeLine ("\tora\t%s+1", lbuf);
785 AddCodeLine ("\tora\t%s+0", lbuf);
787 AddCodeLine ("\tlda\t%s+3", lbuf);
788 AddCodeLine ("\tsta\tsreg+1");
789 AddCodeLine ("\tlda\t%s+2", lbuf);
790 AddCodeLine ("\tsta\tsreg");
791 AddCodeLine ("\tldx\t%s+1", lbuf);
792 AddCodeLine ("\tlda\t%s", lbuf);
804 void g_getlocal (unsigned flags, int offs)
805 /* Fetch specified local object (local var). */
808 CheckLocalOffs (offs);
809 switch (flags & CF_TYPE) {
812 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
813 if (CPU == CPU_65C02 && offs == 0) {
814 AddCodeLine ("\tlda\t(sp)");
817 AddCodeLine ("\tlda\t(sp),y");
821 AddCodeLine ("\tldx\t#$00");
822 AddCodeLine ("\tlda\t(sp,x)");
825 AddCodeLine ("\tldx\t#$00");
826 AddCodeLine ("\tlda\t(sp),y");
828 if ((flags & CF_UNSIGNED) == 0) {
829 AddCodeLine ("\tbpl\t*+3");
830 AddCodeLine ("\tdex");
831 AddCodeHint ("x:!"); /* X is invalid now */
837 CheckLocalOffs (offs + 1);
838 if (flags & CF_TEST) {
840 AddCodeLine ("\tlda\t(sp),y");
841 AddCodeLine ("\tdey");
842 AddCodeLine ("\tora\t(sp),y");
844 if (CodeSizeFactor > 180) {
846 AddCodeLine ("\tlda\t(sp),y");
847 AddCodeLine ("\ttax");
848 AddCodeLine ("\tdey");
849 AddCodeLine ("\tlda\t(sp),y");
853 AddCodeLine ("\tjsr\tldaxysp");
855 AddCodeLine ("\tjsr\tldax0sp");
864 AddCodeLine ("\tjsr\tldeaxysp");
866 AddCodeLine ("\tjsr\tldeax0sp");
877 void g_getind (unsigned flags, unsigned offs)
878 /* Fetch the specified object type indirect through the primary register
879 * into the primary register
882 /* If the offset is greater than 255, add the part that is > 255 to
883 * the primary. This way we get an easy addition and use the low byte
886 offs = MakeByteOffs (flags, offs);
888 /* Handle the indirect fetch */
889 switch (flags & CF_TYPE) {
892 /* Character sized */
895 if (flags & CF_UNSIGNED) {
896 AddCodeLine ("\tjsr\tldauidx");
898 AddCodeLine ("\tjsr\tldaidx");
901 if (flags & CF_UNSIGNED) {
902 if (CodeSizeFactor > 250) {
903 AddCodeLine ("\tsta\tptr1");
904 AddCodeLine ("\tstx\tptr1+1");
905 AddCodeLine ("\tldx\t#$00");
906 AddCodeLine ("\tlda\t(ptr1,x)");
908 AddCodeLine ("\tjsr\tldaui");
911 AddCodeLine ("\tjsr\tldai");
917 if (flags & CF_TEST) {
919 AddCodeLine ("\tsta\tptr1");
920 AddCodeLine ("\tstx\tptr1+1");
921 AddCodeLine ("\tlda\t(ptr1),y");
922 AddCodeLine ("\tiny");
923 AddCodeLine ("\tora\t(ptr1),y");
926 AddCodeLine ("\tjsr\tldaxi");
929 AddCodeLine ("\tjsr\tldaxidx");
936 AddCodeLine ("\tjsr\tldeaxi");
939 AddCodeLine ("\tjsr\tldeaxidx");
941 if (flags & CF_TEST) {
942 AddCodeLine ("\tjsr\ttsteax");
954 void g_leasp (int offs)
955 /* Fetch the address of the specified symbol into the primary register */
957 /* Calculate the offset relative to sp */
960 /* For value 0 we do direct code */
962 AddCodeLine ("\tlda\tsp");
963 AddCodeLine ("\tldx\tsp+1");
965 if (CodeSizeFactor < 300) {
966 ldaconst (offs); /* Load A with offset value */
967 AddCodeLine ("\tjsr\tleaasp"); /* Load effective address */
969 if (CPU == CPU_65C02 && offs == 1) {
970 AddCodeLine ("\tlda\tsp");
971 AddCodeLine ("\tldx\tsp+1");
972 AddCodeLine ("\tina");
973 AddCodeLine ("\tbne\t*+3");
974 AddCodeLine ("\tinx");
975 AddCodeHint ("x:!"); /* Invalidate X */
978 AddCodeLine ("\tclc");
979 AddCodeLine ("\tldx\tsp+1");
980 AddCodeLine ("\tadc\tsp");
981 AddCodeLine ("\tbcc\t*+3");
982 AddCodeLine ("\tinx");
983 AddCodeHint ("x:!"); /* Invalidate X */
991 void g_leavariadic (int Offs)
992 /* Fetch the address of a parameter in a variadic function into the primary
996 unsigned ArgSizeOffs;
998 /* Calculate the offset relative to sp */
1001 /* Get the offset of the parameter which is stored at sp+0 on function
1002 * entry and check if this offset is reachable with a byte offset.
1005 ArgSizeOffs = -oursp;
1006 CheckLocalOffs (ArgSizeOffs);
1008 /* Get the size of all parameters. */
1009 if (ArgSizeOffs == 0 && CPU == CPU_65C02) {
1010 AddCodeLine ("\tlda\t(sp)");
1012 ldyconst (ArgSizeOffs);
1013 AddCodeLine ("\tlda\t(sp),y");
1016 /* Add the value of the stackpointer */
1017 if (CodeSizeFactor > 250) {
1018 AddCodeLine ("\tldx\tsp+1");
1019 AddCodeLine ("\tclc");
1020 AddCodeLine ("\tadc\tsp");
1021 AddCodeLine ("\tbcc\t*+3");
1022 AddCodeLine ("\tinx");
1023 AddCodeHint ("x:!"); /* Invalidate X */
1025 AddCodeLine ("\tjsr\tleaasp");
1028 /* Add the offset to the primary */
1030 g_inc (CF_INT | CF_CONST, Offs);
1031 } else if (Offs < 0) {
1032 g_dec (CF_INT | CF_CONST, -Offs);
1038 /*****************************************************************************/
1039 /* Store into memory */
1040 /*****************************************************************************/
1044 void g_putstatic (unsigned flags, unsigned long label, unsigned offs)
1045 /* Store the primary register into the specified static memory cell */
1047 /* Create the correct label name */
1048 char* lbuf = GetLabelName (flags, label, offs);
1050 /* Check the size and generate the correct store operation */
1051 switch (flags & CF_TYPE) {
1054 AddCodeLine ("\tsta\t%s", lbuf);
1058 AddCodeLine ("\tsta\t%s", lbuf);
1059 AddCodeLine ("\tstx\t%s+1", lbuf);
1063 AddCodeLine ("\tsta\t%s", lbuf);
1064 AddCodeLine ("\tstx\t%s+1", lbuf);
1065 AddCodeLine ("\tldy\tsreg");
1066 AddCodeLine ("\tsty\t%s+2", lbuf);
1067 AddCodeLine ("\tldy\tsreg+1");
1068 AddCodeLine ("\tsty\t%s+3", lbuf);
1079 void g_putlocal (unsigned Flags, int Offs, long Val)
1080 /* Put data into local object. */
1083 CheckLocalOffs (Offs);
1084 switch (Flags & CF_TYPE) {
1087 if (Flags & CF_CONST) {
1088 AddCodeLine ("\tlda\t#$%02X", (unsigned char) Val);
1090 if (CPU == CPU_65C02 && Offs == 0) {
1091 AddCodeLine ("\tsta\t(sp)");
1094 AddCodeLine ("\tsta\t(sp),y");
1099 if (Flags & CF_CONST) {
1101 AddCodeLine ("\tlda\t#$%02X", (unsigned char) (Val >> 8));
1102 AddCodeLine ("\tsta\t(sp),y");
1103 if ((Flags & CF_NOKEEP) == 0) {
1104 /* Place high byte into X */
1105 AddCodeLine ("\ttax");
1107 if (CPU == CPU_65C02 && Offs == 0) {
1108 AddCodeLine ("\tlda\t#$%02X", (unsigned char) Val);
1109 AddCodeLine ("\tsta\t(sp)");
1111 if ((Val & 0xFF) == Offs+1) {
1112 /* The value we need is already in Y */
1113 AddCodeLine ("\ttya");
1114 AddCodeLine ("\tdey");
1116 AddCodeLine ("\tdey");
1117 AddCodeLine ("\tlda\t#$%02X", (unsigned char) Val);
1119 AddCodeLine ("\tsta\t(sp),y");
1122 if ((Flags & CF_NOKEEP) == 0 || CodeSizeFactor < 160) {
1125 AddCodeLine ("\tjsr\tstaxysp");
1127 AddCodeLine ("\tjsr\tstax0sp");
1130 if (CPU == CPU_65C02 && Offs == 0) {
1131 AddCodeLine ("\tsta\t(sp)");
1133 AddCodeLine ("\ttxa");
1134 AddCodeLine ("\tsta\t(sp),y");
1137 AddCodeLine ("\tsta\t(sp),y");
1138 AddCodeLine ("\tiny");
1139 AddCodeLine ("\ttxa");
1140 AddCodeLine ("\tsta\t(sp),y");
1147 if (Flags & CF_CONST) {
1148 g_getimmed (Flags, Val, 0);
1152 AddCodeLine ("\tjsr\tsteaxysp");
1154 AddCodeLine ("\tjsr\tsteax0sp");
1166 void g_putind (unsigned Flags, unsigned Offs)
1167 /* Store the specified object type in the primary register at the address
1168 * on the top of the stack
1171 /* We can handle offsets below $100 directly, larger offsets must be added
1172 * to the address. Since a/x is in use, best code is achieved by adding
1173 * just the high byte. Be sure to check if the low byte will overflow while
1176 if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
1178 /* Overflow - we need to add the low byte also */
1179 AddCodeLine ("\tldy\t#$00");
1180 AddCodeLine ("\tclc");
1181 AddCodeLine ("\tpha");
1182 AddCodeLine ("\tlda\t#$%02X", Offs & 0xFF);
1183 AddCodeLine ("\tadc\t(sp),y");
1184 AddCodeLine ("\tsta\t(sp),y");
1185 AddCodeLine ("\tiny");
1186 AddCodeLine ("\tlda\t#$%02X", (Offs >> 8) & 0xFF);
1187 AddCodeLine ("\tadc\t(sp),y");
1188 AddCodeLine ("\tsta\t(sp),y");
1189 AddCodeLine ("\tpla");
1191 /* Complete address is on stack, new offset is zero */
1194 } else if ((Offs & 0xFF00) != 0) {
1196 /* We can just add the high byte */
1197 AddCodeLine ("\tldy\t#$01");
1198 AddCodeLine ("\tclc");
1199 AddCodeLine ("\tpha");
1200 AddCodeLine ("\tlda\t#$%02X", (Offs >> 8) & 0xFF);
1201 AddCodeLine ("\tadc\t(sp),y");
1202 AddCodeLine ("\tsta\t(sp),y");
1203 AddCodeLine ("\tpla");
1205 /* Offset is now just the low byte */
1209 /* Check the size and determine operation */
1210 switch (Flags & CF_TYPE) {
1215 AddCodeLine ("\tjsr\tstaspidx");
1217 AddCodeLine ("\tjsr\tstaspp");
1224 AddCodeLine ("\tjsr\tstaxspidx");
1226 AddCodeLine ("\tjsr\tstaxspp");
1233 AddCodeLine ("\tjsr\tsteaxspidx");
1235 AddCodeLine ("\tjsr\tsteaxspp");
1244 /* Pop the argument which is always a pointer */
1250 /*****************************************************************************/
1251 /* type conversion and similiar stuff */
1252 /*****************************************************************************/
1256 void g_toslong (unsigned flags)
1257 /* Make sure, the value on TOS is a long. Convert if necessary */
1259 switch (flags & CF_TYPE) {
1263 if (flags & CF_UNSIGNED) {
1264 AddCodeLine ("\tjsr\ttosulong");
1266 AddCodeLine ("\tjsr\ttoslong");
1281 void g_tosint (unsigned flags)
1282 /* Make sure, the value on TOS is an int. Convert if necessary */
1284 switch (flags & CF_TYPE) {
1291 AddCodeLine ("\tjsr\ttosint");
1302 void g_reglong (unsigned flags)
1303 /* Make sure, the value in the primary register a long. Convert if necessary */
1305 switch (flags & CF_TYPE) {
1309 if (flags & CF_UNSIGNED) {
1310 if (CodeSizeFactor >= 200) {
1312 AddCodeLine ("\tsty\tsreg");
1313 AddCodeLine ("\tsty\tsreg+1");
1315 AddCodeLine ("\tjsr\taxulong");
1318 AddCodeLine ("\tjsr\taxlong");
1332 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1333 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1334 * value, that corresponds to the value on TOS, rhs corresponds to the value
1335 * in (e)ax. The return value is the the flags value for the resulting type.
1338 unsigned ltype, rtype;
1341 /* Get the type spec from the flags */
1342 ltype = lhs & CF_TYPE;
1343 rtype = rhs & CF_TYPE;
1345 /* Check if a conversion is needed */
1346 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1347 /* We must promote the primary register to long */
1349 /* Get the new rhs type */
1350 rhs = (rhs & ~CF_TYPE) | CF_LONG;
1352 } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1353 /* We must promote the lhs to long */
1359 /* Get the new rhs type */
1360 lhs = (lhs & ~CF_TYPE) | CF_LONG;
1364 /* Determine the result type for the operation:
1365 * - The result is const if both operands are const.
1366 * - The result is unsigned if one of the operands is unsigned.
1367 * - The result is long if one of the operands is long.
1368 * - Otherwise the result is int sized.
1370 result = (lhs & CF_CONST) & (rhs & CF_CONST);
1371 result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1372 if (rtype == CF_LONG || ltype == CF_LONG) {
1382 unsigned g_typecast (unsigned lhs, unsigned rhs)
1383 /* Cast the value in the primary register to the operand size that is flagged
1384 * by the lhs value. Return the result value.
1387 unsigned ltype, rtype;
1389 /* Get the type spec from the flags */
1390 ltype = lhs & CF_TYPE;
1391 rtype = rhs & CF_TYPE;
1393 /* Check if a conversion is needed */
1394 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1395 /* We must promote the primary register to long */
1399 /* Do not need any other action. If the left type is int, and the primary
1400 * register is long, it will be automagically truncated. If the right hand
1401 * side is const, it is not located in the primary register and handled by
1402 * the expression parser code.
1405 /* Result is const if the right hand side was const */
1406 lhs |= (rhs & CF_CONST);
1408 /* The resulting type is that of the left hand side (that's why you called
1416 void g_scale (unsigned flags, long val)
1417 /* Scale the value in the primary register by the given value. If val is positive,
1418 * scale up, is val is negative, scale down. This function is used to scale
1419 * the operands or results of pointer arithmetic by the size of the type, the
1420 * pointer points to.
1425 /* Value may not be zero */
1427 Internal ("Data type has no size");
1428 } else if (val > 0) {
1431 if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1433 /* Factor is 2, 4 or 8, use special function */
1434 switch (flags & CF_TYPE) {
1437 if (flags & CF_FORCECHAR) {
1439 AddCodeLine ("\tasl\ta");
1446 if (CodeSizeFactor >= (p2+1)*130U) {
1447 AddCodeLine ("\tstx\ttmp1");
1449 AddCodeLine ("\tasl\ta");
1450 AddCodeLine ("\trol\ttmp1");
1452 AddCodeLine ("\tldx\ttmp1");
1454 if (flags & CF_UNSIGNED) {
1455 AddCodeLine ("\tjsr\tshlax%d", p2);
1457 AddCodeLine ("\tjsr\taslax%d", p2);
1463 if (flags & CF_UNSIGNED) {
1464 AddCodeLine ("\tjsr\tshleax%d", p2);
1466 AddCodeLine ("\tjsr\tasleax%d", p2);
1475 } else if (val != 1) {
1477 /* Use a multiplication instead */
1478 g_mul (flags | CF_CONST, val);
1486 if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1488 /* Factor is 2, 4 or 8, use special function */
1489 switch (flags & CF_TYPE) {
1492 if (flags & CF_FORCECHAR) {
1493 if (flags & CF_UNSIGNED) {
1495 AddCodeLine ("\tlsr\ta");
1498 } else if (p2 <= 2) {
1499 AddCodeLine ("\tcmp\t#$80");
1500 AddCodeLine ("\tror\ta");
1507 if (flags & CF_UNSIGNED) {
1508 if (CodeSizeFactor >= (p2+1)*130U) {
1509 AddCodeLine ("\tstx\ttmp1");
1511 AddCodeLine ("\tlsr\ttmp1");
1512 AddCodeLine ("\tror\ta");
1514 AddCodeLine ("\tldx\ttmp1");
1516 AddCodeLine ("\tjsr\tlsrax%d", p2);
1519 if (CodeSizeFactor >= (p2+1)*150U) {
1520 AddCodeLine ("\tstx\ttmp1");
1522 AddCodeLine ("\tcpx\t#$80");
1523 AddCodeLine ("\tror\ttmp1");
1524 AddCodeLine ("\tror\ta");
1526 AddCodeLine ("\tldx\ttmp1");
1528 AddCodeLine ("\tjsr\tasrax%d", p2);
1534 if (flags & CF_UNSIGNED) {
1535 AddCodeLine ("\tjsr\tlsreax%d", p2);
1537 AddCodeLine ("\tjsr\tasreax%d", p2);
1546 } else if (val != 1) {
1548 /* Use a division instead */
1549 g_div (flags | CF_CONST, val);
1557 /*****************************************************************************/
1558 /* Adds and subs of variables fix a fixed address */
1559 /*****************************************************************************/
1563 void g_addlocal (unsigned flags, int offs)
1564 /* Add a local variable to ax */
1566 /* Correct the offset and check it */
1568 CheckLocalOffs (offs);
1570 switch (flags & CF_TYPE) {
1573 AddCodeLine ("\tldy\t#$%02X", offs & 0xFF);
1574 AddCodeLine ("\tclc");
1575 AddCodeLine ("\tadc\t(sp),y");
1576 AddCodeLine ("\tbcc\t*+3");
1577 AddCodeLine ("\tinx");
1578 AddCodeHint ("x:!");
1582 AddCodeLine ("\tldy\t#$%02X", offs & 0xFF);
1583 AddCodeLine ("\tclc");
1584 AddCodeLine ("\tadc\t(sp),y");
1585 AddCodeLine ("\tpha");
1586 AddCodeLine ("\ttxa");
1587 AddCodeLine ("\tiny");
1588 AddCodeLine ("\tadc\t(sp),y");
1589 AddCodeLine ("\ttax");
1590 AddCodeLine ("\tpla");
1594 /* Do it the old way */
1596 g_getlocal (flags, offs);
1608 void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
1609 /* Add a static variable to ax */
1611 /* Create the correct label name */
1612 char* lbuf = GetLabelName (flags, label, offs);
1614 switch (flags & CF_TYPE) {
1617 AddCodeLine ("\tclc");
1618 AddCodeLine ("\tadc\t%s", lbuf);
1619 AddCodeLine ("\tbcc\t*+3");
1620 AddCodeLine ("\tinx");
1621 AddCodeHint ("x:!");
1625 AddCodeLine ("\tclc");
1626 AddCodeLine ("\tadc\t%s", lbuf);
1627 AddCodeLine ("\ttay");
1628 AddCodeLine ("\ttxa");
1629 AddCodeLine ("\tadc\t%s+1", lbuf);
1630 AddCodeLine ("\ttax");
1631 AddCodeLine ("\ttya");
1635 /* Do it the old way */
1637 g_getstatic (flags, label, offs);
1649 /*****************************************************************************/
1650 /* Compares of ax with a variable with fixed address */
1651 /*****************************************************************************/
1655 void g_cmplocal (unsigned flags, int offs)
1656 /* Compare a local variable to ax */
1658 Internal ("g_cmplocal not implemented");
1663 void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
1664 /* Compare a static variable to ax */
1666 Internal ("g_cmpstatic not implemented");
1671 /*****************************************************************************/
1672 /* Special op= functions */
1673 /*****************************************************************************/
1677 void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
1679 /* Emit += for a static variable */
1681 /* Create the correct label name */
1682 char* lbuf = GetLabelName (flags, label, offs);
1684 /* Check the size and determine operation */
1685 switch (flags & CF_TYPE) {
1688 if (flags & CF_FORCECHAR) {
1689 AddCodeLine ("\tldx\t#$00");
1690 if (flags & CF_CONST) {
1692 AddCodeLine ("\tinc\t%s", lbuf);
1693 AddCodeLine ("\tlda\t%s", lbuf);
1695 AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1696 AddCodeLine ("\tclc");
1697 AddCodeLine ("\tadc\t%s", lbuf);
1698 AddCodeLine ("\tsta\t%s", lbuf);
1701 AddCodeLine ("\tclc");
1702 AddCodeLine ("\tadc\t%s", lbuf);
1703 AddCodeLine ("\tsta\t%s", lbuf);
1705 if ((flags & CF_UNSIGNED) == 0) {
1706 AddCodeLine ("\tbpl\t*+3");
1707 AddCodeLine ("\tdex");
1708 AddCodeHint ("x:!"); /* Invalidate X */
1715 if (flags & CF_CONST) {
1717 label = GetLocalLabel ();
1718 AddCodeLine ("\tinc\t%s", lbuf);
1719 AddCodeLine ("\tbne\tL%04X", (int)label);
1720 AddCodeLine ("\tinc\t%s+1", lbuf);
1721 g_defloclabel (label);
1722 AddCodeLine ("\tlda\t%s", lbuf); /* Hmmm... */
1723 AddCodeLine ("\tldx\t%s+1", lbuf);
1725 AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1726 AddCodeLine ("\tclc");
1727 AddCodeLine ("\tadc\t%s", lbuf);
1728 AddCodeLine ("\tsta\t%s", lbuf);
1730 label = GetLocalLabel ();
1731 AddCodeLine ("\tbcc\tL%04X", (int)label);
1732 AddCodeLine ("\tinc\t%s+1", lbuf);
1733 g_defloclabel (label);
1734 AddCodeLine ("\tldx\t%s+1", lbuf);
1736 AddCodeLine ("\tlda\t#$%02X", (unsigned char)(val >> 8));
1737 AddCodeLine ("\tadc\t%s+1", lbuf);
1738 AddCodeLine ("\tsta\t%s+1", lbuf);
1739 AddCodeLine ("\ttax");
1740 AddCodeLine ("\tlda\t%s", lbuf);
1744 AddCodeLine ("\tclc");
1745 AddCodeLine ("\tadc\t%s", lbuf);
1746 AddCodeLine ("\tsta\t%s", lbuf);
1747 AddCodeLine ("\ttxa");
1748 AddCodeLine ("\tadc\t%s+1", lbuf);
1749 AddCodeLine ("\tsta\t%s+1", lbuf);
1750 AddCodeLine ("\ttax");
1751 AddCodeLine ("\tlda\t%s", lbuf);
1756 if (flags & CF_CONST) {
1758 AddCodeLine ("\tldy\t#<(%s)", lbuf);
1759 AddCodeLine ("\tsty\tptr1");
1760 AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
1762 AddCodeLine ("\tjsr\tladdeq1");
1764 AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1765 AddCodeLine ("\tjsr\tladdeqa");
1768 g_getstatic (flags, label, offs);
1770 g_putstatic (flags, label, offs);
1773 AddCodeLine ("\tldy\t#<(%s)", lbuf);
1774 AddCodeLine ("\tsty\tptr1");
1775 AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
1776 AddCodeLine ("\tjsr\tladdeq");
1787 void g_addeqlocal (unsigned flags, int offs, unsigned long val)
1788 /* Emit += for a local variable */
1790 /* Calculate the true offset, check it, load it into Y */
1792 CheckLocalOffs (offs);
1794 /* Check the size and determine operation */
1795 switch (flags & CF_TYPE) {
1798 if (flags & CF_FORCECHAR) {
1800 AddCodeLine ("\tldx\t#$00");
1801 if (flags & CF_CONST) {
1802 AddCodeLine ("\tclc");
1803 AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1804 AddCodeLine ("\tadc\t(sp,x)");
1805 AddCodeLine ("\tsta\t(sp,x)");
1807 AddCodeLine ("\tclc");
1808 AddCodeLine ("\tadc\t(sp,x)");
1809 AddCodeLine ("\tsta\t(sp,x)");
1813 AddCodeLine ("\tldx\t#$00");
1814 if (flags & CF_CONST) {
1815 AddCodeLine ("\tclc");
1816 AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1817 AddCodeLine ("\tadc\t(sp),y");
1818 AddCodeLine ("\tsta\t(sp),y");
1820 AddCodeLine ("\tclc");
1821 AddCodeLine ("\tadc\t(sp),y");
1822 AddCodeLine ("\tsta\t(sp),y");
1825 if ((flags & CF_UNSIGNED) == 0) {
1826 AddCodeLine ("\tbpl\t*+3");
1827 AddCodeLine ("\tdex");
1828 AddCodeHint ("x:!"); /* Invalidate X */
1835 if (flags & CF_CONST) {
1836 g_getimmed (flags, val, 0);
1839 AddCodeLine ("\tjsr\taddeq0sp");
1842 AddCodeLine ("\tjsr\taddeqysp");
1847 if (flags & CF_CONST) {
1848 g_getimmed (flags, val, 0);
1851 AddCodeLine ("\tjsr\tladdeq0sp");
1854 AddCodeLine ("\tjsr\tladdeqysp");
1865 void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1866 /* Emit += for the location with address in ax */
1868 /* If the offset is too large for a byte register, add the high byte
1869 * of the offset to the primary. Beware: We need a special correction
1870 * if the offset in the low byte will overflow in the operation.
1872 offs = MakeByteOffs (flags, offs);
1874 /* Check the size and determine operation */
1875 switch (flags & CF_TYPE) {
1878 AddCodeLine ("\tsta\tptr1");
1879 AddCodeLine ("\tstx\tptr1+1");
1881 AddCodeLine ("\tldx\t#$00");
1882 AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1883 AddCodeLine ("\tclc");
1884 AddCodeLine ("\tadc\t(ptr1,x)");
1885 AddCodeLine ("\tsta\t(ptr1,x)");
1887 AddCodeLine ("\tldy\t#$%02X", offs);
1888 AddCodeLine ("\tldx\t#$00");
1889 AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1890 AddCodeLine ("\tclc");
1891 AddCodeLine ("\tadc\t(ptr1),y");
1892 AddCodeLine ("\tsta\t(ptr1),y");
1897 if (CodeSizeFactor >= 200) {
1898 /* Lots of code, use only if size is not important */
1899 AddCodeLine ("\tsta\tptr1");
1900 AddCodeLine ("\tstx\tptr1+1");
1901 AddCodeLine ("\tldy\t#$%02X", offs);
1902 AddCodeLine ("\tlda\t#$%02X", (int)(val & 0xFF));
1903 AddCodeLine ("\tclc");
1904 AddCodeLine ("\tadc\t(ptr1),y");
1905 AddCodeLine ("\tsta\t(ptr1),y");
1906 AddCodeLine ("\tpha");
1907 AddCodeLine ("\tiny");
1908 AddCodeLine ("\tlda\t#$%02X", (unsigned char)(val >> 8));
1909 AddCodeLine ("\tadc\t(ptr1),y");
1910 AddCodeLine ("\tsta\t(ptr1),y");
1911 AddCodeLine ("\ttax");
1912 AddCodeLine ("\tpla");
1918 AddCodeLine ("\tjsr\tpushax"); /* Push the address */
1919 push (flags); /* Correct the internal sp */
1920 g_getind (flags, offs); /* Fetch the value */
1921 g_inc (flags, val); /* Increment value in primary */
1922 g_putind (flags, offs); /* Store the value back */
1932 void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
1934 /* Emit -= for a static variable */
1936 /* Create the correct label name */
1937 char* lbuf = GetLabelName (flags, label, offs);
1939 /* Check the size and determine operation */
1940 switch (flags & CF_TYPE) {
1943 if (flags & CF_FORCECHAR) {
1944 AddCodeLine ("\tldx\t#$00");
1945 if (flags & CF_CONST) {
1947 AddCodeLine ("\tdec\t%s", lbuf);
1948 AddCodeLine ("\tlda\t%s", lbuf);
1950 AddCodeLine ("\tsec");
1951 AddCodeLine ("\tlda\t%s", lbuf);
1952 AddCodeLine ("\tsbc\t#$%02X", (int)(val & 0xFF));
1953 AddCodeLine ("\tsta\t%s", lbuf);
1956 AddCodeLine ("\tsec");
1957 AddCodeLine ("\tsta\ttmp1");
1958 AddCodeLine ("\tlda\t%s", lbuf);
1959 AddCodeLine ("\tsbc\ttmp1");
1960 AddCodeLine ("\tsta\t%s", lbuf);
1962 if ((flags & CF_UNSIGNED) == 0) {
1963 AddCodeLine ("\tbpl\t*+3");
1964 AddCodeLine ("\tdex");
1965 AddCodeHint ("x:!"); /* Invalidate X */
1972 AddCodeLine ("\tsec");
1973 if (flags & CF_CONST) {
1974 AddCodeLine ("\tlda\t%s", lbuf);
1975 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
1976 AddCodeLine ("\tsta\t%s", lbuf);
1978 label = GetLocalLabel ();
1979 AddCodeLine ("\tbcs\tL%04X", (unsigned)label);
1980 AddCodeLine ("\tdec\t%s+1", lbuf);
1981 g_defloclabel (label);
1982 AddCodeLine ("\tldx\t%s+1", lbuf);
1984 AddCodeLine ("\tlda\t%s+1", lbuf);
1985 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)(val >> 8));
1986 AddCodeLine ("\tsta\t%s+1", lbuf);
1987 AddCodeLine ("\ttax");
1988 AddCodeLine ("\tlda\t%s", lbuf);
1991 AddCodeLine ("\tsta\ttmp1");
1992 AddCodeLine ("\tlda\t%s", lbuf);
1993 AddCodeLine ("\tsbc\ttmp1");
1994 AddCodeLine ("\tsta\t%s", lbuf);
1995 AddCodeLine ("\tstx\ttmp1");
1996 AddCodeLine ("\tlda\t%s+1", lbuf);
1997 AddCodeLine ("\tsbc\ttmp1");
1998 AddCodeLine ("\tsta\t%s+1", lbuf);
1999 AddCodeLine ("\ttax");
2000 AddCodeLine ("\tlda\t%s", lbuf);
2005 if (flags & CF_CONST) {
2007 AddCodeLine ("\tldy\t#<(%s)", lbuf);
2008 AddCodeLine ("\tsty\tptr1");
2009 AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
2011 AddCodeLine ("\tjsr\tlsubeq1");
2013 AddCodeLine ("\tlda\t#$%02X", (unsigned char)val);
2014 AddCodeLine ("\tjsr\tlsubeqa");
2017 g_getstatic (flags, label, offs);
2019 g_putstatic (flags, label, offs);
2022 AddCodeLine ("\tldy\t#<(%s)", lbuf);
2023 AddCodeLine ("\tsty\tptr1");
2024 AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
2025 AddCodeLine ("\tjsr\tlsubeq");
2036 void g_subeqlocal (unsigned flags, int offs, unsigned long val)
2037 /* Emit -= for a local variable */
2039 /* Calculate the true offset, check it, load it into Y */
2041 CheckLocalOffs (offs);
2043 /* Check the size and determine operation */
2044 switch (flags & CF_TYPE) {
2047 if (flags & CF_FORCECHAR) {
2049 AddCodeLine ("\tldx\t#$00");
2050 AddCodeLine ("\tsec");
2051 if (flags & CF_CONST) {
2052 AddCodeLine ("\tlda\t(sp),y");
2053 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
2055 AddCodeLine ("\tsta\ttmp1");
2056 AddCodeLine ("\tlda\t(sp),y");
2057 AddCodeLine ("\tsbc\ttmp1");
2059 AddCodeLine ("\tsta\t(sp),y");
2060 if ((flags & CF_UNSIGNED) == 0) {
2061 AddCodeLine ("\tbpl\t*+3");
2062 AddCodeLine ("\tdex");
2063 AddCodeHint ("x:!"); /* Invalidate X */
2070 if (flags & CF_CONST) {
2071 g_getimmed (flags, val, 0);
2074 AddCodeLine ("\tjsr\tsubeq0sp");
2077 AddCodeLine ("\tjsr\tsubeqysp");
2082 if (flags & CF_CONST) {
2083 g_getimmed (flags, val, 0);
2086 AddCodeLine ("\tjsr\tlsubeq0sp");
2089 AddCodeLine ("\tjsr\tlsubeqysp");
2100 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
2101 /* Emit -= for the location with address in ax */
2103 /* If the offset is too large for a byte register, add the high byte
2104 * of the offset to the primary. Beware: We need a special correction
2105 * if the offset in the low byte will overflow in the operation.
2107 offs = MakeByteOffs (flags, offs);
2109 /* Check the size and determine operation */
2110 switch (flags & CF_TYPE) {
2113 AddCodeLine ("\tsta\tptr1");
2114 AddCodeLine ("\tstx\tptr1+1");
2116 AddCodeLine ("\tldx\t#$00");
2117 AddCodeLine ("\tlda\t(ptr1,x)");
2118 AddCodeLine ("\tsec");
2119 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
2120 AddCodeLine ("\tsta\t(ptr1,x)");
2122 AddCodeLine ("\tldy\t#$%02X", offs);
2123 AddCodeLine ("\tldx\t#$00");
2124 AddCodeLine ("\tlda\t(ptr1),y");
2125 AddCodeLine ("\tsec");
2126 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
2127 AddCodeLine ("\tsta\t(ptr1),y");
2132 if (CodeSizeFactor >= 200) {
2133 /* Lots of code, use only if size is not important */
2134 AddCodeLine ("\tsta\tptr1");
2135 AddCodeLine ("\tstx\tptr1+1");
2136 AddCodeLine ("\tldy\t#$%02X", offs);
2137 AddCodeLine ("\tlda\t(ptr1),y");
2138 AddCodeLine ("\tsec");
2139 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
2140 AddCodeLine ("\tsta\t(ptr1),y");
2141 AddCodeLine ("\tpha");
2142 AddCodeLine ("\tiny");
2143 AddCodeLine ("\tlda\t(ptr1),y");
2144 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)(val >> 8));
2145 AddCodeLine ("\tsta\t(ptr1),y");
2146 AddCodeLine ("\ttax");
2147 AddCodeLine ("\tpla");
2153 AddCodeLine ("\tjsr\tpushax"); /* Push the address */
2154 push (flags); /* Correct the internal sp */
2155 g_getind (flags, offs); /* Fetch the value */
2156 g_dec (flags, val); /* Increment value in primary */
2157 g_putind (flags, offs); /* Store the value back */
2167 /*****************************************************************************/
2168 /* Add a variable address to the value in ax */
2169 /*****************************************************************************/
2173 void g_addaddr_local (unsigned flags, int offs)
2174 /* Add the address of a local variable to ax */
2176 /* Add the offset */
2179 /* We cannot address more then 256 bytes of locals anyway */
2180 CheckLocalOffs (offs);
2181 AddCodeLine ("\tclc");
2182 AddCodeLine ("\tadc\t#$%02X", offs & 0xFF);
2183 AddCodeLine ("\tbcc\t*+4"); /* Do also skip the CLC insn below */
2184 AddCodeLine ("\tinx");
2185 AddCodeHint ("x:!"); /* Invalidate X */
2188 /* Add the current stackpointer value */
2189 AddCodeLine ("\tclc");
2190 AddCodeLine ("\tadc\tsp");
2191 AddCodeLine ("\ttay");
2192 AddCodeLine ("\ttxa");
2193 AddCodeLine ("\tadc\tsp+1");
2194 AddCodeLine ("\ttax");
2195 AddCodeLine ("\ttya");
2200 void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
2201 /* Add the address of a static variable to ax */
2203 /* Create the correct label name */
2204 char* lbuf = GetLabelName (flags, label, offs);
2206 /* Add the address to the current ax value */
2207 AddCodeLine ("\tclc");
2208 AddCodeLine ("\tadc\t#<(%s)", lbuf);
2209 AddCodeLine ("\ttay");
2210 AddCodeLine ("\ttxa");
2211 AddCodeLine ("\tadc\t#>(%s)", lbuf);
2212 AddCodeLine ("\ttax");
2213 AddCodeLine ("\ttya");
2218 /*****************************************************************************/
2220 /*****************************************************************************/
2224 void g_save (unsigned flags)
2225 /* Copy primary register to hold register. */
2227 /* Check the size and determine operation */
2228 switch (flags & CF_TYPE) {
2231 if (flags & CF_FORCECHAR) {
2232 AddCodeLine ("\tpha");
2238 AddCodeLine ("\tsta\tregsave");
2239 AddCodeLine ("\tstx\tregsave+1");
2243 AddCodeLine ("\tjsr\tsaveeax");
2253 void g_restore (unsigned flags)
2254 /* Copy hold register to P. */
2256 /* Check the size and determine operation */
2257 switch (flags & CF_TYPE) {
2260 if (flags & CF_FORCECHAR) {
2261 AddCodeLine ("\tpla");
2267 AddCodeLine ("\tlda\tregsave");
2268 AddCodeLine ("\tldx\tregsave+1");
2272 AddCodeLine ("\tjsr\tresteax");
2282 void g_cmp (unsigned flags, unsigned long val)
2283 /* Immidiate compare. The primary register will not be changed, Z flag
2287 /* Check the size and determine operation */
2288 switch (flags & CF_TYPE) {
2291 if (flags & CF_FORCECHAR) {
2292 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
2298 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
2299 AddCodeLine ("\tbne\t*+4");
2300 AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
2304 Internal ("g_cmp: Long compares not implemented");
2314 static void oper (unsigned flags, unsigned long val, char** subs)
2315 /* Encode a binary operation. subs is a pointer to four groups of three
2317 * 0-2 --> Operate on ints
2318 * 3-5 --> Operate on unsigneds
2319 * 6-8 --> Operate on longs
2320 * 9-11 --> Operate on unsigned longs
2322 * The first subroutine names in each string group is used to encode an
2323 * operation with a zero constant, the second to encode an operation with
2324 * a 8 bit constant, and the third is used in all other cases.
2329 /* Determine the offset into the array */
2330 offs = (flags & CF_UNSIGNED)? 3 : 0;
2331 switch (flags & CF_TYPE) {
2344 /* Encode the operation */
2345 if (flags & CF_CONST) {
2346 /* Constant value given */
2347 if (val == 0 && subs [offs+0]) {
2348 /* Special case: constant with value zero */
2349 AddCodeLine ("\tjsr\t%s", subs [offs+0]);
2350 } else if (val < 0x100 && subs [offs+1]) {
2351 /* Special case: constant with high byte zero */
2352 ldaconst (val); /* Load low byte */
2353 AddCodeLine ("\tjsr\t%s", subs [offs+1]);
2355 /* Others: arbitrary constant value */
2356 g_getimmed (flags, val, 0); /* Load value */
2357 AddCodeLine ("\tjsr\t%s", subs [offs+2]);
2360 /* Value not constant (is already in (e)ax) */
2361 AddCodeLine ("\tjsr\t%s", subs [offs+2]);
2364 /* The operation will pop it's argument */
2370 void g_test (unsigned flags)
2371 /* Force a test to set cond codes right */
2373 switch (flags & CF_TYPE) {
2376 if (flags & CF_FORCECHAR) {
2377 AddCodeLine ("\ttax");
2383 AddCodeLine ("\tstx\ttmp1");
2384 AddCodeLine ("\tora\ttmp1");
2388 if (flags & CF_UNSIGNED) {
2389 AddCodeLine ("\tjsr\tutsteax");
2391 AddCodeLine ("\tjsr\ttsteax");
2403 void g_push (unsigned flags, unsigned long val)
2404 /* Push the primary register or a constant value onto the stack */
2408 if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2410 /* We have a constant 8 or 16 bit value */
2411 if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2413 /* Handle as 8 bit value */
2414 if (CodeSizeFactor >= 165 || val > 2) {
2416 AddCodeLine ("\tjsr\tpusha");
2418 AddCodeLine ("\tjsr\tpushc%d", (int) val);
2423 /* Handle as 16 bit value */
2424 hi = (unsigned char) (val >> 8);
2426 AddCodeLine ("\tjsr\tpush%u", (unsigned) val);
2427 } else if (hi == 0 || hi == 0xFF) {
2428 /* Use special function */
2430 AddCodeLine ("\tjsr\t%s", (hi == 0)? "pusha0" : "pushaFF");
2433 g_getimmed (flags, val, 0);
2434 AddCodeLine ("\tjsr\tpushax");
2440 /* Value is not 16 bit or not constant */
2441 if (flags & CF_CONST) {
2442 /* Constant 32 bit value, load into eax */
2443 g_getimmed (flags, val, 0);
2446 /* Push the primary register */
2447 switch (flags & CF_TYPE) {
2450 if (flags & CF_FORCECHAR) {
2451 /* Handle as char */
2452 AddCodeLine ("\tjsr\tpusha");
2457 AddCodeLine ("\tjsr\tpushax");
2461 AddCodeLine ("\tjsr\tpusheax");
2471 /* Adjust the stack offset */
2477 void g_swap (unsigned flags)
2478 /* Swap the primary register and the top of the stack. flags give the type
2479 * of *both* values (must have same size).
2482 switch (flags & CF_TYPE) {
2486 AddCodeLine ("\tjsr\tswapstk");
2490 AddCodeLine ("\tjsr\tswapestk");
2501 void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2502 /* Call the specified subroutine name */
2504 if ((Flags & CF_FIXARGC) == 0) {
2505 /* Pass the argument count */
2508 AddCodeLine ("\tjsr\t_%s", Label);
2509 oursp += ArgSize; /* callee pops args */
2514 void g_callind (unsigned Flags, unsigned ArgSize)
2515 /* Call subroutine with address in AX */
2517 if ((Flags & CF_FIXARGC) == 0) {
2518 /* Pass arg count */
2521 AddCodeLine ("\tjsr\tcallax"); /* do the call */
2522 oursp += ArgSize; /* callee pops args */
2527 void g_jump (unsigned Label)
2528 /* Jump to specified internal label number */
2530 AddCodeLine ("\tjmp\tL%04X", Label);
2535 void g_switch (unsigned Flags)
2536 /* Output switch statement preamble */
2538 switch (Flags & CF_TYPE) {
2542 AddCodeLine ("\tjsr\tswitch");
2546 AddCodeLine ("\tjsr\tlswitch");
2557 void g_case (unsigned flags, unsigned label, unsigned long val)
2558 /* Create table code for one case selector */
2560 switch (flags & CF_TYPE) {
2564 AddCodeLine ("\t.word\t$%04X, L%04X",
2565 (unsigned)(val & 0xFFFF),
2566 (unsigned)(label & 0xFFFF));
2570 AddCodeLine ("\t.dword\t$%08lX", val);
2571 AddCodeLine ("\t.word\tL%04X", label & 0xFFFF);
2582 void g_truejump (unsigned flags, unsigned label)
2583 /* Jump to label if zero flag clear */
2585 if (flags & CF_SHORT) {
2586 AddCodeLine ("\tbne\tL%04X", label);
2588 AddCodeLine ("\tjne\tL%04X", label);
2594 void g_falsejump (unsigned flags, unsigned label)
2595 /* Jump to label if zero flag set */
2597 if (flags & CF_SHORT) {
2598 AddCodeLine ("\tbeq\tL%04X", label);
2600 AddCodeLine ("\tjeq\tL%04X", label);
2606 static void mod_internal (int k, char* verb1, char* verb2)
2609 AddCodeLine ("\tjsr\t%ssp%c", verb1, k + '0');
2613 AddCodeLine ("\tjsr\t%ssp", verb2);
2619 void g_space (int space)
2620 /* Create or drop space on the stack */
2623 mod_internal (-space, "inc", "addy");
2624 } else if (space > 0) {
2625 mod_internal (space, "dec", "suby");
2631 void g_cstackcheck (void)
2632 /* Check for a C stack overflow */
2634 AddCodeLine ("\tjsr\tcstkchk");
2639 void g_stackcheck (void)
2640 /* Check for a stack overflow */
2642 AddCodeLine ("\tjsr\tstkchk");
2647 void g_add (unsigned flags, unsigned long val)
2648 /* Primary = TOS + Primary */
2650 static char* ops [12] = {
2651 0, "tosadda0", "tosaddax",
2652 0, "tosadda0", "tosaddax",
2657 if (flags & CF_CONST) {
2658 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2659 g_push (flags & ~CF_CONST, 0);
2661 oper (flags, val, ops);
2666 void g_sub (unsigned flags, unsigned long val)
2667 /* Primary = TOS - Primary */
2669 static char* ops [12] = {
2670 0, "tossuba0", "tossubax",
2671 0, "tossuba0", "tossubax",
2676 if (flags & CF_CONST) {
2677 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2678 g_push (flags & ~CF_CONST, 0);
2680 oper (flags, val, ops);
2685 void g_rsub (unsigned flags, unsigned long val)
2686 /* Primary = Primary - TOS */
2688 static char* ops [12] = {
2689 0, "tosrsuba0", "tosrsubax",
2690 0, "tosrsuba0", "tosrsubax",
2694 oper (flags, val, ops);
2699 void g_mul (unsigned flags, unsigned long val)
2700 /* Primary = TOS * Primary */
2702 static char* ops [12] = {
2703 0, "tosmula0", "tosmulax",
2704 0, "tosumula0", "tosumulax",
2711 /* Do strength reduction if the value is constant and a power of two */
2712 if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2713 /* Generate a shift instead */
2718 /* If the right hand side is const, the lhs is not on stack but still
2719 * in the primary register.
2721 if (flags & CF_CONST) {
2723 switch (flags & CF_TYPE) {
2726 if (flags & CF_FORCECHAR) {
2727 /* Handle some special cases */
2731 AddCodeLine ("\tsta\ttmp1");
2732 AddCodeLine ("\tasl\ta");
2733 AddCodeLine ("\tclc");
2734 AddCodeLine ("\tadc\ttmp1");
2738 AddCodeLine ("\tsta\ttmp1");
2739 AddCodeLine ("\tasl\ta");
2740 AddCodeLine ("\tasl\ta");
2741 AddCodeLine ("\tclc");
2742 AddCodeLine ("\tadc\ttmp1");
2746 AddCodeLine ("\tsta\ttmp1");
2747 AddCodeLine ("\tasl\ta");
2748 AddCodeLine ("\tasl\ta");
2749 AddCodeLine ("\tclc");
2750 AddCodeLine ("\tadc\ttmp1");
2751 AddCodeLine ("\tasl\ta");
2767 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2768 * into the normal, non-optimized stuff.
2770 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2771 g_push (flags & ~CF_CONST, 0);
2775 /* Use long way over the stack */
2776 oper (flags, val, ops);
2781 void g_div (unsigned flags, unsigned long val)
2782 /* Primary = TOS / Primary */
2784 static char* ops [12] = {
2785 0, "tosdiva0", "tosdivax",
2786 0, "tosudiva0", "tosudivax",
2791 /* Do strength reduction if the value is constant and a power of two */
2793 if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2794 /* Generate a shift instead */
2797 /* Generate a division */
2798 if (flags & CF_CONST) {
2799 /* lhs is not on stack */
2800 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2801 g_push (flags & ~CF_CONST, 0);
2803 oper (flags, val, ops);
2809 void g_mod (unsigned flags, unsigned long val)
2810 /* Primary = TOS % Primary */
2812 static char* ops [12] = {
2813 0, "tosmoda0", "tosmodax",
2814 0, "tosumoda0", "tosumodax",
2820 /* Check if we can do some cost reduction */
2821 if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2822 /* We can do that with an AND operation */
2823 g_and (flags, val - 1);
2825 /* Do it the hard way... */
2826 if (flags & CF_CONST) {
2827 /* lhs is not on stack */
2828 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2829 g_push (flags & ~CF_CONST, 0);
2831 oper (flags, val, ops);
2837 void g_or (unsigned flags, unsigned long val)
2838 /* Primary = TOS | Primary */
2840 static char* ops [12] = {
2841 0, "tosora0", "tosorax",
2842 0, "tosora0", "tosorax",
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 if ((val & 0xFF) != 0xFF) {
2857 AddCodeLine ("\tora\t#$%02X", (unsigned char)val);
2865 AddCodeLine ("\tora\t#$%02X", (unsigned char)val);
2872 AddCodeLine ("\tora\t#$%02X", (unsigned char)val);
2881 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2882 * into the normal, non-optimized stuff.
2884 g_push (flags & ~CF_CONST, 0);
2888 /* Use long way over the stack */
2889 oper (flags, val, ops);
2894 void g_xor (unsigned flags, unsigned long val)
2895 /* Primary = TOS ^ Primary */
2897 static char* ops [12] = {
2898 0, "tosxora0", "tosxorax",
2899 0, "tosxora0", "tosxorax",
2905 /* If the right hand side is const, the lhs is not on stack but still
2906 * in the primary register.
2908 if (flags & CF_CONST) {
2910 switch (flags & CF_TYPE) {
2913 if (flags & CF_FORCECHAR) {
2914 if ((val & 0xFF) != 0) {
2915 AddCodeLine ("\teor\t#$%02X", (unsigned char)val);
2924 AddCodeLine ("\teor\t#$%02X", (unsigned char)val);
2927 } else if ((val & 0xFF) == 0) {
2928 AddCodeLine ("\tpha");
2929 AddCodeLine ("\ttxa");
2930 AddCodeLine ("\teor\t#$%02X", (unsigned char)(val >> 8));
2931 AddCodeLine ("\ttax");
2932 AddCodeLine ("\tpla");
2940 AddCodeLine ("\teor\t#$%02X", (unsigned char)val);
2950 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2951 * into the normal, non-optimized stuff.
2953 g_push (flags & ~CF_CONST, 0);
2957 /* Use long way over the stack */
2958 oper (flags, val, ops);
2963 void g_and (unsigned flags, unsigned long val)
2964 /* Primary = TOS & Primary */
2966 static char* ops [12] = {
2967 0, "tosanda0", "tosandax",
2968 0, "tosanda0", "tosandax",
2973 /* If the right hand side is const, the lhs is not on stack but still
2974 * in the primary register.
2976 if (flags & CF_CONST) {
2978 switch (flags & CF_TYPE) {
2981 if (flags & CF_FORCECHAR) {
2982 AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
2987 if ((val & 0xFFFF) != 0xFFFF) {
2992 } else if (val != 0xFF) {
2993 AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
2995 } else if ((val & 0xFF00) == 0xFF00) {
2996 AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
2997 } else if ((val & 0x00FF) == 0x0000) {
2998 AddCodeLine ("\ttxa");
2999 AddCodeLine ("\tand\t#$%02X", (unsigned char)(val >> 8));
3000 AddCodeLine ("\ttax");
3003 AddCodeLine ("\ttay");
3004 AddCodeLine ("\ttxa");
3005 AddCodeLine ("\tand\t#$%02X", (unsigned char)(val >> 8));
3006 AddCodeLine ("\ttax");
3007 AddCodeLine ("\ttya");
3008 if ((val & 0x00FF) != 0x00FF) {
3009 AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
3018 AddCodeLine ("\tstx\tsreg+1");
3019 AddCodeLine ("\tstx\tsreg");
3020 if ((val & 0xFF) != 0xFF) {
3021 AddCodeLine ("\tand\t#$%02X", (unsigned char)val);
3024 } else if (val == 0xFF00) {
3026 AddCodeLine ("\tsta\tsreg+1");
3027 AddCodeLine ("\tsta\tsreg");
3036 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3037 * into the normal, non-optimized stuff.
3039 g_push (flags & ~CF_CONST, 0);
3043 /* Use long way over the stack */
3044 oper (flags, val, ops);
3049 void g_asr (unsigned flags, unsigned long val)
3050 /* Primary = TOS >> Primary */
3052 static char* ops [12] = {
3053 0, "tosasra0", "tosasrax",
3054 0, "tosshra0", "tosshrax",
3059 /* If the right hand side is const, the lhs is not on stack but still
3060 * in the primary register.
3062 if (flags & CF_CONST) {
3064 switch (flags & CF_TYPE) {
3068 if (val >= 1 && val <= 3) {
3069 if (flags & CF_UNSIGNED) {
3070 AddCodeLine ("\tjsr\tshrax%ld", val);
3072 AddCodeLine ("\tjsr\tasrax%ld", val);
3075 } else if (val == 8 && (flags & CF_UNSIGNED)) {
3076 AddCodeLine ("\ttxa");
3083 if (val >= 1 && val <= 3) {
3084 if (flags & CF_UNSIGNED) {
3085 AddCodeLine ("\tjsr\tshreax%ld", val);
3087 AddCodeLine ("\tjsr\tasreax%ld", val);
3090 } else if (val == 8 && (flags & CF_UNSIGNED)) {
3091 AddCodeLine ("\ttxa");
3092 AddCodeLine ("\tldx\tsreg");
3093 AddCodeLine ("\tldy\tsreg+1");
3094 AddCodeLine ("\tsty\tsreg");
3095 AddCodeLine ("\tldy\t#$00");
3096 AddCodeLine ("\tsty\tsreg+1");
3098 } else if (val == 16) {
3099 AddCodeLine ("\tldy\t#$00");
3100 AddCodeLine ("\tldx\tsreg+1");
3101 if ((flags & CF_UNSIGNED) == 0) {
3102 AddCodeLine ("\tbpl\t*+3");
3103 AddCodeLine ("\tdey");
3104 AddCodeHint ("y:!");
3106 AddCodeLine ("\tlda\tsreg");
3107 AddCodeLine ("\tsty\tsreg+1");
3108 AddCodeLine ("\tsty\tsreg");
3117 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3118 * into the normal, non-optimized stuff.
3120 g_push (flags & ~CF_CONST, 0);
3124 /* Use long way over the stack */
3125 oper (flags, val, ops);
3130 void g_asl (unsigned flags, unsigned long val)
3131 /* Primary = TOS << Primary */
3133 static char* ops [12] = {
3134 0, "tosasla0", "tosaslax",
3135 0, "tosshla0", "tosshlax",
3141 /* If the right hand side is const, the lhs is not on stack but still
3142 * in the primary register.
3144 if (flags & CF_CONST) {
3146 switch (flags & CF_TYPE) {
3150 if (val >= 1 && val <= 3) {
3151 if (flags & CF_UNSIGNED) {
3152 AddCodeLine ("\tjsr\tshlax%ld", val);
3154 AddCodeLine ("\tjsr\taslax%ld", val);
3157 } else if (val == 8) {
3158 AddCodeLine ("\ttax");
3159 AddCodeLine ("\tlda\t#$00");
3165 if (val >= 1 && val <= 3) {
3166 if (flags & CF_UNSIGNED) {
3167 AddCodeLine ("\tjsr\tshleax%ld", val);
3169 AddCodeLine ("\tjsr\tasleax%ld", val);
3172 } else if (val == 8) {
3173 AddCodeLine ("\tldy\tsreg");
3174 AddCodeLine ("\tsty\tsreg+1");
3175 AddCodeLine ("\tstx\tsreg");
3176 AddCodeLine ("\ttax");
3177 AddCodeLine ("\tlda\t#$00");
3179 } else if (val == 16) {
3180 AddCodeLine ("\tstx\tsreg+1");
3181 AddCodeLine ("\tsta\tsreg");
3182 AddCodeLine ("\tlda\t#$00");
3183 AddCodeLine ("\ttax");
3192 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3193 * into the normal, non-optimized stuff.
3195 g_push (flags & ~CF_CONST, 0);
3199 /* Use long way over the stack */
3200 oper (flags, val, ops);
3205 void g_neg (unsigned flags)
3206 /* Primary = -Primary */
3208 switch (flags & CF_TYPE) {
3212 AddCodeLine ("\tjsr\tnegax");
3216 AddCodeLine ("\tjsr\tnegeax");
3226 void g_bneg (unsigned flags)
3227 /* Primary = !Primary */
3229 switch (flags & CF_TYPE) {
3232 AddCodeLine ("\tjsr\tbnega");
3236 AddCodeLine ("\tjsr\tbnegax");
3240 AddCodeLine ("\tjsr\tbnegeax");
3250 void g_com (unsigned flags)
3251 /* Primary = ~Primary */
3253 switch (flags & CF_TYPE) {
3257 AddCodeLine ("\tjsr\tcomplax");
3261 AddCodeLine ("\tjsr\tcompleax");
3271 void g_inc (unsigned flags, unsigned long val)
3272 /* Increment the primary register by a given number */
3274 /* Don't inc by zero */
3279 /* Generate code for the supported types */
3281 switch (flags & CF_TYPE) {
3284 if (flags & CF_FORCECHAR) {
3285 if (CPU == CPU_65C02 && val <= 2) {
3287 AddCodeLine ("\tina");
3290 AddCodeLine ("\tclc");
3291 AddCodeLine ("\tadc\t#$%02X", (unsigned char)val);
3298 if (CPU == CPU_65C02 && val == 1) {
3299 AddCodeLine ("\tina");
3300 AddCodeLine ("\tbne\t*+3");
3301 AddCodeLine ("\tinx");
3302 /* Tell the optimizer that the X register may be invalid */
3303 AddCodeHint ("x:!");
3304 } else if (CodeSizeFactor < 200) {
3307 AddCodeLine ("\tjsr\tincax%lu", val);
3308 } else if (val <= 255) {
3310 AddCodeLine ("\tjsr\tincaxy");
3312 g_add (flags | CF_CONST, val);
3315 /* Inline the code */
3317 if ((val & 0xFF) != 0) {
3318 AddCodeLine ("\tclc");
3319 AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
3320 AddCodeLine ("\tbcc\t*+3");
3321 AddCodeLine ("\tinx");
3322 /* Tell the optimizer that the X register may be invalid */
3323 AddCodeHint ("x:!");
3326 AddCodeLine ("\tinx");
3329 AddCodeLine ("\tinx");
3332 AddCodeLine ("\tclc");
3333 if ((val & 0xFF) != 0) {
3334 AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
3335 /* Tell the optimizer that the X register may be invalid */
3336 AddCodeHint ("x:!");
3338 AddCodeLine ("\tpha");
3339 AddCodeLine ("\ttxa");
3340 AddCodeLine ("\tadc\t#$%02X", (unsigned char) (val >> 8));
3341 AddCodeLine ("\ttax");
3342 AddCodeLine ("\tpla");
3350 AddCodeLine ("\tjsr\tinceaxy");
3352 g_add (flags | CF_CONST, val);
3364 void g_dec (unsigned flags, unsigned long val)
3365 /* Decrement the primary register by a given number */
3367 /* Don't dec by zero */
3372 /* Generate code for the supported types */
3374 switch (flags & CF_TYPE) {
3377 if (flags & CF_FORCECHAR) {
3378 if (CPU == CPU_65C02 && val <= 2) {
3380 AddCodeLine ("\tdea");
3383 AddCodeLine ("\tsec");
3384 AddCodeLine ("\tsbc\t#$%02X", (unsigned char)val);
3391 if (CodeSizeFactor < 200) {
3392 /* Use subroutines */
3394 AddCodeLine ("\tjsr\tdecax%d", (int) val);
3395 } else if (val <= 255) {
3397 AddCodeLine ("\tjsr\tdecaxy");
3399 g_sub (flags | CF_CONST, val);
3402 /* Inline the code */
3404 if ((val & 0xFF) != 0) {
3405 AddCodeLine ("\tsec");
3406 AddCodeLine ("\tsbc\t#$%02X", (unsigned char) val);
3407 AddCodeLine ("\tbcs\t*+3");
3408 AddCodeLine ("\tdex");
3409 /* Tell the optimizer that the X register may be invalid */
3410 AddCodeHint ("x:!");
3413 AddCodeLine ("\tdex");
3416 AddCodeLine ("\tdex");
3419 AddCodeLine ("\tsec");
3420 if ((val & 0xFF) != 0) {
3421 AddCodeLine ("\tsbc\t#$%02X", (unsigned char) val);
3422 /* Tell the optimizer that the X register may be invalid */
3423 AddCodeHint ("x:!");
3425 AddCodeLine ("\tpha");
3426 AddCodeLine ("\ttxa");
3427 AddCodeLine ("\tsbc\t#$%02X", (unsigned char) (val >> 8));
3428 AddCodeLine ("\ttax");
3429 AddCodeLine ("\tpla");
3437 AddCodeLine ("\tjsr\tdeceaxy");
3439 g_sub (flags | CF_CONST, val);
3452 * Following are the conditional operators. They compare the TOS against
3453 * the primary and put a literal 1 in the primary if the condition is
3454 * true, otherwise they clear the primary register
3459 void g_eq (unsigned flags, unsigned long val)
3460 /* Test for equal */
3462 static char* ops [12] = {
3463 "toseq00", "toseqa0", "toseqax",
3464 "toseq00", "toseqa0", "toseqax",
3469 /* If the right hand side is const, the lhs is not on stack but still
3470 * in the primary register.
3472 if (flags & CF_CONST) {
3474 switch (flags & CF_TYPE) {
3477 if (flags & CF_FORCECHAR) {
3478 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3479 AddCodeLine ("\tjsr\tbooleq");
3485 AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3486 AddCodeLine ("\tbne\t*+4");
3487 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3488 AddCodeLine ("\tjsr\tbooleq");
3498 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3499 * into the normal, non-optimized stuff.
3501 g_push (flags & ~CF_CONST, 0);
3505 /* Use long way over the stack */
3506 oper (flags, val, ops);
3511 void g_ne (unsigned flags, unsigned long val)
3512 /* Test for not equal */
3514 static char* ops [12] = {
3515 "tosne00", "tosnea0", "tosneax",
3516 "tosne00", "tosnea0", "tosneax",
3522 /* If the right hand side is const, the lhs is not on stack but still
3523 * in the primary register.
3525 if (flags & CF_CONST) {
3527 switch (flags & CF_TYPE) {
3530 if (flags & CF_FORCECHAR) {
3531 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3532 AddCodeLine ("\tjsr\tboolne");
3538 AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3539 AddCodeLine ("\tbne\t*+4");
3540 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3541 AddCodeLine ("\tjsr\tboolne");
3551 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3552 * into the normal, non-optimized stuff.
3554 g_push (flags & ~CF_CONST, 0);
3558 /* Use long way over the stack */
3559 oper (flags, val, ops);
3564 void g_lt (unsigned flags, unsigned long val)
3565 /* Test for less than */
3567 static char* ops [12] = {
3568 "toslt00", "toslta0", "tosltax",
3569 "tosult00", "tosulta0", "tosultax",
3574 /* If the right hand side is const, the lhs is not on stack but still
3575 * in the primary register.
3577 if (flags & CF_CONST) {
3579 /* Give a warning in some special cases */
3580 if ((flags & CF_UNSIGNED) && val == 0) {
3581 Warning ("Condition is never true");
3584 /* Look at the type */
3585 switch (flags & CF_TYPE) {
3588 if (flags & CF_FORCECHAR) {
3589 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3590 if (flags & CF_UNSIGNED) {
3591 AddCodeLine ("\tjsr\tboolult");
3593 AddCodeLine ("\tjsr\tboollt");
3600 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3601 /* If we have a signed compare against zero, we only need to
3602 * test the high byte.
3604 AddCodeLine ("\ttxa");
3605 AddCodeLine ("\tjsr\tboollt");
3608 /* Direct code only for unsigned data types */
3609 if (flags & CF_UNSIGNED) {
3610 AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3611 AddCodeLine ("\tbne\t*+4");
3612 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3613 AddCodeLine ("\tjsr\tboolult");
3625 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3626 * into the normal, non-optimized stuff.
3628 g_push (flags & ~CF_CONST, 0);
3632 /* Use long way over the stack */
3633 oper (flags, val, ops);
3638 void g_le (unsigned flags, unsigned long val)
3639 /* Test for less than or equal to */
3641 static char* ops [12] = {
3642 "tosle00", "toslea0", "tosleax",
3643 "tosule00", "tosulea0", "tosuleax",
3649 /* If the right hand side is const, the lhs is not on stack but still
3650 * in the primary register.
3652 if (flags & CF_CONST) {
3654 /* Look at the type */
3655 switch (flags & CF_TYPE) {
3658 if (flags & CF_FORCECHAR) {
3659 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3660 if (flags & CF_UNSIGNED) {
3661 AddCodeLine ("\tjsr\tboolule");
3663 AddCodeLine ("\tjsr\tboolle");
3670 if (flags & CF_UNSIGNED) {
3671 AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3672 AddCodeLine ("\tbne\t*+4");
3673 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3674 AddCodeLine ("\tjsr\tboolule");
3686 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3687 * into the normal, non-optimized stuff.
3689 g_push (flags & ~CF_CONST, 0);
3693 /* Use long way over the stack */
3694 oper (flags, val, ops);
3699 void g_gt (unsigned flags, unsigned long val)
3700 /* Test for greater than */
3702 static char* ops [12] = {
3703 "tosgt00", "tosgta0", "tosgtax",
3704 "tosugt00", "tosugta0", "tosugtax",
3710 /* If the right hand side is const, the lhs is not on stack but still
3711 * in the primary register.
3713 if (flags & CF_CONST) {
3715 /* Look at the type */
3716 switch (flags & CF_TYPE) {
3719 if (flags & CF_FORCECHAR) {
3720 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3721 if (flags & CF_UNSIGNED) {
3722 /* If we have a compare > 0, we will replace it by
3723 * != 0 here, since both are identical but the latter
3724 * is easier to optimize.
3727 AddCodeLine ("\tjsr\tboolugt");
3729 AddCodeLine ("\tjsr\tboolne");
3732 AddCodeLine ("\tjsr\tboolgt");
3739 if (flags & CF_UNSIGNED) {
3740 /* If we have a compare > 0, we will replace it by
3741 * != 0 here, since both are identical but the latter
3742 * is easier to optimize.
3744 if ((val & 0xFFFF) == 0) {
3745 AddCodeLine ("\tstx\ttmp1");
3746 AddCodeLine ("\tora\ttmp1");
3747 AddCodeLine ("\tjsr\tboolne");
3749 AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3750 AddCodeLine ("\tbne\t*+4");
3751 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3752 AddCodeLine ("\tjsr\tboolugt");
3765 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3766 * into the normal, non-optimized stuff.
3768 g_push (flags & ~CF_CONST, 0);
3772 /* Use long way over the stack */
3773 oper (flags, val, ops);
3778 void g_ge (unsigned flags, unsigned long val)
3779 /* Test for greater than or equal to */
3781 static char* ops [12] = {
3782 "tosge00", "tosgea0", "tosgeax",
3783 "tosuge00", "tosugea0", "tosugeax",
3789 /* If the right hand side is const, the lhs is not on stack but still
3790 * in the primary register.
3792 if (flags & CF_CONST) {
3794 /* Give a warning in some special cases */
3795 if ((flags & CF_UNSIGNED) && val == 0) {
3796 Warning ("Condition is always true");
3799 /* Look at the type */
3800 switch (flags & CF_TYPE) {
3803 if (flags & CF_FORCECHAR) {
3804 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3805 if (flags & CF_UNSIGNED) {
3806 AddCodeLine ("\tjsr\tbooluge");
3808 AddCodeLine ("\tjsr\tboolge");
3815 if (flags & CF_UNSIGNED) {
3816 AddCodeLine ("\tcpx\t#$%02X", (unsigned char)(val >> 8));
3817 AddCodeLine ("\tbne\t*+4");
3818 AddCodeLine ("\tcmp\t#$%02X", (unsigned char)val);
3819 AddCodeLine ("\tjsr\tbooluge");
3831 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3832 * into the normal, non-optimized stuff.
3834 g_push (flags & ~CF_CONST, 0);
3838 /* Use long way over the stack */
3839 oper (flags, val, ops);
3844 /*****************************************************************************/
3845 /* Allocating static storage */
3846 /*****************************************************************************/
3850 void g_res (unsigned n)
3851 /* Reserve static storage, n bytes */
3853 AddCodeLine ("\t.res\t%u,$00", n);
3858 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3859 /* Define data with the size given in flags */
3861 if (flags & CF_CONST) {
3863 /* Numeric constant */
3864 switch (flags & CF_TYPE) {
3867 AddCodeLine ("\t.byte\t$%02lX", val & 0xFF);
3871 AddCodeLine ("\t.word\t$%04lX", val & 0xFFFF);
3875 AddCodeLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
3886 /* Create the correct label name */
3887 const char* Label = GetLabelName (flags, val, offs);
3889 /* Labels are always 16 bit */
3890 AddCodeLine ("\t.word\t%s", Label);
3897 void g_defbytes (const void* Bytes, unsigned Count)
3898 /* Output a row of bytes as a constant */
3904 /* Cast the buffer pointer */
3905 const unsigned char* Data = (const unsigned char*) Bytes;
3907 /* Output the stuff */
3910 /* How many go into this line? */
3911 if ((Chunk = Count) > 16) {
3916 /* Output one line */
3917 strcpy (Buf, "\t.byte\t");
3920 B += sprintf (B, "$%02X", *Data++);
3926 /* Output the line */
3933 void g_zerobytes (unsigned n)
3934 /* Output n bytes of data initialized with zero */
3936 AddCodeLine ("\t.res\t%u,$00", n);
3941 /*****************************************************************************/
3942 /* Inlined known functions */
3943 /*****************************************************************************/
3947 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3948 /* Inline the strlen() function */
3950 /* We need a label in both cases */
3951 unsigned label = GetLocalLabel ();
3953 /* Two different encodings */
3954 if (flags & CF_CONST) {
3956 /* The address of the string is constant. Create the correct label name */
3957 char* lbuf = GetLabelName (flags, val, offs);
3959 /* Generate the strlen code */
3960 AddCodeLine ("\tldy\t#$FF");
3961 g_defloclabel (label);
3962 AddCodeLine ("\tiny");
3963 AddCodeLine ("\tlda\t%s,y", lbuf);
3964 AddCodeLine ("\tbne\tL%04X", label);
3965 AddCodeLine ("\ttax");
3966 AddCodeLine ("\ttya");
3970 /* Address not constant but in primary */
3971 if (CodeSizeFactor < 400) {
3972 /* This is too much code, so call strlen instead of inlining */
3973 AddCodeLine ("\tjsr\t_strlen");
3975 /* Inline the function */
3976 AddCodeLine ("\tsta\tptr1");
3977 AddCodeLine ("\tstx\tptr1+1");
3978 AddCodeLine ("\tldy\t#$FF");
3979 g_defloclabel (label);
3980 AddCodeLine ("\tiny");
3981 AddCodeLine ("\tlda\t(ptr1),y");
3982 AddCodeLine ("\tbne\tL%04X", label);
3983 AddCodeLine ("\ttax");
3984 AddCodeLine ("\ttya");