4 * Ullrich von Bassewitz, 08.06.1998
12 #include "../common/version.h"
28 /*****************************************************************************/
30 /*****************************************************************************/
34 /* Compiler relative stk ptr */
39 SEG_INV = -1, /* Invalid segment */
47 static char* SegmentNames [4];
48 static char* SegmentHints [4] = {
49 "seg:code", "seg:rodata", "seg:data", "seg:bss"
53 /*****************************************************************************/
55 /*****************************************************************************/
59 static void typeerror (unsigned type)
60 /* Print an error message about an invalid operand type */
62 Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPE);
67 static void CheckLocalOffs (unsigned Offs)
68 /* Check the offset into the stack for 8bit range */
71 /* Too many local vars */
72 AddCodeLine (";*** Too many locals");
73 Error (ERR_TOO_MANY_LOCALS);
79 static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs)
81 static char lbuf [128]; /* Label name */
83 /* Create the correct label name */
84 switch (flags & CF_ADDRMASK) {
87 /* Static memory cell */
88 sprintf (lbuf, "L%04X+%u", (unsigned)(label & 0xFFFF), offs);
93 sprintf (lbuf, "_%s+%u", (char*) label, offs);
97 /* Absolute address */
98 sprintf (lbuf, "$%04X", (unsigned)((label+offs) & 0xFFFF));
102 /* Variable in register bank */
103 sprintf (lbuf, "regbank+%u", (unsigned)((label+offs) & 0xFFFF));
107 Internal ("Invalid address flags");
110 /* Return a pointer to the static buffer */
116 /*****************************************************************************/
117 /* Pre- and postamble */
118 /*****************************************************************************/
122 void g_preamble (void)
123 /* Generate the assembler code preamble */
125 AddCodeLine ("; File generated by cc65 v %u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
128 /* Insert some object file options */
129 AddCodeLine (".fopt\t\tcompiler,\"cc65 v %u.%u.%u\"", VER_MAJOR, VER_MINOR, VER_PATCH);
132 /* Allow auto import for runtime library routines */
133 AddCodeLine (".autoimport\ton");
135 /* Switch the assembler into case sensible mode */
136 AddCodeLine (".case\t\ton");
138 /* Tell the assembler if we want to generate debug info */
139 AddCodeLine (".debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
141 /* Import the stack pointer for direct auto variable access */
142 AddCodeLine (".importzp\tsp, sreg, regsave, regbank, tmp1, ptr1");
144 /* Define long branch macros */
145 AddCodeLine (".macpack\tlongbranch");
148 /* Define the ldax macro */
149 AddCodeLine (".macro ldax Value");
150 AddCodeLine (" lda #<(Value)");
151 AddCodeLine (" ldx #>(Value)");
152 AddCodeLine (".endmacro");
155 /* Define the default names for the segments */
156 SegmentNames [SEG_CODE] = xstrdup ("CODE");
157 SegmentNames [SEG_RODATA] = xstrdup ("RODATA");
158 SegmentNames [SEG_DATA] = xstrdup ("DATA");
159 SegmentNames [SEG_BSS] = xstrdup ("BSS");
161 /* Tell the optimizer that this is the end of the preamble */
162 AddCodeHint ("end_of_preamble");
167 void g_postamble (void)
168 /* Generate assembler code postamble */
170 /* Tell the optimizer that this is the start of the postamble */
171 AddCodeHint ("start_of_postamble");
176 /*****************************************************************************/
177 /* Segment support */
178 /*****************************************************************************/
182 static void UseSeg (int NewSeg)
183 /* Switch to a specific segment */
185 if (CurSeg != NewSeg) {
187 AddCodeLine (".segment\t\"%s\"", SegmentNames [CurSeg]);
188 AddCodeHint (SegmentHints [CurSeg]);
194 void g_usecode (void)
195 /* Switch to the code segment */
202 void g_userodata (void)
203 /* Switch to the read only data segment */
210 void g_usedata (void)
211 /* Switch to the data segment */
219 /* Switch to the bss segment */
226 static void SegName (int Seg, const char* Name)
227 /* Set the name of a segment */
229 /* Free the old name and set a new one */
230 xfree (SegmentNames [Seg]);
231 SegmentNames [Seg] = xstrdup (Name);
233 /* If the new segment is the current segment, emit a segment directive
237 CurSeg = SEG_INV; /* Invalidate */
244 void g_codename (const char* Name)
245 /* Set the name of the CODE segment */
247 SegName (SEG_CODE, Name);
252 void g_rodataname (const char* Name)
253 /* Set the name of the RODATA segment */
255 SegName (SEG_RODATA, Name);
260 void g_dataname (const char* Name)
261 /* Set the name of the DATA segment */
263 SegName (SEG_DATA, Name);
268 void g_bssname (const char* Name)
269 /* Set the name of the BSS segment */
271 SegName (SEG_BSS, Name);
276 /*****************************************************************************/
278 /*****************************************************************************/
282 unsigned sizeofarg (unsigned flags)
283 /* Return the size of a function argument type that is encoded in flags */
285 switch (flags & CF_TYPE) {
288 return (flags & CF_FORCECHAR)? 1 : 2;
305 int pop (unsigned flags)
306 /* Pop an argument of the given size */
308 return oursp += sizeofarg (flags);
313 int push (unsigned flags)
314 /* Push an argument of the given size */
316 return oursp -= sizeofarg (flags);
321 static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
322 /* The value in Offs is an offset to an address in a/x. Make sure, an object
323 * of the type given in Flags can be loaded or stored into this address by
324 * adding part of the offset to the address in ax, so that the remaining
325 * offset fits into an index register. Return the remaining offset.
328 /* If the offset is too large for a byte register, add the high byte
329 * of the offset to the primary. Beware: We need a special correction
330 * if the offset in the low byte will overflow in the operation.
332 unsigned O = Offs & ~0xFFU;
333 if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
334 /* We need to add the low byte also */
338 /* Do the correction if we need one */
340 g_inc (CF_INT | CF_CONST, O);
344 /* Return the new offset */
350 /*****************************************************************************/
351 /* Functions handling local labels */
352 /*****************************************************************************/
356 void g_defloclabel (unsigned label)
357 /* Define a local label */
359 AddCodeLine ("L%04X:", label & 0xFFFF);
364 /*****************************************************************************/
365 /* Functions handling global labels */
366 /*****************************************************************************/
370 void g_defgloblabel (const char* Name)
371 /* Define a global label with the given name */
373 AddCodeLine ("_%s:", Name);
378 void g_defexport (const char* Name, int ZP)
379 /* Export the given label */
382 AddCodeLine ("\t.exportzp\t_%s", Name);
384 AddCodeLine ("\t.export\t\t_%s", Name);
390 void g_defimport (const char* Name, int ZP)
391 /* Import the given label */
394 AddCodeLine ("\t.importzp\t_%s", Name);
396 AddCodeLine ("\t.import\t\t_%s", Name);
402 /*****************************************************************************/
403 /* Load functions for various registers */
404 /*****************************************************************************/
408 static void ldaconst (unsigned val)
409 /* Load a with a constant */
411 AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
416 static void ldxconst (unsigned val)
417 /* Load x with a constant */
419 AddCodeLine ("\tldx\t#$%02X", val & 0xFF);
424 static void ldyconst (unsigned val)
425 /* Load y with a constant */
427 AddCodeLine ("\tldy\t#$%02X", val & 0xFF);
432 /*****************************************************************************/
433 /* Function entry and exit */
434 /*****************************************************************************/
438 /* Remember the argument size of a function. The variable is set by g_enter
439 * and used by g_leave. If the functions gets its argument size by the caller
440 * (variable param list or function without prototype), g_enter will set the
446 void g_enter (unsigned flags, unsigned argsize)
447 /* Function prologue */
449 if ((flags & CF_FIXARGC) != 0) {
450 /* Just remember the argument size for the leave */
454 AddCodeLine ("\tjsr\tenter");
460 void g_leave (int flags, int val)
461 /* Function epilogue */
466 /* How many bytes of locals do we have to drop? */
469 /* If we didn't have a variable argument list, don't call leave */
472 /* Load a function return code if needed */
473 if ((flags & CF_CONST) != 0) {
474 g_getimmed (flags, val, 0);
477 /* Drop stackframe or leave with rts */
480 AddCodeLine ("\trts");
482 AddCodeLine ("\tjmp\tincsp%d", k);
486 AddCodeLine ("\tjmp\taddysp");
491 strcpy (buf, "\tjmp\tleave");
493 /* We've a stack frame to drop */
497 if (flags & CF_CONST) {
498 if ((flags & CF_TYPE) != CF_LONG) {
499 /* Constant int sized value given for return code */
501 /* Special case: return 0 */
503 } else if (((val >> 8) & 0xFF) == 0) {
504 /* Special case: constant with high byte zero */
505 ldaconst (val); /* Load low byte */
508 /* Others: arbitrary constant value */
509 g_getimmed (flags, val, 0); /* Load value */
512 /* Constant long value: No shortcut possible */
513 g_getimmed (flags, val, 0);
517 /* Output the jump */
521 /* Add an empty line after a function to make the code more readable */
527 /*****************************************************************************/
528 /* Register variables */
529 /*****************************************************************************/
533 void g_save_regvars (int RegOffs, unsigned Bytes)
534 /* Save register variables */
536 /* Don't loop for up to two bytes */
539 AddCodeLine ("\tlda\tregbank%+d", RegOffs);
540 AddCodeLine ("\tjsr\tpusha");
542 } else if (Bytes == 2) {
544 AddCodeLine ("\tlda\tregbank%+d", RegOffs);
545 AddCodeLine ("\tldx\tregbank%+d", RegOffs+1);
546 AddCodeLine ("\tjsr\tpushax");
550 /* More than two bytes - loop */
551 unsigned Label = GetLabel ();
553 ldyconst (Bytes - 1);
555 g_defloclabel (Label);
556 AddCodeLine ("\tlda\tregbank%+d,x", RegOffs-1);
557 AddCodeLine ("\tsta\t(sp),y");
558 AddCodeLine ("\tdey");
559 AddCodeLine ("\tdex");
560 AddCodeLine ("\tbne\tL%04X", Label);
564 /* We pushed stuff, correct the stack pointer */
570 void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
571 /* Restore register variables */
573 /* Calculate the actual stack offset and check it */
575 CheckLocalOffs (StackOffs);
577 /* Don't loop for up to two bytes */
580 ldyconst (StackOffs);
581 AddCodeLine ("\tlda\t(sp),y");
582 AddCodeLine ("\tsta\tregbank%+d", RegOffs);
584 } else if (Bytes == 2) {
586 ldyconst (StackOffs);
587 AddCodeLine ("\tlda\t(sp),y");
588 AddCodeLine ("\tsta\tregbank%+d", RegOffs);
589 AddCodeLine ("\tiny");
590 AddCodeLine ("\tlda\t(sp),y");
591 AddCodeLine ("\tsta\tregbank%+d", RegOffs+1);
595 /* More than two bytes - loop */
596 unsigned Label = GetLabel ();
597 ldyconst (StackOffs+Bytes-1);
599 g_defloclabel (Label);
600 AddCodeLine ("\tlda\t(sp),y");
601 AddCodeLine ("\tsta\tregbank%+d,x", RegOffs-1);
602 AddCodeLine ("\tdey");
603 AddCodeLine ("\tdex");
604 AddCodeLine ("\tbne\tL%04X", Label);
611 /*****************************************************************************/
612 /* Fetching memory cells */
613 /*****************************************************************************/
617 void g_getimmed (unsigned flags, unsigned long val, unsigned offs)
618 /* Load a constant into the primary register */
620 if ((flags & CF_CONST) != 0) {
622 /* Numeric constant */
623 switch (flags & CF_TYPE) {
626 if ((flags & CF_FORCECHAR) != 0) {
632 ldxconst ((val >> 8) & 0xFF);
633 ldaconst (val & 0xFF);
638 AddCodeLine ("\tldx\t#$00");
639 AddCodeLine ("\tstx\tsreg+1");
640 AddCodeLine ("\tstx\tsreg");
641 AddCodeLine ("\tlda\t#$%02X", (unsigned char) val);
642 } else if ((val & 0xFFFF00FF) == 0) {
643 AddCodeLine ("\tlda\t#$00");
644 AddCodeLine ("\tsta\tsreg+1");
645 AddCodeLine ("\tsta\tsreg");
646 AddCodeLine ("\tldx\t#$%02X", (unsigned char) (val >> 8));
647 } else if ((val & 0xFFFF0000) == 0 && FavourSize == 0) {
648 AddCodeLine ("\tlda\t#$00");
649 AddCodeLine ("\tsta\tsreg+1");
650 AddCodeLine ("\tsta\tsreg");
651 AddCodeLine ("\tlda\t#$%02X", (unsigned char) val);
652 AddCodeLine ("\tldx\t#$%02X", (unsigned char) (val >> 8));
653 } else if ((val & 0xFFFFFF00) == 0xFFFFFF00) {
654 AddCodeLine ("\tldx\t#$FF");
655 AddCodeLine ("\tstx\tsreg+1");
656 AddCodeLine ("\tstx\tsreg");
657 if ((val & 0xFF) == 0xFF) {
658 AddCodeLine ("\ttxa");
660 AddCodeLine ("\tlda\t#$%02X", (unsigned char) val);
662 } else if ((val & 0xFFFF00FF) == 0xFFFF00FF) {
663 AddCodeLine ("\tlda\t#$FF");
664 AddCodeLine ("\tsta\tsreg+1");
665 AddCodeLine ("\tsta\tsreg");
666 AddCodeLine ("\tldx\t#$%02X", (unsigned char) (val >> 8));
668 /* Call a subroutine that will load following value */
669 AddCodeLine ("\tjsr\tldeax");
670 AddCodeLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
682 /* Some sort of label */
683 const char* Label = GetLabelName (flags, val, offs);
685 /* Load the address into the primary */
686 AddCodeLine ("\tldax\t%s", Label);
693 void g_getstatic (unsigned flags, unsigned long label, unsigned offs)
694 /* Fetch an static memory cell into the primary register */
696 /* Create the correct label name */
697 char* lbuf = GetLabelName (flags, label, offs);
699 /* Check the size and generate the correct load operation */
700 switch (flags & CF_TYPE) {
703 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
704 AddCodeLine ("\tlda\t%s", lbuf); /* load A from the label */
707 AddCodeLine ("\tlda\t%s", lbuf); /* load A from the label */
708 if (!(flags & CF_UNSIGNED)) {
709 /* Must sign extend */
710 AddCodeLine ("\tbpl\t*+3");
711 AddCodeLine ("\tdex");
712 AddCodeHint ("x:!"); /* X is invalid now */
718 AddCodeLine ("\tlda\t%s", lbuf);
719 if (flags & CF_TEST) {
720 AddCodeLine ("\tora\t%s+1", lbuf);
722 AddCodeLine ("\tldx\t%s+1", lbuf);
727 if (flags & CF_TEST) {
728 AddCodeLine ("\tlda\t%s+3", lbuf);
729 AddCodeLine ("\tora\t%s+2", lbuf);
730 AddCodeLine ("\tora\t%s+1", lbuf);
731 AddCodeLine ("\tora\t%s+0", lbuf);
733 AddCodeLine ("\tlda\t%s+3", lbuf);
734 AddCodeLine ("\tsta\tsreg+1");
735 AddCodeLine ("\tlda\t%s+2", lbuf);
736 AddCodeLine ("\tsta\tsreg");
737 AddCodeLine ("\tldx\t%s+1", lbuf);
738 AddCodeLine ("\tlda\t%s", lbuf);
750 void g_getlocal (unsigned flags, int offs)
751 /* Fetch specified local object (local var). */
754 CheckLocalOffs (offs);
755 switch (flags & CF_TYPE) {
758 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
760 AddCodeLine ("\tlda\t(sp),y");
763 AddCodeLine ("\tldx\t#$00");
764 AddCodeLine ("\tlda\t(sp,x)");
767 AddCodeLine ("\tldx\t#$00");
768 AddCodeLine ("\tlda\t(sp),y");
770 if ((flags & CF_UNSIGNED) == 0) {
771 AddCodeLine ("\tbpl\t*+3");
772 AddCodeLine ("\tdex");
773 AddCodeHint ("x:!"); /* X is invalid now */
779 CheckLocalOffs (offs + 1);
780 if (flags & CF_TEST) {
782 AddCodeLine ("\tlda\t(sp),y");
783 AddCodeLine ("\tdey");
784 AddCodeLine ("\tora\t(sp),y");
789 AddCodeLine ("\tjsr\tldaxysp");
791 AddCodeLine ("\tjsr\tldax0sp");
795 AddCodeLine ("\tlda\t(sp),y");
796 AddCodeLine ("\ttax");
797 AddCodeLine ("\tdey");
798 AddCodeLine ("\tlda\t(sp),y");
806 AddCodeLine ("\tjsr\tldeaxysp");
808 AddCodeLine ("\tjsr\tldeax0sp");
819 void g_getind (unsigned flags, unsigned offs)
820 /* Fetch the specified object type indirect through the primary register
821 * into the primary register
824 /* If the offset is greater than 255, add the part that is > 255 to
825 * the primary. This way we get an easy addition and use the low byte
828 offs = MakeByteOffs (flags, offs);
830 /* Handle the indirect fetch */
831 switch (flags & CF_TYPE) {
834 /* Character sized */
837 if (flags & CF_UNSIGNED) {
838 AddCodeLine ("\tjsr\tldauidx");
840 AddCodeLine ("\tjsr\tldaidx");
843 if (flags & CF_UNSIGNED) {
845 AddCodeLine ("\tjsr\tldaui");
847 AddCodeLine ("\tsta\tptr1");
848 AddCodeLine ("\tstx\tptr1+1");
849 AddCodeLine ("\tldx\t#$00");
850 AddCodeLine ("\tlda\t(ptr1,x)");
853 AddCodeLine ("\tjsr\tldai");
859 if (flags & CF_TEST) {
861 AddCodeLine ("\tsta\tptr1");
862 AddCodeLine ("\tstx\tptr1+1");
863 AddCodeLine ("\tlda\t(ptr1),y");
864 AddCodeLine ("\tiny");
865 AddCodeLine ("\tora\t(ptr1),y");
868 AddCodeLine ("\tjsr\tldaxi");
871 AddCodeLine ("\tjsr\tldaxidx");
878 AddCodeLine ("\tjsr\tldeaxi");
881 AddCodeLine ("\tjsr\tldeaxidx");
883 if (flags & CF_TEST) {
884 AddCodeLine ("\tjsr\ttsteax");
896 void g_leasp (int offs)
897 /* Fetch the address of the specified symbol into the primary register */
899 /* Calculate the offset relative to sp */
902 /* For value 0 we do direct code */
904 AddCodeLine ("\tlda\tsp");
905 AddCodeLine ("\tldx\tsp+1");
908 ldyconst (offs); /* Load Y with offset value */
909 AddCodeLine ("\tjsr\tleaysp"); /* Load effective address */
912 AddCodeLine ("\tclc");
913 AddCodeLine ("\tldx\tsp+1");
914 AddCodeLine ("\tadc\tsp");
915 AddCodeLine ("\tbcc\t*+3");
916 AddCodeLine ("\tinx");
917 AddCodeHint ("x:!"); /* Invalidate X */
924 /*****************************************************************************/
925 /* Store into memory */
926 /*****************************************************************************/
930 void g_putstatic (unsigned flags, unsigned long label, unsigned offs)
931 /* Store the primary register into the specified static memory cell */
933 /* Create the correct label name */
934 char* lbuf = GetLabelName (flags, label, offs);
936 /* Check the size and generate the correct store operation */
937 switch (flags & CF_TYPE) {
940 AddCodeLine ("\tsta\t%s", lbuf);
944 AddCodeLine ("\tsta\t%s", lbuf);
945 AddCodeLine ("\tstx\t%s+1", lbuf);
949 AddCodeLine ("\tsta\t%s", lbuf);
950 AddCodeLine ("\tstx\t%s+1", lbuf);
951 AddCodeLine ("\tldy\tsreg");
952 AddCodeLine ("\tsty\t%s+2", lbuf);
953 AddCodeLine ("\tldy\tsreg+1");
954 AddCodeLine ("\tsty\t%s+3", lbuf);
965 void g_putlocal (unsigned flags, int offs)
966 /* Put data into local object. */
969 CheckLocalOffs (offs);
970 switch (flags & CF_TYPE) {
974 AddCodeLine ("\tsta\t(sp),y");
980 AddCodeLine ("\tjsr\tstaxysp");
982 AddCodeLine ("\tjsr\tstax0sp");
989 AddCodeLine ("\tjsr\tsteaxysp");
991 AddCodeLine ("\tjsr\tsteax0sp");
1003 void g_putind (unsigned flags, unsigned offs)
1004 /* Store the specified object type in the primary register at the address
1005 * on the top of the stack
1008 /* We cannot currently handle more than byte sized offsets */
1009 if (offs > 256 - sizeofarg (flags)) {
1010 Internal ("g_putind: Large offsets not implemented");
1013 /* Check the size and determine operation */
1014 switch (flags & CF_TYPE) {
1019 AddCodeLine ("\tjsr\tstaspidx");
1021 AddCodeLine ("\tjsr\tstaspp");
1028 AddCodeLine ("\tjsr\tstaxspidx");
1030 AddCodeLine ("\tjsr\tstaxspp");
1037 AddCodeLine ("\tjsr\tsteaxspidx");
1039 AddCodeLine ("\tjsr\tsteaxspp");
1048 /* Pop the argument which is always a pointer */
1054 /*****************************************************************************/
1055 /* type conversion and similiar stuff */
1056 /*****************************************************************************/
1060 void g_toslong (unsigned flags)
1061 /* Make sure, the value on TOS is a long. Convert if necessary */
1063 switch (flags & CF_TYPE) {
1067 if (flags & CF_UNSIGNED) {
1068 AddCodeLine ("\tjsr\ttosulong");
1070 AddCodeLine ("\tjsr\ttoslong");
1085 void g_tosint (unsigned flags)
1086 /* Make sure, the value on TOS is an int. Convert if necessary */
1088 switch (flags & CF_TYPE) {
1095 AddCodeLine ("\tjsr\ttosint");
1106 void g_reglong (unsigned flags)
1107 /* Make sure, the value in the primary register a long. Convert if necessary */
1109 switch (flags & CF_TYPE) {
1113 if (flags & CF_UNSIGNED) {
1115 AddCodeLine ("\tjsr\taxulong");
1118 AddCodeLine ("\tsty\tsreg");
1119 AddCodeLine ("\tsty\tsreg+1");
1122 AddCodeLine ("\tjsr\taxlong");
1136 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1137 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1138 * value, that corresponds to the value on TOS, rhs corresponds to the value
1139 * in (e)ax. The return value is the the flags value for the resulting type.
1142 unsigned ltype, rtype;
1145 /* Get the type spec from the flags */
1146 ltype = lhs & CF_TYPE;
1147 rtype = rhs & CF_TYPE;
1149 /* Check if a conversion is needed */
1150 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1151 /* We must promote the primary register to long */
1153 /* Get the new rhs type */
1154 rhs = (rhs & ~CF_TYPE) | CF_LONG;
1156 } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1157 /* We must promote the lhs to long */
1163 /* Get the new rhs type */
1164 lhs = (lhs & ~CF_TYPE) | CF_LONG;
1168 /* Determine the result type for the operation:
1169 * - The result is const if both operands are const.
1170 * - The result is unsigned if one of the operands is unsigned.
1171 * - The result is long if one of the operands is long.
1172 * - Otherwise the result is int sized.
1174 result = (lhs & CF_CONST) & (rhs & CF_CONST);
1175 result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1176 if (rtype == CF_LONG || ltype == CF_LONG) {
1186 unsigned g_typecast (unsigned lhs, unsigned rhs)
1187 /* Cast the value in the primary register to the operand size that is flagged
1188 * by the lhs value. Return the result value.
1191 unsigned ltype, rtype;
1193 /* Get the type spec from the flags */
1194 ltype = lhs & CF_TYPE;
1195 rtype = rhs & CF_TYPE;
1197 /* Check if a conversion is needed */
1198 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1199 /* We must promote the primary register to long */
1203 /* Do not need any other action. If the left type is int, and the primary
1204 * register is long, it will be automagically truncated. If the right hand
1205 * side is const, it is not located in the primary register and handled by
1206 * the expression parser code.
1209 /* Result is const if the right hand side was const */
1210 lhs |= (rhs & CF_CONST);
1212 /* The resulting type is that of the left hand side (that's why you called
1220 void g_scale (unsigned flags, long val)
1221 /* Scale the value in the primary register by the given value. If val is positive,
1222 * scale up, is val is negative, scale down. This function is used to scale
1223 * the operands or results of pointer arithmetic by the size of the type, the
1224 * pointer points to.
1229 /* Value may not be zero */
1231 Internal ("Data type has no size");
1232 } else if (val > 0) {
1235 if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1237 /* Factor is 2, 4 or 8, use special function */
1238 switch (flags & CF_TYPE) {
1241 if (flags & CF_FORCECHAR) {
1243 AddCodeLine ("\tasl\ta");
1250 if (FavourSize || p2 >= 3) {
1251 if (flags & CF_UNSIGNED) {
1252 AddCodeLine ("\tjsr\tshlax%d", p2);
1254 AddCodeLine ("\tjsr\taslax%d", p2);
1257 AddCodeLine ("\tstx\ttmp1");
1259 AddCodeLine ("\tasl\ta");
1260 AddCodeLine ("\trol\ttmp1");
1262 AddCodeLine ("\tldx\ttmp1");
1267 if (flags & CF_UNSIGNED) {
1268 AddCodeLine ("\tjsr\tshleax%d", p2);
1270 AddCodeLine ("\tjsr\tasleax%d", p2);
1279 } else if (val != 1) {
1281 /* Use a multiplication instead */
1282 g_mul (flags | CF_CONST, val);
1290 if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1292 /* Factor is 2, 4 or 8, use special function */
1293 switch (flags & CF_TYPE) {
1296 if (flags & CF_FORCECHAR) {
1297 if (flags & CF_UNSIGNED) {
1299 AddCodeLine ("\tlsr\ta");
1302 } else if (p2 <= 2) {
1303 AddCodeLine ("\tcmp\t#$80");
1304 AddCodeLine ("\tror\ta");
1311 if (flags & CF_UNSIGNED) {
1312 if (FavourSize || p2 >= 3) {
1313 AddCodeLine ("\tjsr\tlsrax%d", p2);
1315 AddCodeLine ("\tstx\ttmp1");
1317 AddCodeLine ("\tlsr\ttmp1");
1318 AddCodeLine ("\tror\ta");
1320 AddCodeLine ("\tldx\ttmp1");
1323 if (FavourSize || p2 >= 3) {
1324 AddCodeLine ("\tjsr\tasrax%d", p2);
1326 AddCodeLine ("\tstx\ttmp1");
1328 AddCodeLine ("\tcpx\t#$80");
1329 AddCodeLine ("\tror\ttmp1");
1330 AddCodeLine ("\tror\ta");
1332 AddCodeLine ("\tldx\ttmp1");
1338 if (flags & CF_UNSIGNED) {
1339 AddCodeLine ("\tjsr\tlsreax%d", p2);
1341 AddCodeLine ("\tjsr\tasreax%d", p2);
1350 } else if (val != 1) {
1352 /* Use a division instead */
1353 g_div (flags | CF_CONST, val);
1361 /*****************************************************************************/
1362 /* Adds and subs of variables fix a fixed address */
1363 /*****************************************************************************/
1367 void g_addlocal (unsigned flags, int offs)
1368 /* Add a local variable to ax */
1370 /* Correct the offset and check it */
1372 CheckLocalOffs (offs);
1374 switch (flags & CF_TYPE) {
1377 AddCodeLine ("\tldy\t#$%02X", offs & 0xFF);
1378 AddCodeLine ("\tclc");
1379 AddCodeLine ("\tadc\t(sp),y");
1380 AddCodeLine ("\tbcc\t*+3");
1381 AddCodeLine ("\tinx");
1382 AddCodeHint ("x:!");
1386 AddCodeLine ("\tldy\t#$%02X", offs & 0xFF);
1387 AddCodeLine ("\tclc");
1388 AddCodeLine ("\tadc\t(sp),y");
1389 AddCodeLine ("\tpha");
1390 AddCodeLine ("\ttxa");
1391 AddCodeLine ("\tiny");
1392 AddCodeLine ("\tadc\t(sp),y");
1393 AddCodeLine ("\ttax");
1394 AddCodeLine ("\tpla");
1398 /* Do it the old way */
1400 g_getlocal (flags, offs);
1412 void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
1413 /* Add a static variable to ax */
1415 /* Create the correct label name */
1416 char* lbuf = GetLabelName (flags, label, offs);
1418 switch (flags & CF_TYPE) {
1421 AddCodeLine ("\tclc");
1422 AddCodeLine ("\tadc\t%s", lbuf);
1423 AddCodeLine ("\tbcc\t*+3");
1424 AddCodeLine ("\tinx");
1425 AddCodeHint ("x:!");
1429 AddCodeLine ("\tclc");
1430 AddCodeLine ("\tadc\t%s", lbuf);
1431 AddCodeLine ("\ttay");
1432 AddCodeLine ("\ttxa");
1433 AddCodeLine ("\tadc\t%s+1", lbuf);
1434 AddCodeLine ("\ttax");
1435 AddCodeLine ("\ttya");
1439 /* Do it the old way */
1441 g_getstatic (flags, label, offs);
1453 /*****************************************************************************/
1454 /* Compares of ax with a variable with fixed address */
1455 /*****************************************************************************/
1459 void g_cmplocal (unsigned flags, int offs)
1460 /* Compare a local variable to ax */
1462 Internal ("g_cmplocal not implemented");
1467 void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
1468 /* Compare a static variable to ax */
1470 Internal ("g_cmpstatic not implemented");
1475 /*****************************************************************************/
1476 /* Special op= functions */
1477 /*****************************************************************************/
1481 void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
1483 /* Emit += for a static variable */
1485 /* Create the correct label name */
1486 char* lbuf = GetLabelName (flags, label, offs);
1488 /* Check the size and determine operation */
1489 switch (flags & CF_TYPE) {
1492 if (flags & CF_FORCECHAR) {
1493 AddCodeLine ("\tldx\t#$00");
1494 if (flags & CF_CONST) {
1496 AddCodeLine ("\tinc\t%s", lbuf);
1497 AddCodeLine ("\tlda\t%s", lbuf);
1499 AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
1500 AddCodeLine ("\tclc");
1501 AddCodeLine ("\tadc\t%s", lbuf);
1502 AddCodeLine ("\tsta\t%s", lbuf);
1505 AddCodeLine ("\tclc");
1506 AddCodeLine ("\tadc\t%s", lbuf);
1507 AddCodeLine ("\tsta\t%s", lbuf);
1509 if ((flags & CF_UNSIGNED) == 0) {
1510 AddCodeLine ("\tbpl\t*+3");
1511 AddCodeLine ("\tdex");
1512 AddCodeHint ("x:!"); /* Invalidate X */
1519 if (flags & CF_CONST) {
1521 label = GetLabel ();
1522 AddCodeLine ("\tinc\t%s", lbuf);
1523 AddCodeLine ("\tbne\tL%04X", label);
1524 AddCodeLine ("\tinc\t%s+1", lbuf);
1525 g_defloclabel (label);
1526 AddCodeLine ("\tlda\t%s", lbuf); /* Hmmm... */
1527 AddCodeLine ("\tldx\t%s+1", lbuf);
1529 AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
1530 AddCodeLine ("\tclc");
1531 AddCodeLine ("\tadc\t%s", lbuf);
1532 AddCodeLine ("\tsta\t%s", lbuf);
1534 label = GetLabel ();
1535 AddCodeLine ("\tbcc\tL%04X", label);
1536 AddCodeLine ("\tinc\t%s+1", lbuf);
1537 g_defloclabel (label);
1538 AddCodeLine ("\tldx\t%s+1", lbuf);
1540 AddCodeLine ("\tlda\t#$%02X", (val >> 8) & 0xFF);
1541 AddCodeLine ("\tadc\t%s+1", lbuf);
1542 AddCodeLine ("\tsta\t%s+1", lbuf);
1543 AddCodeLine ("\ttax");
1544 AddCodeLine ("\tlda\t%s", lbuf);
1548 AddCodeLine ("\tclc");
1549 AddCodeLine ("\tadc\t%s", lbuf);
1550 AddCodeLine ("\tsta\t%s", lbuf);
1551 AddCodeLine ("\ttxa");
1552 AddCodeLine ("\tadc\t%s+1", lbuf);
1553 AddCodeLine ("\tsta\t%s+1", lbuf);
1554 AddCodeLine ("\ttax");
1555 AddCodeLine ("\tlda\t%s", lbuf);
1560 if (flags & CF_CONST) {
1562 AddCodeLine ("\tldy\t#<(%s)", lbuf);
1563 AddCodeLine ("\tsty\tptr1");
1564 AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
1566 AddCodeLine ("\tjsr\tladdeq1");
1568 AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
1569 AddCodeLine ("\tjsr\tladdeqa");
1572 g_getstatic (flags, label, offs);
1574 g_putstatic (flags, label, offs);
1577 AddCodeLine ("\tldy\t#<(%s)", lbuf);
1578 AddCodeLine ("\tsty\tptr1");
1579 AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
1580 AddCodeLine ("\tjsr\tladdeq");
1591 void g_addeqlocal (unsigned flags, int offs, unsigned long val)
1592 /* Emit += for a local variable */
1594 /* Calculate the true offset, check it, load it into Y */
1596 CheckLocalOffs (offs);
1598 /* Check the size and determine operation */
1599 switch (flags & CF_TYPE) {
1602 if (flags & CF_FORCECHAR) {
1604 AddCodeLine ("\tldx\t#$00");
1605 if (flags & CF_CONST) {
1606 AddCodeLine ("\tclc");
1607 AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
1608 AddCodeLine ("\tadc\t(sp,x)");
1609 AddCodeLine ("\tsta\t(sp,x)");
1611 AddCodeLine ("\tclc");
1612 AddCodeLine ("\tadc\t(sp,x)");
1613 AddCodeLine ("\tsta\t(sp,x)");
1617 AddCodeLine ("\tldx\t#$00");
1618 if (flags & CF_CONST) {
1619 AddCodeLine ("\tclc");
1620 AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
1621 AddCodeLine ("\tadc\t(sp),y");
1622 AddCodeLine ("\tsta\t(sp),y");
1624 AddCodeLine ("\tclc");
1625 AddCodeLine ("\tadc\t(sp),y");
1626 AddCodeLine ("\tsta\t(sp),y");
1629 if ((flags & CF_UNSIGNED) == 0) {
1630 AddCodeLine ("\tbpl\t*+3");
1631 AddCodeLine ("\tdex");
1632 AddCodeHint ("x:!"); /* Invalidate X */
1639 if (flags & CF_CONST) {
1640 g_getimmed (flags, val, 0);
1643 AddCodeLine ("\tjsr\taddeq0sp");
1646 AddCodeLine ("\tjsr\taddeqysp");
1651 if (flags & CF_CONST) {
1652 g_getimmed (flags, val, 0);
1655 AddCodeLine ("\tjsr\tladdeq0sp");
1658 AddCodeLine ("\tjsr\tladdeqysp");
1669 void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1670 /* Emit += for the location with address in ax */
1672 /* If the offset is too large for a byte register, add the high byte
1673 * of the offset to the primary. Beware: We need a special correction
1674 * if the offset in the low byte will overflow in the operation.
1676 offs = MakeByteOffs (flags, offs);
1678 /* Check the size and determine operation */
1679 switch (flags & CF_TYPE) {
1682 AddCodeLine ("\tsta\tptr1");
1683 AddCodeLine ("\tstx\tptr1+1");
1685 AddCodeLine ("\tldx\t#$00");
1686 AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
1687 AddCodeLine ("\tclc");
1688 AddCodeLine ("\tadc\t(ptr1,x)");
1689 AddCodeLine ("\tsta\t(ptr1,x)");
1691 AddCodeLine ("\tldy\t#$%02X", offs);
1692 AddCodeLine ("\tldx\t#$00");
1693 AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
1694 AddCodeLine ("\tclc");
1695 AddCodeLine ("\tadc\t(ptr1),y");
1696 AddCodeLine ("\tsta\t(ptr1),y");
1702 /* Lots of code, use only if size is not important */
1703 AddCodeLine ("\tsta\tptr1");
1704 AddCodeLine ("\tstx\tptr1+1");
1705 AddCodeLine ("\tldy\t#$%02X", offs);
1706 AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
1707 AddCodeLine ("\tclc");
1708 AddCodeLine ("\tadc\t(ptr1),y");
1709 AddCodeLine ("\tsta\t(ptr1),y");
1710 AddCodeLine ("\tpha");
1711 AddCodeLine ("\tiny");
1712 AddCodeLine ("\tlda\t#$%02X", (val >> 8) & 0xFF);
1713 AddCodeLine ("\tadc\t(ptr1),y");
1714 AddCodeLine ("\tsta\t(ptr1),y");
1715 AddCodeLine ("\ttax");
1716 AddCodeLine ("\tpla");
1722 AddCodeLine ("\tjsr\tpushax"); /* Push the address */
1723 push (flags); /* Correct the internal sp */
1724 g_getind (flags, offs); /* Fetch the value */
1725 g_inc (flags, val); /* Increment value in primary */
1726 g_putind (flags, offs); /* Store the value back */
1736 void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
1738 /* Emit -= for a static variable */
1740 /* Create the correct label name */
1741 char* lbuf = GetLabelName (flags, label, offs);
1743 /* Check the size and determine operation */
1744 switch (flags & CF_TYPE) {
1747 if (flags & CF_FORCECHAR) {
1748 AddCodeLine ("\tldx\t#$00");
1749 if (flags & CF_CONST) {
1751 AddCodeLine ("\tdec\t%s", lbuf);
1752 AddCodeLine ("\tlda\t%s", lbuf);
1754 AddCodeLine ("\tsec");
1755 AddCodeLine ("\tlda\t%s", lbuf);
1756 AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
1757 AddCodeLine ("\tsta\t%s", lbuf);
1760 AddCodeLine ("\tsec");
1761 AddCodeLine ("\tsta\ttmp1");
1762 AddCodeLine ("\tlda\t%s", lbuf);
1763 AddCodeLine ("\tsbc\ttmp1");
1764 AddCodeLine ("\tsta\t%s", lbuf);
1766 if ((flags & CF_UNSIGNED) == 0) {
1767 AddCodeLine ("\tbpl\t*+3");
1768 AddCodeLine ("\tdex");
1769 AddCodeHint ("x:!"); /* Invalidate X */
1776 AddCodeLine ("\tsec");
1777 if (flags & CF_CONST) {
1778 AddCodeLine ("\tlda\t%s", lbuf);
1779 AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
1780 AddCodeLine ("\tsta\t%s", lbuf);
1782 label = GetLabel ();
1783 AddCodeLine ("\tbcs\tL%04X", label);
1784 AddCodeLine ("\tdec\t%s+1", lbuf);
1785 g_defloclabel (label);
1786 AddCodeLine ("\tldx\t%s+1", lbuf);
1788 AddCodeLine ("\tlda\t%s+1", lbuf);
1789 AddCodeLine ("\tsbc\t#$%02X", (val >> 8) & 0xFF);
1790 AddCodeLine ("\tsta\t%s+1", lbuf);
1791 AddCodeLine ("\ttax");
1792 AddCodeLine ("\tlda\t%s", lbuf);
1795 AddCodeLine ("\tsta\ttmp1");
1796 AddCodeLine ("\tlda\t%s", lbuf);
1797 AddCodeLine ("\tsbc\ttmp1");
1798 AddCodeLine ("\tsta\t%s", lbuf);
1799 AddCodeLine ("\tstx\ttmp1");
1800 AddCodeLine ("\tlda\t%s+1", lbuf);
1801 AddCodeLine ("\tsbc\ttmp1");
1802 AddCodeLine ("\tsta\t%s+1", lbuf);
1803 AddCodeLine ("\ttax");
1804 AddCodeLine ("\tlda\t%s", lbuf);
1809 if (flags & CF_CONST) {
1811 AddCodeLine ("\tldy\t#<(%s)", lbuf);
1812 AddCodeLine ("\tsty\tptr1");
1813 AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
1815 AddCodeLine ("\tjsr\tlsubeq1");
1817 AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
1818 AddCodeLine ("\tjsr\tlsubeqa");
1821 g_getstatic (flags, label, offs);
1823 g_putstatic (flags, label, offs);
1826 AddCodeLine ("\tldy\t#<(%s)", lbuf);
1827 AddCodeLine ("\tsty\tptr1");
1828 AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
1829 AddCodeLine ("\tjsr\tlsubeq");
1840 void g_subeqlocal (unsigned flags, int offs, unsigned long val)
1841 /* Emit -= for a local variable */
1843 /* Calculate the true offset, check it, load it into Y */
1845 CheckLocalOffs (offs);
1847 /* Check the size and determine operation */
1848 switch (flags & CF_TYPE) {
1851 if (flags & CF_FORCECHAR) {
1853 AddCodeLine ("\tldx\t#$00");
1854 AddCodeLine ("\tsec");
1855 if (flags & CF_CONST) {
1856 AddCodeLine ("\tlda\t(sp),y");
1857 AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
1859 AddCodeLine ("\tsta\ttmp1");
1860 AddCodeLine ("\tlda\t(sp),y");
1861 AddCodeLine ("\tsbc\ttmp1");
1863 AddCodeLine ("\tsta\t(sp),y");
1864 if ((flags & CF_UNSIGNED) == 0) {
1865 AddCodeLine ("\tbpl\t*+3");
1866 AddCodeLine ("\tdex");
1867 AddCodeHint ("x:!"); /* Invalidate X */
1874 if (flags & CF_CONST) {
1875 g_getimmed (flags, val, 0);
1878 AddCodeLine ("\tjsr\tsubeq0sp");
1881 AddCodeLine ("\tjsr\tsubeqysp");
1886 if (flags & CF_CONST) {
1887 g_getimmed (flags, val, 0);
1890 AddCodeLine ("\tjsr\tlsubeq0sp");
1893 AddCodeLine ("\tjsr\tlsubeqysp");
1904 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
1905 /* Emit -= for the location with address in ax */
1907 /* If the offset is too large for a byte register, add the high byte
1908 * of the offset to the primary. Beware: We need a special correction
1909 * if the offset in the low byte will overflow in the operation.
1911 offs = MakeByteOffs (flags, offs);
1913 /* Check the size and determine operation */
1914 switch (flags & CF_TYPE) {
1917 AddCodeLine ("\tsta\tptr1");
1918 AddCodeLine ("\tstx\tptr1+1");
1920 AddCodeLine ("\tldx\t#$00");
1921 AddCodeLine ("\tlda\t(ptr1,x)");
1922 AddCodeLine ("\tsec");
1923 AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
1924 AddCodeLine ("\tsta\t(ptr1,x)");
1926 AddCodeLine ("\tldy\t#$%02X", offs);
1927 AddCodeLine ("\tldx\t#$00");
1928 AddCodeLine ("\tlda\t(ptr1),y");
1929 AddCodeLine ("\tsec");
1930 AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
1931 AddCodeLine ("\tsta\t(ptr1),y");
1937 /* Lots of code, use only if size is not important */
1938 AddCodeLine ("\tsta\tptr1");
1939 AddCodeLine ("\tstx\tptr1+1");
1940 AddCodeLine ("\tldy\t#$%02X", offs);
1941 AddCodeLine ("\tlda\t(ptr1),y");
1942 AddCodeLine ("\tsec");
1943 AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
1944 AddCodeLine ("\tsta\t(ptr1),y");
1945 AddCodeLine ("\tpha");
1946 AddCodeLine ("\tiny");
1947 AddCodeLine ("\tlda\t(ptr1),y");
1948 AddCodeLine ("\tsbc\t#$%02X", (val >> 8) & 0xFF);
1949 AddCodeLine ("\tsta\t(ptr1),y");
1950 AddCodeLine ("\ttax");
1951 AddCodeLine ("\tpla");
1957 AddCodeLine ("\tjsr\tpushax"); /* Push the address */
1958 push (flags); /* Correct the internal sp */
1959 g_getind (flags, offs); /* Fetch the value */
1960 g_dec (flags, val); /* Increment value in primary */
1961 g_putind (flags, offs); /* Store the value back */
1971 /*****************************************************************************/
1972 /* Add a variable address to the value in ax */
1973 /*****************************************************************************/
1977 void g_addaddr_local (unsigned flags, int offs)
1978 /* Add the address of a local variable to ax */
1980 /* Add the offset */
1983 /* We cannot address more then 256 bytes of locals anyway */
1984 CheckLocalOffs (offs);
1985 AddCodeLine ("\tclc");
1986 AddCodeLine ("\tadc\t#$%02X", offs & 0xFF);
1987 AddCodeLine ("\tbcc\t*+4"); /* Do also skip the CLC insn below */
1988 AddCodeLine ("\tinx");
1989 AddCodeHint ("x:!"); /* Invalidate X */
1992 /* Add the current stackpointer value */
1993 AddCodeLine ("\tclc");
1994 AddCodeLine ("\tadc\tsp");
1995 AddCodeLine ("\ttay");
1996 AddCodeLine ("\ttxa");
1997 AddCodeLine ("\tadc\tsp+1");
1998 AddCodeLine ("\ttax");
1999 AddCodeLine ("\ttya");
2004 void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
2005 /* Add the address of a static variable to ax */
2007 /* Create the correct label name */
2008 char* lbuf = GetLabelName (flags, label, offs);
2010 /* Add the address to the current ax value */
2011 AddCodeLine ("\tclc");
2012 AddCodeLine ("\tadc\t#<(%s)", lbuf);
2013 AddCodeLine ("\ttay");
2014 AddCodeLine ("\ttxa");
2015 AddCodeLine ("\tadc\t#>(%s)", lbuf);
2016 AddCodeLine ("\ttax");
2017 AddCodeLine ("\ttya");
2022 /*****************************************************************************/
2024 /*****************************************************************************/
2028 void g_save (unsigned flags)
2029 /* Copy primary register to hold register. */
2031 /* Check the size and determine operation */
2032 switch (flags & CF_TYPE) {
2035 if (flags & CF_FORCECHAR) {
2036 AddCodeLine ("\tpha");
2042 AddCodeLine ("\tsta\tregsave");
2043 AddCodeLine ("\tstx\tregsave+1");
2047 AddCodeLine ("\tjsr\tsaveeax");
2057 void g_restore (unsigned flags)
2058 /* Copy hold register to P. */
2060 /* Check the size and determine operation */
2061 switch (flags & CF_TYPE) {
2064 if (flags & CF_FORCECHAR) {
2065 AddCodeLine ("\tpla");
2071 AddCodeLine ("\tlda\tregsave");
2072 AddCodeLine ("\tldx\tregsave+1");
2076 AddCodeLine ("\tjsr\tresteax");
2086 void g_cmp (unsigned flags, unsigned long val)
2087 /* Immidiate compare. The primary register will not be changed, Z flag
2091 /* Check the size and determine operation */
2092 switch (flags & CF_TYPE) {
2095 if (flags & CF_FORCECHAR) {
2096 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
2102 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
2103 AddCodeLine ("\tbne\t*+4");
2104 AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
2108 Internal ("g_cmp: Long compares not implemented");
2118 static void oper (unsigned flags, unsigned long val, char** subs)
2119 /* Encode a binary operation. subs is a pointer to four groups of three
2121 * 0-2 --> Operate on ints
2122 * 3-5 --> Operate on unsigneds
2123 * 6-8 --> Operate on longs
2124 * 9-11 --> Operate on unsigned longs
2126 * The first subroutine names in each string group is used to encode an
2127 * operation with a zero constant, the second to encode an operation with
2128 * a 8 bit constant, and the third is used in all other cases.
2133 /* Determine the offset into the array */
2134 offs = (flags & CF_UNSIGNED)? 3 : 0;
2135 switch (flags & CF_TYPE) {
2148 /* Encode the operation */
2149 if (flags & CF_CONST) {
2150 /* Constant value given */
2151 if (val == 0 && subs [offs+0]) {
2152 /* Special case: constant with value zero */
2153 AddCodeLine ("\tjsr\t%s", subs [offs+0]);
2154 } else if (val < 0x100 && subs [offs+1]) {
2155 /* Special case: constant with high byte zero */
2156 ldaconst (val); /* Load low byte */
2157 AddCodeLine ("\tjsr\t%s", subs [offs+1]);
2159 /* Others: arbitrary constant value */
2160 g_getimmed (flags, val, 0); /* Load value */
2161 AddCodeLine ("\tjsr\t%s", subs [offs+2]);
2164 /* Value not constant (is already in (e)ax) */
2165 AddCodeLine ("\tjsr\t%s", subs [offs+2]);
2168 /* The operation will pop it's argument */
2174 void g_test (unsigned flags)
2175 /* Force a test to set cond codes right */
2177 switch (flags & CF_TYPE) {
2180 if (flags & CF_FORCECHAR) {
2181 AddCodeLine ("\ttax");
2187 AddCodeLine ("\tstx\ttmp1");
2188 AddCodeLine ("\tora\ttmp1");
2192 if (flags & CF_UNSIGNED) {
2193 AddCodeLine ("\tjsr\tutsteax");
2195 AddCodeLine ("\tjsr\ttsteax");
2207 void g_push (unsigned flags, unsigned long val)
2208 /* Push the primary register or a constant value onto the stack */
2212 if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2214 /* We have a constant 8 or 16 bit value */
2215 if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2217 /* Handle as 8 bit value */
2218 if (FavourSize && val <= 2) {
2219 AddCodeLine ("\tjsr\tpushc%d", (int) val);
2222 AddCodeLine ("\tjsr\tpusha");
2227 /* Handle as 16 bit value */
2228 hi = (unsigned char) (val >> 8);
2230 AddCodeLine ("\tjsr\tpush%u", (unsigned) val);
2231 } else if (hi == 0 || hi == 0xFF) {
2232 /* Use special function */
2234 AddCodeLine ("\tjsr\t%s", (hi == 0)? "pusha0" : "pushaFF");
2237 g_getimmed (flags, val, 0);
2238 AddCodeLine ("\tjsr\tpushax");
2244 /* Value is not 16 bit or not constant */
2245 if (flags & CF_CONST) {
2246 /* Constant 32 bit value, load into eax */
2247 g_getimmed (flags, val, 0);
2250 /* Push the primary register */
2251 switch (flags & CF_TYPE) {
2254 if (flags & CF_FORCECHAR) {
2255 /* Handle as char */
2256 AddCodeLine ("\tjsr\tpusha");
2261 AddCodeLine ("\tjsr\tpushax");
2265 AddCodeLine ("\tjsr\tpusheax");
2275 /* Adjust the stack offset */
2281 void g_swap (unsigned flags)
2282 /* Swap the primary register and the top of the stack. flags give the type
2283 * of *both* values (must have same size).
2286 switch (flags & CF_TYPE) {
2290 AddCodeLine ("\tjsr\tswapstk");
2294 AddCodeLine ("\tjsr\tswapestk");
2305 void g_call (unsigned flags, char* lbl, unsigned argsize)
2306 /* Call the specified subroutine name */
2308 if ((flags & CF_FIXARGC) == 0) {
2309 /* Pass arg count */
2312 AddCodeLine ("\tjsr\t_%s", lbl);
2313 oursp += argsize; /* callee pops args */
2318 void g_callind (unsigned flags, unsigned argsize)
2319 /* Call subroutine with address in AX */
2321 if ((flags & CF_FIXARGC) == 0) {
2322 /* Pass arg count */
2325 AddCodeLine ("\tjsr\tcallax"); /* do the call */
2326 oursp += argsize; /* callee pops args */
2331 void g_jump (unsigned label)
2332 /* Jump to specified internal label number */
2334 AddCodeLine ("\tjmp\tL%04X", label);
2339 void g_switch (unsigned flags)
2340 /* Output switch statement preample */
2342 switch (flags & CF_TYPE) {
2346 AddCodeLine ("\tjsr\tswitch");
2350 AddCodeLine ("\tjsr\tlswitch");
2361 void g_case (unsigned flags, unsigned label, unsigned long val)
2362 /* Create table code for one case selector */
2364 switch (flags & CF_TYPE) {
2368 AddCodeLine ("\t.word\t$%04X, L%04X", val & 0xFFFF, label & 0xFFFF);
2372 AddCodeLine ("\t.dword\t$%08X", val);
2373 AddCodeLine ("\t.word\tL%04X", label & 0xFFFF);
2384 void g_truejump (unsigned flags, unsigned label)
2385 /* Jump to label if zero flag clear */
2387 if (flags & CF_SHORT) {
2388 AddCodeLine ("\tbne\tL%04X", label);
2390 AddCodeLine ("\tjne\tL%04X", label);
2396 void g_falsejump (unsigned flags, unsigned label)
2397 /* Jump to label if zero flag set */
2399 if (flags & CF_SHORT) {
2400 AddCodeLine ("\tbeq\tL%04X", label);
2402 AddCodeLine ("\tjeq\tL%04X", label);
2408 static void mod_internal (int k, char* verb1, char* verb2)
2411 AddCodeLine ("\tjsr\t%ssp%c", verb1, k + '0');
2415 AddCodeLine ("\tjsr\t%ssp", verb2);
2421 void g_space (int space)
2422 /* Create or drop space on the stack */
2425 mod_internal (-space, "inc", "addy");
2426 } else if (space > 0) {
2427 mod_internal (space, "dec", "suby");
2433 void g_add (unsigned flags, unsigned long val)
2434 /* Primary = TOS + Primary */
2436 static char* ops [12] = {
2437 0, "tosadda0", "tosaddax",
2438 0, "tosadda0", "tosaddax",
2443 if (flags & CF_CONST) {
2444 flags &= ~CF_FORCECHAR; // Handle chars as ints
2445 g_push (flags & ~CF_CONST, 0);
2447 oper (flags, val, ops);
2452 void g_sub (unsigned flags, unsigned long val)
2453 /* Primary = TOS - Primary */
2455 static char* ops [12] = {
2456 0, "tossuba0", "tossubax",
2457 0, "tossuba0", "tossubax",
2462 if (flags & CF_CONST) {
2463 flags &= ~CF_FORCECHAR; // Handle chars as ints
2464 g_push (flags & ~CF_CONST, 0);
2466 oper (flags, val, ops);
2471 void g_rsub (unsigned flags, unsigned long val)
2472 /* Primary = Primary - TOS */
2474 static char* ops [12] = {
2475 0, "tosrsuba0", "tosrsubax",
2476 0, "tosrsuba0", "tosrsubax",
2480 oper (flags, val, ops);
2485 void g_mul (unsigned flags, unsigned long val)
2486 /* Primary = TOS * Primary */
2488 static char* ops [12] = {
2489 0, "tosmula0", "tosmulax",
2490 0, "tosumula0", "tosumulax",
2497 /* Do strength reduction if the value is constant and a power of two */
2498 if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2499 /* Generate a shift instead */
2504 /* If the right hand side is const, the lhs is not on stack but still
2505 * in the primary register.
2507 if (flags & CF_CONST) {
2509 switch (flags & CF_TYPE) {
2512 if (flags & CF_FORCECHAR) {
2513 /* Handle some special cases */
2517 AddCodeLine ("\tsta\ttmp1");
2518 AddCodeLine ("\tasl\ta");
2519 AddCodeLine ("\tclc");
2520 AddCodeLine ("\tadc\ttmp1");
2524 AddCodeLine ("\tsta\ttmp1");
2525 AddCodeLine ("\tasl\ta");
2526 AddCodeLine ("\tasl\ta");
2527 AddCodeLine ("\tclc");
2528 AddCodeLine ("\tadc\ttmp1");
2532 AddCodeLine ("\tsta\ttmp1");
2533 AddCodeLine ("\tasl\ta");
2534 AddCodeLine ("\tasl\ta");
2535 AddCodeLine ("\tclc");
2536 AddCodeLine ("\tadc\ttmp1");
2537 AddCodeLine ("\tasl\ta");
2553 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2554 * into the normal, non-optimized stuff.
2556 flags &= ~CF_FORCECHAR; // Handle chars as ints
2557 g_push (flags & ~CF_CONST, 0);
2561 /* Use long way over the stack */
2562 oper (flags, val, ops);
2567 void g_div (unsigned flags, unsigned long val)
2568 /* Primary = TOS / Primary */
2570 static char* ops [12] = {
2571 0, "tosdiva0", "tosdivax",
2572 0, "tosudiva0", "tosudivax",
2577 /* Do strength reduction if the value is constant and a power of two */
2579 if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2580 /* Generate a shift instead */
2583 /* Generate a division */
2584 if (flags & CF_CONST) {
2585 /* lhs is not on stack */
2586 flags &= ~CF_FORCECHAR; // Handle chars as ints
2587 g_push (flags & ~CF_CONST, 0);
2589 oper (flags, val, ops);
2595 void g_mod (unsigned flags, unsigned long val)
2596 /* Primary = TOS % Primary */
2598 static char* ops [12] = {
2599 0, "tosmoda0", "tosmodax",
2600 0, "tosumoda0", "tosumodax",
2606 /* Check if we can do some cost reduction */
2607 if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2608 /* We can do that with an AND operation */
2609 g_and (flags, val - 1);
2611 /* Do it the hard way... */
2612 if (flags & CF_CONST) {
2613 /* lhs is not on stack */
2614 flags &= ~CF_FORCECHAR; // Handle chars as ints
2615 g_push (flags & ~CF_CONST, 0);
2617 oper (flags, val, ops);
2623 void g_or (unsigned flags, unsigned long val)
2624 /* Primary = TOS | Primary */
2626 static char* ops [12] = {
2627 0, "tosora0", "tosorax",
2628 0, "tosora0", "tosorax",
2633 /* If the right hand side is const, the lhs is not on stack but still
2634 * in the primary register.
2636 if (flags & CF_CONST) {
2638 switch (flags & CF_TYPE) {
2641 if (flags & CF_FORCECHAR) {
2642 if ((val & 0xFF) != 0xFF) {
2643 AddCodeLine ("\tora\t#$%02X", val & 0xFF);
2651 AddCodeLine ("\tora\t#$%02X", val & 0xFF);
2658 AddCodeLine ("\tora\t#$%02X", val & 0xFF);
2667 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2668 * into the normal, non-optimized stuff.
2670 g_push (flags & ~CF_CONST, 0);
2674 /* Use long way over the stack */
2675 oper (flags, val, ops);
2680 void g_xor (unsigned flags, unsigned long val)
2681 /* Primary = TOS ^ Primary */
2683 static char* ops [12] = {
2684 0, "tosxora0", "tosxorax",
2685 0, "tosxora0", "tosxorax",
2691 /* If the right hand side is const, the lhs is not on stack but still
2692 * in the primary register.
2694 if (flags & CF_CONST) {
2696 switch (flags & CF_TYPE) {
2699 if (flags & CF_FORCECHAR) {
2700 if ((val & 0xFF) != 0) {
2701 AddCodeLine ("\teor\t#$%02X", val & 0xFF);
2710 AddCodeLine ("\teor\t#$%02X", val);
2713 } else if ((val & 0xFF) == 0) {
2714 AddCodeLine ("\tpha");
2715 AddCodeLine ("\ttxa");
2716 AddCodeLine ("\teor\t#$%02X", (val >> 8) & 0xFF);
2717 AddCodeLine ("\ttax");
2718 AddCodeLine ("\tpla");
2726 AddCodeLine ("\teor\t#$%02X", val & 0xFF);
2736 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2737 * into the normal, non-optimized stuff.
2739 g_push (flags & ~CF_CONST, 0);
2743 /* Use long way over the stack */
2744 oper (flags, val, ops);
2749 void g_and (unsigned flags, unsigned long val)
2750 /* Primary = TOS & Primary */
2752 static char* ops [12] = {
2753 0, "tosanda0", "tosandax",
2754 0, "tosanda0", "tosandax",
2759 /* If the right hand side is const, the lhs is not on stack but still
2760 * in the primary register.
2762 if (flags & CF_CONST) {
2764 switch (flags & CF_TYPE) {
2767 if (flags & CF_FORCECHAR) {
2768 AddCodeLine ("\tand\t#$%02X", val & 0xFF);
2773 if ((val & 0xFFFF) != 0xFFFF) {
2778 } else if (val != 0xFF) {
2779 AddCodeLine ("\tand\t#$%02X", val & 0xFF);
2781 } else if ((val & 0xFF00) == 0xFF00) {
2782 AddCodeLine ("\tand\t#$%02X", val & 0xFF);
2783 } else if ((val & 0x00FF) == 0x0000) {
2784 AddCodeLine ("\ttxa");
2785 AddCodeLine ("\tand\t#$%02X", (val >> 8) & 0xFF);
2786 AddCodeLine ("\ttax");
2789 AddCodeLine ("\ttay");
2790 AddCodeLine ("\ttxa");
2791 AddCodeLine ("\tand\t#$%02X", (val >> 8) & 0xFF);
2792 AddCodeLine ("\ttax");
2793 AddCodeLine ("\ttya");
2794 if ((val & 0x00FF) != 0x00FF) {
2795 AddCodeLine ("\tand\t#$%02X", val & 0xFF);
2804 AddCodeLine ("\tstx\tsreg+1");
2805 AddCodeLine ("\tstx\tsreg");
2806 if ((val & 0xFF) != 0xFF) {
2807 AddCodeLine ("\tand\t#$%02X", val & 0xFF);
2810 } else if (val == 0xFF00) {
2812 AddCodeLine ("\tsta\tsreg+1");
2813 AddCodeLine ("\tsta\tsreg");
2822 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2823 * into the normal, non-optimized stuff.
2825 g_push (flags & ~CF_CONST, 0);
2829 /* Use long way over the stack */
2830 oper (flags, val, ops);
2835 void g_asr (unsigned flags, unsigned long val)
2836 /* Primary = TOS >> Primary */
2838 static char* ops [12] = {
2839 0, "tosasra0", "tosasrax",
2840 0, "tosshra0", "tosshrax",
2845 /* If the right hand side is const, the lhs is not on stack but still
2846 * in the primary register.
2848 if (flags & CF_CONST) {
2850 switch (flags & CF_TYPE) {
2854 if (val >= 1 && val <= 3) {
2855 if (flags & CF_UNSIGNED) {
2856 AddCodeLine ("\tjsr\tshrax%ld", val);
2858 AddCodeLine ("\tjsr\tasrax%ld", val);
2861 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2862 AddCodeLine ("\ttxa");
2869 if (val >= 1 && val <= 3) {
2870 if (flags & CF_UNSIGNED) {
2871 AddCodeLine ("\tjsr\tshreax%ld", val);
2873 AddCodeLine ("\tjsr\tasreax%ld", val);
2876 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2877 AddCodeLine ("\ttxa");
2878 AddCodeLine ("\tldx\tsreg");
2879 AddCodeLine ("\tldy\tsreg+1");
2880 AddCodeLine ("\tsty\tsreg");
2881 AddCodeLine ("\tldy\t#$00");
2882 AddCodeLine ("\tsty\tsreg+1");
2884 } else if (val == 16) {
2885 AddCodeLine ("\tldy\t#$00");
2886 AddCodeLine ("\tldx\tsreg+1");
2887 if ((flags & CF_UNSIGNED) == 0) {
2888 AddCodeLine ("\tbpl\t*+3");
2889 AddCodeLine ("\tdey");
2890 AddCodeHint ("y:!");
2892 AddCodeLine ("\tlda\tsreg");
2893 AddCodeLine ("\tsty\tsreg+1");
2894 AddCodeLine ("\tsty\tsreg");
2903 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2904 * into the normal, non-optimized stuff.
2906 g_push (flags & ~CF_CONST, 0);
2910 /* Use long way over the stack */
2911 oper (flags, val, ops);
2916 void g_asl (unsigned flags, unsigned long val)
2917 /* Primary = TOS << Primary */
2919 static char* ops [12] = {
2920 0, "tosasla0", "tosaslax",
2921 0, "tosshla0", "tosshlax",
2927 /* If the right hand side is const, the lhs is not on stack but still
2928 * in the primary register.
2930 if (flags & CF_CONST) {
2932 switch (flags & CF_TYPE) {
2936 if (val >= 1 && val <= 3) {
2937 if (flags & CF_UNSIGNED) {
2938 AddCodeLine ("\tjsr\tshlax%ld", val);
2940 AddCodeLine ("\tjsr\taslax%ld", val);
2943 } else if (val == 8) {
2944 AddCodeLine ("\ttax");
2945 AddCodeLine ("\tlda\t#$00");
2951 if (val >= 1 && val <= 3) {
2952 if (flags & CF_UNSIGNED) {
2953 AddCodeLine ("\tjsr\tshleax%ld", val);
2955 AddCodeLine ("\tjsr\tasleax%ld", val);
2958 } else if (val == 8) {
2959 AddCodeLine ("\tldy\tsreg");
2960 AddCodeLine ("\tsty\tsreg+1");
2961 AddCodeLine ("\tstx\tsreg");
2962 AddCodeLine ("\ttax");
2963 AddCodeLine ("\tlda\t#$00");
2965 } else if (val == 16) {
2966 AddCodeLine ("\tstx\tsreg+1");
2967 AddCodeLine ("\tsta\tsreg");
2968 AddCodeLine ("\tlda\t#$00");
2969 AddCodeLine ("\ttax");
2978 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2979 * into the normal, non-optimized stuff.
2981 g_push (flags & ~CF_CONST, 0);
2985 /* Use long way over the stack */
2986 oper (flags, val, ops);
2991 void g_neg (unsigned flags)
2992 /* Primary = -Primary */
2994 switch (flags & CF_TYPE) {
2998 AddCodeLine ("\tjsr\tnegax");
3002 AddCodeLine ("\tjsr\tnegeax");
3012 void g_bneg (unsigned flags)
3013 /* Primary = !Primary */
3015 switch (flags & CF_TYPE) {
3018 AddCodeLine ("\tjsr\tbnega");
3022 AddCodeLine ("\tjsr\tbnegax");
3026 AddCodeLine ("\tjsr\tbnegeax");
3036 void g_com (unsigned flags)
3037 /* Primary = ~Primary */
3039 switch (flags & CF_TYPE) {
3043 AddCodeLine ("\tjsr\tcomplax");
3047 AddCodeLine ("\tjsr\tcompleax");
3057 void g_inc (unsigned flags, unsigned long val)
3058 /* Increment the primary register by a given number */
3060 /* Don't inc by zero */
3065 /* Generate code for the supported types */
3067 switch (flags & CF_TYPE) {
3070 if (flags & CF_FORCECHAR) {
3071 AddCodeLine ("\tclc");
3072 AddCodeLine ("\tadc\t#$%02X", val & 0xFF);
3081 AddCodeLine ("\tjsr\tincax%u", val);
3082 } else if (val <= 255) {
3084 AddCodeLine ("\tjsr\tincaxy");
3086 g_add (flags | CF_CONST, val);
3089 /* Inline the code */
3091 if ((val & 0xFF) != 0) {
3092 AddCodeLine ("\tclc");
3093 AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
3094 AddCodeLine ("\tbcc\t*+3");
3095 AddCodeLine ("\tinx");
3096 /* Tell the optimizer that the X register may be invalid */
3097 AddCodeHint ("x:!");
3100 AddCodeLine ("\tinx");
3103 AddCodeLine ("\tinx");
3106 AddCodeLine ("\tclc");
3107 if ((val & 0xFF) != 0) {
3108 AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
3109 /* Tell the optimizer that the X register may be invalid */
3110 AddCodeHint ("x:!");
3112 AddCodeLine ("\tpha");
3113 AddCodeLine ("\ttxa");
3114 AddCodeLine ("\tadc\t#$%02X", (unsigned char) (val >> 8));
3115 AddCodeLine ("\ttax");
3116 AddCodeLine ("\tpla");
3124 AddCodeLine ("\tjsr\tinceaxy");
3126 g_add (flags | CF_CONST, val);
3138 void g_dec (unsigned flags, unsigned long val)
3139 /* Decrement the primary register by a given number */
3141 /* Generate code for the supported types */
3143 switch (flags & CF_TYPE) {
3146 if (flags & CF_FORCECHAR) {
3147 AddCodeLine ("\tsec");
3148 AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
3155 AddCodeLine ("\tjsr\tdecax%d", (int) val);
3156 } else if (val <= 255) {
3158 AddCodeLine ("\tjsr\tdecaxy");
3160 g_sub (flags | CF_CONST, val);
3167 AddCodeLine ("\tjsr\tdeceaxy");
3169 g_sub (flags | CF_CONST, val);
3182 * Following are the conditional operators. They compare the TOS against
3183 * the primary and put a literal 1 in the primary if the condition is
3184 * true, otherwise they clear the primary register
3189 void g_eq (unsigned flags, unsigned long val)
3190 /* Test for equal */
3192 static char* ops [12] = {
3193 "toseq00", "toseqa0", "toseqax",
3194 "toseq00", "toseqa0", "toseqax",
3199 /* If the right hand side is const, the lhs is not on stack but still
3200 * in the primary register.
3202 if (flags & CF_CONST) {
3204 switch (flags & CF_TYPE) {
3207 if (flags & CF_FORCECHAR) {
3208 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3209 AddCodeLine ("\tjsr\tbooleq");
3215 AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
3216 AddCodeLine ("\tbne\t*+4");
3217 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3218 AddCodeLine ("\tjsr\tbooleq");
3228 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3229 * into the normal, non-optimized stuff.
3231 g_push (flags & ~CF_CONST, 0);
3235 /* Use long way over the stack */
3236 oper (flags, val, ops);
3241 void g_ne (unsigned flags, unsigned long val)
3242 /* Test for not equal */
3244 static char* ops [12] = {
3245 "tosne00", "tosnea0", "tosneax",
3246 "tosne00", "tosnea0", "tosneax",
3252 /* If the right hand side is const, the lhs is not on stack but still
3253 * in the primary register.
3255 if (flags & CF_CONST) {
3257 switch (flags & CF_TYPE) {
3260 if (flags & CF_FORCECHAR) {
3261 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3262 AddCodeLine ("\tjsr\tboolne");
3268 AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
3269 AddCodeLine ("\tbne\t*+4");
3270 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3271 AddCodeLine ("\tjsr\tboolne");
3281 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3282 * into the normal, non-optimized stuff.
3284 g_push (flags & ~CF_CONST, 0);
3288 /* Use long way over the stack */
3289 oper (flags, val, ops);
3294 void g_lt (unsigned flags, unsigned long val)
3295 /* Test for less than */
3297 static char* ops [12] = {
3298 "toslt00", "toslta0", "tosltax",
3299 "tosult00", "tosulta0", "tosultax",
3304 /* If the right hand side is const, the lhs is not on stack but still
3305 * in the primary register.
3307 if (flags & CF_CONST) {
3309 /* Give a warning in some special cases */
3310 if ((flags & CF_UNSIGNED) && val == 0) {
3311 Warning (WARN_COND_NEVER_TRUE);
3314 /* Look at the type */
3315 switch (flags & CF_TYPE) {
3318 if (flags & CF_FORCECHAR) {
3319 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3320 if (flags & CF_UNSIGNED) {
3321 AddCodeLine ("\tjsr\tboolult");
3323 AddCodeLine ("\tjsr\tboollt");
3330 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3331 /* If we have a signed compare against zero, we only need to
3332 * test the high byte.
3334 AddCodeLine ("\ttxa");
3335 AddCodeLine ("\tjsr\tboollt");
3338 /* Direct code only for unsigned data types */
3339 if (flags & CF_UNSIGNED) {
3340 AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
3341 AddCodeLine ("\tbne\t*+4");
3342 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3343 AddCodeLine ("\tjsr\tboolult");
3355 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3356 * into the normal, non-optimized stuff.
3358 g_push (flags & ~CF_CONST, 0);
3362 /* Use long way over the stack */
3363 oper (flags, val, ops);
3368 void g_le (unsigned flags, unsigned long val)
3369 /* Test for less than or equal to */
3371 static char* ops [12] = {
3372 "tosle00", "toslea0", "tosleax",
3373 "tosule00", "tosulea0", "tosuleax",
3379 /* If the right hand side is const, the lhs is not on stack but still
3380 * in the primary register.
3382 if (flags & CF_CONST) {
3384 /* Look at the type */
3385 switch (flags & CF_TYPE) {
3388 if (flags & CF_FORCECHAR) {
3389 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3390 if (flags & CF_UNSIGNED) {
3391 AddCodeLine ("\tjsr\tboolule");
3393 AddCodeLine ("\tjsr\tboolle");
3400 if (flags & CF_UNSIGNED) {
3401 AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
3402 AddCodeLine ("\tbne\t*+4");
3403 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3404 AddCodeLine ("\tjsr\tboolule");
3416 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3417 * into the normal, non-optimized stuff.
3419 g_push (flags & ~CF_CONST, 0);
3423 /* Use long way over the stack */
3424 oper (flags, val, ops);
3429 void g_gt (unsigned flags, unsigned long val)
3430 /* Test for greater than */
3432 static char* ops [12] = {
3433 "tosgt00", "tosgta0", "tosgtax",
3434 "tosugt00", "tosugta0", "tosugtax",
3440 /* If the right hand side is const, the lhs is not on stack but still
3441 * in the primary register.
3443 if (flags & CF_CONST) {
3445 /* Look at the type */
3446 switch (flags & CF_TYPE) {
3449 if (flags & CF_FORCECHAR) {
3450 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3451 if (flags & CF_UNSIGNED) {
3452 /* If we have a compare > 0, we will replace it by
3453 * != 0 here, since both are identical but the latter
3454 * is easier to optimize.
3457 AddCodeLine ("\tjsr\tboolugt");
3459 AddCodeLine ("\tjsr\tboolne");
3462 AddCodeLine ("\tjsr\tboolgt");
3469 if (flags & CF_UNSIGNED) {
3470 /* If we have a compare > 0, we will replace it by
3471 * != 0 here, since both are identical but the latter
3472 * is easier to optimize.
3474 if ((val & 0xFFFF) == 0) {
3475 AddCodeLine ("\tstx\ttmp1");
3476 AddCodeLine ("\tora\ttmp1");
3477 AddCodeLine ("\tjsr\tboolne");
3479 AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
3480 AddCodeLine ("\tbne\t*+4");
3481 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3482 AddCodeLine ("\tjsr\tboolugt");
3495 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3496 * into the normal, non-optimized stuff.
3498 g_push (flags & ~CF_CONST, 0);
3502 /* Use long way over the stack */
3503 oper (flags, val, ops);
3508 void g_ge (unsigned flags, unsigned long val)
3509 /* Test for greater than or equal to */
3511 static char* ops [12] = {
3512 "tosge00", "tosgea0", "tosgeax",
3513 "tosuge00", "tosugea0", "tosugeax",
3519 /* If the right hand side is const, the lhs is not on stack but still
3520 * in the primary register.
3522 if (flags & CF_CONST) {
3524 /* Give a warning in some special cases */
3525 if ((flags & CF_UNSIGNED) && val == 0) {
3526 Warning (WARN_COND_ALWAYS_TRUE);
3529 /* Look at the type */
3530 switch (flags & CF_TYPE) {
3533 if (flags & CF_FORCECHAR) {
3534 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3535 if (flags & CF_UNSIGNED) {
3536 AddCodeLine ("\tjsr\tbooluge");
3538 AddCodeLine ("\tjsr\tboolge");
3545 if (flags & CF_UNSIGNED) {
3546 AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
3547 AddCodeLine ("\tbne\t*+4");
3548 AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
3549 AddCodeLine ("\tjsr\tbooluge");
3561 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3562 * into the normal, non-optimized stuff.
3564 g_push (flags & ~CF_CONST, 0);
3568 /* Use long way over the stack */
3569 oper (flags, val, ops);
3574 /*****************************************************************************/
3575 /* Allocating static storage */
3576 /*****************************************************************************/
3580 void g_res (unsigned n)
3581 /* reserve static storage, n bytes */
3583 AddCodeLine ("\t.res\t%u", n);
3588 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3589 /* Define data with the size given in flags */
3591 if (flags & CF_CONST) {
3593 /* Numeric constant */
3594 switch (flags & CF_TYPE) {
3597 AddCodeLine ("\t.byte\t$%02lX", val & 0xFF);
3601 AddCodeLine ("\t.word\t$%04lX", val & 0xFFFF);
3605 AddCodeLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
3616 /* Create the correct label name */
3617 const char* Label = GetLabelName (flags, val, offs);
3619 /* Labels are always 16 bit */
3620 AddCodeLine ("\t.word\t%s", Label);
3627 void g_defbytes (const unsigned char* Bytes, unsigned Count)
3628 /* output a row of bytes as a constant */
3634 /* Output the stuff */
3637 /* How many go into this line? */
3638 if ((Chunk = Count) > 16) {
3643 /* Output one line */
3644 strcpy (Buf, "\t.byte\t");
3647 B += sprintf (B, "$%02X", *Bytes++ & 0xFF);
3653 /* Output the line */
3660 void g_zerobytes (unsigned n)
3661 /* Output n bytes of data initialized with zero */
3663 AddCodeLine ("\t.res\t%u", n);
3668 /*****************************************************************************/
3669 /* Inlined known functions */
3670 /*****************************************************************************/
3674 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3675 /* Inline the strlen() function */
3677 /* We need a label in both cases */
3678 unsigned label = GetLabel ();
3680 /* Two different encodings */
3681 if (flags & CF_CONST) {
3683 /* The address of the string is constant. Create the correct label name */
3684 char* lbuf = GetLabelName (flags, val, offs);
3686 /* Generate the strlen code */
3687 AddCodeLine ("\tldy\t#$FF");
3688 g_defloclabel (label);
3689 AddCodeLine ("\tiny");
3690 AddCodeLine ("\tlda\t%s,y", lbuf);
3691 AddCodeLine ("\tbne\tL%04X", label);
3692 AddCodeLine ("\ttya");
3693 AddCodeLine ("\tldx\t#$00");
3697 /* Address not constant but in primary */
3699 /* This is too much code, so call strlen instead of inlining */
3700 AddCodeLine ("\tjsr\t_strlen");
3702 /* Inline the function */
3703 AddCodeLine ("\tsta\tptr1");
3704 AddCodeLine ("\tstx\tptr1+1");
3705 AddCodeLine ("\tldy\t#$FF");
3706 g_defloclabel (label);
3707 AddCodeLine ("\tiny");
3708 AddCodeLine ("\tlda\t(ptr1),y");
3709 AddCodeLine ("\tbne\tL%04X", label);
3710 AddCodeLine ("\ttya");
3711 AddCodeLine ("\tldx\t#$00");