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 */
70 segment_t CurSeg = SEG_INV;
74 /*****************************************************************************/
76 /*****************************************************************************/
80 static void typeerror (unsigned type)
81 /* Print an error message about an invalid operand type */
83 Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPE);
88 static void CheckLocalOffs (unsigned Offs)
89 /* Check the offset into the stack for 8bit range */
92 /* Too many local vars */
93 Error ("Too many local variables");
99 static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs)
101 static char lbuf [128]; /* Label name */
103 /* Create the correct label name */
104 switch (flags & CF_ADDRMASK) {
107 /* Static memory cell */
108 sprintf (lbuf, "%s+%u", LocalLabelName (label), offs);
113 sprintf (lbuf, "_%s+%u", (char*) label, offs);
117 /* Absolute address */
118 sprintf (lbuf, "$%04X", (unsigned)((label+offs) & 0xFFFF));
122 /* Variable in register bank */
123 sprintf (lbuf, "regbank+%u", (unsigned)((label+offs) & 0xFFFF));
127 Internal ("Invalid address flags");
130 /* Return a pointer to the static buffer */
136 /*****************************************************************************/
137 /* Pre- and postamble */
138 /*****************************************************************************/
142 void g_preamble (void)
143 /* Generate the assembler code preamble */
145 /* Generate the global segments and push them */
146 PushCodeSeg (NewCodeSeg (SegmentNames[SEG_CODE], ""));
147 PushDataSeg (NewDataSeg (""));
149 /* Identify the compiler version */
150 AddDataSegLine (DS, "; File generated by cc65 v %u.%u.%u",
151 VER_MAJOR, VER_MINOR, VER_PATCH);
153 /* Insert some object file options */
154 AddDataSegLine (DS, ".fopt\t\tcompiler,\"cc65 v %u.%u.%u\"",
155 VER_MAJOR, VER_MINOR, VER_PATCH);
157 /* If we're producing code for some other CPU, switch the command set */
158 if (CPU == CPU_65C02) {
159 AddDataSegLine (DS, ".pc02");
162 /* Allow auto import for runtime library routines */
163 AddDataSegLine (DS, ".autoimport\ton");
165 /* Switch the assembler into case sensitive mode */
166 AddDataSegLine (DS, ".case\t\ton");
168 /* Tell the assembler if we want to generate debug info */
169 AddDataSegLine (DS, ".debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
171 /* Import the stack pointer for direct auto variable access */
172 AddDataSegLine (DS, ".importzp\tsp, sreg, regsave, regbank, tmp1, ptr1");
174 /* Define long branch macros */
175 AddDataSegLine (DS, ".macpack\tlongbranch");
180 /*****************************************************************************/
181 /* Segment support */
182 /*****************************************************************************/
186 static void UseSeg (int NewSeg)
187 /* Switch to a specific segment */
189 if (CurSeg != NewSeg) {
190 CurSeg = (segment_t) NewSeg;
191 if (CurSeg != SEG_CODE) {
192 AddDataSegLine (DS, ".segment\t\"%s\"", SegmentNames [CurSeg]);
199 void g_pushseg (struct CodeSeg** FCS, struct DataSeg** FDS, const char* FuncName)
200 /* Push the current segments and generate new ones for the given function */
202 PushCodeSeg (NewCodeSeg (SegmentNames[SEG_CODE], FuncName));
204 PushDataSeg (NewDataSeg (FuncName));
211 /* Restore the old segments */
219 void g_userodata (void)
220 /* Switch to the read only data segment */
227 void g_usedata (void)
228 /* Switch to the data segment */
236 /* Switch to the bss segment */
243 static void SegName (segment_t Seg, const char* Name)
244 /* Set the name of a segment */
246 /* Free the old name and set a new one */
247 NewSegName (Seg, Name);
249 /* If the new segment is the current segment, emit a segment directive
253 CurSeg = SEG_INV; /* Invalidate */
260 void g_codename (const char* Name)
261 /* Set the name of the CODE segment */
263 SegName (SEG_CODE, Name);
268 void g_rodataname (const char* Name)
269 /* Set the name of the RODATA segment */
271 SegName (SEG_RODATA, Name);
276 void g_dataname (const char* Name)
277 /* Set the name of the DATA segment */
279 SegName (SEG_DATA, Name);
284 void g_bssname (const char* Name)
285 /* Set the name of the BSS segment */
287 SegName (SEG_BSS, Name);
292 /*****************************************************************************/
294 /*****************************************************************************/
298 unsigned sizeofarg (unsigned flags)
299 /* Return the size of a function argument type that is encoded in flags */
301 switch (flags & CF_TYPE) {
304 return (flags & CF_FORCECHAR)? 1 : 2;
321 int pop (unsigned flags)
322 /* Pop an argument of the given size */
324 return oursp += sizeofarg (flags);
329 int push (unsigned flags)
330 /* Push an argument of the given size */
332 return oursp -= sizeofarg (flags);
337 static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
338 /* The value in Offs is an offset to an address in a/x. Make sure, an object
339 * of the type given in Flags can be loaded or stored into this address by
340 * adding part of the offset to the address in ax, so that the remaining
341 * offset fits into an index register. Return the remaining offset.
344 /* If the offset is too large for a byte register, add the high byte
345 * of the offset to the primary. Beware: We need a special correction
346 * if the offset in the low byte will overflow in the operation.
348 unsigned O = Offs & ~0xFFU;
349 if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
350 /* We need to add the low byte also */
354 /* Do the correction if we need one */
356 g_inc (CF_INT | CF_CONST, O);
360 /* Return the new offset */
366 /*****************************************************************************/
367 /* Functions handling local labels */
368 /*****************************************************************************/
372 void g_defcodelabel (unsigned label)
373 /* Define a local code label */
375 AddCodeLabel (CS, LocalLabelName (label));
380 void g_defdatalabel (unsigned label)
381 /* Define a local data label */
383 AddDataSegLine (DS, "%s:", LocalLabelName (label));
388 /*****************************************************************************/
389 /* Functions handling global labels */
390 /*****************************************************************************/
394 void g_defgloblabel (const char* Name)
395 /* Define a global label with the given name */
397 /* Global labels are always data labels */
398 AddDataSegLine (DS, "_%s:", Name);
403 void g_defexport (const char* Name, int ZP)
404 /* Export the given label */
407 AddDataSegLine (DS, "\t.exportzp\t_%s", Name);
409 AddDataSegLine (DS, "\t.export\t\t_%s", Name);
415 void g_defimport (const char* Name, int ZP)
416 /* Import the given label */
419 AddDataSegLine (DS, "\t.importzp\t_%s", Name);
421 AddDataSegLine (DS, "\t.import\t\t_%s", Name);
427 /*****************************************************************************/
428 /* Load functions for various registers */
429 /*****************************************************************************/
433 static void ldaconst (unsigned val)
434 /* Load a with a constant */
436 AddCodeSegLine (CS, "lda #$%02X", val & 0xFF);
441 static void ldxconst (unsigned val)
442 /* Load x with a constant */
444 AddCodeSegLine (CS, "ldx #$%02X", val & 0xFF);
449 static void ldyconst (unsigned val)
450 /* Load y with a constant */
452 AddCodeSegLine (CS, "ldy #$%02X", val & 0xFF);
457 /*****************************************************************************/
458 /* Function entry and exit */
459 /*****************************************************************************/
463 /* Remember the argument size of a function. The variable is set by g_enter
464 * and used by g_leave. If the functions gets its argument size by the caller
465 * (variable param list or function without prototype), g_enter will set the
471 void g_enter (unsigned flags, unsigned argsize)
472 /* Function prologue */
474 if ((flags & CF_FIXARGC) != 0) {
475 /* Just remember the argument size for the leave */
479 AddCodeSegLine (CS, "jsr enter");
485 void g_leave (int flags, int val)
486 /* Function epilogue */
491 /* CF_REG is set if we're returning a value from the function */
492 if ((flags & CF_REG) == 0) {
497 /* How many bytes of locals do we have to drop? */
500 /* If we didn't have a variable argument list, don't call leave */
503 /* Load a function return code if needed */
504 if ((flags & CF_CONST) != 0) {
505 g_getimmed (flags, val, 0);
508 /* Drop stackframe or leave with rts */
511 AddCodeHint ("y:-"); /* Y register no longer used */
512 AddCodeSegLine (CS, "rts");
514 AddCodeHint ("y:-"); /* Y register no longer used */
515 AddCodeSegLine (CS, "jmp incsp%d", k);
519 AddCodeSegLine (CS, "jmp addysp");
524 strcpy (buf, "\tjmp\tleave");
526 /* We've a stack frame to drop */
530 /* Y register no longer used */
533 if (flags & CF_CONST) {
534 if ((flags & CF_TYPE) != CF_LONG) {
535 /* Constant int sized value given for return code */
537 /* Special case: return 0 */
539 } else if (((val >> 8) & 0xFF) == 0) {
540 /* Special case: constant with high byte zero */
541 ldaconst (val); /* Load low byte */
544 /* Others: arbitrary constant value */
545 g_getimmed (flags, val, 0); /* Load value */
548 /* Constant long value: No shortcut possible */
549 g_getimmed (flags, val, 0);
553 /* Output the jump */
554 AddCodeSegLine (CS, buf);
560 /*****************************************************************************/
561 /* Register variables */
562 /*****************************************************************************/
566 void g_save_regvars (int RegOffs, unsigned Bytes)
567 /* Save register variables */
569 /* Don't loop for up to two bytes */
572 AddCodeSegLine (CS, "lda regbank%+d", RegOffs);
573 AddCodeSegLine (CS, "jsr pusha");
575 } else if (Bytes == 2) {
577 AddCodeSegLine (CS, "lda regbank%+d", RegOffs);
578 AddCodeSegLine (CS, "ldx regbank%+d", RegOffs+1);
579 AddCodeSegLine (CS, "jsr pushax");
583 /* More than two bytes - loop */
584 unsigned Label = GetLocalLabel ();
586 ldyconst (Bytes - 1);
588 g_defcodelabel (Label);
589 AddCodeSegLine (CS, "lda regbank%+d,x", RegOffs-1);
590 AddCodeSegLine (CS, "sta (sp),y");
591 AddCodeSegLine (CS, "dey");
592 AddCodeSegLine (CS, "dex");
593 AddCodeSegLine (CS, "bne %s", LocalLabelName (Label));
597 /* We pushed stuff, correct the stack pointer */
603 void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
604 /* Restore register variables */
606 /* Calculate the actual stack offset and check it */
608 CheckLocalOffs (StackOffs);
610 /* Don't loop for up to two bytes */
613 ldyconst (StackOffs);
614 AddCodeSegLine (CS, "lda (sp),y");
615 AddCodeSegLine (CS, "sta regbank%+d", RegOffs);
617 } else if (Bytes == 2) {
619 ldyconst (StackOffs);
620 AddCodeSegLine (CS, "lda (sp),y");
621 AddCodeSegLine (CS, "sta regbank%+d", RegOffs);
622 AddCodeSegLine (CS, "iny");
623 AddCodeSegLine (CS, "lda (sp),y");
624 AddCodeSegLine (CS, "sta regbank%+d", RegOffs+1);
628 /* More than two bytes - loop */
629 unsigned Label = GetLocalLabel ();
630 ldyconst (StackOffs+Bytes-1);
632 g_defcodelabel (Label);
633 AddCodeSegLine (CS, "lda (sp),y");
634 AddCodeSegLine (CS, "sta regbank%+d,x", RegOffs-1);
635 AddCodeSegLine (CS, "dey");
636 AddCodeSegLine (CS, "dex");
637 AddCodeSegLine (CS, "bne %s", LocalLabelName (Label));
644 /*****************************************************************************/
645 /* Fetching memory cells */
646 /*****************************************************************************/
650 void g_getimmed (unsigned flags, unsigned long val, unsigned offs)
651 /* Load a constant into the primary register */
653 if ((flags & CF_CONST) != 0) {
655 /* Numeric constant */
656 switch (flags & CF_TYPE) {
659 if ((flags & CF_FORCECHAR) != 0) {
665 ldxconst ((val >> 8) & 0xFF);
666 ldaconst (val & 0xFF);
671 AddCodeSegLine (CS, "ldx #$00");
672 AddCodeSegLine (CS, "stx sreg+1");
673 AddCodeSegLine (CS, "stx sreg");
674 AddCodeSegLine (CS, "lda #$%02X", (unsigned char) val);
675 } else if ((val & 0xFFFF00FF) == 0) {
676 AddCodeSegLine (CS, "lda #$00");
677 AddCodeSegLine (CS, "sta sreg+1");
678 AddCodeSegLine (CS, "sta sreg");
679 AddCodeSegLine (CS, "ldx #$%02X", (unsigned char) (val >> 8));
680 } else if ((val & 0xFFFF0000) == 0 && CodeSizeFactor > 140) {
681 AddCodeSegLine (CS, "lda #$00");
682 AddCodeSegLine (CS, "sta sreg+1");
683 AddCodeSegLine (CS, "sta sreg");
684 AddCodeSegLine (CS, "lda #$%02X", (unsigned char) val);
685 AddCodeSegLine (CS, "ldx #$%02X", (unsigned char) (val >> 8));
686 } else if ((val & 0xFFFFFF00) == 0xFFFFFF00) {
687 AddCodeSegLine (CS, "ldx #$FF");
688 AddCodeSegLine (CS, "stx sreg+1");
689 AddCodeSegLine (CS, "stx sreg");
690 if ((val & 0xFF) == 0xFF) {
691 AddCodeSegLine (CS, "txa");
693 AddCodeSegLine (CS, "lda #$%02X", (unsigned char) val);
695 } else if ((val & 0xFFFF00FF) == 0xFFFF00FF) {
696 AddCodeSegLine (CS, "lda #$FF");
697 AddCodeSegLine (CS, "sta sreg+1");
698 AddCodeSegLine (CS, "sta sreg");
699 AddCodeSegLine (CS, "ldx #$%02X", (unsigned char) (val >> 8));
701 /* Call a subroutine that will load following value */
702 AddCodeSegLine (CS, "jsr ldeax");
703 AddCodeSegLine (CS, ".dword $%08lX", val & 0xFFFFFFFF);
715 /* Some sort of label */
716 const char* Label = GetLabelName (flags, val, offs);
718 /* Load the address into the primary */
719 AddCodeSegLine (CS, "lda #<(%s)", Label);
720 AddCodeSegLine (CS, "ldx #>(%s)", Label);
727 void g_getstatic (unsigned flags, unsigned long label, unsigned offs)
728 /* Fetch an static memory cell into the primary register */
730 /* Create the correct label name */
731 char* lbuf = GetLabelName (flags, label, offs);
733 /* Check the size and generate the correct load operation */
734 switch (flags & CF_TYPE) {
737 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
738 AddCodeSegLine (CS, "lda %s", lbuf); /* load A from the label */
741 AddCodeSegLine (CS, "lda %s", lbuf); /* load A from the label */
742 if (!(flags & CF_UNSIGNED)) {
743 /* Must sign extend */
744 AddCodeSegLine (CS, "bpl *+3");
745 AddCodeSegLine (CS, "dex");
746 AddCodeHint ("x:!"); /* X is invalid now */
752 AddCodeSegLine (CS, "lda %s", lbuf);
753 if (flags & CF_TEST) {
754 AddCodeSegLine (CS, "ora %s+1", lbuf);
756 AddCodeSegLine (CS, "ldx %s+1", lbuf);
761 if (flags & CF_TEST) {
762 AddCodeSegLine (CS, "lda %s+3", lbuf);
763 AddCodeSegLine (CS, "ora %s+2", lbuf);
764 AddCodeSegLine (CS, "ora %s+1", lbuf);
765 AddCodeSegLine (CS, "ora %s+0", lbuf);
767 AddCodeSegLine (CS, "lda %s+3", lbuf);
768 AddCodeSegLine (CS, "sta sreg+1");
769 AddCodeSegLine (CS, "lda %s+2", lbuf);
770 AddCodeSegLine (CS, "sta sreg");
771 AddCodeSegLine (CS, "ldx %s+1", lbuf);
772 AddCodeSegLine (CS, "lda %s", lbuf);
784 void g_getlocal (unsigned flags, int offs)
785 /* Fetch specified local object (local var). */
788 CheckLocalOffs (offs);
789 switch (flags & CF_TYPE) {
792 if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
793 if (CPU == CPU_65C02 && offs == 0) {
794 AddCodeSegLine (CS, "lda (sp)");
797 AddCodeSegLine (CS, "lda (sp),y");
801 AddCodeSegLine (CS, "ldx #$00");
802 AddCodeSegLine (CS, "lda (sp,x)");
805 AddCodeSegLine (CS, "ldx #$00");
806 AddCodeSegLine (CS, "lda (sp),y");
808 if ((flags & CF_UNSIGNED) == 0) {
809 AddCodeSegLine (CS, "bpl *+3");
810 AddCodeSegLine (CS, "dex");
811 AddCodeHint ("x:!"); /* X is invalid now */
817 CheckLocalOffs (offs + 1);
818 if (flags & CF_TEST) {
820 AddCodeSegLine (CS, "lda (sp),y");
821 AddCodeSegLine (CS, "dey");
822 AddCodeSegLine (CS, "ora (sp),y");
824 if (CodeSizeFactor > 180) {
826 AddCodeSegLine (CS, "lda (sp),y");
827 AddCodeSegLine (CS, "tax");
828 AddCodeSegLine (CS, "dey");
829 AddCodeSegLine (CS, "lda (sp),y");
833 AddCodeSegLine (CS, "jsr ldaxysp");
835 AddCodeSegLine (CS, "jsr ldax0sp");
844 AddCodeSegLine (CS, "jsr ldeaxysp");
846 AddCodeSegLine (CS, "jsr ldeax0sp");
857 void g_getind (unsigned flags, unsigned offs)
858 /* Fetch the specified object type indirect through the primary register
859 * into the primary register
862 /* If the offset is greater than 255, add the part that is > 255 to
863 * the primary. This way we get an easy addition and use the low byte
866 offs = MakeByteOffs (flags, offs);
868 /* Handle the indirect fetch */
869 switch (flags & CF_TYPE) {
872 /* Character sized */
875 if (flags & CF_UNSIGNED) {
876 AddCodeSegLine (CS, "jsr ldauidx");
878 AddCodeSegLine (CS, "jsr ldaidx");
881 if (flags & CF_UNSIGNED) {
882 if (CodeSizeFactor > 250) {
883 AddCodeSegLine (CS, "sta ptr1");
884 AddCodeSegLine (CS, "stx ptr1+1");
885 AddCodeSegLine (CS, "ldx #$00");
886 AddCodeSegLine (CS, "lda (ptr1,x)");
888 AddCodeSegLine (CS, "jsr ldaui");
891 AddCodeSegLine (CS, "jsr ldai");
897 if (flags & CF_TEST) {
899 AddCodeSegLine (CS, "sta ptr1");
900 AddCodeSegLine (CS, "stx ptr1+1");
901 AddCodeSegLine (CS, "lda (ptr1),y");
902 AddCodeSegLine (CS, "iny");
903 AddCodeSegLine (CS, "ora (ptr1),y");
906 AddCodeSegLine (CS, "jsr ldaxi");
909 AddCodeSegLine (CS, "jsr ldaxidx");
916 AddCodeSegLine (CS, "jsr ldeaxi");
919 AddCodeSegLine (CS, "jsr ldeaxidx");
921 if (flags & CF_TEST) {
922 AddCodeSegLine (CS, "jsr tsteax");
934 void g_leasp (int offs)
935 /* Fetch the address of the specified symbol into the primary register */
937 /* Calculate the offset relative to sp */
940 /* For value 0 we do direct code */
942 AddCodeSegLine (CS, "lda sp");
943 AddCodeSegLine (CS, "ldx sp+1");
945 if (CodeSizeFactor < 300) {
946 ldaconst (offs); /* Load A with offset value */
947 AddCodeSegLine (CS, "jsr leaasp"); /* Load effective address */
949 if (CPU == CPU_65C02 && offs == 1) {
950 AddCodeSegLine (CS, "lda sp");
951 AddCodeSegLine (CS, "ldx sp+1");
952 AddCodeSegLine (CS, "ina");
953 AddCodeSegLine (CS, "bne *+3");
954 AddCodeSegLine (CS, "inx");
955 AddCodeHint ("x:!"); /* Invalidate X */
958 AddCodeSegLine (CS, "clc");
959 AddCodeSegLine (CS, "ldx sp+1");
960 AddCodeSegLine (CS, "adc sp");
961 AddCodeSegLine (CS, "bcc *+3");
962 AddCodeSegLine (CS, "inx");
963 AddCodeHint ("x:!"); /* Invalidate X */
971 void g_leavariadic (int Offs)
972 /* Fetch the address of a parameter in a variadic function into the primary
976 unsigned ArgSizeOffs;
978 /* Calculate the offset relative to sp */
981 /* Get the offset of the parameter which is stored at sp+0 on function
982 * entry and check if this offset is reachable with a byte offset.
985 ArgSizeOffs = -oursp;
986 CheckLocalOffs (ArgSizeOffs);
988 /* Get the size of all parameters. */
989 if (ArgSizeOffs == 0 && CPU == CPU_65C02) {
990 AddCodeSegLine (CS, "lda (sp)");
992 ldyconst (ArgSizeOffs);
993 AddCodeSegLine (CS, "lda (sp),y");
996 /* Add the value of the stackpointer */
997 if (CodeSizeFactor > 250) {
998 AddCodeSegLine (CS, "ldx sp+1");
999 AddCodeSegLine (CS, "clc");
1000 AddCodeSegLine (CS, "adc sp");
1001 AddCodeSegLine (CS, "bcc *+3");
1002 AddCodeSegLine (CS, "inx");
1003 AddCodeHint ("x:!"); /* Invalidate X */
1005 AddCodeSegLine (CS, "jsr leaasp");
1008 /* Add the offset to the primary */
1010 g_inc (CF_INT | CF_CONST, Offs);
1011 } else if (Offs < 0) {
1012 g_dec (CF_INT | CF_CONST, -Offs);
1018 /*****************************************************************************/
1019 /* Store into memory */
1020 /*****************************************************************************/
1024 void g_putstatic (unsigned flags, unsigned long label, unsigned offs)
1025 /* Store the primary register into the specified static memory cell */
1027 /* Create the correct label name */
1028 char* lbuf = GetLabelName (flags, label, offs);
1030 /* Check the size and generate the correct store operation */
1031 switch (flags & CF_TYPE) {
1034 AddCodeSegLine (CS, "sta %s", lbuf);
1038 AddCodeSegLine (CS, "sta %s", lbuf);
1039 AddCodeSegLine (CS, "stx %s+1", lbuf);
1043 AddCodeSegLine (CS, "sta %s", lbuf);
1044 AddCodeSegLine (CS, "stx %s+1", lbuf);
1045 AddCodeSegLine (CS, "ldy sreg");
1046 AddCodeSegLine (CS, "sty %s+2", lbuf);
1047 AddCodeSegLine (CS, "ldy sreg+1");
1048 AddCodeSegLine (CS, "sty %s+3", lbuf);
1059 void g_putlocal (unsigned Flags, int Offs, long Val)
1060 /* Put data into local object. */
1063 CheckLocalOffs (Offs);
1064 switch (Flags & CF_TYPE) {
1067 if (Flags & CF_CONST) {
1068 AddCodeSegLine (CS, "lda #$%02X", (unsigned char) Val);
1070 if (CPU == CPU_65C02 && Offs == 0) {
1071 AddCodeSegLine (CS, "sta (sp)");
1074 AddCodeSegLine (CS, "sta (sp),y");
1079 if (Flags & CF_CONST) {
1081 AddCodeSegLine (CS, "lda #$%02X", (unsigned char) (Val >> 8));
1082 AddCodeSegLine (CS, "sta (sp),y");
1083 if ((Flags & CF_NOKEEP) == 0) {
1084 /* Place high byte into X */
1085 AddCodeSegLine (CS, "tax");
1087 if (CPU == CPU_65C02 && Offs == 0) {
1088 AddCodeSegLine (CS, "lda #$%02X", (unsigned char) Val);
1089 AddCodeSegLine (CS, "sta (sp)");
1091 if ((Val & 0xFF) == Offs+1) {
1092 /* The value we need is already in Y */
1093 AddCodeSegLine (CS, "tya");
1094 AddCodeSegLine (CS, "dey");
1096 AddCodeSegLine (CS, "dey");
1097 AddCodeSegLine (CS, "lda #$%02X", (unsigned char) Val);
1099 AddCodeSegLine (CS, "sta (sp),y");
1102 if ((Flags & CF_NOKEEP) == 0 || CodeSizeFactor < 160) {
1105 AddCodeSegLine (CS, "jsr staxysp");
1107 AddCodeSegLine (CS, "jsr stax0sp");
1110 if (CPU == CPU_65C02 && Offs == 0) {
1111 AddCodeSegLine (CS, "sta (sp)");
1113 AddCodeSegLine (CS, "txa");
1114 AddCodeSegLine (CS, "sta (sp),y");
1117 AddCodeSegLine (CS, "sta (sp),y");
1118 AddCodeSegLine (CS, "iny");
1119 AddCodeSegLine (CS, "txa");
1120 AddCodeSegLine (CS, "sta (sp),y");
1127 if (Flags & CF_CONST) {
1128 g_getimmed (Flags, Val, 0);
1132 AddCodeSegLine (CS, "jsr steaxysp");
1134 AddCodeSegLine (CS, "jsr steax0sp");
1146 void g_putind (unsigned Flags, unsigned Offs)
1147 /* Store the specified object type in the primary register at the address
1148 * on the top of the stack
1151 /* We can handle offsets below $100 directly, larger offsets must be added
1152 * to the address. Since a/x is in use, best code is achieved by adding
1153 * just the high byte. Be sure to check if the low byte will overflow while
1156 if ((Offs & 0xFF) > 256 - sizeofarg (Flags | CF_FORCECHAR)) {
1158 /* Overflow - we need to add the low byte also */
1159 AddCodeSegLine (CS, "ldy #$00");
1160 AddCodeSegLine (CS, "clc");
1161 AddCodeSegLine (CS, "pha");
1162 AddCodeSegLine (CS, "lda #$%02X", Offs & 0xFF);
1163 AddCodeSegLine (CS, "adc (sp),y");
1164 AddCodeSegLine (CS, "sta (sp),y");
1165 AddCodeSegLine (CS, "iny");
1166 AddCodeSegLine (CS, "lda #$%02X", (Offs >> 8) & 0xFF);
1167 AddCodeSegLine (CS, "adc (sp),y");
1168 AddCodeSegLine (CS, "sta (sp),y");
1169 AddCodeSegLine (CS, "pla");
1171 /* Complete address is on stack, new offset is zero */
1174 } else if ((Offs & 0xFF00) != 0) {
1176 /* We can just add the high byte */
1177 AddCodeSegLine (CS, "ldy #$01");
1178 AddCodeSegLine (CS, "clc");
1179 AddCodeSegLine (CS, "pha");
1180 AddCodeSegLine (CS, "lda #$%02X", (Offs >> 8) & 0xFF);
1181 AddCodeSegLine (CS, "adc (sp),y");
1182 AddCodeSegLine (CS, "sta (sp),y");
1183 AddCodeSegLine (CS, "pla");
1185 /* Offset is now just the low byte */
1189 /* Check the size and determine operation */
1190 switch (Flags & CF_TYPE) {
1195 AddCodeSegLine (CS, "jsr staspidx");
1197 AddCodeSegLine (CS, "jsr staspp");
1204 AddCodeSegLine (CS, "jsr staxspidx");
1206 AddCodeSegLine (CS, "jsr staxspp");
1213 AddCodeSegLine (CS, "jsr steaxspidx");
1215 AddCodeSegLine (CS, "jsr steaxspp");
1224 /* Pop the argument which is always a pointer */
1230 /*****************************************************************************/
1231 /* type conversion and similiar stuff */
1232 /*****************************************************************************/
1236 void g_toslong (unsigned flags)
1237 /* Make sure, the value on TOS is a long. Convert if necessary */
1239 switch (flags & CF_TYPE) {
1243 if (flags & CF_UNSIGNED) {
1244 AddCodeSegLine (CS, "jsr tosulong");
1246 AddCodeSegLine (CS, "jsr toslong");
1261 void g_tosint (unsigned flags)
1262 /* Make sure, the value on TOS is an int. Convert if necessary */
1264 switch (flags & CF_TYPE) {
1271 AddCodeSegLine (CS, "jsr tosint");
1282 void g_reglong (unsigned flags)
1283 /* Make sure, the value in the primary register a long. Convert if necessary */
1285 switch (flags & CF_TYPE) {
1289 if (flags & CF_UNSIGNED) {
1290 if (CodeSizeFactor >= 200) {
1292 AddCodeSegLine (CS, "sty sreg");
1293 AddCodeSegLine (CS, "sty sreg+1");
1295 AddCodeSegLine (CS, "jsr axulong");
1298 AddCodeSegLine (CS, "jsr axlong");
1312 unsigned g_typeadjust (unsigned lhs, unsigned rhs)
1313 /* Adjust the integer operands before doing a binary operation. lhs is a flags
1314 * value, that corresponds to the value on TOS, rhs corresponds to the value
1315 * in (e)ax. The return value is the the flags value for the resulting type.
1318 unsigned ltype, rtype;
1321 /* Get the type spec from the flags */
1322 ltype = lhs & CF_TYPE;
1323 rtype = rhs & CF_TYPE;
1325 /* Check if a conversion is needed */
1326 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1327 /* We must promote the primary register to long */
1329 /* Get the new rhs type */
1330 rhs = (rhs & ~CF_TYPE) | CF_LONG;
1332 } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
1333 /* We must promote the lhs to long */
1339 /* Get the new rhs type */
1340 lhs = (lhs & ~CF_TYPE) | CF_LONG;
1344 /* Determine the result type for the operation:
1345 * - The result is const if both operands are const.
1346 * - The result is unsigned if one of the operands is unsigned.
1347 * - The result is long if one of the operands is long.
1348 * - Otherwise the result is int sized.
1350 result = (lhs & CF_CONST) & (rhs & CF_CONST);
1351 result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
1352 if (rtype == CF_LONG || ltype == CF_LONG) {
1362 unsigned g_typecast (unsigned lhs, unsigned rhs)
1363 /* Cast the value in the primary register to the operand size that is flagged
1364 * by the lhs value. Return the result value.
1367 unsigned ltype, rtype;
1369 /* Get the type spec from the flags */
1370 ltype = lhs & CF_TYPE;
1371 rtype = rhs & CF_TYPE;
1373 /* Check if a conversion is needed */
1374 if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
1375 /* We must promote the primary register to long */
1379 /* Do not need any other action. If the left type is int, and the primary
1380 * register is long, it will be automagically truncated. If the right hand
1381 * side is const, it is not located in the primary register and handled by
1382 * the expression parser code.
1385 /* Result is const if the right hand side was const */
1386 lhs |= (rhs & CF_CONST);
1388 /* The resulting type is that of the left hand side (that's why you called
1396 void g_scale (unsigned flags, long val)
1397 /* Scale the value in the primary register by the given value. If val is positive,
1398 * scale up, is val is negative, scale down. This function is used to scale
1399 * the operands or results of pointer arithmetic by the size of the type, the
1400 * pointer points to.
1405 /* Value may not be zero */
1407 Internal ("Data type has no size");
1408 } else if (val > 0) {
1411 if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1413 /* Factor is 2, 4 or 8, use special function */
1414 switch (flags & CF_TYPE) {
1417 if (flags & CF_FORCECHAR) {
1419 AddCodeSegLine (CS, "asl a");
1426 if (CodeSizeFactor >= (p2+1)*130U) {
1427 AddCodeSegLine (CS, "stx tmp1");
1429 AddCodeSegLine (CS, "asl a");
1430 AddCodeSegLine (CS, "rol tmp1");
1432 AddCodeSegLine (CS, "ldx tmp1");
1434 if (flags & CF_UNSIGNED) {
1435 AddCodeSegLine (CS, "jsr shlax%d", p2);
1437 AddCodeSegLine (CS, "jsr aslax%d", p2);
1443 if (flags & CF_UNSIGNED) {
1444 AddCodeSegLine (CS, "jsr shleax%d", p2);
1446 AddCodeSegLine (CS, "jsr asleax%d", p2);
1455 } else if (val != 1) {
1457 /* Use a multiplication instead */
1458 g_mul (flags | CF_CONST, val);
1466 if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
1468 /* Factor is 2, 4 or 8, use special function */
1469 switch (flags & CF_TYPE) {
1472 if (flags & CF_FORCECHAR) {
1473 if (flags & CF_UNSIGNED) {
1475 AddCodeSegLine (CS, "lsr a");
1478 } else if (p2 <= 2) {
1479 AddCodeSegLine (CS, "cmp #$80");
1480 AddCodeSegLine (CS, "ror a");
1487 if (flags & CF_UNSIGNED) {
1488 if (CodeSizeFactor >= (p2+1)*130U) {
1489 AddCodeSegLine (CS, "stx tmp1");
1491 AddCodeSegLine (CS, "lsr tmp1");
1492 AddCodeSegLine (CS, "ror a");
1494 AddCodeSegLine (CS, "ldx tmp1");
1496 AddCodeSegLine (CS, "jsr lsrax%d", p2);
1499 if (CodeSizeFactor >= (p2+1)*150U) {
1500 AddCodeSegLine (CS, "stx tmp1");
1502 AddCodeSegLine (CS, "cpx #$80");
1503 AddCodeSegLine (CS, "ror tmp1");
1504 AddCodeSegLine (CS, "ror a");
1506 AddCodeSegLine (CS, "ldx tmp1");
1508 AddCodeSegLine (CS, "jsr asrax%d", p2);
1514 if (flags & CF_UNSIGNED) {
1515 AddCodeSegLine (CS, "jsr lsreax%d", p2);
1517 AddCodeSegLine (CS, "jsr asreax%d", p2);
1526 } else if (val != 1) {
1528 /* Use a division instead */
1529 g_div (flags | CF_CONST, val);
1537 /*****************************************************************************/
1538 /* Adds and subs of variables fix a fixed address */
1539 /*****************************************************************************/
1543 void g_addlocal (unsigned flags, int offs)
1544 /* Add a local variable to ax */
1546 /* Correct the offset and check it */
1548 CheckLocalOffs (offs);
1550 switch (flags & CF_TYPE) {
1553 AddCodeSegLine (CS, "ldy #$%02X", offs & 0xFF);
1554 AddCodeSegLine (CS, "clc");
1555 AddCodeSegLine (CS, "adc (sp),y");
1556 AddCodeSegLine (CS, "bcc *+3");
1557 AddCodeSegLine (CS, "inx");
1558 AddCodeHint ("x:!");
1562 AddCodeSegLine (CS, "ldy #$%02X", offs & 0xFF);
1563 AddCodeSegLine (CS, "clc");
1564 AddCodeSegLine (CS, "adc (sp),y");
1565 AddCodeSegLine (CS, "pha");
1566 AddCodeSegLine (CS, "txa");
1567 AddCodeSegLine (CS, "iny");
1568 AddCodeSegLine (CS, "adc (sp),y");
1569 AddCodeSegLine (CS, "tax");
1570 AddCodeSegLine (CS, "pla");
1574 /* Do it the old way */
1576 g_getlocal (flags, offs);
1588 void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
1589 /* Add a static variable to ax */
1591 /* Create the correct label name */
1592 char* lbuf = GetLabelName (flags, label, offs);
1594 switch (flags & CF_TYPE) {
1597 AddCodeSegLine (CS, "clc");
1598 AddCodeSegLine (CS, "adc %s", lbuf);
1599 AddCodeSegLine (CS, "bcc *+3");
1600 AddCodeSegLine (CS, "inx");
1601 AddCodeHint ("x:!");
1605 AddCodeSegLine (CS, "clc");
1606 AddCodeSegLine (CS, "adc %s", lbuf);
1607 AddCodeSegLine (CS, "tay");
1608 AddCodeSegLine (CS, "txa");
1609 AddCodeSegLine (CS, "adc %s+1", lbuf);
1610 AddCodeSegLine (CS, "tax");
1611 AddCodeSegLine (CS, "tya");
1615 /* Do it the old way */
1617 g_getstatic (flags, label, offs);
1629 /*****************************************************************************/
1630 /* Compares of ax with a variable with fixed address */
1631 /*****************************************************************************/
1635 void g_cmplocal (unsigned flags, int offs)
1636 /* Compare a local variable to ax */
1638 Internal ("g_cmplocal not implemented");
1643 void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
1644 /* Compare a static variable to ax */
1646 Internal ("g_cmpstatic not implemented");
1651 /*****************************************************************************/
1652 /* Special op= functions */
1653 /*****************************************************************************/
1657 void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
1659 /* Emit += for a static variable */
1661 /* Create the correct label name */
1662 char* lbuf = GetLabelName (flags, label, offs);
1664 /* Check the size and determine operation */
1665 switch (flags & CF_TYPE) {
1668 if (flags & CF_FORCECHAR) {
1669 AddCodeSegLine (CS, "ldx #$00");
1670 if (flags & CF_CONST) {
1672 AddCodeSegLine (CS, "inc %s", lbuf);
1673 AddCodeSegLine (CS, "lda %s", lbuf);
1675 AddCodeSegLine (CS, "lda #$%02X", (int)(val & 0xFF));
1676 AddCodeSegLine (CS, "clc");
1677 AddCodeSegLine (CS, "adc %s", lbuf);
1678 AddCodeSegLine (CS, "sta %s", lbuf);
1681 AddCodeSegLine (CS, "clc");
1682 AddCodeSegLine (CS, "adc %s", lbuf);
1683 AddCodeSegLine (CS, "sta %s", lbuf);
1685 if ((flags & CF_UNSIGNED) == 0) {
1686 AddCodeSegLine (CS, "bpl *+3");
1687 AddCodeSegLine (CS, "dex");
1688 AddCodeHint ("x:!"); /* Invalidate X */
1695 if (flags & CF_CONST) {
1697 unsigned L = GetLocalLabel ();
1698 AddCodeSegLine (CS, "inc %s", lbuf);
1699 AddCodeSegLine (CS, "bne %s", LocalLabelName (L));
1700 AddCodeSegLine (CS, "inc %s+1", lbuf);
1702 AddCodeSegLine (CS, "lda %s", lbuf); /* Hmmm... */
1703 AddCodeSegLine (CS, "ldx %s+1", lbuf);
1705 AddCodeSegLine (CS, "lda #$%02X", (int)(val & 0xFF));
1706 AddCodeSegLine (CS, "clc");
1707 AddCodeSegLine (CS, "adc %s", lbuf);
1708 AddCodeSegLine (CS, "sta %s", lbuf);
1710 unsigned L = GetLocalLabel ();
1711 AddCodeSegLine (CS, "bcc %s", LocalLabelName (L));
1712 AddCodeSegLine (CS, "inc %s+1", lbuf);
1714 AddCodeSegLine (CS, "ldx %s+1", lbuf);
1716 AddCodeSegLine (CS, "lda #$%02X", (unsigned char)(val >> 8));
1717 AddCodeSegLine (CS, "adc %s+1", lbuf);
1718 AddCodeSegLine (CS, "sta %s+1", lbuf);
1719 AddCodeSegLine (CS, "tax");
1720 AddCodeSegLine (CS, "lda %s", lbuf);
1724 AddCodeSegLine (CS, "clc");
1725 AddCodeSegLine (CS, "adc %s", lbuf);
1726 AddCodeSegLine (CS, "sta %s", lbuf);
1727 AddCodeSegLine (CS, "txa");
1728 AddCodeSegLine (CS, "adc %s+1", lbuf);
1729 AddCodeSegLine (CS, "sta %s+1", lbuf);
1730 AddCodeSegLine (CS, "tax");
1731 AddCodeSegLine (CS, "lda %s", lbuf);
1736 if (flags & CF_CONST) {
1738 AddCodeSegLine (CS, "ldy #<(%s)", lbuf);
1739 AddCodeSegLine (CS, "sty ptr1");
1740 AddCodeSegLine (CS, "ldy #>(%s+1)", lbuf);
1742 AddCodeSegLine (CS, "jsr laddeq1");
1744 AddCodeSegLine (CS, "lda #$%02X", (int)(val & 0xFF));
1745 AddCodeSegLine (CS, "jsr laddeqa");
1748 g_getstatic (flags, label, offs);
1750 g_putstatic (flags, label, offs);
1753 AddCodeSegLine (CS, "ldy #<(%s)", lbuf);
1754 AddCodeSegLine (CS, "sty ptr1");
1755 AddCodeSegLine (CS, "ldy #>(%s+1)", lbuf);
1756 AddCodeSegLine (CS, "jsr laddeq");
1767 void g_addeqlocal (unsigned flags, int offs, unsigned long val)
1768 /* Emit += for a local variable */
1770 /* Calculate the true offset, check it, load it into Y */
1772 CheckLocalOffs (offs);
1774 /* Check the size and determine operation */
1775 switch (flags & CF_TYPE) {
1778 if (flags & CF_FORCECHAR) {
1780 AddCodeSegLine (CS, "ldx #$00");
1781 if (flags & CF_CONST) {
1782 AddCodeSegLine (CS, "clc");
1783 AddCodeSegLine (CS, "lda #$%02X", (int)(val & 0xFF));
1784 AddCodeSegLine (CS, "adc (sp,x)");
1785 AddCodeSegLine (CS, "sta (sp,x)");
1787 AddCodeSegLine (CS, "clc");
1788 AddCodeSegLine (CS, "adc (sp,x)");
1789 AddCodeSegLine (CS, "sta (sp,x)");
1793 AddCodeSegLine (CS, "ldx #$00");
1794 if (flags & CF_CONST) {
1795 AddCodeSegLine (CS, "clc");
1796 AddCodeSegLine (CS, "lda #$%02X", (int)(val & 0xFF));
1797 AddCodeSegLine (CS, "adc (sp),y");
1798 AddCodeSegLine (CS, "sta (sp),y");
1800 AddCodeSegLine (CS, "clc");
1801 AddCodeSegLine (CS, "adc (sp),y");
1802 AddCodeSegLine (CS, "sta (sp),y");
1805 if ((flags & CF_UNSIGNED) == 0) {
1806 AddCodeSegLine (CS, "bpl *+3");
1807 AddCodeSegLine (CS, "dex");
1808 AddCodeHint ("x:!"); /* Invalidate X */
1815 if (flags & CF_CONST) {
1816 g_getimmed (flags, val, 0);
1819 AddCodeSegLine (CS, "jsr addeq0sp");
1822 AddCodeSegLine (CS, "jsr addeqysp");
1827 if (flags & CF_CONST) {
1828 g_getimmed (flags, val, 0);
1831 AddCodeSegLine (CS, "jsr laddeq0sp");
1834 AddCodeSegLine (CS, "jsr laddeqysp");
1845 void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
1846 /* Emit += for the location with address in ax */
1848 /* If the offset is too large for a byte register, add the high byte
1849 * of the offset to the primary. Beware: We need a special correction
1850 * if the offset in the low byte will overflow in the operation.
1852 offs = MakeByteOffs (flags, offs);
1854 /* Check the size and determine operation */
1855 switch (flags & CF_TYPE) {
1858 AddCodeSegLine (CS, "sta ptr1");
1859 AddCodeSegLine (CS, "stx ptr1+1");
1861 AddCodeSegLine (CS, "ldx #$00");
1862 AddCodeSegLine (CS, "lda #$%02X", (int)(val & 0xFF));
1863 AddCodeSegLine (CS, "clc");
1864 AddCodeSegLine (CS, "adc (ptr1,x)");
1865 AddCodeSegLine (CS, "sta (ptr1,x)");
1867 AddCodeSegLine (CS, "ldy #$%02X", offs);
1868 AddCodeSegLine (CS, "ldx #$00");
1869 AddCodeSegLine (CS, "lda #$%02X", (int)(val & 0xFF));
1870 AddCodeSegLine (CS, "clc");
1871 AddCodeSegLine (CS, "adc (ptr1),y");
1872 AddCodeSegLine (CS, "sta (ptr1),y");
1877 if (CodeSizeFactor >= 200) {
1878 /* Lots of code, use only if size is not important */
1879 AddCodeSegLine (CS, "sta ptr1");
1880 AddCodeSegLine (CS, "stx ptr1+1");
1881 AddCodeSegLine (CS, "ldy #$%02X", offs);
1882 AddCodeSegLine (CS, "lda #$%02X", (int)(val & 0xFF));
1883 AddCodeSegLine (CS, "clc");
1884 AddCodeSegLine (CS, "adc (ptr1),y");
1885 AddCodeSegLine (CS, "sta (ptr1),y");
1886 AddCodeSegLine (CS, "pha");
1887 AddCodeSegLine (CS, "iny");
1888 AddCodeSegLine (CS, "lda #$%02X", (unsigned char)(val >> 8));
1889 AddCodeSegLine (CS, "adc (ptr1),y");
1890 AddCodeSegLine (CS, "sta (ptr1),y");
1891 AddCodeSegLine (CS, "tax");
1892 AddCodeSegLine (CS, "pla");
1898 AddCodeSegLine (CS, "jsr pushax"); /* Push the address */
1899 push (flags); /* Correct the internal sp */
1900 g_getind (flags, offs); /* Fetch the value */
1901 g_inc (flags, val); /* Increment value in primary */
1902 g_putind (flags, offs); /* Store the value back */
1912 void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
1914 /* Emit -= for a static variable */
1916 /* Create the correct label name */
1917 char* lbuf = GetLabelName (flags, label, offs);
1919 /* Check the size and determine operation */
1920 switch (flags & CF_TYPE) {
1923 if (flags & CF_FORCECHAR) {
1924 AddCodeSegLine (CS, "ldx #$00");
1925 if (flags & CF_CONST) {
1927 AddCodeSegLine (CS, "dec %s", lbuf);
1928 AddCodeSegLine (CS, "lda %s", lbuf);
1930 AddCodeSegLine (CS, "sec");
1931 AddCodeSegLine (CS, "lda %s", lbuf);
1932 AddCodeSegLine (CS, "sbc #$%02X", (int)(val & 0xFF));
1933 AddCodeSegLine (CS, "sta %s", lbuf);
1936 AddCodeSegLine (CS, "sec");
1937 AddCodeSegLine (CS, "sta tmp1");
1938 AddCodeSegLine (CS, "lda %s", lbuf);
1939 AddCodeSegLine (CS, "sbc tmp1");
1940 AddCodeSegLine (CS, "sta %s", lbuf);
1942 if ((flags & CF_UNSIGNED) == 0) {
1943 AddCodeSegLine (CS, "bpl *+3");
1944 AddCodeSegLine (CS, "dex");
1945 AddCodeHint ("x:!"); /* Invalidate X */
1952 AddCodeSegLine (CS, "sec");
1953 if (flags & CF_CONST) {
1954 AddCodeSegLine (CS, "lda %s", lbuf);
1955 AddCodeSegLine (CS, "sbc #$%02X", (unsigned char)val);
1956 AddCodeSegLine (CS, "sta %s", lbuf);
1958 unsigned L = GetLocalLabel ();
1959 AddCodeSegLine (CS, "bcs %s", LocalLabelName (L));
1960 AddCodeSegLine (CS, "dec %s+1", lbuf);
1962 AddCodeSegLine (CS, "ldx %s+1", lbuf);
1964 AddCodeSegLine (CS, "lda %s+1", lbuf);
1965 AddCodeSegLine (CS, "sbc #$%02X", (unsigned char)(val >> 8));
1966 AddCodeSegLine (CS, "sta %s+1", lbuf);
1967 AddCodeSegLine (CS, "tax");
1968 AddCodeSegLine (CS, "lda %s", lbuf);
1971 AddCodeSegLine (CS, "sta tmp1");
1972 AddCodeSegLine (CS, "lda %s", lbuf);
1973 AddCodeSegLine (CS, "sbc tmp1");
1974 AddCodeSegLine (CS, "sta %s", lbuf);
1975 AddCodeSegLine (CS, "stx tmp1");
1976 AddCodeSegLine (CS, "lda %s+1", lbuf);
1977 AddCodeSegLine (CS, "sbc tmp1");
1978 AddCodeSegLine (CS, "sta %s+1", lbuf);
1979 AddCodeSegLine (CS, "tax");
1980 AddCodeSegLine (CS, "lda %s", lbuf);
1985 if (flags & CF_CONST) {
1987 AddCodeSegLine (CS, "ldy #<(%s)", lbuf);
1988 AddCodeSegLine (CS, "sty ptr1");
1989 AddCodeSegLine (CS, "ldy #>(%s+1)", lbuf);
1991 AddCodeSegLine (CS, "jsr lsubeq1");
1993 AddCodeSegLine (CS, "lda #$%02X", (unsigned char)val);
1994 AddCodeSegLine (CS, "jsr lsubeqa");
1997 g_getstatic (flags, label, offs);
1999 g_putstatic (flags, label, offs);
2002 AddCodeSegLine (CS, "ldy #<(%s)", lbuf);
2003 AddCodeSegLine (CS, "sty ptr1");
2004 AddCodeSegLine (CS, "ldy #>(%s+1)", lbuf);
2005 AddCodeSegLine (CS, "jsr lsubeq");
2016 void g_subeqlocal (unsigned flags, int offs, unsigned long val)
2017 /* Emit -= for a local variable */
2019 /* Calculate the true offset, check it, load it into Y */
2021 CheckLocalOffs (offs);
2023 /* Check the size and determine operation */
2024 switch (flags & CF_TYPE) {
2027 if (flags & CF_FORCECHAR) {
2029 AddCodeSegLine (CS, "ldx #$00");
2030 AddCodeSegLine (CS, "sec");
2031 if (flags & CF_CONST) {
2032 AddCodeSegLine (CS, "lda (sp),y");
2033 AddCodeSegLine (CS, "sbc #$%02X", (unsigned char)val);
2035 AddCodeSegLine (CS, "sta tmp1");
2036 AddCodeSegLine (CS, "lda (sp),y");
2037 AddCodeSegLine (CS, "sbc tmp1");
2039 AddCodeSegLine (CS, "sta (sp),y");
2040 if ((flags & CF_UNSIGNED) == 0) {
2041 AddCodeSegLine (CS, "bpl *+3");
2042 AddCodeSegLine (CS, "dex");
2043 AddCodeHint ("x:!"); /* Invalidate X */
2050 if (flags & CF_CONST) {
2051 g_getimmed (flags, val, 0);
2054 AddCodeSegLine (CS, "jsr subeq0sp");
2057 AddCodeSegLine (CS, "jsr subeqysp");
2062 if (flags & CF_CONST) {
2063 g_getimmed (flags, val, 0);
2066 AddCodeSegLine (CS, "jsr lsubeq0sp");
2069 AddCodeSegLine (CS, "jsr lsubeqysp");
2080 void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
2081 /* Emit -= for the location with address in ax */
2083 /* If the offset is too large for a byte register, add the high byte
2084 * of the offset to the primary. Beware: We need a special correction
2085 * if the offset in the low byte will overflow in the operation.
2087 offs = MakeByteOffs (flags, offs);
2089 /* Check the size and determine operation */
2090 switch (flags & CF_TYPE) {
2093 AddCodeSegLine (CS, "sta ptr1");
2094 AddCodeSegLine (CS, "stx ptr1+1");
2096 AddCodeSegLine (CS, "ldx #$00");
2097 AddCodeSegLine (CS, "lda (ptr1,x)");
2098 AddCodeSegLine (CS, "sec");
2099 AddCodeSegLine (CS, "sbc #$%02X", (unsigned char)val);
2100 AddCodeSegLine (CS, "sta (ptr1,x)");
2102 AddCodeSegLine (CS, "ldy #$%02X", offs);
2103 AddCodeSegLine (CS, "ldx #$00");
2104 AddCodeSegLine (CS, "lda (ptr1),y");
2105 AddCodeSegLine (CS, "sec");
2106 AddCodeSegLine (CS, "sbc #$%02X", (unsigned char)val);
2107 AddCodeSegLine (CS, "sta (ptr1),y");
2112 if (CodeSizeFactor >= 200) {
2113 /* Lots of code, use only if size is not important */
2114 AddCodeSegLine (CS, "sta ptr1");
2115 AddCodeSegLine (CS, "stx ptr1+1");
2116 AddCodeSegLine (CS, "ldy #$%02X", offs);
2117 AddCodeSegLine (CS, "lda (ptr1),y");
2118 AddCodeSegLine (CS, "sec");
2119 AddCodeSegLine (CS, "sbc #$%02X", (unsigned char)val);
2120 AddCodeSegLine (CS, "sta (ptr1),y");
2121 AddCodeSegLine (CS, "pha");
2122 AddCodeSegLine (CS, "iny");
2123 AddCodeSegLine (CS, "lda (ptr1),y");
2124 AddCodeSegLine (CS, "sbc #$%02X", (unsigned char)(val >> 8));
2125 AddCodeSegLine (CS, "sta (ptr1),y");
2126 AddCodeSegLine (CS, "tax");
2127 AddCodeSegLine (CS, "pla");
2133 AddCodeSegLine (CS, "jsr pushax"); /* Push the address */
2134 push (flags); /* Correct the internal sp */
2135 g_getind (flags, offs); /* Fetch the value */
2136 g_dec (flags, val); /* Increment value in primary */
2137 g_putind (flags, offs); /* Store the value back */
2147 /*****************************************************************************/
2148 /* Add a variable address to the value in ax */
2149 /*****************************************************************************/
2153 void g_addaddr_local (unsigned flags, int offs)
2154 /* Add the address of a local variable to ax */
2156 /* Add the offset */
2159 /* We cannot address more then 256 bytes of locals anyway */
2160 CheckLocalOffs (offs);
2161 AddCodeSegLine (CS, "clc");
2162 AddCodeSegLine (CS, "adc #$%02X", offs & 0xFF);
2163 AddCodeSegLine (CS, "bcc *+4"); /* Do also skip the CLC insn below */
2164 AddCodeSegLine (CS, "inx");
2165 AddCodeHint ("x:!"); /* Invalidate X */
2168 /* Add the current stackpointer value */
2169 AddCodeSegLine (CS, "clc");
2170 AddCodeSegLine (CS, "adc sp");
2171 AddCodeSegLine (CS, "tay");
2172 AddCodeSegLine (CS, "txa");
2173 AddCodeSegLine (CS, "adc sp+1");
2174 AddCodeSegLine (CS, "tax");
2175 AddCodeSegLine (CS, "tya");
2180 void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
2181 /* Add the address of a static variable to ax */
2183 /* Create the correct label name */
2184 char* lbuf = GetLabelName (flags, label, offs);
2186 /* Add the address to the current ax value */
2187 AddCodeSegLine (CS, "clc");
2188 AddCodeSegLine (CS, "adc #<(%s)", lbuf);
2189 AddCodeSegLine (CS, "tay");
2190 AddCodeSegLine (CS, "txa");
2191 AddCodeSegLine (CS, "adc #>(%s)", lbuf);
2192 AddCodeSegLine (CS, "tax");
2193 AddCodeSegLine (CS, "tya");
2198 /*****************************************************************************/
2200 /*****************************************************************************/
2204 void g_save (unsigned flags)
2205 /* Copy primary register to hold register. */
2207 /* Check the size and determine operation */
2208 switch (flags & CF_TYPE) {
2211 if (flags & CF_FORCECHAR) {
2212 AddCodeSegLine (CS, "pha");
2218 AddCodeSegLine (CS, "sta regsave");
2219 AddCodeSegLine (CS, "stx regsave+1");
2223 AddCodeSegLine (CS, "jsr saveeax");
2233 void g_restore (unsigned flags)
2234 /* Copy hold register to primary. */
2236 /* Check the size and determine operation */
2237 switch (flags & CF_TYPE) {
2240 if (flags & CF_FORCECHAR) {
2241 AddCodeSegLine (CS, "pla");
2247 AddCodeSegLine (CS, "lda regsave");
2248 AddCodeSegLine (CS, "ldx regsave+1");
2252 AddCodeSegLine (CS, "jsr resteax");
2262 void g_cmp (unsigned flags, unsigned long val)
2263 /* Immidiate compare. The primary register will not be changed, Z flag
2267 /* Check the size and determine operation */
2268 switch (flags & CF_TYPE) {
2271 if (flags & CF_FORCECHAR) {
2272 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
2278 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
2279 AddCodeSegLine (CS, "bne *+4");
2280 AddCodeSegLine (CS, "cpx #$%02X", (unsigned char)(val >> 8));
2284 Internal ("g_cmp: Long compares not implemented");
2294 static void oper (unsigned flags, unsigned long val, char** subs)
2295 /* Encode a binary operation. subs is a pointer to four groups of three
2297 * 0-2 --> Operate on ints
2298 * 3-5 --> Operate on unsigneds
2299 * 6-8 --> Operate on longs
2300 * 9-11 --> Operate on unsigned longs
2302 * The first subroutine names in each string group is used to encode an
2303 * operation with a zero constant, the second to encode an operation with
2304 * a 8 bit constant, and the third is used in all other cases.
2309 /* Determine the offset into the array */
2310 offs = (flags & CF_UNSIGNED)? 3 : 0;
2311 switch (flags & CF_TYPE) {
2324 /* Encode the operation */
2325 if (flags & CF_CONST) {
2326 /* Constant value given */
2327 if (val == 0 && subs [offs+0]) {
2328 /* Special case: constant with value zero */
2329 AddCodeSegLine (CS, "jsr %s", subs [offs+0]);
2330 } else if (val < 0x100 && subs [offs+1]) {
2331 /* Special case: constant with high byte zero */
2332 ldaconst (val); /* Load low byte */
2333 AddCodeSegLine (CS, "jsr %s", subs [offs+1]);
2335 /* Others: arbitrary constant value */
2336 g_getimmed (flags, val, 0); /* Load value */
2337 AddCodeSegLine (CS, "jsr %s", subs [offs+2]);
2340 /* Value not constant (is already in (e)ax) */
2341 AddCodeSegLine (CS, "jsr %s", subs [offs+2]);
2344 /* The operation will pop it's argument */
2350 void g_test (unsigned flags)
2351 /* Test the value in the primary and set the condition codes */
2353 switch (flags & CF_TYPE) {
2356 if (flags & CF_FORCECHAR) {
2357 AddCodeSegLine (CS, "tax");
2363 AddCodeSegLine (CS, "stx tmp1");
2364 AddCodeSegLine (CS, "ora tmp1");
2368 if (flags & CF_UNSIGNED) {
2369 AddCodeSegLine (CS, "jsr utsteax");
2371 AddCodeSegLine (CS, "jsr tsteax");
2383 void g_push (unsigned flags, unsigned long val)
2384 /* Push the primary register or a constant value onto the stack */
2388 if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
2390 /* We have a constant 8 or 16 bit value */
2391 if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
2393 /* Handle as 8 bit value */
2394 if (CodeSizeFactor >= 165 || val > 2) {
2396 AddCodeSegLine (CS, "jsr pusha");
2398 AddCodeSegLine (CS, "jsr pushc%d", (int) val);
2403 /* Handle as 16 bit value */
2404 hi = (unsigned char) (val >> 8);
2406 AddCodeSegLine (CS, "jsr push%u", (unsigned) val);
2407 } else if (hi == 0 || hi == 0xFF) {
2408 /* Use special function */
2410 AddCodeSegLine (CS, "jsr %s", (hi == 0)? "pusha0" : "pushaFF");
2413 g_getimmed (flags, val, 0);
2414 AddCodeSegLine (CS, "jsr pushax");
2420 /* Value is not 16 bit or not constant */
2421 if (flags & CF_CONST) {
2422 /* Constant 32 bit value, load into eax */
2423 g_getimmed (flags, val, 0);
2426 /* Push the primary register */
2427 switch (flags & CF_TYPE) {
2430 if (flags & CF_FORCECHAR) {
2431 /* Handle as char */
2432 AddCodeSegLine (CS, "jsr pusha");
2437 AddCodeSegLine (CS, "jsr pushax");
2441 AddCodeSegLine (CS, "jsr pusheax");
2451 /* Adjust the stack offset */
2457 void g_swap (unsigned flags)
2458 /* Swap the primary register and the top of the stack. flags give the type
2459 * of *both* values (must have same size).
2462 switch (flags & CF_TYPE) {
2466 AddCodeSegLine (CS, "jsr swapstk");
2470 AddCodeSegLine (CS, "jsr swapestk");
2481 void g_call (unsigned Flags, const char* Label, unsigned ArgSize)
2482 /* Call the specified subroutine name */
2484 if ((Flags & CF_FIXARGC) == 0) {
2485 /* Pass the argument count */
2488 AddCodeSegLine (CS, "jsr _%s", Label);
2489 oursp += ArgSize; /* callee pops args */
2494 void g_callind (unsigned Flags, unsigned ArgSize)
2495 /* Call subroutine with address in AX */
2497 if ((Flags & CF_FIXARGC) == 0) {
2498 /* Pass arg count */
2501 AddCodeSegLine (CS, "jsr callax"); /* do the call */
2502 oursp += ArgSize; /* callee pops args */
2507 void g_jump (unsigned Label)
2508 /* Jump to specified internal label number */
2510 AddCodeSegLine (CS, "jmp %s", LocalLabelName (Label));
2515 void g_switch (unsigned Flags)
2516 /* Output switch statement preamble */
2518 switch (Flags & CF_TYPE) {
2522 AddCodeSegLine (CS, "jsr switch");
2526 AddCodeSegLine (CS, "jsr lswitch");
2537 void g_case (unsigned flags, unsigned label, unsigned long val)
2538 /* Create table code for one case selector */
2540 switch (flags & CF_TYPE) {
2544 AddCodeSegLine (CS, ".word $%04X, %s",
2545 (unsigned)(val & 0xFFFF),
2546 LocalLabelName (label));
2550 AddCodeSegLine (CS, ".dword $%08lX", val);
2551 AddCodeSegLine (CS, ".word %s", LocalLabelName (label));
2562 void g_truejump (unsigned flags, unsigned label)
2563 /* Jump to label if zero flag clear */
2565 AddCodeSegLine (CS, "jne %s", LocalLabelName (label));
2570 void g_falsejump (unsigned flags, unsigned label)
2571 /* Jump to label if zero flag set */
2573 AddCodeSegLine (CS, "jeq %s", LocalLabelName (label));
2578 static void mod_internal (int k, char* verb1, char* verb2)
2581 AddCodeSegLine (CS, "jsr %ssp%c", verb1, k + '0');
2585 AddCodeSegLine (CS, "jsr %ssp", verb2);
2591 void g_space (int space)
2592 /* Create or drop space on the stack */
2595 mod_internal (-space, "inc", "addy");
2596 } else if (space > 0) {
2597 mod_internal (space, "dec", "suby");
2603 void g_cstackcheck (void)
2604 /* Check for a C stack overflow */
2606 AddCodeSegLine (CS, "jsr cstkchk");
2611 void g_stackcheck (void)
2612 /* Check for a stack overflow */
2614 AddCodeSegLine (CS, "jsr stkchk");
2619 void g_add (unsigned flags, unsigned long val)
2620 /* Primary = TOS + Primary */
2622 static char* ops [12] = {
2623 0, "tosadda0", "tosaddax",
2624 0, "tosadda0", "tosaddax",
2629 if (flags & CF_CONST) {
2630 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2631 g_push (flags & ~CF_CONST, 0);
2633 oper (flags, val, ops);
2638 void g_sub (unsigned flags, unsigned long val)
2639 /* Primary = TOS - Primary */
2641 static char* ops [12] = {
2642 0, "tossuba0", "tossubax",
2643 0, "tossuba0", "tossubax",
2648 if (flags & CF_CONST) {
2649 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2650 g_push (flags & ~CF_CONST, 0);
2652 oper (flags, val, ops);
2657 void g_rsub (unsigned flags, unsigned long val)
2658 /* Primary = Primary - TOS */
2660 static char* ops [12] = {
2661 0, "tosrsuba0", "tosrsubax",
2662 0, "tosrsuba0", "tosrsubax",
2666 oper (flags, val, ops);
2671 void g_mul (unsigned flags, unsigned long val)
2672 /* Primary = TOS * Primary */
2674 static char* ops [12] = {
2675 0, "tosmula0", "tosmulax",
2676 0, "tosumula0", "tosumulax",
2683 /* Do strength reduction if the value is constant and a power of two */
2684 if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
2685 /* Generate a shift instead */
2690 /* If the right hand side is const, the lhs is not on stack but still
2691 * in the primary register.
2693 if (flags & CF_CONST) {
2695 switch (flags & CF_TYPE) {
2698 if (flags & CF_FORCECHAR) {
2699 /* Handle some special cases */
2703 AddCodeSegLine (CS, "sta tmp1");
2704 AddCodeSegLine (CS, "asl a");
2705 AddCodeSegLine (CS, "clc");
2706 AddCodeSegLine (CS, "adc tmp1");
2710 AddCodeSegLine (CS, "sta tmp1");
2711 AddCodeSegLine (CS, "asl a");
2712 AddCodeSegLine (CS, "asl a");
2713 AddCodeSegLine (CS, "clc");
2714 AddCodeSegLine (CS, "adc tmp1");
2718 AddCodeSegLine (CS, "sta tmp1");
2719 AddCodeSegLine (CS, "asl a");
2720 AddCodeSegLine (CS, "asl a");
2721 AddCodeSegLine (CS, "clc");
2722 AddCodeSegLine (CS, "adc tmp1");
2723 AddCodeSegLine (CS, "asl a");
2739 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2740 * into the normal, non-optimized stuff.
2742 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2743 g_push (flags & ~CF_CONST, 0);
2747 /* Use long way over the stack */
2748 oper (flags, val, ops);
2753 void g_div (unsigned flags, unsigned long val)
2754 /* Primary = TOS / Primary */
2756 static char* ops [12] = {
2757 0, "tosdiva0", "tosdivax",
2758 0, "tosudiva0", "tosudivax",
2763 /* Do strength reduction if the value is constant and a power of two */
2765 if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
2766 /* Generate a shift instead */
2769 /* Generate a division */
2770 if (flags & CF_CONST) {
2771 /* lhs is not on stack */
2772 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2773 g_push (flags & ~CF_CONST, 0);
2775 oper (flags, val, ops);
2781 void g_mod (unsigned flags, unsigned long val)
2782 /* Primary = TOS % Primary */
2784 static char* ops [12] = {
2785 0, "tosmoda0", "tosmodax",
2786 0, "tosumoda0", "tosumodax",
2792 /* Check if we can do some cost reduction */
2793 if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
2794 /* We can do that with an AND operation */
2795 g_and (flags, val - 1);
2797 /* Do it the hard way... */
2798 if (flags & CF_CONST) {
2799 /* lhs is not on stack */
2800 flags &= ~CF_FORCECHAR; /* Handle chars as ints */
2801 g_push (flags & ~CF_CONST, 0);
2803 oper (flags, val, ops);
2809 void g_or (unsigned flags, unsigned long val)
2810 /* Primary = TOS | Primary */
2812 static char* ops [12] = {
2813 0, "tosora0", "tosorax",
2814 0, "tosora0", "tosorax",
2819 /* If the right hand side is const, the lhs is not on stack but still
2820 * in the primary register.
2822 if (flags & CF_CONST) {
2824 switch (flags & CF_TYPE) {
2827 if (flags & CF_FORCECHAR) {
2828 if ((val & 0xFF) != 0xFF) {
2829 AddCodeSegLine (CS, "ora #$%02X", (unsigned char)val);
2837 AddCodeSegLine (CS, "ora #$%02X", (unsigned char)val);
2844 AddCodeSegLine (CS, "ora #$%02X", (unsigned char)val);
2853 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2854 * into the normal, non-optimized stuff.
2856 g_push (flags & ~CF_CONST, 0);
2860 /* Use long way over the stack */
2861 oper (flags, val, ops);
2866 void g_xor (unsigned flags, unsigned long val)
2867 /* Primary = TOS ^ Primary */
2869 static char* ops [12] = {
2870 0, "tosxora0", "tosxorax",
2871 0, "tosxora0", "tosxorax",
2877 /* If the right hand side is const, the lhs is not on stack but still
2878 * in the primary register.
2880 if (flags & CF_CONST) {
2882 switch (flags & CF_TYPE) {
2885 if (flags & CF_FORCECHAR) {
2886 if ((val & 0xFF) != 0) {
2887 AddCodeSegLine (CS, "eor #$%02X", (unsigned char)val);
2896 AddCodeSegLine (CS, "eor #$%02X", (unsigned char)val);
2899 } else if ((val & 0xFF) == 0) {
2900 AddCodeSegLine (CS, "pha");
2901 AddCodeSegLine (CS, "txa");
2902 AddCodeSegLine (CS, "eor #$%02X", (unsigned char)(val >> 8));
2903 AddCodeSegLine (CS, "tax");
2904 AddCodeSegLine (CS, "pla");
2912 AddCodeSegLine (CS, "eor #$%02X", (unsigned char)val);
2922 /* If we go here, we didn't emit code. Push the lhs on stack and fall
2923 * into the normal, non-optimized stuff.
2925 g_push (flags & ~CF_CONST, 0);
2929 /* Use long way over the stack */
2930 oper (flags, val, ops);
2935 void g_and (unsigned flags, unsigned long val)
2936 /* Primary = TOS & Primary */
2938 static char* ops [12] = {
2939 0, "tosanda0", "tosandax",
2940 0, "tosanda0", "tosandax",
2945 /* If the right hand side is const, the lhs is not on stack but still
2946 * in the primary register.
2948 if (flags & CF_CONST) {
2950 switch (flags & CF_TYPE) {
2953 if (flags & CF_FORCECHAR) {
2954 AddCodeSegLine (CS, "and #$%02X", (unsigned char)val);
2959 if ((val & 0xFFFF) != 0xFFFF) {
2964 } else if (val != 0xFF) {
2965 AddCodeSegLine (CS, "and #$%02X", (unsigned char)val);
2967 } else if ((val & 0xFF00) == 0xFF00) {
2968 AddCodeSegLine (CS, "and #$%02X", (unsigned char)val);
2969 } else if ((val & 0x00FF) == 0x0000) {
2970 AddCodeSegLine (CS, "txa");
2971 AddCodeSegLine (CS, "and #$%02X", (unsigned char)(val >> 8));
2972 AddCodeSegLine (CS, "tax");
2975 AddCodeSegLine (CS, "tay");
2976 AddCodeSegLine (CS, "txa");
2977 AddCodeSegLine (CS, "and #$%02X", (unsigned char)(val >> 8));
2978 AddCodeSegLine (CS, "tax");
2979 AddCodeSegLine (CS, "tya");
2980 if ((val & 0x00FF) != 0x00FF) {
2981 AddCodeSegLine (CS, "and #$%02X", (unsigned char)val);
2990 AddCodeSegLine (CS, "stx sreg+1");
2991 AddCodeSegLine (CS, "stx sreg");
2992 if ((val & 0xFF) != 0xFF) {
2993 AddCodeSegLine (CS, "and #$%02X", (unsigned char)val);
2996 } else if (val == 0xFF00) {
2998 AddCodeSegLine (CS, "sta sreg+1");
2999 AddCodeSegLine (CS, "sta sreg");
3008 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3009 * into the normal, non-optimized stuff.
3011 g_push (flags & ~CF_CONST, 0);
3015 /* Use long way over the stack */
3016 oper (flags, val, ops);
3021 void g_asr (unsigned flags, unsigned long val)
3022 /* Primary = TOS >> Primary */
3024 static char* ops [12] = {
3025 0, "tosasra0", "tosasrax",
3026 0, "tosshra0", "tosshrax",
3031 /* If the right hand side is const, the lhs is not on stack but still
3032 * in the primary register.
3034 if (flags & CF_CONST) {
3036 switch (flags & CF_TYPE) {
3040 if (val >= 1 && val <= 3) {
3041 if (flags & CF_UNSIGNED) {
3042 AddCodeSegLine (CS, "jsr shrax%ld", val);
3044 AddCodeSegLine (CS, "jsr asrax%ld", val);
3047 } else if (val == 8 && (flags & CF_UNSIGNED)) {
3048 AddCodeSegLine (CS, "txa");
3055 if (val >= 1 && val <= 3) {
3056 if (flags & CF_UNSIGNED) {
3057 AddCodeSegLine (CS, "jsr shreax%ld", val);
3059 AddCodeSegLine (CS, "jsr asreax%ld", val);
3062 } else if (val == 8 && (flags & CF_UNSIGNED)) {
3063 AddCodeSegLine (CS, "txa");
3064 AddCodeSegLine (CS, "ldx sreg");
3065 AddCodeSegLine (CS, "ldy sreg+1");
3066 AddCodeSegLine (CS, "sty sreg");
3067 AddCodeSegLine (CS, "ldy #$00");
3068 AddCodeSegLine (CS, "sty sreg+1");
3070 } else if (val == 16) {
3071 AddCodeSegLine (CS, "ldy #$00");
3072 AddCodeSegLine (CS, "ldx sreg+1");
3073 if ((flags & CF_UNSIGNED) == 0) {
3074 AddCodeSegLine (CS, "bpl *+3");
3075 AddCodeSegLine (CS, "dey");
3076 AddCodeHint ("y:!");
3078 AddCodeSegLine (CS, "lda sreg");
3079 AddCodeSegLine (CS, "sty sreg+1");
3080 AddCodeSegLine (CS, "sty sreg");
3089 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3090 * into the normal, non-optimized stuff.
3092 g_push (flags & ~CF_CONST, 0);
3096 /* Use long way over the stack */
3097 oper (flags, val, ops);
3102 void g_asl (unsigned flags, unsigned long val)
3103 /* Primary = TOS << Primary */
3105 static char* ops [12] = {
3106 0, "tosasla0", "tosaslax",
3107 0, "tosshla0", "tosshlax",
3113 /* If the right hand side is const, the lhs is not on stack but still
3114 * in the primary register.
3116 if (flags & CF_CONST) {
3118 switch (flags & CF_TYPE) {
3122 if (val >= 1 && val <= 3) {
3123 if (flags & CF_UNSIGNED) {
3124 AddCodeSegLine (CS, "jsr shlax%ld", val);
3126 AddCodeSegLine (CS, "jsr aslax%ld", val);
3129 } else if (val == 8) {
3130 AddCodeSegLine (CS, "tax");
3131 AddCodeSegLine (CS, "lda #$00");
3137 if (val >= 1 && val <= 3) {
3138 if (flags & CF_UNSIGNED) {
3139 AddCodeSegLine (CS, "jsr shleax%ld", val);
3141 AddCodeSegLine (CS, "jsr asleax%ld", val);
3144 } else if (val == 8) {
3145 AddCodeSegLine (CS, "ldy sreg");
3146 AddCodeSegLine (CS, "sty sreg+1");
3147 AddCodeSegLine (CS, "stx sreg");
3148 AddCodeSegLine (CS, "tax");
3149 AddCodeSegLine (CS, "lda #$00");
3151 } else if (val == 16) {
3152 AddCodeSegLine (CS, "stx sreg+1");
3153 AddCodeSegLine (CS, "sta sreg");
3154 AddCodeSegLine (CS, "lda #$00");
3155 AddCodeSegLine (CS, "tax");
3164 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3165 * into the normal, non-optimized stuff.
3167 g_push (flags & ~CF_CONST, 0);
3171 /* Use long way over the stack */
3172 oper (flags, val, ops);
3177 void g_neg (unsigned flags)
3178 /* Primary = -Primary */
3180 switch (flags & CF_TYPE) {
3184 AddCodeSegLine (CS, "jsr negax");
3188 AddCodeSegLine (CS, "jsr negeax");
3198 void g_bneg (unsigned flags)
3199 /* Primary = !Primary */
3201 switch (flags & CF_TYPE) {
3204 AddCodeSegLine (CS, "jsr bnega");
3208 AddCodeSegLine (CS, "jsr bnegax");
3212 AddCodeSegLine (CS, "jsr bnegeax");
3222 void g_com (unsigned flags)
3223 /* Primary = ~Primary */
3225 switch (flags & CF_TYPE) {
3229 AddCodeSegLine (CS, "jsr complax");
3233 AddCodeSegLine (CS, "jsr compleax");
3243 void g_inc (unsigned flags, unsigned long val)
3244 /* Increment the primary register by a given number */
3246 /* Don't inc by zero */
3251 /* Generate code for the supported types */
3253 switch (flags & CF_TYPE) {
3256 if (flags & CF_FORCECHAR) {
3257 if (CPU == CPU_65C02 && val <= 2) {
3259 AddCodeSegLine (CS, "ina");
3262 AddCodeSegLine (CS, "clc");
3263 AddCodeSegLine (CS, "adc #$%02X", (unsigned char)val);
3270 if (CPU == CPU_65C02 && val == 1) {
3271 AddCodeSegLine (CS, "ina");
3272 AddCodeSegLine (CS, "bne *+3");
3273 AddCodeSegLine (CS, "inx");
3274 /* Tell the optimizer that the X register may be invalid */
3275 AddCodeHint ("x:!");
3276 } else if (CodeSizeFactor < 200) {
3279 AddCodeSegLine (CS, "jsr incax%lu", val);
3280 } else if (val <= 255) {
3282 AddCodeSegLine (CS, "jsr incaxy");
3284 g_add (flags | CF_CONST, val);
3287 /* Inline the code */
3289 if ((val & 0xFF) != 0) {
3290 AddCodeSegLine (CS, "clc");
3291 AddCodeSegLine (CS, "adc #$%02X", (unsigned char) val);
3292 AddCodeSegLine (CS, "bcc *+3");
3293 AddCodeSegLine (CS, "inx");
3294 /* Tell the optimizer that the X register may be invalid */
3295 AddCodeHint ("x:!");
3298 AddCodeSegLine (CS, "inx");
3301 AddCodeSegLine (CS, "inx");
3304 AddCodeSegLine (CS, "clc");
3305 if ((val & 0xFF) != 0) {
3306 AddCodeSegLine (CS, "adc #$%02X", (unsigned char) val);
3307 /* Tell the optimizer that the X register may be invalid */
3308 AddCodeHint ("x:!");
3310 AddCodeSegLine (CS, "pha");
3311 AddCodeSegLine (CS, "txa");
3312 AddCodeSegLine (CS, "adc #$%02X", (unsigned char) (val >> 8));
3313 AddCodeSegLine (CS, "tax");
3314 AddCodeSegLine (CS, "pla");
3322 AddCodeSegLine (CS, "jsr inceaxy");
3324 g_add (flags | CF_CONST, val);
3336 void g_dec (unsigned flags, unsigned long val)
3337 /* Decrement the primary register by a given number */
3339 /* Don't dec by zero */
3344 /* Generate code for the supported types */
3346 switch (flags & CF_TYPE) {
3349 if (flags & CF_FORCECHAR) {
3350 if (CPU == CPU_65C02 && val <= 2) {
3352 AddCodeSegLine (CS, "dea");
3355 AddCodeSegLine (CS, "sec");
3356 AddCodeSegLine (CS, "sbc #$%02X", (unsigned char)val);
3363 if (CodeSizeFactor < 200) {
3364 /* Use subroutines */
3366 AddCodeSegLine (CS, "jsr decax%d", (int) val);
3367 } else if (val <= 255) {
3369 AddCodeSegLine (CS, "jsr decaxy");
3371 g_sub (flags | CF_CONST, val);
3374 /* Inline the code */
3376 if ((val & 0xFF) != 0) {
3377 AddCodeSegLine (CS, "sec");
3378 AddCodeSegLine (CS, "sbc #$%02X", (unsigned char) val);
3379 AddCodeSegLine (CS, "bcs *+3");
3380 AddCodeSegLine (CS, "dex");
3381 /* Tell the optimizer that the X register may be invalid */
3382 AddCodeHint ("x:!");
3385 AddCodeSegLine (CS, "dex");
3388 AddCodeSegLine (CS, "dex");
3391 AddCodeSegLine (CS, "sec");
3392 if ((val & 0xFF) != 0) {
3393 AddCodeSegLine (CS, "sbc #$%02X", (unsigned char) val);
3394 /* Tell the optimizer that the X register may be invalid */
3395 AddCodeHint ("x:!");
3397 AddCodeSegLine (CS, "pha");
3398 AddCodeSegLine (CS, "txa");
3399 AddCodeSegLine (CS, "sbc #$%02X", (unsigned char) (val >> 8));
3400 AddCodeSegLine (CS, "tax");
3401 AddCodeSegLine (CS, "pla");
3409 AddCodeSegLine (CS, "jsr deceaxy");
3411 g_sub (flags | CF_CONST, val);
3424 * Following are the conditional operators. They compare the TOS against
3425 * the primary and put a literal 1 in the primary if the condition is
3426 * true, otherwise they clear the primary register
3431 void g_eq (unsigned flags, unsigned long val)
3432 /* Test for equal */
3434 static char* ops [12] = {
3435 "toseq00", "toseqa0", "toseqax",
3436 "toseq00", "toseqa0", "toseqax",
3441 /* If the right hand side is const, the lhs is not on stack but still
3442 * in the primary register.
3444 if (flags & CF_CONST) {
3446 switch (flags & CF_TYPE) {
3449 if (flags & CF_FORCECHAR) {
3450 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
3451 AddCodeSegLine (CS, "jsr booleq");
3457 AddCodeSegLine (CS, "cpx #$%02X", (unsigned char)(val >> 8));
3458 AddCodeSegLine (CS, "bne *+4");
3459 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
3460 AddCodeSegLine (CS, "jsr booleq");
3470 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3471 * into the normal, non-optimized stuff.
3473 g_push (flags & ~CF_CONST, 0);
3477 /* Use long way over the stack */
3478 oper (flags, val, ops);
3483 void g_ne (unsigned flags, unsigned long val)
3484 /* Test for not equal */
3486 static char* ops [12] = {
3487 "tosne00", "tosnea0", "tosneax",
3488 "tosne00", "tosnea0", "tosneax",
3494 /* If the right hand side is const, the lhs is not on stack but still
3495 * in the primary register.
3497 if (flags & CF_CONST) {
3499 switch (flags & CF_TYPE) {
3502 if (flags & CF_FORCECHAR) {
3503 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
3504 AddCodeSegLine (CS, "jsr boolne");
3510 AddCodeSegLine (CS, "cpx #$%02X", (unsigned char)(val >> 8));
3511 AddCodeSegLine (CS, "bne *+4");
3512 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
3513 AddCodeSegLine (CS, "jsr boolne");
3523 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3524 * into the normal, non-optimized stuff.
3526 g_push (flags & ~CF_CONST, 0);
3530 /* Use long way over the stack */
3531 oper (flags, val, ops);
3536 void g_lt (unsigned flags, unsigned long val)
3537 /* Test for less than */
3539 static char* ops [12] = {
3540 "toslt00", "toslta0", "tosltax",
3541 "tosult00", "tosulta0", "tosultax",
3546 /* If the right hand side is const, the lhs is not on stack but still
3547 * in the primary register.
3549 if (flags & CF_CONST) {
3551 /* Give a warning in some special cases */
3552 if ((flags & CF_UNSIGNED) && val == 0) {
3553 Warning ("Condition is never true");
3556 /* Look at the type */
3557 switch (flags & CF_TYPE) {
3560 if (flags & CF_FORCECHAR) {
3561 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
3562 if (flags & CF_UNSIGNED) {
3563 AddCodeSegLine (CS, "jsr boolult");
3565 AddCodeSegLine (CS, "jsr boollt");
3572 if ((flags & CF_UNSIGNED) == 0 && val == 0) {
3573 /* If we have a signed compare against zero, we only need to
3574 * test the high byte.
3576 AddCodeSegLine (CS, "txa");
3577 AddCodeSegLine (CS, "jsr boollt");
3580 /* Direct code only for unsigned data types */
3581 if (flags & CF_UNSIGNED) {
3582 AddCodeSegLine (CS, "cpx #$%02X", (unsigned char)(val >> 8));
3583 AddCodeSegLine (CS, "bne *+4");
3584 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
3585 AddCodeSegLine (CS, "jsr boolult");
3597 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3598 * into the normal, non-optimized stuff.
3600 g_push (flags & ~CF_CONST, 0);
3604 /* Use long way over the stack */
3605 oper (flags, val, ops);
3610 void g_le (unsigned flags, unsigned long val)
3611 /* Test for less than or equal to */
3613 static char* ops [12] = {
3614 "tosle00", "toslea0", "tosleax",
3615 "tosule00", "tosulea0", "tosuleax",
3621 /* If the right hand side is const, the lhs is not on stack but still
3622 * in the primary register.
3624 if (flags & CF_CONST) {
3626 /* Look at the type */
3627 switch (flags & CF_TYPE) {
3630 if (flags & CF_FORCECHAR) {
3631 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
3632 if (flags & CF_UNSIGNED) {
3633 AddCodeSegLine (CS, "jsr boolule");
3635 AddCodeSegLine (CS, "jsr boolle");
3642 if (flags & CF_UNSIGNED) {
3643 AddCodeSegLine (CS, "cpx #$%02X", (unsigned char)(val >> 8));
3644 AddCodeSegLine (CS, "bne *+4");
3645 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
3646 AddCodeSegLine (CS, "jsr boolule");
3658 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3659 * into the normal, non-optimized stuff.
3661 g_push (flags & ~CF_CONST, 0);
3665 /* Use long way over the stack */
3666 oper (flags, val, ops);
3671 void g_gt (unsigned flags, unsigned long val)
3672 /* Test for greater than */
3674 static char* ops [12] = {
3675 "tosgt00", "tosgta0", "tosgtax",
3676 "tosugt00", "tosugta0", "tosugtax",
3682 /* If the right hand side is const, the lhs is not on stack but still
3683 * in the primary register.
3685 if (flags & CF_CONST) {
3687 /* Look at the type */
3688 switch (flags & CF_TYPE) {
3691 if (flags & CF_FORCECHAR) {
3692 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
3693 if (flags & CF_UNSIGNED) {
3694 /* If we have a compare > 0, we will replace it by
3695 * != 0 here, since both are identical but the latter
3696 * is easier to optimize.
3699 AddCodeSegLine (CS, "jsr boolugt");
3701 AddCodeSegLine (CS, "jsr boolne");
3704 AddCodeSegLine (CS, "jsr boolgt");
3711 if (flags & CF_UNSIGNED) {
3712 /* If we have a compare > 0, we will replace it by
3713 * != 0 here, since both are identical but the latter
3714 * is easier to optimize.
3716 if ((val & 0xFFFF) == 0) {
3717 AddCodeSegLine (CS, "stx tmp1");
3718 AddCodeSegLine (CS, "ora tmp1");
3719 AddCodeSegLine (CS, "jsr boolne");
3721 AddCodeSegLine (CS, "cpx #$%02X", (unsigned char)(val >> 8));
3722 AddCodeSegLine (CS, "bne *+4");
3723 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
3724 AddCodeSegLine (CS, "jsr boolugt");
3737 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3738 * into the normal, non-optimized stuff.
3740 g_push (flags & ~CF_CONST, 0);
3744 /* Use long way over the stack */
3745 oper (flags, val, ops);
3750 void g_ge (unsigned flags, unsigned long val)
3751 /* Test for greater than or equal to */
3753 static char* ops [12] = {
3754 "tosge00", "tosgea0", "tosgeax",
3755 "tosuge00", "tosugea0", "tosugeax",
3761 /* If the right hand side is const, the lhs is not on stack but still
3762 * in the primary register.
3764 if (flags & CF_CONST) {
3766 /* Give a warning in some special cases */
3767 if ((flags & CF_UNSIGNED) && val == 0) {
3768 Warning ("Condition is always true");
3771 /* Look at the type */
3772 switch (flags & CF_TYPE) {
3775 if (flags & CF_FORCECHAR) {
3776 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
3777 if (flags & CF_UNSIGNED) {
3778 AddCodeSegLine (CS, "jsr booluge");
3780 AddCodeSegLine (CS, "jsr boolge");
3787 if (flags & CF_UNSIGNED) {
3788 AddCodeSegLine (CS, "cpx #$%02X", (unsigned char)(val >> 8));
3789 AddCodeSegLine (CS, "bne *+4");
3790 AddCodeSegLine (CS, "cmp #$%02X", (unsigned char)val);
3791 AddCodeSegLine (CS, "jsr booluge");
3803 /* If we go here, we didn't emit code. Push the lhs on stack and fall
3804 * into the normal, non-optimized stuff.
3806 g_push (flags & ~CF_CONST, 0);
3810 /* Use long way over the stack */
3811 oper (flags, val, ops);
3816 /*****************************************************************************/
3817 /* Allocating static storage */
3818 /*****************************************************************************/
3822 void g_res (unsigned n)
3823 /* Reserve static storage, n bytes */
3825 AddDataSegLine (DS, "\t.res\t%u,$00", n);
3830 void g_defdata (unsigned flags, unsigned long val, unsigned offs)
3831 /* Define data with the size given in flags */
3833 if (flags & CF_CONST) {
3835 /* Numeric constant */
3836 switch (flags & CF_TYPE) {
3839 AddDataSegLine (DS, "\t.byte\t$%02lX", val & 0xFF);
3843 AddDataSegLine (DS, "\t.word\t$%04lX", val & 0xFFFF);
3847 AddDataSegLine (DS, "\t.dword\t$%08lX", val & 0xFFFFFFFF);
3858 /* Create the correct label name */
3859 const char* Label = GetLabelName (flags, val, offs);
3861 /* Labels are always 16 bit */
3862 AddDataSegLine (DS, "\t.word\t%s", Label);
3869 void g_defbytes (const void* Bytes, unsigned Count)
3870 /* Output a row of bytes as a constant */
3876 /* Cast the buffer pointer */
3877 const unsigned char* Data = (const unsigned char*) Bytes;
3879 /* Output the stuff */
3882 /* How many go into this line? */
3883 if ((Chunk = Count) > 16) {
3888 /* Output one line */
3889 strcpy (Buf, "\t.byte\t");
3892 B += sprintf (B, "$%02X", *Data++);
3898 /* Output the line */
3899 AddDataSegLine (DS, Buf);
3905 void g_zerobytes (unsigned n)
3906 /* Output n bytes of data initialized with zero */
3908 AddDataSegLine (DS, "\t.res\t%u,$00", n);
3913 /*****************************************************************************/
3914 /* User supplied assembler code */
3915 /*****************************************************************************/
3919 void g_asmcode (const char* Line, int Len)
3920 /* Output one line of assembler code. If Len is greater than zero, it is used
3921 * as the maximum number of characters to use from Line.
3925 AddCodeSegLine (CS, "%.*s", Len, Line);
3927 AddCodeSegLine (CS, "%s", Line);
3933 /*****************************************************************************/
3934 /* Inlined known functions */
3935 /*****************************************************************************/
3939 void g_strlen (unsigned flags, unsigned long val, unsigned offs)
3940 /* Inline the strlen() function */
3942 /* We need a label in both cases */
3943 unsigned label = GetLocalLabel ();
3945 /* Two different encodings */
3946 if (flags & CF_CONST) {
3948 /* The address of the string is constant. Create the correct label name */
3949 char* lbuf = GetLabelName (flags, val, offs);
3951 /* Generate the strlen code */
3952 AddCodeSegLine (CS, "ldy #$FF");
3953 g_defcodelabel (label);
3954 AddCodeSegLine (CS, "iny");
3955 AddCodeSegLine (CS, "lda %s,y", lbuf);
3956 AddCodeSegLine (CS, "bne %s", LocalLabelName (label));
3957 AddCodeSegLine (CS, "tax");
3958 AddCodeSegLine (CS, "tya");
3962 /* Address not constant but in primary */
3963 if (CodeSizeFactor < 400) {
3964 /* This is too much code, so call strlen instead of inlining */
3965 AddCodeSegLine (CS, "jsr _strlen");
3967 /* Inline the function */
3968 AddCodeSegLine (CS, "sta ptr1");
3969 AddCodeSegLine (CS, "stx ptr1+1");
3970 AddCodeSegLine (CS, "ldy #$FF");
3971 g_defcodelabel (label);
3972 AddCodeSegLine (CS, "iny");
3973 AddCodeSegLine (CS, "lda (ptr1),y");
3974 AddCodeSegLine (CS, "bne %s", LocalLabelName (label));
3975 AddCodeSegLine (CS, "tax");
3976 AddCodeSegLine (CS, "tya");