1 /*****************************************************************************/
5 /* 6502 code generator */
9 /* (C) 1998-2001 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
60 /*****************************************************************************/
62 /*****************************************************************************/
66 /* Compiler relative stack pointer */
71 /*****************************************************************************/
73 /*****************************************************************************/
77 static void typeerror (unsigned type)
78 /* Print an error message about an invalid operand type */
80 Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPE);
85 static void CheckLocalOffs (unsigned Offs)
86 /* Check the offset into the stack for 8bit range */
89 /* Too many local vars */
90 Error ("Too many local variables");
96 static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs)
98 static char lbuf [128]; /* Label name */
100 /* Create the correct label name */
101 switch (flags & CF_ADDRMASK) {
104 /* Static memory cell */
105 sprintf (lbuf, "%s+%u", LocalLabelName (label), offs);
110 sprintf (lbuf, "_%s+%u", (char*) label, offs);
114 /* Absolute address */
115 sprintf (lbuf, "$%04X", (unsigned)((label+offs) & 0xFFFF));
119 /* Variable in register bank */
120 sprintf (lbuf, "regbank+%u", (unsigned)((label+offs) & 0xFFFF));
124 Internal ("Invalid address flags");
127 /* Return a pointer to the static buffer */
133 const char* NumToStr (long Val)
134 /* Convert the given parameter converted to a string in a static buffer */
136 static char Buf [64];
137 sprintf (Buf, "$%04X", (unsigned) (Val & 0xFFFF));
143 const char* ByteToStr (unsigned Val)
144 /* Convert the given byte parameter converted to a string in a static buffer */
146 static char Buf [16];
147 sprintf (Buf, "$%02X", Val & 0xFF);
153 const char* WordToStr (unsigned Val)
154 /* Convert the given word parameter converted to a string in a static buffer */
156 static char Buf [16];
157 sprintf (Buf, "$%04X", Val & 0xFFFF);
163 const char* DWordToStr (unsigned long Val)
164 /* Convert the given dword parameter converted to a string in a static buffer */
166 static char Buf [16];
167 sprintf (Buf, "$%08lX", Val & 0xFFFFFFFF);
173 /*****************************************************************************/
174 /* Pre- and postamble */
175 /*****************************************************************************/
179 void g_preamble (void)
180 /* Generate the assembler code preamble */
182 /* Create a new segment list */
185 /* Identify the compiler version */
187 AddTextLine ("; File generated by cc65 v %u.%u.%u",
188 VER_MAJOR, VER_MINOR, VER_PATCH);
191 /* Insert some object file options */
192 AddTextLine ("\t.fopt\t\tcompiler,\"cc65 v %u.%u.%u\"",
193 VER_MAJOR, VER_MINOR, VER_PATCH);
195 /* If we're producing code for some other CPU, switch the command set */
196 if (CPU == CPU_65C02) {
197 AddTextLine ("\t.pc02");
200 /* Allow auto import for runtime library routines */
201 AddTextLine ("\t.autoimport\ton");
203 /* Switch the assembler into case sensitive mode */
204 AddTextLine ("\t.case\t\ton");
206 /* Tell the assembler if we want to generate debug info */
207 AddTextLine ("\t.debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
209 /* Import the stack pointer for direct auto variable access */
210 AddTextLine ("\t.importzp\tsp, sreg, regsave, regbank, tmp1, ptr1");
212 /* Define long branch macros */
213 AddTextLine ("\t.macpack\tlongbranch");
218 void g_fileinfo (const char* Name, unsigned long Size, unsigned long MTime)
219 /* If debug info is enabled, place a file info into the source */
222 AddTextLine ("\t.dbg\t\tfile, \"%s\", %lu, %lu", Name, Size, MTime);
228 /*****************************************************************************/
229 /* Segment support */
230 /*****************************************************************************/
234 void g_userodata (void)
235 /* Switch to the read only data segment */
237 UseDataSeg (SEG_RODATA);
242 void g_usedata (void)
243 /* Switch to the data segment */
245 UseDataSeg (SEG_DATA);
251 /* Switch to the bss segment */
253 UseDataSeg (SEG_BSS);
258 static void OutputDataLine (DataSeg* S, const char* Format, ...)
259 /* Add a line to the current data segment */
262 va_start (ap, Format);
263 DS_AddLine (S, Format, ap);
269 void g_segname (segment_t Seg, const char* Name)
270 /* Set the name of a segment */
274 /* Remember the new name */
275 NewSegName (Seg, Name);
277 /* Emit a segment directive for the data style segments */
279 case SEG_RODATA: S = CS->ROData; break;
280 case SEG_DATA: S = CS->Data; break;
281 case SEG_BSS: S = CS->BSS; break;
282 default: S = 0; break;
285 OutputDataLine (S, ".segment\t\"%s\"", Name);
291 /*****************************************************************************/
293 /*****************************************************************************/
297 unsigned sizeofarg (unsigned flags)
298 /* Return the size of a function argument type that is encoded in flags */
300 switch (flags & CF_TYPE) {
303 return (flags & CF_FORCECHAR)? 1 : 2;
320 int pop (unsigned flags)
321 /* Pop an argument of the given size */
323 return oursp += sizeofarg (flags);
328 int push (unsigned flags)
329 /* Push an argument of the given size */
331 return oursp -= sizeofarg (flags);
336 static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
337 /* The value in Offs is an offset to an address in a/x. Make sure, an object
338 * of the type given in Flags can be loaded or stored into this address by
339 * adding part of the offset to the address in ax, so that the remaining
340 * offset fits into an index register. Return the remaining offset.
343 /* If the offset is too large for a byte register, add the high byte
344 * of the offset to the primary. Beware: We need a special correction
345 * if the offset in the low byte will overflow in the operation.
347 unsigned O = Offs & ~0xFFU;
348 if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
349 /* We need to add the low byte also */
353 /* Do the correction if we need one */
355 g_inc (CF_INT | CF_CONST, O);
359 /* Return the new offset */
365 /*****************************************************************************/
366 /* Functions handling local labels */
367 /*****************************************************************************/
371 void g_defcodelabel (unsigned label)
372 /* Define a local code label */
374 CS_AddLabel (CS->Code, LocalLabelName (label));
379 void g_defdatalabel (unsigned label)
380 /* Define a local data label */
382 AddDataLine ("%s:", LocalLabelName (label));
387 /*****************************************************************************/
388 /* Functions handling global labels */
389 /*****************************************************************************/
393 void g_defgloblabel (const char* Name)
394 /* Define a global label with the given name */
396 /* Global labels are always data labels */
397 AddDataLine ("_%s:", Name);
402 void g_defexport (const char* Name, int ZP)
403 /* Export the given label */
406 AddTextLine ("\t.exportzp\t_%s", Name);
408 AddTextLine ("\t.export\t\t_%s", Name);
414 void g_defimport (const char* Name, int ZP)
415 /* Import the given label */
418 AddTextLine ("\t.importzp\t_%s", Name);
420 AddTextLine ("\t.import\t\t_%s", Name);
426 /*****************************************************************************/
427 /* Load functions for various registers */
428 /*****************************************************************************/
432 static void ldaconst (unsigned val)
433 /* Load a with a constant */
435 AddCodeLine ("lda #$%02X", val & 0xFF);
440 static void ldxconst (unsigned val)
441 /* Load x with a constant */
443 AddCodeLine ("ldx #$%02X", val & 0xFF);
448 static void ldyconst (unsigned val)
449 /* Load y with a constant */
451 AddCodeLine ("ldy #$%02X", val & 0xFF);
456 /*****************************************************************************/
457 /* Function entry and exit */
458 /*****************************************************************************/
462 /* Remember the argument size of a function. The variable is set by g_enter
463 * and used by g_leave. If the functions gets its argument size by the caller
464 * (variable param list or function without prototype), g_enter will set the
470 void g_enter (unsigned flags, unsigned argsize)
471 /* Function prologue */
473 if ((flags & CF_FIXARGC) != 0) {
474 /* Just remember the argument size for the leave */
478 AddCode (OPC_ENTER, AM_IMP, 0, 0);
485 /* Function epilogue */
487 /* How many bytes of locals do we have to drop? */
490 /* If we didn't have a variable argument list, don't call leave */
493 /* Drop stackframe if needed */
497 AddCode (OPC_SPACE, AM_IMM, NumToStr (-k), 0);
503 AddCode (OPC_SPACE, AM_IMM, NumToStr (-k), 0);
505 AddCode (OPC_LEAVE, AM_IMP, 0, 0);
508 /* Add the final rts */
509 AddCode (OPC_RET, AM_IMP, 0, 0);
514 /*****************************************************************************/
515 /* Register variables */
516 /*****************************************************************************/
520 void g_save_regvars (int RegOffs, unsigned Bytes)
521 /* Save register variables */
523 /* Don't loop for up to two bytes */
526 AddCodeLine ("lda regbank%+d", RegOffs);
527 AddCodeLine ("jsr pusha");
529 } else if (Bytes == 2) {
531 AddCodeLine ("lda regbank%+d", RegOffs);
532 AddCodeLine ("ldx regbank%+d", RegOffs+1);
533 AddCodeLine ("jsr pushax");
537 /* More than two bytes - loop */
538 unsigned Label = GetLocalLabel ();
540 ldyconst (Bytes - 1);
542 g_defcodelabel (Label);
543 AddCodeLine ("lda regbank%+d,x", RegOffs-1);
544 AddCodeLine ("sta (sp),y");
547 AddCodeLine ("bne %s", LocalLabelName (Label));
551 /* We pushed stuff, correct the stack pointer */
557 void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
558 /* Restore register variables */
560 /* Calculate the actual stack offset and check it */
562 CheckLocalOffs (StackOffs);
564 /* Don't loop for up to two bytes */
567 ldyconst (StackOffs);
568 AddCodeLine ("lda (sp),y");
569 AddCodeLine ("sta regbank%+d", RegOffs);
571 } else if (Bytes == 2) {
573 ldyconst (StackOffs);
574 AddCodeLine ("lda (sp),y");
575 AddCodeLine ("sta regbank%+d", RegOffs);
577 AddCodeLine ("lda (sp),y");
578 AddCodeLine ("sta regbank%+d", RegOffs+1);
582 /* More than two bytes - loop */
583 unsigned Label = GetLocalLabel ();
584 ldyconst (StackOffs+Bytes-1);
586 g_defcodelabel (Label);
587 AddCodeLine ("lda (sp),y");
588 AddCodeLine ("sta regbank%+d,x", RegOffs-1);
591 AddCodeLine ("bne %s", LocalLabelName (Label));
598 /*****************************************************************************/
599 /* Fetching memory cells */
600 /*****************************************************************************/
604 void g_getimmed (unsigned Flags, unsigned long Val, unsigned Offs)
605 /* Load a constant into the primary register */
607 if ((Flags & CF_CONST) != 0) {
609 /* Numeric constant */
610 switch (Flags & CF_TYPE) {
613 if ((Flags & CF_FORCECHAR) != 0) {
614 AddCode (OPC_LDA, AM_IMM, ByteToStr (Val), 0);
619 AddCode (OPC_LDAX, AM_IMM, WordToStr (Val), 0);
623 AddCode (OPC_LDEAX, AM_IMM, DWordToStr (Val), 0);
634 /* Some sort of label, load it into the primary */
635 AddCode (OPC_LEA, AM_ABS, GetLabelName (Flags, Val, Offs), 0);
642 void g_getstatic (unsigned flags, unsigned long label, unsigned offs)
643 /* Fetch an static memory cell into the primary register */
645 /* Create the correct label name */
646 char* lbuf = GetLabelName (flags, label, offs);
648 /* Check the size and generate the correct load operation */
649 switch (flags & CF_TYPE) {
652 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
653 AddCodeLine ("lda %s", lbuf); /* load A from the label */
656 AddCodeLine ("lda %s", lbuf); /* load A from the label */
657 if (!(flags & CF_UNSIGNED)) {
658 /* Must sign extend */
659 unsigned L = GetLocalLabel ();
660 AddCodeLine ("bpl %s", LocalLabelName (L));
668 AddCodeLine ("lda %s", lbuf);
669 if (flags & CF_TEST) {
670 AddCodeLine ("ora %s+1", lbuf);
672 AddCodeLine ("ldx %s+1", lbuf);
677 if (flags & CF_TEST) {
678 AddCodeLine ("lda %s+3", lbuf);
679 AddCodeLine ("ora %s+2", lbuf);
680 AddCodeLine ("ora %s+1", lbuf);
681 AddCodeLine ("ora %s+0", lbuf);
683 AddCodeLine ("lda %s+3", lbuf);
684 AddCodeLine ("sta sreg+1");
685 AddCodeLine ("lda %s+2", lbuf);
686 AddCodeLine ("sta sreg");
687 AddCodeLine ("ldx %s+1", lbuf);
688 AddCodeLine ("lda %s", lbuf);
700 void g_getlocal (unsigned flags, int offs)
701 /* Fetch specified local object (local var). */
704 CheckLocalOffs (offs);
705 switch (flags & CF_TYPE) {
708 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
709 if (CPU == CPU_65C02 && offs == 0) {
710 AddCodeLine ("lda (sp)");
713 AddCodeLine ("lda (sp),y");
717 AddCodeLine ("ldx #$00");
718 AddCodeLine ("lda (sp),y");
719 if ((flags & CF_UNSIGNED) == 0) {
720 unsigned L = GetLocalLabel();
721 AddCodeLine ("bpl %s", LocalLabelName (L));
729 CheckLocalOffs (offs + 1);
730 if (flags & CF_TEST) {
732 AddCodeLine ("lda (sp),y");
734 AddCodeLine ("ora (sp),y");
736 if (CodeSizeFactor > 180) {
738 AddCodeLine ("lda (sp),y");
741 AddCodeLine ("lda (sp),y");
745 AddCodeLine ("jsr ldaxysp");
747 AddCodeLine ("jsr ldax0sp");
756 AddCodeLine ("jsr ldeaxysp");
758 AddCodeLine ("jsr ldeax0sp");
769 void g_getind (unsigned flags, unsigned offs)
770 /* Fetch the specified object type indirect through the primary register
771 * into the primary register
774 /* If the offset is greater than 255, add the part that is > 255 to
775 * the primary. This way we get an easy addition and use the low byte
778 offs = MakeByteOffs (flags, offs);
780 /* Handle the indirect fetch */
781 switch (flags & CF_TYPE) {
784 /* Character sized */
787 if (flags & CF_UNSIGNED) {
788 AddCodeLine ("jsr ldauidx");
790 AddCodeLine ("jsr ldaidx");
793 if (flags & CF_UNSIGNED) {
794 if (CodeSizeFactor > 330) {
795 AddCodeLine ("sta ptr1");
796 AddCodeLine ("stx ptr1+1");
797 AddCodeLine ("ldy #$00");
798 AddCodeLine ("ldx #$00");
799 AddCodeLine ("lda (ptr1),y");
801 AddCodeLine ("jsr ldaui");
804 AddCodeLine ("jsr ldai");
810 if (flags & CF_TEST) {
812 AddCodeLine ("sta ptr1");
813 AddCodeLine ("stx ptr1+1");
814 AddCodeLine ("lda (ptr1),y");
816 AddCodeLine ("ora (ptr1),y");
819 AddCodeLine ("jsr ldaxi");
822 AddCodeLine ("jsr ldaxidx");
829 AddCodeLine ("jsr ldeaxi");
832 AddCodeLine ("jsr ldeaxidx");
834 if (flags & CF_TEST) {
835 AddCodeLine ("jsr tsteax");
847 void g_leasp (int offs)
848 /* Fetch the address of the specified symbol into the primary register */
850 /* Calculate the offset relative to sp */
854 AddCode (OPC_LEA, AM_STACK, WordToStr (offs), 0);
859 void g_leavariadic (int Offs)
860 /* Fetch the address of a parameter in a variadic function into the primary
864 unsigned ArgSizeOffs;
866 /* Calculate the offset relative to sp */
869 /* Get the offset of the parameter which is stored at sp+0 on function
870 * entry and check if this offset is reachable with a byte offset.
873 ArgSizeOffs = -oursp;
874 CheckLocalOffs (ArgSizeOffs);
876 /* Get the size of all parameters. */
877 if (ArgSizeOffs == 0 && CPU == CPU_65C02) {
878 AddCodeLine ("lda (sp)");
880 ldyconst (ArgSizeOffs);
881 AddCodeLine ("lda (sp),y");
884 /* Add the value of the stackpointer */
885 if (CodeSizeFactor > 250) {
886 unsigned L = GetLocalLabel();
887 AddCodeLine ("ldx sp+1");
889 AddCodeLine ("adc sp");
890 AddCodeLine ("bcc %s", LocalLabelName (L));
894 AddCodeLine ("jsr leaasp");
897 /* Add the offset to the primary */
899 g_inc (CF_INT | CF_CONST, Offs);
900 } else if (Offs < 0) {
901 g_dec (CF_INT | CF_CONST, -Offs);
907 /*****************************************************************************/
908 /* Store into memory */
909 /*****************************************************************************/
913 void g_putstatic (unsigned flags, unsigned long label, unsigned offs)
914 /* Store the primary register into the specified static memory cell */
916 /* Create the correct label name */
917 char* lbuf = GetLabelName (flags, label, offs);
919 /* Check the size and generate the correct store operation */
920 switch (flags & CF_TYPE) {
923 AddCode (OPC_STA, AM_ABS, lbuf, 0);
927 AddCode (OPC_STAX, AM_ABS, lbuf, 0);
931 AddCode (OPC_STEAX, AM_ABS, lbuf, 0);
942 void g_putlocal (unsigned Flags, int Offs, long Val)
943 /* Put data into local object. */
946 CheckLocalOffs (Offs);
948 if (Flags & CF_CONST) {
949 g_getimmed (Flags, Val, Offs);
952 switch (Flags & CF_TYPE) {
955 AddCode (OPC_STA, AM_STACK, WordToStr (Offs), 0);
959 AddCode (OPC_STAX, AM_STACK, WordToStr (Offs), 0);
963 AddCode (OPC_STEAX, AM_STACK, WordToStr (Offs), 0);
974 void g_putind (unsigned Flags, unsigned Offs)
975 /* Store the specified object type in the primary register at the address
976 * on the top of the stack
979 /* We can handle offsets below $100 directly, larger offsets must be added
980 * to the address. Since a/x is in use, best code is achieved by adding
981 * just the high byte. Be sure to check if the low byte will overflow while
984 if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
986 /* Overflow - we need to add the low byte also */
987 AddCodeLine ("ldy #$00");
990 AddCodeLine ("lda #$%02X", Offs & 0xFF);
991 AddCodeLine ("adc (sp),y");
992 AddCodeLine ("sta (sp),y");
994 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
995 AddCodeLine ("adc (sp),y");
996 AddCodeLine ("sta (sp),y");
999 /* Complete address is on stack, new offset is zero */
1002 } else if ((Offs & 0xFF00) != 0) {
1004 /* We can just add the high byte */
1005 AddCodeLine ("ldy #$01");
1006 AddCodeLine ("clc");
1007 AddCodeLine ("pha");
1008 AddCodeLine ("lda #$%02X", (Offs >> 8) & 0xFF);
1009 AddCodeLine ("adc (sp),y");
1010 AddCodeLine ("sta (sp),y");
1011 AddCodeLine ("pla");
1013 /* Offset is now just the low byte */
1017 /* Check the size and determine operation */
1018 switch (Flags & CF_TYPE) {
1023 AddCodeLine ("jsr staspidx");
1025 AddCodeLine ("jsr staspp");
1032 AddCodeLine ("jsr staxspidx");
1034 AddCodeLine ("jsr staxspp");
1041 AddCodeLine ("jsr steaxspidx");
1043 AddCodeLine ("jsr steaxspp");
1052 /* Pop the argument which is always a pointer */
1058 /*****************************************************************************/
1059 /* type conversion and similiar stuff */
1060 /*****************************************************************************/
1064 void g_toslong (unsigned flags)
1065 /* Make sure, the value on TOS is a long. Convert if necessary */
1067 switch (flags & CF_TYPE) {
1071 if (flags & CF_UNSIGNED) {
1072 AddCodeLine ("jsr tosulong");
1074 AddCodeLine ("jsr toslong");
1089 void g_tosint (unsigned flags)
1090 /* Make sure, the value on TOS is an int. Convert if necessary */
1092 switch (flags & CF_TYPE) {
1099 AddCodeLine ("jsr tosint");
1110 void g_reglong (unsigned flags)
1111 /* Make sure, the value in the primary register a long. Convert if necessary */
1113 switch (flags & CF_TYPE) {
1117 if (flags & CF_UNSIGNED) {
1118 if (CodeSizeFactor >= 200) {
1120 AddCodeLine ("sty sreg");
1121 AddCodeLine ("sty sreg+1");
1123 AddCodeLine ("jsr axulong");
1126 AddCodeLine ("jsr axlong");
1140 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1141 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1142 * value, that corresponds to the value on TOS, rhs corresponds to the value
1143 * in (e)ax. The return value is the the flags value for the resulting type.
1146 unsigned ltype, rtype;
1149 /* Get the type spec from the flags */
1150 ltype = lhs & CF_TYPE;
1151 rtype = rhs & CF_TYPE;
1153 /* Check if a conversion is needed */
1154 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1155 /* We must promote the primary register to long */
1157 /* Get the new rhs type */
1158 rhs = (rhs & ~CF_TYPE) | CF_LONG;
1160 } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1161 /* We must promote the lhs to long */
1167 /* Get the new rhs type */
1168 lhs = (lhs & ~CF_TYPE) | CF_LONG;
1172 /* Determine the result type for the operation:
1173 * - The result is const if both operands are const.
1174 * - The result is unsigned if one of the operands is unsigned.
1175 * - The result is long if one of the operands is long.
1176 * - Otherwise the result is int sized.
1178 result = (lhs & CF_CONST) & (rhs & CF_CONST);
1179 result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1180 if (rtype == CF_LONG || ltype == CF_LONG) {
1190 unsigned g_typecast (unsigned lhs, unsigned rhs)
1191 /* Cast the value in the primary register to the operand size that is flagged
1192 * by the lhs value. Return the result value.
1195 unsigned ltype, rtype;
1197 /* Get the type spec from the flags */
1198 ltype = lhs & CF_TYPE;
1199 rtype = rhs & CF_TYPE;
1201 /* Check if a conversion is needed */
1202 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1203 /* We must promote the primary register to long */
1207 /* Do not need any other action. If the left type is int, and the primary
1208 * register is long, it will be automagically truncated. If the right hand
1209 * side is const, it is not located in the primary register and handled by
1210 * the expression parser code.
1213 /* Result is const if the right hand side was const */
1214 lhs |= (rhs & CF_CONST);
1216 /* The resulting type is that of the left hand side (that's why you called
1224 void g_scale (unsigned flags, long val)
1225 /* Scale the value in the primary register by the given value. If val is positive,
1226 * scale up, is val is negative, scale down. This function is used to scale
1227 * the operands or results of pointer arithmetic by the size of the type, the
1228 * pointer points to.
1233 /* Value may not be zero */
1235 Internal ("Data type has no size");
1236 } else if (val > 0) {
1239 if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1241 /* Factor is 2, 4 or 8, use special function */
1242 switch (flags & CF_TYPE) {
1245 if (flags & CF_FORCECHAR) {
1247 AddCodeLine ("asl a");
1254 if (CodeSizeFactor >= (p2+1)*130U) {
1255 AddCodeLine ("stx tmp1");
1257 AddCodeLine ("asl a");
1258 AddCodeLine ("rol tmp1");
1260 AddCodeLine ("ldx tmp1");
1262 if (flags & CF_UNSIGNED) {
1263 AddCodeLine ("jsr shlax%d", p2);
1265 AddCodeLine ("jsr aslax%d", p2);
1271 if (flags & CF_UNSIGNED) {
1272 AddCodeLine ("jsr shleax%d", p2);
1274 AddCodeLine ("jsr asleax%d", p2);
1283 } else if (val != 1) {
1285 /* Use a multiplication instead */
1286 g_mul (flags | CF_CONST, val);
1294 if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1296 /* Factor is 2, 4 or 8, use special function */
1297 switch (flags & CF_TYPE) {
1300 if (flags & CF_FORCECHAR) {
1301 if (flags & CF_UNSIGNED) {
1303 AddCodeLine ("lsr a");
1306 } else if (p2 <= 2) {
1307 AddCodeLine ("cmp #$80");
1308 AddCodeLine ("ror a");
1315 if (flags & CF_UNSIGNED) {
1316 if (CodeSizeFactor >= (p2+1)*130U) {
1317 AddCodeLine ("stx tmp1");
1319 AddCodeLine ("lsr tmp1");
1320 AddCodeLine ("ror a");
1322 AddCodeLine ("ldx tmp1");
1324 AddCodeLine ("jsr lsrax%d", p2);
1327 if (CodeSizeFactor >= (p2+1)*150U) {
1328 AddCodeLine ("stx tmp1");
1330 AddCodeLine ("cpx #$80");
1331 AddCodeLine ("ror tmp1");
1332 AddCodeLine ("ror a");
1334 AddCodeLine ("ldx tmp1");
1336 AddCodeLine ("jsr asrax%d", p2);
1342 if (flags & CF_UNSIGNED) {
1343 AddCodeLine ("jsr lsreax%d", p2);
1345 AddCodeLine ("jsr asreax%d", p2);
1354 } else if (val != 1) {
1356 /* Use a division instead */
1357 g_div (flags | CF_CONST, val);
1365 /*****************************************************************************/
1366 /* Adds and subs of variables fix a fixed address */
1367 /*****************************************************************************/
1371 void g_addlocal (unsigned flags, int offs)
1372 /* Add a local variable to ax */
1376 /* Correct the offset and check it */
1378 CheckLocalOffs (offs);
1380 switch (flags & CF_TYPE) {
1383 L = GetLocalLabel();
1384 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1385 AddCodeLine ("clc");
1386 AddCodeLine ("adc (sp),y");
1387 AddCodeLine ("bcc %s", LocalLabelName (L));
1388 AddCodeLine ("inx");
1393 AddCodeLine ("ldy #$%02X", offs & 0xFF);
1394 AddCodeLine ("clc");
1395 AddCodeLine ("adc (sp),y");
1396 AddCodeLine ("pha");
1397 AddCodeLine ("txa");
1398 AddCodeLine ("iny");
1399 AddCodeLine ("adc (sp),y");
1400 AddCodeLine ("tax");
1401 AddCodeLine ("pla");
1405 /* Do it the old way */
1407 g_getlocal (flags, offs);
1419 void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
1420 /* Add a static variable to ax */
1424 /* Create the correct label name */
1425 char* lbuf = GetLabelName (flags, label, offs);
1427 switch (flags & CF_TYPE) {
1430 L = GetLocalLabel();
1431 AddCodeLine ("clc");
1432 AddCodeLine ("adc %s", lbuf);
1433 AddCodeLine ("bcc %s", LocalLabelName (L));
1434 AddCodeLine ("inx");
1439 AddCodeLine ("clc");
1440 AddCodeLine ("adc %s", lbuf);
1441 AddCodeLine ("tay");
1442 AddCodeLine ("txa");
1443 AddCodeLine ("adc %s+1", lbuf);
1444 AddCodeLine ("tax");
1445 AddCodeLine ("tya");
1449 /* Do it the old way */
1451 g_getstatic (flags, label, offs);
1463 /*****************************************************************************/
1464 /* Special op= functions */
1465 /*****************************************************************************/
1469 void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
1471 /* Emit += for a static variable */
1473 /* Create the correct label name */
1474 char* lbuf = GetLabelName (flags, label, offs);
1476 /* Check the size and determine operation */
1477 switch (flags & CF_TYPE) {
1480 if (flags & CF_FORCECHAR) {
1481 AddCodeLine ("ldx #$00");
1482 if (flags & CF_CONST) {
1484 AddCodeLine ("inc %s", lbuf);
1485 AddCodeLine ("lda %s", lbuf);
1487 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1488 AddCodeLine ("clc");
1489 AddCodeLine ("adc %s", lbuf);
1490 AddCodeLine ("sta %s", lbuf);
1493 AddCodeLine ("clc");
1494 AddCodeLine ("adc %s", lbuf);
1495 AddCodeLine ("sta %s", lbuf);
1497 if ((flags & CF_UNSIGNED) == 0) {
1498 unsigned L = GetLocalLabel();
1499 AddCodeLine ("bpl %s", LocalLabelName (L));
1500 AddCodeLine ("dex");
1508 if (flags & CF_CONST) {
1510 unsigned L = GetLocalLabel ();
1511 AddCodeLine ("inc %s", lbuf);
1512 AddCodeLine ("bne %s", LocalLabelName (L));
1513 AddCodeLine ("inc %s+1", lbuf);
1515 AddCodeLine ("lda %s", lbuf); /* Hmmm... */
1516 AddCodeLine ("ldx %s+1", lbuf);
1518 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1519 AddCodeLine ("clc");
1520 AddCodeLine ("adc %s", lbuf);
1521 AddCodeLine ("sta %s", lbuf);
1523 unsigned L = GetLocalLabel ();
1524 AddCodeLine ("bcc %s", LocalLabelName (L));
1525 AddCodeLine ("inc %s+1", lbuf);
1527 AddCodeLine ("ldx %s+1", lbuf);
1529 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1530 AddCodeLine ("adc %s+1", lbuf);
1531 AddCodeLine ("sta %s+1", lbuf);
1532 AddCodeLine ("tax");
1533 AddCodeLine ("lda %s", lbuf);
1537 AddCodeLine ("clc");
1538 AddCodeLine ("adc %s", lbuf);
1539 AddCodeLine ("sta %s", lbuf);
1540 AddCodeLine ("txa");
1541 AddCodeLine ("adc %s+1", lbuf);
1542 AddCodeLine ("sta %s+1", lbuf);
1543 AddCodeLine ("tax");
1544 AddCodeLine ("lda %s", lbuf);
1549 if (flags & CF_CONST) {
1551 AddCodeLine ("ldy #<(%s)", lbuf);
1552 AddCodeLine ("sty ptr1");
1553 AddCodeLine ("ldy #>(%s+1)", lbuf);
1555 AddCodeLine ("jsr laddeq1");
1557 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1558 AddCodeLine ("jsr laddeqa");
1561 g_getstatic (flags, label, offs);
1563 g_putstatic (flags, label, offs);
1566 AddCodeLine ("ldy #<(%s)", lbuf);
1567 AddCodeLine ("sty ptr1");
1568 AddCodeLine ("ldy #>(%s+1)", lbuf);
1569 AddCodeLine ("jsr laddeq");
1580 void g_addeqlocal (unsigned flags, int offs, unsigned long val)
1581 /* Emit += for a local variable */
1583 /* Calculate the true offset, check it, load it into Y */
1585 CheckLocalOffs (offs);
1587 /* Check the size and determine operation */
1588 switch (flags & CF_TYPE) {
1591 if (flags & CF_FORCECHAR) {
1593 AddCodeLine ("ldx #$00");
1594 if (flags & CF_CONST) {
1595 AddCodeLine ("clc");
1596 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1597 AddCodeLine ("adc (sp),y");
1598 AddCodeLine ("sta (sp),y");
1600 AddCodeLine ("clc");
1601 AddCodeLine ("adc (sp),y");
1602 AddCodeLine ("sta (sp),y");
1604 if ((flags & CF_UNSIGNED) == 0) {
1605 unsigned L = GetLocalLabel();
1606 AddCodeLine ("bpl %s", LocalLabelName (L));
1607 AddCodeLine ("dex");
1615 if (flags & CF_CONST) {
1616 g_getimmed (flags, val, 0);
1619 AddCodeLine ("jsr addeq0sp");
1622 AddCodeLine ("jsr addeqysp");
1627 if (flags & CF_CONST) {
1628 g_getimmed (flags, val, 0);
1631 AddCodeLine ("jsr laddeq0sp");
1634 AddCodeLine ("jsr laddeqysp");
1645 void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1646 /* Emit += for the location with address in ax */
1648 /* If the offset is too large for a byte register, add the high byte
1649 * of the offset to the primary. Beware: We need a special correction
1650 * if the offset in the low byte will overflow in the operation.
1652 offs = MakeByteOffs (flags, offs);
1654 /* Check the size and determine operation */
1655 switch (flags & CF_TYPE) {
1658 AddCodeLine ("sta ptr1");
1659 AddCodeLine ("stx ptr1+1");
1660 AddCodeLine ("ldy #$%02X", offs);
1661 AddCodeLine ("ldx #$00");
1662 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1663 AddCodeLine ("clc");
1664 AddCodeLine ("adc (ptr1),y");
1665 AddCodeLine ("sta (ptr1),y");
1669 if (CodeSizeFactor >= 200) {
1670 /* Lots of code, use only if size is not important */
1671 AddCodeLine ("sta ptr1");
1672 AddCodeLine ("stx ptr1+1");
1673 AddCodeLine ("ldy #$%02X", offs);
1674 AddCodeLine ("lda #$%02X", (int)(val & 0xFF));
1675 AddCodeLine ("clc");
1676 AddCodeLine ("adc (ptr1),y");
1677 AddCodeLine ("sta (ptr1),y");
1678 AddCodeLine ("pha");
1679 AddCodeLine ("iny");
1680 AddCodeLine ("lda #$%02X", (unsigned char)(val >> 8));
1681 AddCodeLine ("adc (ptr1),y");
1682 AddCodeLine ("sta (ptr1),y");
1683 AddCodeLine ("tax");
1684 AddCodeLine ("pla");
1690 AddCodeLine ("jsr pushax"); /* Push the address */
1691 push (flags); /* Correct the internal sp */
1692 g_getind (flags, offs); /* Fetch the value */
1693 g_inc (flags, val); /* Increment value in primary */
1694 g_putind (flags, offs); /* Store the value back */
1704 void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
1706 /* Emit -= for a static variable */
1708 /* Create the correct label name */
1709 char* lbuf = GetLabelName (flags, label, offs);
1711 /* Check the size and determine operation */
1712 switch (flags & CF_TYPE) {
1715 if (flags & CF_FORCECHAR) {
1716 AddCodeLine ("ldx #$00");
1717 if (flags & CF_CONST) {
1719 AddCodeLine ("dec %s", lbuf);
1720 AddCodeLine ("lda %s", lbuf);
1722 AddCodeLine ("sec");
1723 AddCodeLine ("lda %s", lbuf);
1724 AddCodeLine ("sbc #$%02X", (int)(val & 0xFF));
1725 AddCodeLine ("sta %s", lbuf);
1728 AddCodeLine ("sec");
1729 AddCodeLine ("sta tmp1");
1730 AddCodeLine ("lda %s", lbuf);
1731 AddCodeLine ("sbc tmp1");
1732 AddCodeLine ("sta %s", lbuf);
1734 if ((flags & CF_UNSIGNED) == 0) {
1735 unsigned L = GetLocalLabel();
1736 AddCodeLine ("bpl %s", LocalLabelName (L));
1737 AddCodeLine ("dex");
1745 AddCodeLine ("sec");
1746 if (flags & CF_CONST) {
1747 AddCodeLine ("lda %s", lbuf);
1748 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1749 AddCodeLine ("sta %s", lbuf);
1751 unsigned L = GetLocalLabel ();
1752 AddCodeLine ("bcs %s", LocalLabelName (L));
1753 AddCodeLine ("dec %s+1", lbuf);
1755 AddCodeLine ("ldx %s+1", lbuf);
1757 AddCodeLine ("lda %s+1", lbuf);
1758 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1759 AddCodeLine ("sta %s+1", lbuf);
1760 AddCodeLine ("tax");
1761 AddCodeLine ("lda %s", lbuf);
1764 AddCodeLine ("sta tmp1");
1765 AddCodeLine ("lda %s", lbuf);
1766 AddCodeLine ("sbc tmp1");
1767 AddCodeLine ("sta %s", lbuf);
1768 AddCodeLine ("stx tmp1");
1769 AddCodeLine ("lda %s+1", lbuf);
1770 AddCodeLine ("sbc tmp1");
1771 AddCodeLine ("sta %s+1", lbuf);
1772 AddCodeLine ("tax");
1773 AddCodeLine ("lda %s", lbuf);
1778 if (flags & CF_CONST) {
1780 AddCodeLine ("ldy #<(%s)", lbuf);
1781 AddCodeLine ("sty ptr1");
1782 AddCodeLine ("ldy #>(%s+1)", lbuf);
1784 AddCodeLine ("jsr lsubeq1");
1786 AddCodeLine ("lda #$%02X", (unsigned char)val);
1787 AddCodeLine ("jsr lsubeqa");
1790 g_getstatic (flags, label, offs);
1792 g_putstatic (flags, label, offs);
1795 AddCodeLine ("ldy #<(%s)", lbuf);
1796 AddCodeLine ("sty ptr1");
1797 AddCodeLine ("ldy #>(%s+1)", lbuf);
1798 AddCodeLine ("jsr lsubeq");
1809 void g_subeqlocal (unsigned flags, int offs, unsigned long val)
1810 /* Emit -= for a local variable */
1812 /* Calculate the true offset, check it, load it into Y */
1814 CheckLocalOffs (offs);
1816 /* Check the size and determine operation */
1817 switch (flags & CF_TYPE) {
1820 if (flags & CF_FORCECHAR) {
1822 AddCodeLine ("ldx #$00");
1823 AddCodeLine ("sec");
1824 if (flags & CF_CONST) {
1825 AddCodeLine ("lda (sp),y");
1826 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1828 AddCodeLine ("sta tmp1");
1829 AddCodeLine ("lda (sp),y");
1830 AddCodeLine ("sbc tmp1");
1832 AddCodeLine ("sta (sp),y");
1833 if ((flags & CF_UNSIGNED) == 0) {
1834 unsigned L = GetLocalLabel();
1835 AddCodeLine ("bpl %s", LocalLabelName (L));
1836 AddCodeLine ("dex");
1844 if (flags & CF_CONST) {
1845 g_getimmed (flags, val, 0);
1848 AddCodeLine ("jsr subeq0sp");
1851 AddCodeLine ("jsr subeqysp");
1856 if (flags & CF_CONST) {
1857 g_getimmed (flags, val, 0);
1860 AddCodeLine ("jsr lsubeq0sp");
1863 AddCodeLine ("jsr lsubeqysp");
1874 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
1875 /* Emit -= for the location with address in ax */
1877 /* If the offset is too large for a byte register, add the high byte
1878 * of the offset to the primary. Beware: We need a special correction
1879 * if the offset in the low byte will overflow in the operation.
1881 offs = MakeByteOffs (flags, offs);
1883 /* Check the size and determine operation */
1884 switch (flags & CF_TYPE) {
1887 AddCodeLine ("sta ptr1");
1888 AddCodeLine ("stx ptr1+1");
1889 AddCodeLine ("ldy #$%02X", offs);
1890 AddCodeLine ("ldx #$00");
1891 AddCodeLine ("lda (ptr1),y");
1892 AddCodeLine ("sec");
1893 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1894 AddCodeLine ("sta (ptr1),y");
1898 if (CodeSizeFactor >= 200) {
1899 /* Lots of code, use only if size is not important */
1900 AddCodeLine ("sta ptr1");
1901 AddCodeLine ("stx ptr1+1");
1902 AddCodeLine ("ldy #$%02X", offs);
1903 AddCodeLine ("lda (ptr1),y");
1904 AddCodeLine ("sec");
1905 AddCodeLine ("sbc #$%02X", (unsigned char)val);
1906 AddCodeLine ("sta (ptr1),y");
1907 AddCodeLine ("pha");
1908 AddCodeLine ("iny");
1909 AddCodeLine ("lda (ptr1),y");
1910 AddCodeLine ("sbc #$%02X", (unsigned char)(val >> 8));
1911 AddCodeLine ("sta (ptr1),y");
1912 AddCodeLine ("tax");
1913 AddCodeLine ("pla");
1919 AddCodeLine ("jsr pushax"); /* Push the address */
1920 push (flags); /* Correct the internal sp */
1921 g_getind (flags, offs); /* Fetch the value */
1922 g_dec (flags, val); /* Increment value in primary */
1923 g_putind (flags, offs); /* Store the value back */
1933 /*****************************************************************************/
1934 /* Add a variable address to the value in ax */
1935 /*****************************************************************************/
1939 void g_addaddr_local (unsigned flags, int offs)
1940 /* Add the address of a local variable to ax */
1944 /* Add the offset */
1947 /* We cannot address more then 256 bytes of locals anyway */
1948 L = GetLocalLabel();
1949 CheckLocalOffs (offs);
1950 AddCodeLine ("clc");
1951 AddCodeLine ("adc #$%02X", offs & 0xFF);
1952 /* Do also skip the CLC insn below */
1953 AddCodeLine ("bcc %s", LocalLabelName (L));
1954 AddCodeLine ("inx");
1957 /* Add the current stackpointer value */
1958 AddCodeLine ("clc");
1960 /* Label was used above */
1963 AddCodeLine ("adc sp");
1964 AddCodeLine ("tay");
1965 AddCodeLine ("txa");
1966 AddCodeLine ("adc sp+1");
1967 AddCodeLine ("tax");
1968 AddCodeLine ("tya");
1973 void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
1974 /* Add the address of a static variable to ax */
1976 /* Create the correct label name */
1977 char* lbuf = GetLabelName (flags, label, offs);
1979 /* Add the address to the current ax value */
1980 AddCodeLine ("clc");
1981 AddCodeLine ("adc #<(%s)", lbuf);
1982 AddCodeLine ("tay");
1983 AddCodeLine ("txa");
1984 AddCodeLine ("adc #>(%s)", lbuf);
1985 AddCodeLine ("tax");
1986 AddCodeLine ("tya");
1991 /*****************************************************************************/
1993 /*****************************************************************************/
1997 void g_save (unsigned flags)
1998 /* Copy primary register to hold register. */
2000 /* Check the size and determine operation */
2001 switch (flags & CF_TYPE) {
2004 if (flags & CF_FORCECHAR) {
2005 AddCodeLine ("pha");
2011 AddCodeLine ("sta regsave");
2012 AddCodeLine ("stx regsave+1");
2016 AddCodeLine ("jsr saveeax");
2026 void g_restore (unsigned flags)
2027 /* Copy hold register to primary. */
2029 /* Check the size and determine operation */
2030 switch (flags & CF_TYPE) {
2033 if (flags & CF_FORCECHAR) {
2034 AddCodeLine ("pla");
2040 AddCodeLine ("lda regsave");
2041 AddCodeLine ("ldx regsave+1");
2045 AddCodeLine ("jsr resteax");
2055 void g_cmp (unsigned flags, unsigned long val)
2056 /* Immidiate compare. The primary register will not be changed, Z flag
2062 /* Check the size and determine operation */
2063 switch (flags & CF_TYPE) {
2066 if (flags & CF_FORCECHAR) {
2067 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2073 L = GetLocalLabel();
2074 AddCodeLine ("cmp #$%02X", (unsigned char)val);
2075 AddCodeLine ("bne %s", LocalLabelName (L));
2076 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
2081 Internal ("g_cmp: Long compares not implemented");
2091 static void oper (unsigned flags, unsigned long val, char** subs)
2092 /* Encode a binary operation. subs is a pointer to four groups of three
2094 * 0-2 --> Operate on ints
2095 * 3-5 --> Operate on unsigneds
2096 * 6-8 --> Operate on longs
2097 * 9-11 --> Operate on unsigned longs
2099 * The first subroutine names in each string group is used to encode an
2100 * operation with a zero constant, the second to encode an operation with
2101 * a 8 bit constant, and the third is used in all other cases.
2106 /* Determine the offset into the array */
2107 offs = (flags & CF_UNSIGNED)? 3 : 0;
2108 switch (flags & CF_TYPE) {
2121 /* Encode the operation */
2122 if (flags & CF_CONST) {
2123 /* Constant value given */
2124 if (val == 0 && subs [offs+0]) {
2125 /* Special case: constant with value zero */
2126 AddCodeLine ("jsr %s", subs [offs+0]);
2127 } else if (val < 0x100 && subs [offs+1]) {
2128 /* Special case: constant with high byte zero */
2129 ldaconst (val); /* Load low byte */
2130 AddCodeLine ("jsr %s", subs [offs+1]);
2132 /* Others: arbitrary constant value */
2133 g_getimmed (flags, val, 0); /* Load value */
2134 AddCodeLine ("jsr %s", subs [offs+2]);
2137 /* Value not constant (is already in (e)ax) */
2138 AddCodeLine ("jsr %s", subs [offs+2]);
2141 /* The operation will pop it's argument */
2147 void g_test (unsigned flags)
2148 /* Test the value in the primary and set the condition codes */
2150 switch (flags & CF_TYPE) {
2153 if (flags & CF_FORCECHAR) {
2154 AddCodeLine ("tax");
2160 AddCodeLine ("stx tmp1");
2161 AddCodeLine ("ora tmp1");
2165 if (flags & CF_UNSIGNED) {
2166 AddCodeLine ("jsr utsteax");
2168 AddCodeLine ("jsr tsteax");
2180 void g_push (unsigned flags, unsigned long val)
2181 /* Push the primary register or a constant value onto the stack */
2185 if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2187 /* We have a constant 8 or 16 bit value */
2188 if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2190 /* Handle as 8 bit value */
2191 if (CodeSizeFactor >= 165 || val > 2) {
2193 AddCodeLine ("jsr pusha");
2195 AddCodeLine ("jsr pushc%d", (int) val);
2200 /* Handle as 16 bit value */
2201 hi = (unsigned char) (val >> 8);
2203 AddCodeLine ("jsr push%u", (unsigned) val);
2204 } else if (hi == 0 || hi == 0xFF) {
2205 /* Use special function */
2207 AddCodeLine ("jsr %s", (hi == 0)? "pusha0" : "pushaFF");
2210 g_getimmed (flags, val, 0);
2211 AddCodeLine ("jsr pushax");
2217 /* Value is not 16 bit or not constant */
2218 if (flags & CF_CONST) {
2219 /* Constant 32 bit value, load into eax */
2220 g_getimmed (flags, val, 0);
2223 /* Push the primary register */
2224 switch (flags & CF_TYPE) {
2227 if (flags & CF_FORCECHAR) {
2228 /* Handle as char */
2229 AddCodeLine ("jsr pusha");
2234 AddCodeLine ("jsr pushax");
2238 AddCodeLine ("jsr pusheax");
2248 /* Adjust the stack offset */
2254 void g_swap (unsigned flags)
2255 /* Swap the primary register and the top of the stack. flags give the type
2256 * of *both* values (must have same size).
2259 switch (flags & CF_TYPE) {
2263 AddCodeLine ("jsr swapstk");
2267 AddCodeLine ("jsr swapestk");
2278 void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2279 /* Call the specified subroutine name */
2281 if ((Flags & CF_FIXARGC) == 0) {
2282 /* Pass the argument count */
2285 AddCodeLine ("jsr _%s", Label);
2286 oursp += ArgSize; /* callee pops args */
2291 void g_callind (unsigned Flags, unsigned ArgSize)
2292 /* Call subroutine with address in AX */
2294 if ((Flags & CF_FIXARGC) == 0) {
2295 /* Pass arg count */
2298 AddCodeLine ("jsr callax"); /* do the call */
2299 oursp += ArgSize; /* callee pops args */
2304 void g_jump (unsigned Label)
2305 /* Jump to specified internal label number */
2307 AddCodeLine ("jmp %s", LocalLabelName (Label));
2312 void g_switch (unsigned Flags)
2313 /* Output switch statement preamble */
2315 switch (Flags & CF_TYPE) {
2319 AddCodeLine ("jsr switch");
2323 AddCodeLine ("jsr lswitch");
2334 void g_case (unsigned flags, unsigned label, unsigned long val)
2335 /* Create table code for one case selector */
2337 switch (flags & CF_TYPE) {
2341 AddCodeLine (".word $%04X, %s",
2342 (unsigned)(val & 0xFFFF),
2343 LocalLabelName (label));
2347 AddCodeLine (".dword $%08lX", val);
2348 AddCodeLine (".word %s", LocalLabelName (label));
2359 void g_truejump (unsigned flags, unsigned label)
2360 /* Jump to label if zero flag clear */
2362 AddCodeLine ("jne %s", LocalLabelName (label));
2367 void g_falsejump (unsigned flags, unsigned label)
2368 /* Jump to label if zero flag set */
2370 AddCodeLine ("jeq %s", LocalLabelName (label));
2375 static void mod_internal (int k, char* verb1, char* verb2)
2378 AddCodeLine ("jsr %ssp%c", verb1, k + '0');
2382 AddCodeLine ("jsr %ssp", verb2);
2388 void g_space (int space)
2389 /* Create or drop space on the stack */
2392 mod_internal (-space, "inc", "addy");
2393 } else if (space > 0) {
2394 mod_internal (space, "dec", "suby");
2400 void g_cstackcheck (void)
2401 /* Check for a C stack overflow */
2403 AddCodeLine ("jsr cstkchk");
2408 void g_stackcheck (void)
2409 /* Check for a stack overflow */
2411 AddCodeLine ("jsr stkchk");
2416 void g_add (unsigned flags, unsigned long val)
2417 /* Primary = TOS + Primary */
2419 static char* ops [12] = {
2420 0, "tosadda0", "tosaddax",
2421 0, "tosadda0", "tosaddax",
2426 if (flags & CF_CONST) {
2427 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2428 g_push (flags & ~CF_CONST, 0);
2430 oper (flags, val, ops);
2435 void g_sub (unsigned flags, unsigned long val)
2436 /* Primary = TOS - Primary */
2438 static char* ops [12] = {
2439 0, "tossuba0", "tossubax",
2440 0, "tossuba0", "tossubax",
2445 if (flags & CF_CONST) {
2446 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2447 g_push (flags & ~CF_CONST, 0);
2449 oper (flags, val, ops);
2454 void g_rsub (unsigned flags, unsigned long val)
2455 /* Primary = Primary - TOS */
2457 static char* ops [12] = {
2458 0, "tosrsuba0", "tosrsubax",
2459 0, "tosrsuba0", "tosrsubax",
2463 oper (flags, val, ops);
2468 void g_mul (unsigned flags, unsigned long val)
2469 /* Primary = TOS * Primary */
2471 static char* ops [12] = {
2472 0, "tosmula0", "tosmulax",
2473 0, "tosumula0", "tosumulax",
2480 /* Do strength reduction if the value is constant and a power of two */
2481 if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2482 /* Generate a shift instead */
2487 /* If the right hand side is const, the lhs is not on stack but still
2488 * in the primary register.
2490 if (flags & CF_CONST) {
2492 switch (flags & CF_TYPE) {
2495 if (flags & CF_FORCECHAR) {
2496 /* Handle some special cases */
2500 AddCodeLine ("sta tmp1");
2501 AddCodeLine ("asl a");
2502 AddCodeLine ("clc");
2503 AddCodeLine ("adc tmp1");
2507 AddCodeLine ("sta tmp1");
2508 AddCodeLine ("asl a");
2509 AddCodeLine ("asl a");
2510 AddCodeLine ("clc");
2511 AddCodeLine ("adc tmp1");
2515 AddCodeLine ("sta tmp1");
2516 AddCodeLine ("asl a");
2517 AddCodeLine ("asl a");
2518 AddCodeLine ("clc");
2519 AddCodeLine ("adc tmp1");
2520 AddCodeLine ("asl a");
2536 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2537 * into the normal, non-optimized stuff.
2539 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2540 g_push (flags & ~CF_CONST, 0);
2544 /* Use long way over the stack */
2545 oper (flags, val, ops);
2550 void g_div (unsigned flags, unsigned long val)
2551 /* Primary = TOS / Primary */
2553 static char* ops [12] = {
2554 0, "tosdiva0", "tosdivax",
2555 0, "tosudiva0", "tosudivax",
2560 /* Do strength reduction if the value is constant and a power of two */
2562 if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2563 /* Generate a shift instead */
2566 /* Generate a division */
2567 if (flags & CF_CONST) {
2568 /* lhs is not on stack */
2569 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2570 g_push (flags & ~CF_CONST, 0);
2572 oper (flags, val, ops);
2578 void g_mod (unsigned flags, unsigned long val)
2579 /* Primary = TOS % Primary */
2581 static char* ops [12] = {
2582 0, "tosmoda0", "tosmodax",
2583 0, "tosumoda0", "tosumodax",
2589 /* Check if we can do some cost reduction */
2590 if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2591 /* We can do that with an AND operation */
2592 g_and (flags, val - 1);
2594 /* Do it the hard way... */
2595 if (flags & CF_CONST) {
2596 /* lhs is not on stack */
2597 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2598 g_push (flags & ~CF_CONST, 0);
2600 oper (flags, val, ops);
2606 void g_or (unsigned flags, unsigned long val)
2607 /* Primary = TOS | Primary */
2609 static char* ops [12] = {
2610 0, "tosora0", "tosorax",
2611 0, "tosora0", "tosorax",
2616 /* If the right hand side is const, the lhs is not on stack but still
2617 * in the primary register.
2619 if (flags & CF_CONST) {
2621 switch (flags & CF_TYPE) {
2624 if (flags & CF_FORCECHAR) {
2625 if ((val & 0xFF) != 0xFF) {
2626 AddCodeLine ("ora #$%02X", (unsigned char)val);
2634 AddCodeLine ("ora #$%02X", (unsigned char)val);
2641 AddCodeLine ("ora #$%02X", (unsigned char)val);
2650 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2651 * into the normal, non-optimized stuff.
2653 g_push (flags & ~CF_CONST, 0);
2657 /* Use long way over the stack */
2658 oper (flags, val, ops);
2663 void g_xor (unsigned flags, unsigned long val)
2664 /* Primary = TOS ^ Primary */
2666 static char* ops [12] = {
2667 0, "tosxora0", "tosxorax",
2668 0, "tosxora0", "tosxorax",
2674 /* If the right hand side is const, the lhs is not on stack but still
2675 * in the primary register.
2677 if (flags & CF_CONST) {
2679 switch (flags & CF_TYPE) {
2682 if (flags & CF_FORCECHAR) {
2683 if ((val & 0xFF) != 0) {
2684 AddCodeLine ("eor #$%02X", (unsigned char)val);
2693 AddCodeLine ("eor #$%02X", (unsigned char)val);
2696 } else if ((val & 0xFF) == 0) {
2697 AddCodeLine ("pha");
2698 AddCodeLine ("txa");
2699 AddCodeLine ("eor #$%02X", (unsigned char)(val >> 8));
2700 AddCodeLine ("tax");
2701 AddCodeLine ("pla");
2709 AddCodeLine ("eor #$%02X", (unsigned char)val);
2719 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2720 * into the normal, non-optimized stuff.
2722 g_push (flags & ~CF_CONST, 0);
2726 /* Use long way over the stack */
2727 oper (flags, val, ops);
2732 void g_and (unsigned flags, unsigned long val)
2733 /* Primary = TOS & Primary */
2735 static char* ops [12] = {
2736 0, "tosanda0", "tosandax",
2737 0, "tosanda0", "tosandax",
2742 /* If the right hand side is const, the lhs is not on stack but still
2743 * in the primary register.
2745 if (flags & CF_CONST) {
2747 switch (flags & CF_TYPE) {
2750 if (flags & CF_FORCECHAR) {
2751 AddCodeLine ("and #$%02X", (unsigned char)val);
2756 if ((val & 0xFFFF) != 0xFFFF) {
2761 } else if (val != 0xFF) {
2762 AddCodeLine ("and #$%02X", (unsigned char)val);
2764 } else if ((val & 0xFF00) == 0xFF00) {
2765 AddCodeLine ("and #$%02X", (unsigned char)val);
2766 } else if ((val & 0x00FF) == 0x0000) {
2767 AddCodeLine ("txa");
2768 AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2769 AddCodeLine ("tax");
2772 AddCodeLine ("tay");
2773 AddCodeLine ("txa");
2774 AddCodeLine ("and #$%02X", (unsigned char)(val >> 8));
2775 AddCodeLine ("tax");
2776 AddCodeLine ("tya");
2777 if ((val & 0x00FF) != 0x00FF) {
2778 AddCodeLine ("and #$%02X", (unsigned char)val);
2787 AddCodeLine ("stx sreg+1");
2788 AddCodeLine ("stx sreg");
2789 if ((val & 0xFF) != 0xFF) {
2790 AddCodeLine ("and #$%02X", (unsigned char)val);
2793 } else if (val == 0xFF00) {
2795 AddCodeLine ("sta sreg+1");
2796 AddCodeLine ("sta sreg");
2805 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2806 * into the normal, non-optimized stuff.
2808 g_push (flags & ~CF_CONST, 0);
2812 /* Use long way over the stack */
2813 oper (flags, val, ops);
2818 void g_asr (unsigned flags, unsigned long val)
2819 /* Primary = TOS >> Primary */
2821 static char* ops [12] = {
2822 0, "tosasra0", "tosasrax",
2823 0, "tosshra0", "tosshrax",
2828 /* If the right hand side is const, the lhs is not on stack but still
2829 * in the primary register.
2831 if (flags & CF_CONST) {
2833 switch (flags & CF_TYPE) {
2837 if (val >= 1 && val <= 3) {
2838 if (flags & CF_UNSIGNED) {
2839 AddCodeLine ("jsr shrax%ld", val);
2841 AddCodeLine ("jsr asrax%ld", val);
2844 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2845 AddCodeLine ("txa");
2852 if (val >= 1 && val <= 3) {
2853 if (flags & CF_UNSIGNED) {
2854 AddCodeLine ("jsr shreax%ld", val);
2856 AddCodeLine ("jsr asreax%ld", val);
2859 } else if (val == 8 && (flags & CF_UNSIGNED)) {
2860 AddCodeLine ("txa");
2861 AddCodeLine ("ldx sreg");
2862 AddCodeLine ("ldy sreg+1");
2863 AddCodeLine ("sty sreg");
2864 AddCodeLine ("ldy #$00");
2865 AddCodeLine ("sty sreg+1");
2867 } else if (val == 16) {
2868 AddCodeLine ("ldy #$00");
2869 AddCodeLine ("ldx sreg+1");
2870 if ((flags & CF_UNSIGNED) == 0) {
2871 unsigned L = GetLocalLabel();
2872 AddCodeLine ("bpl %s", LocalLabelName (L));
2873 AddCodeLine ("dey");
2876 AddCodeLine ("lda sreg");
2877 AddCodeLine ("sty sreg+1");
2878 AddCodeLine ("sty sreg");
2887 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2888 * into the normal, non-optimized stuff.
2890 g_push (flags & ~CF_CONST, 0);
2894 /* Use long way over the stack */
2895 oper (flags, val, ops);
2900 void g_asl (unsigned flags, unsigned long val)
2901 /* Primary = TOS << Primary */
2903 static char* ops [12] = {
2904 0, "tosasla0", "tosaslax",
2905 0, "tosshla0", "tosshlax",
2911 /* If the right hand side is const, the lhs is not on stack but still
2912 * in the primary register.
2914 if (flags & CF_CONST) {
2916 switch (flags & CF_TYPE) {
2920 if (val >= 1 && val <= 3) {
2921 if (flags & CF_UNSIGNED) {
2922 AddCodeLine ("jsr shlax%ld", val);
2924 AddCodeLine ("jsr aslax%ld", val);
2927 } else if (val == 8) {
2928 AddCodeLine ("tax");
2929 AddCodeLine ("lda #$00");
2935 if (val >= 1 && val <= 3) {
2936 if (flags & CF_UNSIGNED) {
2937 AddCodeLine ("jsr shleax%ld", val);
2939 AddCodeLine ("jsr asleax%ld", val);
2942 } else if (val == 8) {
2943 AddCodeLine ("ldy sreg");
2944 AddCodeLine ("sty sreg+1");
2945 AddCodeLine ("stx sreg");
2946 AddCodeLine ("tax");
2947 AddCodeLine ("lda #$00");
2949 } else if (val == 16) {
2950 AddCodeLine ("stx sreg+1");
2951 AddCodeLine ("sta sreg");
2952 AddCodeLine ("lda #$00");
2953 AddCodeLine ("tax");
2962 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2963 * into the normal, non-optimized stuff.
2965 g_push (flags & ~CF_CONST, 0);
2969 /* Use long way over the stack */
2970 oper (flags, val, ops);
2975 void g_neg (unsigned flags)
2976 /* Primary = -Primary */
2978 switch (flags & CF_TYPE) {
2982 AddCodeLine ("jsr negax");
2986 AddCodeLine ("jsr negeax");
2996 void g_bneg (unsigned flags)
2997 /* Primary = !Primary */
2999 switch (flags & CF_TYPE) {
3002 AddCodeLine ("jsr bnega");
3006 AddCodeLine ("jsr bnegax");
3010 AddCodeLine ("jsr bnegeax");
3020 void g_com (unsigned flags)
3021 /* Primary = ~Primary */
3023 switch (flags & CF_TYPE) {
3027 AddCodeLine ("jsr complax");
3031 AddCodeLine ("jsr compleax");
3041 void g_inc (unsigned flags, unsigned long val)
3042 /* Increment the primary register by a given number */
3044 /* Don't inc by zero */
3049 /* Generate code for the supported types */
3051 switch (flags & CF_TYPE) {
3054 if (flags & CF_FORCECHAR) {
3055 if (CPU == CPU_65C02 && val <= 2) {
3057 AddCodeLine ("ina");
3060 AddCodeLine ("clc");
3061 AddCodeLine ("adc #$%02X", (unsigned char)val);
3068 if (CPU == CPU_65C02 && val == 1) {
3069 unsigned L = GetLocalLabel();
3070 AddCodeLine ("ina");
3071 AddCodeLine ("bne %s", LocalLabelName (L));
3072 AddCodeLine ("inx");
3074 } else if (CodeSizeFactor < 200) {
3077 AddCodeLine ("jsr incax%lu", val);
3078 } else if (val <= 255) {
3080 AddCodeLine ("jsr incaxy");
3082 g_add (flags | CF_CONST, val);
3085 /* Inline the code */
3087 if ((val & 0xFF) != 0) {
3088 unsigned L = GetLocalLabel();
3089 AddCodeLine ("clc");
3090 AddCodeLine ("adc #$%02X", (unsigned char) val);
3091 AddCodeLine ("bcc %s", LocalLabelName (L));
3092 AddCodeLine ("inx");
3096 AddCodeLine ("inx");
3099 AddCodeLine ("inx");
3102 AddCodeLine ("clc");
3103 if ((val & 0xFF) != 0) {
3104 AddCodeLine ("adc #$%02X", (unsigned char) val);
3106 AddCodeLine ("pha");
3107 AddCodeLine ("txa");
3108 AddCodeLine ("adc #$%02X", (unsigned char) (val >> 8));
3109 AddCodeLine ("tax");
3110 AddCodeLine ("pla");
3118 AddCodeLine ("jsr inceaxy");
3120 g_add (flags | CF_CONST, val);
3132 void g_dec (unsigned flags, unsigned long val)
3133 /* Decrement the primary register by a given number */
3135 /* Don't dec by zero */
3140 /* Generate code for the supported types */
3142 switch (flags & CF_TYPE) {
3145 if (flags & CF_FORCECHAR) {
3146 if (CPU == CPU_65C02 && val <= 2) {
3148 AddCodeLine ("dea");
3151 AddCodeLine ("sec");
3152 AddCodeLine ("sbc #$%02X", (unsigned char)val);
3159 if (CodeSizeFactor < 200) {
3160 /* Use subroutines */
3162 AddCodeLine ("jsr decax%d", (int) val);
3163 } else if (val <= 255) {
3165 AddCodeLine ("jsr decaxy");
3167 g_sub (flags | CF_CONST, val);
3170 /* Inline the code */
3172 if ((val & 0xFF) != 0) {
3173 unsigned L = GetLocalLabel();
3174 AddCodeLine ("sec");
3175 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3176 AddCodeLine ("bcs %s", LocalLabelName (L));
3177 AddCodeLine ("dex");
3181 AddCodeLine ("dex");
3184 AddCodeLine ("dex");
3187 AddCodeLine ("sec");
3188 if ((val & 0xFF) != 0) {
3189 AddCodeLine ("sbc #$%02X", (unsigned char) val);
3191 AddCodeLine ("pha");
3192 AddCodeLine ("txa");
3193 AddCodeLine ("sbc #$%02X", (unsigned char) (val >> 8));
3194 AddCodeLine ("tax");
3195 AddCodeLine ("pla");
3203 AddCodeLine ("jsr deceaxy");
3205 g_sub (flags | CF_CONST, val);
3218 * Following are the conditional operators. They compare the TOS against
3219 * the primary and put a literal 1 in the primary if the condition is
3220 * true, otherwise they clear the primary register
3225 void g_eq (unsigned flags, unsigned long val)
3226 /* Test for equal */
3228 static char* ops [12] = {
3229 "toseq00", "toseqa0", "toseqax",
3230 "toseq00", "toseqa0", "toseqax",
3237 /* If the right hand side is const, the lhs is not on stack but still
3238 * in the primary register.
3240 if (flags & CF_CONST) {
3242 switch (flags & CF_TYPE) {
3245 if (flags & CF_FORCECHAR) {
3246 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3247 AddCodeLine ("jsr booleq");
3253 L = GetLocalLabel();
3254 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3255 AddCodeLine ("bne %s", LocalLabelName (L));
3256 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3258 AddCodeLine ("jsr booleq");
3268 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3269 * into the normal, non-optimized stuff.
3271 g_push (flags & ~CF_CONST, 0);
3275 /* Use long way over the stack */
3276 oper (flags, val, ops);
3281 void g_ne (unsigned flags, unsigned long val)
3282 /* Test for not equal */
3284 static char* ops [12] = {
3285 "tosne00", "tosnea0", "tosneax",
3286 "tosne00", "tosnea0", "tosneax",
3293 /* If the right hand side is const, the lhs is not on stack but still
3294 * in the primary register.
3296 if (flags & CF_CONST) {
3298 switch (flags & CF_TYPE) {
3301 if (flags & CF_FORCECHAR) {
3302 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3303 AddCodeLine ("jsr boolne");
3309 L = GetLocalLabel();
3310 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3311 AddCodeLine ("bne %s", LocalLabelName (L));
3312 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3314 AddCodeLine ("jsr boolne");
3324 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3325 * into the normal, non-optimized stuff.
3327 g_push (flags & ~CF_CONST, 0);
3331 /* Use long way over the stack */
3332 oper (flags, val, ops);
3337 void g_lt (unsigned flags, unsigned long val)
3338 /* Test for less than */
3340 static char* ops [12] = {
3341 "toslt00", "toslta0", "tosltax",
3342 "tosult00", "tosulta0", "tosultax",
3347 /* If the right hand side is const, the lhs is not on stack but still
3348 * in the primary register.
3350 if (flags & CF_CONST) {
3352 /* Give a warning in some special cases */
3353 if ((flags & CF_UNSIGNED) && val == 0) {
3354 Warning ("Condition is never true");
3357 /* Look at the type */
3358 switch (flags & CF_TYPE) {
3361 if (flags & CF_FORCECHAR) {
3362 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3363 if (flags & CF_UNSIGNED) {
3364 AddCodeLine ("jsr boolult");
3366 AddCodeLine ("jsr boollt");
3373 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3374 /* If we have a signed compare against zero, we only need to
3375 * test the high byte.
3377 AddCodeLine ("txa");
3378 AddCodeLine ("jsr boollt");
3381 /* Direct code only for unsigned data types */
3382 if (flags & CF_UNSIGNED) {
3383 unsigned L = GetLocalLabel();
3384 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3385 AddCodeLine ("bne %s", LocalLabelName (L));
3386 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3388 AddCodeLine ("jsr boolult");
3394 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3395 /* If we have a signed compare against zero, we only need to
3396 * test the high byte.
3398 AddCodeLine ("lda sreg+1");
3399 AddCodeLine ("jsr boollt");
3408 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3409 * into the normal, non-optimized stuff.
3411 g_push (flags & ~CF_CONST, 0);
3415 /* Use long way over the stack */
3416 oper (flags, val, ops);
3421 void g_le (unsigned flags, unsigned long val)
3422 /* Test for less than or equal to */
3424 static char* ops [12] = {
3425 "tosle00", "toslea0", "tosleax",
3426 "tosule00", "tosulea0", "tosuleax",
3432 /* If the right hand side is const, the lhs is not on stack but still
3433 * in the primary register.
3435 if (flags & CF_CONST) {
3437 /* Look at the type */
3438 switch (flags & CF_TYPE) {
3441 if (flags & CF_FORCECHAR) {
3442 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3443 if (flags & CF_UNSIGNED) {
3444 AddCodeLine ("jsr boolule");
3446 AddCodeLine ("jsr boolle");
3453 if (flags & CF_UNSIGNED) {
3454 unsigned L = GetLocalLabel();
3455 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3456 AddCodeLine ("bne %s", LocalLabelName (L));
3457 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3459 AddCodeLine ("jsr boolule");
3471 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3472 * into the normal, non-optimized stuff.
3474 g_push (flags & ~CF_CONST, 0);
3478 /* Use long way over the stack */
3479 oper (flags, val, ops);
3484 void g_gt (unsigned flags, unsigned long val)
3485 /* Test for greater than */
3487 static char* ops [12] = {
3488 "tosgt00", "tosgta0", "tosgtax",
3489 "tosugt00", "tosugta0", "tosugtax",
3495 /* If the right hand side is const, the lhs is not on stack but still
3496 * in the primary register.
3498 if (flags & CF_CONST) {
3500 /* Look at the type */
3501 switch (flags & CF_TYPE) {
3504 if (flags & CF_FORCECHAR) {
3505 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3506 if (flags & CF_UNSIGNED) {
3507 /* If we have a compare > 0, we will replace it by
3508 * != 0 here, since both are identical but the latter
3509 * is easier to optimize.
3512 AddCodeLine ("jsr boolugt");
3514 AddCodeLine ("jsr boolne");
3517 AddCodeLine ("jsr boolgt");
3524 if (flags & CF_UNSIGNED) {
3525 /* If we have a compare > 0, we will replace it by
3526 * != 0 here, since both are identical but the latter
3527 * is easier to optimize.
3529 if ((val & 0xFFFF) == 0) {
3530 AddCodeLine ("stx tmp1");
3531 AddCodeLine ("ora tmp1");
3532 AddCodeLine ("jsr boolne");
3534 unsigned L = GetLocalLabel();
3535 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3536 AddCodeLine ("bne %s", LocalLabelName (L));
3537 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3539 AddCodeLine ("jsr boolugt");
3552 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3553 * into the normal, non-optimized stuff.
3555 g_push (flags & ~CF_CONST, 0);
3559 /* Use long way over the stack */
3560 oper (flags, val, ops);
3565 void g_ge (unsigned flags, unsigned long val)
3566 /* Test for greater than or equal to */
3568 static char* ops [12] = {
3569 "tosge00", "tosgea0", "tosgeax",
3570 "tosuge00", "tosugea0", "tosugeax",
3576 /* If the right hand side is const, the lhs is not on stack but still
3577 * in the primary register.
3579 if (flags & CF_CONST) {
3581 /* Give a warning in some special cases */
3582 if ((flags & CF_UNSIGNED) && val == 0) {
3583 Warning ("Condition is always true");
3586 /* Look at the type */
3587 switch (flags & CF_TYPE) {
3590 if (flags & CF_FORCECHAR) {
3591 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3592 if (flags & CF_UNSIGNED) {
3593 AddCodeLine ("jsr booluge");
3595 AddCodeLine ("jsr boolge");
3602 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3603 /* If we have a signed compare against zero, we only need to
3604 * test the high byte.
3606 AddCodeLine ("txa");
3607 AddCodeLine ("jsr boolge");
3610 /* Direct code only for unsigned data types */
3611 if (flags & CF_UNSIGNED) {
3612 unsigned L = GetLocalLabel();
3613 AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
3614 AddCodeLine ("bne %s", LocalLabelName (L));
3615 AddCodeLine ("cmp #$%02X", (unsigned char)val);
3617 AddCodeLine ("jsr booluge");
3623 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3624 /* If we have a signed compare against zero, we only need to
3625 * test the high byte.
3627 AddCodeLine ("lda sreg+1");
3628 AddCodeLine ("jsr boolge");
3637 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3638 * into the normal, non-optimized stuff.
3640 g_push (flags & ~CF_CONST, 0);
3644 /* Use long way over the stack */
3645 oper (flags, val, ops);
3650 /*****************************************************************************/
3651 /* Allocating static storage */
3652 /*****************************************************************************/
3656 void g_res (unsigned n)
3657 /* Reserve static storage, n bytes */
3659 AddDataLine ("\t.res\t%u,$00", n);
3664 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3665 /* Define data with the size given in flags */
3667 if (flags & CF_CONST) {
3669 /* Numeric constant */
3670 switch (flags & CF_TYPE) {
3673 AddDataLine ("\t.byte\t$%02lX", val & 0xFF);
3677 AddDataLine ("\t.word\t$%04lX", val & 0xFFFF);
3681 AddDataLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
3692 /* Create the correct label name */
3693 const char* Label = GetLabelName (flags, val, offs);
3695 /* Labels are always 16 bit */
3696 AddDataLine ("\t.word\t%s", Label);
3703 void g_defbytes (const void* Bytes, unsigned Count)
3704 /* Output a row of bytes as a constant */
3710 /* Cast the buffer pointer */
3711 const unsigned char* Data = (const unsigned char*) Bytes;
3713 /* Output the stuff */
3716 /* How many go into this line? */
3717 if ((Chunk = Count) > 16) {
3722 /* Output one line */
3723 strcpy (Buf, "\t.byte\t");
3726 B += sprintf (B, "$%02X", *Data++);
3732 /* Output the line */
3739 void g_zerobytes (unsigned n)
3740 /* Output n bytes of data initialized with zero */
3742 AddDataLine ("\t.res\t%u,$00", n);
3747 /*****************************************************************************/
3748 /* User supplied assembler code */
3749 /*****************************************************************************/
3753 void g_asmcode (const char* Line, int Len)
3754 /* Output one line of assembler code. If Len is greater than zero, it is used
3755 * as the maximum number of characters to use from Line.
3759 AddCodeLine ("%.*s", Len, Line);
3761 AddCodeLine ("%s", Line);
3767 /*****************************************************************************/
3768 /* Inlined known functions */
3769 /*****************************************************************************/
3773 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3774 /* Inline the strlen() function */
3776 /* We need a label in both cases */
3777 unsigned label = GetLocalLabel ();
3779 /* Two different encodings */
3780 if (flags & CF_CONST) {
3782 /* The address of the string is constant. Create the correct label name */
3783 char* lbuf = GetLabelName (flags, val, offs);
3785 /* Generate the strlen code */
3786 AddCodeLine ("ldy #$FF");
3787 g_defcodelabel (label);
3788 AddCodeLine ("iny");
3789 AddCodeLine ("lda %s,y", lbuf);
3790 AddCodeLine ("bne %s", LocalLabelName (label));
3791 AddCodeLine ("tax");
3792 AddCodeLine ("tya");
3796 /* Address not constant but in primary */
3797 if (CodeSizeFactor < 400) {
3798 /* This is too much code, so call strlen instead of inlining */
3799 AddCodeLine ("jsr _strlen");
3801 /* Inline the function */
3802 AddCodeLine ("sta ptr1");
3803 AddCodeLine ("stx ptr1+1");
3804 AddCodeLine ("ldy #$FF");
3805 g_defcodelabel (label);
3806 AddCodeLine ("iny");
3807 AddCodeLine ("lda (ptr1),y");
3808 AddCodeLine ("bne %s", LocalLabelName (label));
3809 AddCodeLine ("tax");
3810 AddCodeLine ("tya");